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 }