mirror of
https://github.com/antonblanchard/chiselwatt.git
synced 2026-03-06 03:20:07 +00:00
203 lines
5.7 KiB
Scala
203 lines
5.7 KiB
Scala
import chisel3._
|
|
import chisel3.util._
|
|
|
|
import Control._
|
|
import Helpers._
|
|
import LoadStoreByteReverse._
|
|
|
|
class LoadStoreInput(val bits: Int) extends Bundle {
|
|
val a = Input(UInt(bits.W))
|
|
val b = Input(UInt(bits.W))
|
|
val data = Input(UInt(bits.W))
|
|
val internalOp = Input(UInt(1.W))
|
|
val length = Input(UInt(2.W))
|
|
val signed = Input(UInt(1.W))
|
|
val byteReverse = Input(UInt(1.W))
|
|
val update = Input(UInt(1.W))
|
|
val reservation = Input(UInt(1.W))
|
|
}
|
|
|
|
/*
|
|
* Simple non pipelined load/store unit
|
|
*
|
|
* if load:
|
|
* 1C: a+b,
|
|
* 2C: load data
|
|
* 3C: de align, byte swap or sign extend data
|
|
*
|
|
* if store:
|
|
* 1C: a+b
|
|
* byte swap or sign extend, align data
|
|
* 2C: form store mask, store data
|
|
*/
|
|
|
|
class LoadStore(val bits: Int, val words: Int) extends Module {
|
|
val io = IO(new Bundle {
|
|
val in = Flipped(Valid(new LoadStoreInput(bits)))
|
|
val out = Output(Valid(UInt(bits.W)))
|
|
val mem = new MemoryPort(bits, words, true)
|
|
val tx = Output(UInt(1.W))
|
|
val rx = Input(UInt(1.W))
|
|
})
|
|
|
|
io.out.valid := false.B
|
|
io.out.bits := 0.U
|
|
|
|
io.mem.addr := 0.U
|
|
io.mem.writeMask := 0.U
|
|
io.mem.writeData := 0.U
|
|
io.mem.writeEnable := false.B
|
|
|
|
val addr = Reg(UInt(bits.W))
|
|
val data = Reg(UInt(bits.W))
|
|
val internalOp = Reg(UInt(2.W))
|
|
val length = Reg(UInt(2.W))
|
|
val signed = Reg(UInt(1.W))
|
|
val byteReverse = Reg(UInt(1.W))
|
|
val reservation = Reg(UInt(1.W))
|
|
val sIdle :: sAccess :: sLoadFormat :: Nil = Enum(3)
|
|
val state = RegInit(sIdle)
|
|
|
|
val fifoLength = 128
|
|
val rxOverclock = 16
|
|
val uart = Module(new Uart(fifoLength, rxOverclock))
|
|
|
|
io.tx := uart.io.tx
|
|
uart.io.rx := io.rx
|
|
|
|
uart.io.txQueue.valid := false.B
|
|
uart.io.txQueue.bits := 0.U
|
|
uart.io.rxQueue.ready := false.B
|
|
|
|
val clockDivisor = RegInit(0.U(8.W))
|
|
uart.io.clockDivisor := clockDivisor
|
|
|
|
switch (state) {
|
|
is (sIdle) {
|
|
when (io.in.valid) {
|
|
val a = io.in.bits.a + io.in.bits.b
|
|
val offset = a(log2Ceil(bits/8)-1, 0)*8.U
|
|
|
|
addr := a
|
|
internalOp := io.in.bits.internalOp
|
|
length := io.in.bits.length
|
|
signed := io.in.bits.signed
|
|
byteReverse := io.in.bits.byteReverse
|
|
reservation := io.in.bits.reservation
|
|
state := sAccess
|
|
|
|
when (io.in.bits.internalOp === LDST_STORE) {
|
|
/* Byte swap or sign extend data. We never do both. */
|
|
when (io.in.bits.signed.asBool) {
|
|
data := io.in.bits.data.signExtend(io.in.bits.length) << offset
|
|
} .elsewhen (io.in.bits.byteReverse.asBool) {
|
|
data := LoadStoreByteReverse(io.in.bits.data, io.in.bits.length) << offset
|
|
} .otherwise {
|
|
data := io.in.bits.data << offset
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
is (sAccess) {
|
|
when (internalOp === LDST_STORE) {
|
|
val offset = addr(log2Ceil(bits/8)-1, 0)
|
|
val lookupTable = Seq(LEN_1B -> "h1".U, LEN_2B -> "h3".U, LEN_4B -> "hf".U, LEN_8B -> "hff".U)
|
|
val mask = Wire(UInt((bits/8).W))
|
|
mask := MuxLookup(length, lookupTable.head._2, lookupTable) << offset
|
|
|
|
/* UART */
|
|
when (addr(31, 8) === "hc00020".U) {
|
|
when (addr(7, 0) === "h00".U) {
|
|
/* TX */
|
|
uart.io.txQueue.valid := true.B
|
|
uart.io.txQueue.bits := data(7, 0)
|
|
} .elsewhen (addr === "hc0002018".U) {
|
|
/* clock divisor */
|
|
clockDivisor := data(7, 0)
|
|
} .otherwise {
|
|
/* ERROR */
|
|
}
|
|
} .otherwise {
|
|
/* memory */
|
|
io.mem.addr := addr >> log2Ceil(bits/8).U
|
|
io.mem.writeEnable := true.B
|
|
io.mem.writeMask := mask
|
|
io.mem.writeData := data
|
|
}
|
|
|
|
/* Done */
|
|
io.out.valid := true.B
|
|
state := sIdle
|
|
} .otherwise {
|
|
io.mem.addr := addr >> log2Ceil(bits/8).U
|
|
state := sLoadFormat
|
|
}
|
|
}
|
|
|
|
is (sLoadFormat) {
|
|
val offset = addr(log2Ceil(bits/8)-1, 0)*8.U
|
|
val d = io.mem.readData >> offset
|
|
|
|
/* Byte swap or sign extend data. We never do both. */
|
|
when (signed.asBool) {
|
|
io.out.bits := d.signExtend(length)
|
|
} .elsewhen (byteReverse.asBool) {
|
|
io.out.bits := LoadStoreByteReverse(d, length)
|
|
} .otherwise {
|
|
io.out.bits := d.zeroExtend(length)
|
|
}
|
|
|
|
/* UART */
|
|
when (addr(31, 8) === "hc00020".U) {
|
|
when (addr(7, 0) === "h08".U) {
|
|
/* RX */
|
|
when (uart.io.rxQueue.valid) {
|
|
uart.io.rxQueue.ready := true.B
|
|
io.out.bits := uart.io.rxQueue.bits
|
|
}
|
|
} .elsewhen (addr(7, 0) === "h10".U) {
|
|
/* Status */
|
|
io.out.bits := uart.io.txFull ## uart.io.rxFull ## uart.io.txEmpty ## uart.io.rxEmpty
|
|
} .elsewhen (addr(7, 0) === "h18".U) {
|
|
/* clock divisor */
|
|
io.out.bits := clockDivisor
|
|
} .otherwise {
|
|
/* ERROR */
|
|
io.out.bits := 0.U
|
|
}
|
|
}
|
|
|
|
/* Done */
|
|
io.out.valid := true.B
|
|
state := sIdle
|
|
}
|
|
}
|
|
}
|
|
|
|
class LoadStoreWrapper(val bits: Int, val size: Int, filename: String) extends Module {
|
|
val io = IO(new Bundle {
|
|
val in = Flipped(Valid(new LoadStoreInput(bits)))
|
|
val out = Output(Valid(UInt(bits.W)))
|
|
})
|
|
|
|
val loadStore = Module(new LoadStore(bits, size/(bits/8)))
|
|
val mem = Module(new MemoryBlackBoxWrapper(bits, size/(bits/8), filename))
|
|
|
|
io.in <> loadStore.io.in
|
|
io.out <> loadStore.io.out
|
|
loadStore.io.mem <> mem.io.loadStorePort
|
|
|
|
loadStore.io.rx := loadStore.io.tx
|
|
|
|
/* Fetch port is unused */
|
|
mem.io.fetchPort.writeData := 0.U
|
|
mem.io.fetchPort.writeEnable := false.B
|
|
mem.io.fetchPort.addr := 0.U
|
|
mem.io.fetchPort.writeMask := 0.U
|
|
}
|
|
|
|
object LoadStoreObj extends App {
|
|
chisel3.Driver.execute(Array[String](), () => new LoadStoreWrapper(64, 128*1024, "test.hex"))
|
|
}
|