Skip to content

Commit 7f57817

Browse files
authored
Merge pull request #10 from SyedAnasAlam/master
Writeable instruction memory over uart, missing reset logic
2 parents 4b8c5cd + 21942ac commit 7f57817

File tree

6 files changed

+411
-0
lines changed

6 files changed

+411
-0
lines changed
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
/*
2+
* Copyright: 2014-2018, Technical University of Denmark, DTU Compute
3+
* Author: Martin Schoeberl ([email protected])
4+
* License: Simplified BSD License
5+
*
6+
* A UART is a serial port, also called an RS232 interface.
7+
*
8+
*/
9+
10+
package leros.uart
11+
12+
import chisel3._
13+
import chisel3.util._
14+
15+
class UartIO extends DecoupledIO(UInt(8.W)) {
16+
}
17+
18+
/**
19+
* Receive part of the UART.
20+
* Use a ready/valid handshaking.
21+
* The following code is inspired by Tommy's receive code at:
22+
* https://github.com/tommythorn/yarvi
23+
*/
24+
class Rx(frequency: Int, baudRate: Int) extends Module {
25+
val io = IO(new Bundle {
26+
val rxd = Input(UInt(1.W))
27+
val channel = new UartIO()
28+
})
29+
30+
val BIT_CNT = ((frequency + baudRate / 2) / baudRate - 1).U
31+
val START_CNT = ((3 * frequency / 2 + baudRate / 2) / baudRate - 1).U
32+
33+
// Sync in the asynchronous RX data, reset to 1 to not start reading after a reset
34+
val rxReg = RegNext(RegNext(io.rxd, 1.U), 1.U)
35+
36+
val shiftReg = RegInit(0.U(8.W))
37+
val cntReg = RegInit(0.U(20.W))
38+
val bitsReg = RegInit(0.U(4.W))
39+
val validReg = RegInit(false.B)
40+
41+
when(cntReg =/= 0.U) {
42+
cntReg := cntReg - 1.U
43+
} .elsewhen(bitsReg =/= 0.U) {
44+
cntReg := BIT_CNT
45+
shiftReg := rxReg ## (shiftReg >> 1)
46+
bitsReg := bitsReg - 1.U
47+
// the last bit shifted in
48+
when(bitsReg === 1.U) {
49+
validReg := true.B
50+
}
51+
} .elsewhen(rxReg === 0.U) {
52+
// wait 1.5 bits after falling edge of start
53+
cntReg := START_CNT
54+
bitsReg := 8.U
55+
}
56+
57+
when(validReg && io.channel.ready) {
58+
validReg := false.B
59+
}
60+
61+
io.channel.bits := shiftReg
62+
io.channel.valid := validReg
63+
}
64+
//- end
65+
66+
/**
67+
* A single byte buffer with a ready/valid interface
68+
*/
69+
class Buffer extends Module {
70+
val io = IO(new Bundle {
71+
val in = Flipped(new UartIO())
72+
val out = new UartIO()
73+
})
74+
75+
object State extends ChiselEnum {
76+
val empty, full = Value
77+
}
78+
import State._
79+
80+
val stateReg = RegInit(empty)
81+
val dataReg = RegInit(0.U(8.W))
82+
83+
io.in.ready := stateReg === empty
84+
io.out.valid := stateReg === full
85+
86+
when(stateReg === empty) {
87+
when(io.in.valid) {
88+
dataReg := io.in.bits
89+
stateReg := full
90+
}
91+
} .otherwise { // full
92+
when(io.out.ready) {
93+
stateReg := empty
94+
}
95+
}
96+
io.out.bits := dataReg
97+
}
98+
99+
/*
100+
* Buffered uart receiver
101+
*/
102+
class UARTRx(frequency: Int, baudRate: Int) extends Module {
103+
val io = IO(new Bundle {
104+
val rxd = Input(UInt(1.W))
105+
val out = new UartIO()
106+
})
107+
val rx = Module(new Rx(frequency, baudRate))
108+
val buf = Module(new Buffer())
109+
110+
val led = RegInit(0.U(8.W))
111+
112+
rx.io.rxd := io.rxd
113+
rx.io.channel <> buf.io.in
114+
115+
io.out <> buf.io.out
116+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/*
2+
* Copyright: 2014-2018, Technical University of Denmark, DTU Compute
3+
* Author: Martin Schoeberl ([email protected])
4+
* License: Simplified BSD License
5+
*
6+
* A UART is a serial port, also called an RS232 interface.
7+
*
8+
*/
9+
10+
package leros.uart
11+
12+
import chisel3._
13+
import chisel3.util._
14+
import java.nio.file._
15+
16+
/**
17+
* Transmit part of the UART.
18+
* A minimal version without any additional buffering.
19+
* Use a ready/valid handshaking.
20+
*/
21+
class Tx(frequency: Int, baudRate: Int) extends Module {
22+
val io = IO(new Bundle {
23+
val txd = Output(UInt(1.W))
24+
val channel = Flipped(new UartIO())
25+
})
26+
27+
val BIT_CNT = ((frequency + baudRate / 2) / baudRate - 1).asUInt
28+
29+
val shiftReg = RegInit(0x7ff.U)
30+
val cntReg = RegInit(0.U(20.W))
31+
val bitsReg = RegInit(0.U(4.W))
32+
33+
io.channel.ready := (cntReg === 0.U) && (bitsReg === 0.U)
34+
io.txd := shiftReg(0)
35+
36+
when(cntReg === 0.U) {
37+
38+
cntReg := BIT_CNT
39+
when(bitsReg =/= 0.U) {
40+
val shift = shiftReg >> 1
41+
shiftReg := 1.U ## shift(9, 0)
42+
bitsReg := bitsReg - 1.U
43+
} .otherwise {
44+
when(io.channel.valid) {
45+
// two stop bits, data, one start bit
46+
shiftReg := 3.U ## io.channel.bits ## 0.U
47+
bitsReg := 11.U
48+
} .otherwise {
49+
shiftReg := 0x7ff.U
50+
}
51+
}
52+
53+
} .otherwise {
54+
cntReg := cntReg - 1.U
55+
}
56+
}
57+
58+
59+
/**
60+
* A transmitter with a single buffer.
61+
*/
62+
class BufferedTx(frequency: Int, baudRate: Int) extends Module {
63+
val io = IO(new Bundle {
64+
val txd = Output(UInt(1.W))
65+
val channel = Flipped(new UartIO())
66+
})
67+
val tx = Module(new Tx(frequency, baudRate))
68+
val buf = Module(new Buffer())
69+
70+
buf.io.in <> io.channel
71+
tx.io.channel <> buf.io.out
72+
io.txd <> tx.io.txd
73+
}
74+
75+
/**
76+
* Send a string.
77+
*/
78+
class Sender(frequency: Int, baudRate: Int, msg : String) extends Module {
79+
val io = IO(new Bundle {
80+
val txd = Output(UInt(1.W))
81+
})
82+
83+
val tx = Module(new BufferedTx(frequency, baudRate))
84+
85+
io.txd := tx.io.txd
86+
87+
val text = VecInit(msg.map(_.U))
88+
val len = msg.length.U
89+
90+
val cntReg = RegInit(0.U(8.W))
91+
92+
tx.io.channel.bits := text(cntReg)
93+
tx.io.channel.valid := cntReg =/= len
94+
95+
when(tx.io.channel.ready && cntReg =/= len) {
96+
cntReg := cntReg + 1.U
97+
}
98+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package leros.wrmem
2+
3+
import chisel3._
4+
import chisel3.util._
5+
import leros._
6+
import leros.uart.Sender
7+
import leros.uart.Sender
8+
9+
10+
class LerosWrMemTest(clockFreq : Int = 100000000, uartBaudrate : Int = 115200, msg : String) extends Module {
11+
val io = IO(new Bundle {
12+
val instr = Output(UInt(16.W))
13+
})
14+
15+
val programmer = Module(new Sender(clockFreq, uartBaudrate, msg))
16+
val wrInstrMem = Module(new WrInstrMemory(8, clockFreq, uartBaudrate))
17+
18+
val idle :: programming :: readout :: Nil = Enum(3)
19+
val state = RegInit(idle)
20+
21+
val pc = RegInit(0.U(8.W))
22+
wrInstrMem.io.instrAddr := pc
23+
24+
wrInstrMem.io.uartRX := programmer.io.txd
25+
26+
switch(state) {
27+
is(idle) {
28+
pc := 0.U
29+
30+
when(wrInstrMem.io.busy) {
31+
state := programming
32+
}
33+
}
34+
is(programming) {
35+
when(~wrInstrMem.io.busy) {
36+
pc := pc + 1.U
37+
}
38+
}
39+
}
40+
41+
io.instr := wrInstrMem.io.instr
42+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package leros.wrmem
2+
3+
import chisel3._
4+
import chisel3.util._
5+
6+
class ProgFSM(memAddrWidth : Int) extends Module {
7+
val io = IO(new Bundle {
8+
val channel = Flipped(new DecoupledIO(UInt(8.W)))
9+
val wrAddr = Output(UInt(memAddrWidth.W))
10+
val wrData = Output(UInt(16.W))
11+
val wrEna = Output(Bool())
12+
13+
val busy = Output(Bool())
14+
})
15+
16+
val PROGRAMMING_DONE = "h64".U(8.W)
17+
18+
val idle :: sampleA :: sampleB :: writeMem :: Nil = Enum(4)
19+
val state = RegInit(idle)
20+
21+
val wrAddr = RegInit(0.U(memAddrWidth.W))
22+
val increment = WireDefault(false.B)
23+
24+
val wrDataA = RegInit(0.U(8.W))
25+
val wrDataB = RegInit(0.U(8.W))
26+
27+
io.channel.ready := false.B
28+
io.wrEna := false.B
29+
io.busy := false.B
30+
31+
switch(state) {
32+
is(idle) {
33+
io.wrEna := false.B
34+
io.channel.ready := false.B
35+
increment := false.B
36+
io.busy := false.B
37+
38+
when(io.channel.valid) {
39+
state := sampleA
40+
}
41+
}
42+
43+
is(sampleA) {
44+
io.wrEna := false.B
45+
io.channel.ready := true.B
46+
increment := false.B
47+
io.busy := true.B
48+
49+
wrDataA := io.channel.bits
50+
51+
when(wrDataA === PROGRAMMING_DONE) {
52+
state := idle
53+
}
54+
. elsewhen(io.channel.valid) {
55+
state := sampleB
56+
}
57+
}
58+
59+
is(sampleB) {
60+
io.wrEna := false.B
61+
io.channel.ready := true.B
62+
increment := false.B
63+
io.busy := true.B
64+
65+
wrDataB := io.channel.bits
66+
67+
when(wrDataB === PROGRAMMING_DONE) {
68+
state := idle
69+
}
70+
. elsewhen(io.channel.valid) {
71+
state := writeMem
72+
}
73+
}
74+
75+
is(writeMem) {
76+
io.wrEna := true.B
77+
io.channel.ready := false.B
78+
increment := true.B
79+
io.busy := true.B
80+
81+
state := sampleA
82+
}
83+
}
84+
85+
when(increment) {
86+
wrAddr := wrAddr + 1.U
87+
}
88+
89+
// little endian
90+
io.wrData := wrDataB ## wrDataA
91+
io.wrAddr := wrAddr
92+
93+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package leros.wrmem
2+
3+
import chisel3._
4+
import chisel3.util._
5+
import leros.uart.UARTRx
6+
import leros.uart.UARTRx
7+
8+
class WrInstrMemory(memAddrWidth : Int, clockFreq : Int, uartBaudrate : Int) extends Module {
9+
val io = IO(new Bundle {
10+
val uartRX = Input(UInt(1.W))
11+
12+
val instrAddr = Input(UInt(memAddrWidth.W))
13+
val instr = Output(UInt(16.W))
14+
15+
val busy = Output(Bool())
16+
})
17+
val progFSM = Module(new ProgFSM(memAddrWidth))
18+
val uartRx = Module(new UARTRx(clockFreq, uartBaudrate))
19+
20+
val wrAddr = WireDefault(0.U(memAddrWidth.W))
21+
val wrData = WireDefault(0.U(16.W))
22+
val wrEna = WireDefault(false.B)
23+
24+
uartRx.io.out <> progFSM.io.channel
25+
uartRx.io.rxd := io.uartRX
26+
27+
wrAddr := progFSM.io.wrAddr
28+
wrData := progFSM.io.wrData
29+
wrEna := progFSM.io.wrEna
30+
31+
val mem = SyncReadMem(scala.math.pow(2, memAddrWidth).toInt, UInt(16.W))
32+
33+
io.instr := mem.read(io.instrAddr)
34+
when(wrEna) {
35+
mem.write(wrAddr , wrData)
36+
}
37+
38+
io.busy := progFSM.io.busy
39+
40+
}

0 commit comments

Comments
 (0)