-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Writeable instruction memory over uart, missing reset logic
- Loading branch information
1 parent
4b8c5cd
commit 21942ac
Showing
6 changed files
with
411 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
/* | ||
* Copyright: 2014-2018, Technical University of Denmark, DTU Compute | ||
* Author: Martin Schoeberl (martin@jopdesign.com) | ||
* License: Simplified BSD License | ||
* | ||
* A UART is a serial port, also called an RS232 interface. | ||
* | ||
*/ | ||
|
||
package leros.uart | ||
|
||
import chisel3._ | ||
import chisel3.util._ | ||
|
||
class UartIO extends DecoupledIO(UInt(8.W)) { | ||
} | ||
|
||
/** | ||
* Receive part of the UART. | ||
* Use a ready/valid handshaking. | ||
* The following code is inspired by Tommy's receive code at: | ||
* https://github.com/tommythorn/yarvi | ||
*/ | ||
class Rx(frequency: Int, baudRate: Int) extends Module { | ||
val io = IO(new Bundle { | ||
val rxd = Input(UInt(1.W)) | ||
val channel = new UartIO() | ||
}) | ||
|
||
val BIT_CNT = ((frequency + baudRate / 2) / baudRate - 1).U | ||
val START_CNT = ((3 * frequency / 2 + baudRate / 2) / baudRate - 1).U | ||
|
||
// Sync in the asynchronous RX data, reset to 1 to not start reading after a reset | ||
val rxReg = RegNext(RegNext(io.rxd, 1.U), 1.U) | ||
|
||
val shiftReg = RegInit(0.U(8.W)) | ||
val cntReg = RegInit(0.U(20.W)) | ||
val bitsReg = RegInit(0.U(4.W)) | ||
val validReg = RegInit(false.B) | ||
|
||
when(cntReg =/= 0.U) { | ||
cntReg := cntReg - 1.U | ||
} .elsewhen(bitsReg =/= 0.U) { | ||
cntReg := BIT_CNT | ||
shiftReg := rxReg ## (shiftReg >> 1) | ||
bitsReg := bitsReg - 1.U | ||
// the last bit shifted in | ||
when(bitsReg === 1.U) { | ||
validReg := true.B | ||
} | ||
} .elsewhen(rxReg === 0.U) { | ||
// wait 1.5 bits after falling edge of start | ||
cntReg := START_CNT | ||
bitsReg := 8.U | ||
} | ||
|
||
when(validReg && io.channel.ready) { | ||
validReg := false.B | ||
} | ||
|
||
io.channel.bits := shiftReg | ||
io.channel.valid := validReg | ||
} | ||
//- end | ||
|
||
/** | ||
* A single byte buffer with a ready/valid interface | ||
*/ | ||
class Buffer extends Module { | ||
val io = IO(new Bundle { | ||
val in = Flipped(new UartIO()) | ||
val out = new UartIO() | ||
}) | ||
|
||
object State extends ChiselEnum { | ||
val empty, full = Value | ||
} | ||
import State._ | ||
|
||
val stateReg = RegInit(empty) | ||
val dataReg = RegInit(0.U(8.W)) | ||
|
||
io.in.ready := stateReg === empty | ||
io.out.valid := stateReg === full | ||
|
||
when(stateReg === empty) { | ||
when(io.in.valid) { | ||
dataReg := io.in.bits | ||
stateReg := full | ||
} | ||
} .otherwise { // full | ||
when(io.out.ready) { | ||
stateReg := empty | ||
} | ||
} | ||
io.out.bits := dataReg | ||
} | ||
|
||
/* | ||
* Buffered uart receiver | ||
*/ | ||
class UARTRx(frequency: Int, baudRate: Int) extends Module { | ||
val io = IO(new Bundle { | ||
val rxd = Input(UInt(1.W)) | ||
val out = new UartIO() | ||
}) | ||
val rx = Module(new Rx(frequency, baudRate)) | ||
val buf = Module(new Buffer()) | ||
|
||
val led = RegInit(0.U(8.W)) | ||
|
||
rx.io.rxd := io.rxd | ||
rx.io.channel <> buf.io.in | ||
|
||
io.out <> buf.io.out | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
/* | ||
* Copyright: 2014-2018, Technical University of Denmark, DTU Compute | ||
* Author: Martin Schoeberl (martin@jopdesign.com) | ||
* License: Simplified BSD License | ||
* | ||
* A UART is a serial port, also called an RS232 interface. | ||
* | ||
*/ | ||
|
||
package leros.uart | ||
|
||
import chisel3._ | ||
import chisel3.util._ | ||
import java.nio.file._ | ||
|
||
/** | ||
* Transmit part of the UART. | ||
* A minimal version without any additional buffering. | ||
* Use a ready/valid handshaking. | ||
*/ | ||
class Tx(frequency: Int, baudRate: Int) extends Module { | ||
val io = IO(new Bundle { | ||
val txd = Output(UInt(1.W)) | ||
val channel = Flipped(new UartIO()) | ||
}) | ||
|
||
val BIT_CNT = ((frequency + baudRate / 2) / baudRate - 1).asUInt | ||
|
||
val shiftReg = RegInit(0x7ff.U) | ||
val cntReg = RegInit(0.U(20.W)) | ||
val bitsReg = RegInit(0.U(4.W)) | ||
|
||
io.channel.ready := (cntReg === 0.U) && (bitsReg === 0.U) | ||
io.txd := shiftReg(0) | ||
|
||
when(cntReg === 0.U) { | ||
|
||
cntReg := BIT_CNT | ||
when(bitsReg =/= 0.U) { | ||
val shift = shiftReg >> 1 | ||
shiftReg := 1.U ## shift(9, 0) | ||
bitsReg := bitsReg - 1.U | ||
} .otherwise { | ||
when(io.channel.valid) { | ||
// two stop bits, data, one start bit | ||
shiftReg := 3.U ## io.channel.bits ## 0.U | ||
bitsReg := 11.U | ||
} .otherwise { | ||
shiftReg := 0x7ff.U | ||
} | ||
} | ||
|
||
} .otherwise { | ||
cntReg := cntReg - 1.U | ||
} | ||
} | ||
|
||
|
||
/** | ||
* A transmitter with a single buffer. | ||
*/ | ||
class BufferedTx(frequency: Int, baudRate: Int) extends Module { | ||
val io = IO(new Bundle { | ||
val txd = Output(UInt(1.W)) | ||
val channel = Flipped(new UartIO()) | ||
}) | ||
val tx = Module(new Tx(frequency, baudRate)) | ||
val buf = Module(new Buffer()) | ||
|
||
buf.io.in <> io.channel | ||
tx.io.channel <> buf.io.out | ||
io.txd <> tx.io.txd | ||
} | ||
|
||
/** | ||
* Send a string. | ||
*/ | ||
class Sender(frequency: Int, baudRate: Int, msg : String) extends Module { | ||
val io = IO(new Bundle { | ||
val txd = Output(UInt(1.W)) | ||
}) | ||
|
||
val tx = Module(new BufferedTx(frequency, baudRate)) | ||
|
||
io.txd := tx.io.txd | ||
|
||
val text = VecInit(msg.map(_.U)) | ||
val len = msg.length.U | ||
|
||
val cntReg = RegInit(0.U(8.W)) | ||
|
||
tx.io.channel.bits := text(cntReg) | ||
tx.io.channel.valid := cntReg =/= len | ||
|
||
when(tx.io.channel.ready && cntReg =/= len) { | ||
cntReg := cntReg + 1.U | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package leros.wrmem | ||
|
||
import chisel3._ | ||
import chisel3.util._ | ||
import leros._ | ||
import leros.uart.Sender | ||
import leros.uart.Sender | ||
|
||
|
||
class LerosWrMemTest(clockFreq : Int = 100000000, uartBaudrate : Int = 115200, msg : String) extends Module { | ||
val io = IO(new Bundle { | ||
val instr = Output(UInt(16.W)) | ||
}) | ||
|
||
val programmer = Module(new Sender(clockFreq, uartBaudrate, msg)) | ||
val wrInstrMem = Module(new WrInstrMemory(8, clockFreq, uartBaudrate)) | ||
|
||
val idle :: programming :: readout :: Nil = Enum(3) | ||
val state = RegInit(idle) | ||
|
||
val pc = RegInit(0.U(8.W)) | ||
wrInstrMem.io.instrAddr := pc | ||
|
||
wrInstrMem.io.uartRX := programmer.io.txd | ||
|
||
switch(state) { | ||
is(idle) { | ||
pc := 0.U | ||
|
||
when(wrInstrMem.io.busy) { | ||
state := programming | ||
} | ||
} | ||
is(programming) { | ||
when(~wrInstrMem.io.busy) { | ||
pc := pc + 1.U | ||
} | ||
} | ||
} | ||
|
||
io.instr := wrInstrMem.io.instr | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
package leros.wrmem | ||
|
||
import chisel3._ | ||
import chisel3.util._ | ||
|
||
class ProgFSM(memAddrWidth : Int) extends Module { | ||
val io = IO(new Bundle { | ||
val channel = Flipped(new DecoupledIO(UInt(8.W))) | ||
val wrAddr = Output(UInt(memAddrWidth.W)) | ||
val wrData = Output(UInt(16.W)) | ||
val wrEna = Output(Bool()) | ||
|
||
val busy = Output(Bool()) | ||
}) | ||
|
||
val PROGRAMMING_DONE = "h64".U(8.W) | ||
|
||
val idle :: sampleA :: sampleB :: writeMem :: Nil = Enum(4) | ||
val state = RegInit(idle) | ||
|
||
val wrAddr = RegInit(0.U(memAddrWidth.W)) | ||
val increment = WireDefault(false.B) | ||
|
||
val wrDataA = RegInit(0.U(8.W)) | ||
val wrDataB = RegInit(0.U(8.W)) | ||
|
||
io.channel.ready := false.B | ||
io.wrEna := false.B | ||
io.busy := false.B | ||
|
||
switch(state) { | ||
is(idle) { | ||
io.wrEna := false.B | ||
io.channel.ready := false.B | ||
increment := false.B | ||
io.busy := false.B | ||
|
||
when(io.channel.valid) { | ||
state := sampleA | ||
} | ||
} | ||
|
||
is(sampleA) { | ||
io.wrEna := false.B | ||
io.channel.ready := true.B | ||
increment := false.B | ||
io.busy := true.B | ||
|
||
wrDataA := io.channel.bits | ||
|
||
when(wrDataA === PROGRAMMING_DONE) { | ||
state := idle | ||
} | ||
. elsewhen(io.channel.valid) { | ||
state := sampleB | ||
} | ||
} | ||
|
||
is(sampleB) { | ||
io.wrEna := false.B | ||
io.channel.ready := true.B | ||
increment := false.B | ||
io.busy := true.B | ||
|
||
wrDataB := io.channel.bits | ||
|
||
when(wrDataB === PROGRAMMING_DONE) { | ||
state := idle | ||
} | ||
. elsewhen(io.channel.valid) { | ||
state := writeMem | ||
} | ||
} | ||
|
||
is(writeMem) { | ||
io.wrEna := true.B | ||
io.channel.ready := false.B | ||
increment := true.B | ||
io.busy := true.B | ||
|
||
state := sampleA | ||
} | ||
} | ||
|
||
when(increment) { | ||
wrAddr := wrAddr + 1.U | ||
} | ||
|
||
// little endian | ||
io.wrData := wrDataB ## wrDataA | ||
io.wrAddr := wrAddr | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package leros.wrmem | ||
|
||
import chisel3._ | ||
import chisel3.util._ | ||
import leros.uart.UARTRx | ||
import leros.uart.UARTRx | ||
|
||
class WrInstrMemory(memAddrWidth : Int, clockFreq : Int, uartBaudrate : Int) extends Module { | ||
val io = IO(new Bundle { | ||
val uartRX = Input(UInt(1.W)) | ||
|
||
val instrAddr = Input(UInt(memAddrWidth.W)) | ||
val instr = Output(UInt(16.W)) | ||
|
||
val busy = Output(Bool()) | ||
}) | ||
val progFSM = Module(new ProgFSM(memAddrWidth)) | ||
val uartRx = Module(new UARTRx(clockFreq, uartBaudrate)) | ||
|
||
val wrAddr = WireDefault(0.U(memAddrWidth.W)) | ||
val wrData = WireDefault(0.U(16.W)) | ||
val wrEna = WireDefault(false.B) | ||
|
||
uartRx.io.out <> progFSM.io.channel | ||
uartRx.io.rxd := io.uartRX | ||
|
||
wrAddr := progFSM.io.wrAddr | ||
wrData := progFSM.io.wrData | ||
wrEna := progFSM.io.wrEna | ||
|
||
val mem = SyncReadMem(scala.math.pow(2, memAddrWidth).toInt, UInt(16.W)) | ||
|
||
io.instr := mem.read(io.instrAddr) | ||
when(wrEna) { | ||
mem.write(wrAddr , wrData) | ||
} | ||
|
||
io.busy := progFSM.io.busy | ||
|
||
} |
Oops, something went wrong.