perilus

RISC-V processor built with Chisel
git clone https://git.bradleygannon.com/perilus.git
Log | Files | Refs | Submodules | README

memory.scala (4216B)


      1 package com.rinthyAi.perilus.memory
      2 
      3 import chisel3._
      4 import chisel3.util._
      5 import chisel3.util.experimental.loadMemoryFromFile
      6 
      7 class Memory(
      8     numWords: Int,
      9     width: Width,
     10     initMem: String = "",
     11     withDebug: Boolean = false
     12 ) extends Module {
     13   val io = IO(new Bundle {
     14     val address = Input(UInt(width))
     15     val writeData = Input(UInt(width))
     16     val writeEnable = Input(Bool())
     17     val readData = Output(UInt(width))
     18     val dataMask = Input(DataMask())
     19     val signExtData = Input(Bool())
     20     val debug =
     21       if (withDebug) Some(new Bundle {
     22         val memAddr = Input(UInt(width))
     23         val memData = Output(Vec(width.get / 8, UInt(8.W)))
     24       })
     25       else None
     26   })
     27 
     28   private val BytesPerWord = width.get / 8
     29   private val AddressShift = log2Ceil(BytesPerWord)
     30 
     31   // TODO: change this into a SyncReadMem, which is apparently more easily mapped to hardware
     32   // but will probably require changes to the control FSM due to synchronous ops
     33   val memory = Mem(numWords, Vec(BytesPerWord, UInt(8.W)))
     34   if (initMem.nonEmpty) {
     35     loadMemoryFromFile(memory, initMem)
     36   }
     37 
     38   io.debug.foreach(d => {
     39     d.memData := memory.read(d.memAddr >> AddressShift)
     40   })
     41 
     42   val byteOffset = Wire(UInt(2.W))
     43   byteOffset := io.address & 3.U
     44 
     45   // TODO unaligned accesses should raise an exception or something...
     46   // for now they just round down to the nearest boundary
     47   val maskValue =
     48     WireDefault(Vec(BytesPerWord, Bool()), VecInit(false.B, false.B, false.B, false.B))
     49   val writeData = WireDefault(Vec(BytesPerWord, UInt(8.W)), VecInit(0.U, 0.U, 0.U, 0.U))
     50   when(io.dataMask === DataMask.byte) {
     51     when(byteOffset === 0.U) {
     52       maskValue(0) := true.B
     53       writeData(0) := io.writeData(7, 0)
     54     }.elsewhen(byteOffset === 1.U) {
     55       maskValue(1) := true.B
     56       writeData(1) := io.writeData(7, 0)
     57     }.elsewhen(byteOffset === 2.U) {
     58       maskValue(2) := true.B
     59       writeData(2) := io.writeData(7, 0)
     60     }.elsewhen(byteOffset === 3.U) {
     61       maskValue(3) := true.B
     62       writeData(3) := io.writeData(7, 0)
     63     }
     64   }.elsewhen(io.dataMask === DataMask.half) {
     65     when(byteOffset === 0.U || byteOffset === 1.U) {
     66       maskValue(0) := true.B
     67       maskValue(1) := true.B
     68       writeData(0) := io.writeData(7, 0)
     69       writeData(1) := io.writeData(15, 8)
     70     }.elsewhen(byteOffset === 2.U || byteOffset === 3.U) {
     71       maskValue(2) := true.B
     72       maskValue(3) := true.B
     73       writeData(2) := io.writeData(7, 0)
     74       writeData(3) := io.writeData(15, 8)
     75     }
     76   }.elsewhen(io.dataMask === DataMask.word) {
     77     maskValue(0) := true.B
     78     maskValue(1) := true.B
     79     maskValue(2) := true.B
     80     maskValue(3) := true.B
     81     writeData(0) := io.writeData(7, 0)
     82     writeData(1) := io.writeData(15, 8)
     83     writeData(2) := io.writeData(23, 16)
     84     writeData(3) := io.writeData(31, 24)
     85   }
     86 
     87   when(io.writeEnable && !reset.asBool) {
     88     memory.write(io.address >> AddressShift, writeData, maskValue)
     89   }
     90 
     91   val readBytes = Wire(Vec(BytesPerWord, UInt(8.W)))
     92   readBytes := memory.read(io.address >> AddressShift)
     93   val returnByte = WireDefault(UInt(8.W), 0.U)
     94   val halfOffset = Wire(UInt(1.W))
     95   halfOffset := io.address(1)
     96   val returnHalf = WireDefault(UInt(16.W), 0.U)
     97   when(io.dataMask === DataMask.byte) {
     98     when(byteOffset === 3.U) {
     99       returnByte := readBytes(3)
    100     }.elsewhen(byteOffset === 2.U) {
    101       returnByte := readBytes(2)
    102     }.elsewhen(byteOffset === 1.U) {
    103       returnByte := readBytes(1)
    104     }.otherwise {
    105       returnByte := readBytes(0)
    106     }
    107     when(io.signExtData) {
    108       io.readData := Cat(Fill(24, returnByte(7)), returnByte)
    109     }.otherwise {
    110       io.readData := returnByte
    111     }
    112   }.elsewhen(io.dataMask === DataMask.half) {
    113     when(halfOffset === 1.U) {
    114       returnHalf := Cat(readBytes(3), readBytes(2))
    115     }.otherwise {
    116       returnHalf := Cat(readBytes(1), readBytes(0))
    117     }
    118     when(io.signExtData) {
    119       io.readData := Cat(Fill(16, returnHalf(15)), returnHalf(15, 8), returnHalf(7, 0))
    120     }.otherwise {
    121       io.readData := Cat(returnHalf(15, 8), returnHalf(7, 0))
    122     }
    123   }.otherwise {
    124     io.readData := Cat(readBytes(3), readBytes(2), readBytes(1), readBytes(0))
    125   }
    126 }
    127 
    128 object DataMask extends ChiselEnum {
    129   val byte, half, word = Value
    130 }