Skip to content

Commit

Permalink
Writeable instruction memory over uart, missing reset logic
Browse files Browse the repository at this point in the history
  • Loading branch information
SyedAnasAlam committed Aug 14, 2024
1 parent 4b8c5cd commit 21942ac
Show file tree
Hide file tree
Showing 6 changed files with 411 additions and 0 deletions.
116 changes: 116 additions & 0 deletions src/main/scala/leros/uart/UARTRx.scala
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
}
98 changes: 98 additions & 0 deletions src/main/scala/leros/uart/UARTTx.scala
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
}
}
42 changes: 42 additions & 0 deletions src/main/scala/leros/wrmem/LerosWrMemTest.scala
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
}
93 changes: 93 additions & 0 deletions src/main/scala/leros/wrmem/ProgFSM.scala
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

}
40 changes: 40 additions & 0 deletions src/main/scala/leros/wrmem/WrInstrMem.scala
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

}
Loading

0 comments on commit 21942ac

Please sign in to comment.