Skip to content

Commit

Permalink
*: Add serial (#41)
Browse files Browse the repository at this point in the history
* SerialRecieveController

* Add serial controller and its test

* Add doc and fix some mispelling words

* Fix problems found on real board
  • Loading branch information
longfangsong committed May 12, 2024
1 parent b01fb22 commit fd22818
Show file tree
Hide file tree
Showing 9 changed files with 551 additions and 59 deletions.
86 changes: 86 additions & 0 deletions doc/Serial.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Serial

串口目前仅考虑实现 9600Hz,8N1,无流控的配置。

串口由输入部分和输出部分组成。

Todo: 支持相关异常(缓冲区空/满)和中断。

## Receive

串口的输入部分负责从外界经过 `rxWire` 接收到的数据送读取到内部环形缓冲区中。

串口的输入部分内部有大小可配置的缓冲区,`rxWire` 上接收到的数据会先存在环形缓冲区中,并异步地由内部总线读取。

可以从总线上读取状态寄存器,来获得目前缓冲区的使用状况。

## Transmit

串口的输出部分负责将由 CPU 等送来的数据发送经过 `txWire` 发送到外界。

串口的输出部分内部有大小可配置的缓冲区,内部总线上送来的数据会先存在环形缓冲区中,并异步地发送到外界。

此外可以从总线上读取状态寄存器,来获得目前缓冲区的使用状况。

## 地址和寄存器

### 基地址

串口的基地址为 0x10014_000。

Transmit 部分和 Receive 部分使用自最低位,从0开始数起第8位进行区分。

#### Receive 部分

Receive 部分的基地址为 0x100140_00。

##### Receive FIFO 寄存器

Receive FIFO 寄存器的地址为 0x10014000。

该寄存器为只读。

这个寄存器记录了目前串口的输入部分等待被读取的值,长度为 1 字节。

读取此寄存器会自增环形缓冲区中的读取 index,使其指向下一个待读取的值。

##### Receive 状态寄存器

Receive 状态寄存器的地址为 0x10014001。

该寄存器为只读。

这个寄存器记录了目前串口的输入部分的状态,包括:
- 环形缓冲区写入 index,指向下一个要由 rxWire 写入的值,从最低的第 0 个 bit 开始,长度为 n bit
- 环形缓冲区读取 index,指向下一个等待被内部总线读取的值,从最低的第 n 个 bit 开始,长度为 n bit

这里的 n 是可配置的,是 “存下最大的 index 需要的 bit 数”,最大的 index 需要是 2 的整数次幂。

#### Transmit 部分

Transmit 部分的基地址为 0x100141_00。

##### Transmit FIFO 寄存器

Transmit FIFO 寄存器的地址为 0x10014100。

该寄存器为只写。

这个寄存器用于向串口的输出部分发送数据,长度为 1 字节。

写入此寄存器会自增环形缓冲区中的读取 index,使其指向下一个待输出的值。

##### Transmit 状态寄存器

Transmit 状态寄存器的地址为 0x10014101。

该寄存器为只读。

这个寄存器记录了目前串口的输出部分的状态,包括:
- 环形缓冲区读取 index,指向下一个由内部总线写入的值,从最低的第 0 个 bit 开始,长度为 n bit
- 环形缓冲区写入 index,指向下一个要由 txWire 输出的值,从最低的第 n 个 bit 开始,长度为 n bit

这里的 n 是可配置的,是 “存下最大的 index 需要的 bit 数”,最大的 index 需要是 2 的整数次幂。



19 changes: 19 additions & 0 deletions src/main/scala/DataBus.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,20 @@ class DataBus extends Module {
val DATA_END_ADDRESS = "h90000000"
val GPIO_BASE_ADDRESS = "h10012000"
val GPIO_END_ADDRESS = "h10013000"
val SERIAL_BASE_ADDRESS = "h10014000"
val SERIAL_END_ADDRESS = "h10015000"

val io = IO(new DataBusBundle {
val timerInterruptPending = Output(Bool())
val gpioOut = Output(UInt(32.W))
val serialRx = Input(Bool())
val serialTx = Output(Bool())
})

val timer = Module(new Timer)
val sram = Module(new ByteAddressedSRAM)
val gpio = Module(new GPIOController)
val serial = Module(new SerialController(25000000,9600,3))

timer.io.readMode := true.B
timer.io.address := 0.U(32.W)
Expand All @@ -41,9 +46,17 @@ class DataBus extends Module {
gpio.io.dataIn := 0.U(32.W)
gpio.io.maskLevel := Mask.NONE

serial.io.readMode := true.B
serial.io.address := 0.U(32.W)
serial.io.dataIn := 0.U(32.W)
serial.io.maskLevel := Mask.NONE

io.dataOut := 0xdead.U(32.W)
io.gpioOut := gpio.io.dataOut

io.timerInterruptPending := timer.io.interruptPending
io.serialTx := serial.io.txWire
serial.io.rxWire := io.serialRx

when(DATA_BASE_ADDRESS.U <= io.address & io.address < DATA_END_ADDRESS.U) {
sram.io.dataIn := io.dataIn
Expand All @@ -57,6 +70,12 @@ class DataBus extends Module {
gpio.io.maskLevel := io.maskLevel
gpio.io.readMode := io.readMode
io.dataOut := gpio.io.dataOut
}.elsewhen(SERIAL_BASE_ADDRESS.U <= io.address & io.address < SERIAL_END_ADDRESS.U) {
serial.io.dataIn := io.dataIn
serial.io.address := io.address - SERIAL_BASE_ADDRESS.U
serial.io.maskLevel := io.maskLevel
serial.io.readMode := io.readMode
io.dataOut := serial.io.dataOut
}.otherwise {
timer.io.dataIn := io.dataIn
timer.io.address := io.address
Expand Down
39 changes: 3 additions & 36 deletions src/main/scala/ProgramROM.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,43 +9,10 @@ class ProgramROMBundle extends Bundle {
// Just for testing, use a real flash rom in real world
class ProgramROM extends Module {
val io = IO(new ProgramROMBundle)
val content = VecInit(Array(
"h00004fb7".U(32.W), // li t6, 0x4000
"h000f8f93".U(32.W),
"h01200513".U(32.W), // li a0, 0x12
"h00afa023".U(32.W), // sw a0, 0(t6)
"h00000513".U(32.W), // li a0, 0x0
"h00afa223".U(32.W), // sw a0, 4(t6)
// todo
val content = VecInit(Array("h00000013".U(32.W)))

"h80020f37".U(32.W), // li t5, 0x80020000
"h00100293".U(32.W), // li t0, 1
"h00200313".U(32.W), // li t1, 2
"h006303b3".U(32.W), // add t2, t1, t1
"h005383b3".U(32.W), // add t2, t2, t0
"h10012e37".U(32.W), // li t3, 0x10012000
"h000e0e13".U(32.W),
"h007e2023".U(32.W), // sw t2, 0(t3)
// label
"h007f2223".U(32.W), // sw t2, 4(t5)
"h004f2e03".U(32.W), // lw t3, 4(t5)
"h01c38eb3".U(32.W), // add t4, t2, t3
"h007eeeb3".U(32.W), // or t4, t4, t2
"h10012e37".U(32.W), // li t3, 0x10012000
"h000e0e13".U(32.W),
"h01de2023".U(32.W), // sw t4, 0(t3)
"h00138393".U(32.W), // addi t2, t2, 1
// j label
"hfe1ff06f".U(32.W)))

val interruptContent = VecInit(Array(
"h000fa503".U(32.W), // lw a0, 0(t6)
"h00a50533".U(32.W), // add a0, a0, a0
"h00afa023".U(32.W), // sw a0, 0(t6)
"h100125b7".U(32.W), // li a1, 0x10012000
"h00058593".U(32.W),
"h00a5a023".U(32.W), // sw a0, 0(a1)
// mret
"h30200073".U(32.W)))
val interruptContent = VecInit(Array("h00000013".U(32.W)))

when(io.address < "h80010000".U) {
io.value := content((io.address - "h80000000".U) (31, 2))
Expand Down
4 changes: 2 additions & 2 deletions src/main/scala/SRAM.scala
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ class ByteAddressedSRAM extends Module {
}
is(HALF_WORD) {
// the last 1 bit must be zero, currently we just ignore it
// since the spec says the behaviour in this situation is implementation defined
// since the spec says the behavior in this situation is implementation defined
// todo: either support unaligned write or raise an exception
when(io.readMode) {
io.dataOut := Mux(io.address(1),
Expand All @@ -91,7 +91,7 @@ class ByteAddressedSRAM extends Module {
}
is(WORD) {
// the last 2 bits must be zero, currently we just ignore it
// since the spec says the behaviour in this situation is implementation defined
// since the spec says the behavior in this situation is implementation defined
// todo: either support unaligned write or raise an exception
when(io.readMode) {
io.dataOut := Cat(inner.io.dataOut(3), inner.io.dataOut(2), inner.io.dataOut(1), inner.io.dataOut(0))
Expand Down

0 comments on commit fd22818

Please sign in to comment.