From fb5790302186502ee87cc8f7ca4e93bd6cd895ae Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 8 Sep 2024 09:26:59 -0700 Subject: [PATCH] vram/VRAMCore: make simulatable in Bluesim, tidy up --- vram/VRAMCore.bsv | 98 +++++++++++++++++++++++++++-------------------- 1 file changed, 56 insertions(+), 42 deletions(-) diff --git a/vram/VRAMCore.bsv b/vram/VRAMCore.bsv index bad4d92..bc120d6 100644 --- a/vram/VRAMCore.bsv +++ b/vram/VRAMCore.bsv @@ -1,15 +1,9 @@ package VRAMCore; -import Connectable::*; import GetPut::*; import ClientServer::*; -import DReg::*; -import BRAM::*; -import Vector::*; -import FIFOF::*; -import SpecialFIFOs::*; +import BRAMCore::*; import Real::*; -import Printf::*; import DelayLine::*; import ECP5_RAM::*; @@ -18,31 +12,71 @@ export VRAMAddr; export VRAMData; export VRAMRequest(..); export VRAMResponse(..); -export VRAMClient(..); -export VRAMServer(..); export VRAMCore(..); export mkVRAMCore; typedef Bit#(8) VRAMData; -// Each byte RAM we build below can address 4096 bytes, which is 12 -// address bits. -typedef UInt#(12) ByteAddr; - +typedef UInt#(17) VRAMAddr; +typedef UInt#(2) ArrayAddr; typedef UInt#(3) ChipAddr; +typedef UInt#(12) ByteAddr; // ByteRAM is two EBRs glued together to make a whole-byte memory. typedef EBR#(ByteAddr, VRAMData, ByteAddr, VRAMData) ByteRAM; +typedef struct { + VRAMAddr addr; + Maybe#(VRAMData) data; +} VRAMRequest deriving (Bits, Eq); + +typedef struct { + VRAMData data; +} VRAMResponse deriving (Bits, Eq); + +module mkNibbleRAM_ECP5(ChipAddr chip_addr, EBR#(ByteAddr, Bit#(4), ByteAddr, Bit#(4)) ifc); + EBRPortConfig cfg = defaultValue; + cfg.chip_select_addr = chip_addr; + let _ret <- mkEBRCore(cfg, cfg); + return _ret; +endmodule + +module mkNibbleRAM_Sim(ChipAddr chip_addr, EBR#(ByteAddr, Bit#(4), ByteAddr, Bit#(4)) ifc); + BRAM_DUAL_PORT#(ByteAddr, Bit#(4)) ram <- mkBRAMCore2(4096, False); + + interface EBRPort portA; + method Action put(UInt#(3) chip_select, Bool write, ByteAddr address, Bit#(4) datain); + if (chip_select == chip_addr) + ram.a.put(write, address, datain); + endmethod + method read = ram.a.read; + endinterface + + interface EBRPort portB; + method Action put(UInt#(3) chip_select, Bool write, ByteAddr address, Bit#(4) datain); + if (chip_select == chip_addr) + ram.b.put(write, address, datain); + endmethod + method read = ram.b.read; + endinterface +endmodule + +module mkNibbleRAM(ChipAddr chip_addr, EBR#(ByteAddr, Bit#(4), ByteAddr, Bit#(4)) ifc); + let _ret; + if (genC()) + _ret <- mkNibbleRAM_Sim(chip_addr); + else + _ret <- mkNibbleRAM_ECP5(chip_addr); + return _ret; +endmodule + // mkByteRAM glues two ECP5 EBRs together to make a 4096x8b memory // block. Like the underlying ECP5 EBRs, callers must bring their own // flow control to read out responses one cycle after putting a read // request. module mkByteRAM(ChipAddr chip_addr, ByteRAM ifc); - EBRPortConfig cfg = defaultValue; - cfg.chip_select_addr = chip_addr; - EBR#(ByteAddr, Bit#(4), ByteAddr, Bit#(4)) upper <- mkEBRCore(cfg, cfg); - EBR#(ByteAddr, Bit#(4), ByteAddr, Bit#(4)) lower <- mkEBRCore(cfg, cfg); + EBR#(ByteAddr, Bit#(4), ByteAddr, Bit#(4)) upper <- mkNibbleRAM(chip_addr); + EBR#(ByteAddr, Bit#(4), ByteAddr, Bit#(4)) lower <- mkNibbleRAM(chip_addr); interface EBRPort portA; method Action put(ChipAddr chip_select, Bool write, ByteAddr addr, VRAMData data_in); @@ -119,25 +153,9 @@ module mkByteRAMArray(Integer num_chips, ByteRAM ifc); endinterface endmodule -typedef UInt#(2) ArrayAddr; - -typedef UInt#(17) VRAMAddr; - -typedef struct { - VRAMAddr addr; - Maybe#(VRAMData) data; -} VRAMRequest deriving (Bits, Eq); - -typedef struct { - VRAMData data; -} VRAMResponse deriving (Bits, Eq); - -typedef Server#(VRAMRequest, VRAMResponse) VRAMServer; -typedef Client#(VRAMRequest, VRAMResponse) VRAMClient; - interface VRAMCore; - interface VRAMServer portA; - interface VRAMServer portB; + interface Server#(VRAMRequest, VRAMResponse) portA; + interface Server#(VRAMRequest, VRAMResponse) portB; endinterface // mkVRAMCore creates a dual port VRAM of the specified size, using @@ -163,11 +181,7 @@ module mkVRAMCore(Integer num_kilobytes, VRAMCore ifc); let num_arrays = ceil(fromInteger(num_byterams) / 8); function Tuple3#(ArrayAddr, ChipAddr, ByteAddr) split_addr(VRAMAddr a); - if (num_bytes < 128*1024) - a = a % fromInteger(num_bytes); - match {.top, .byteaddr} = split(pack(a)); - Tuple2#(Bit#(SizeOf#(ArrayAddr)), Bit#(SizeOf#(ChipAddr))) route = split(top); - return tuple3(unpack(tpl_1(route)), unpack(tpl_2(route)), unpack(byteaddr)); + return unpack(pack(a)); endfunction ByteRAM arrays[num_arrays]; @@ -179,7 +193,7 @@ module mkVRAMCore(Integer num_kilobytes, VRAMCore ifc); Reg#(Maybe#(ArrayAddr)) inflight_A[2] <- mkCReg(2, tagged Invalid); Reg#(Maybe#(ArrayAddr)) inflight_B[2] <- mkCReg(2, tagged Invalid); - interface VRAMServer portA; + interface Server portA; interface Put request; method Action put(VRAMRequest req) if (inflight_A[1] matches tagged Invalid); match {.array, .chip, .byteaddr} = split_addr(req.addr); @@ -196,7 +210,7 @@ module mkVRAMCore(Integer num_kilobytes, VRAMCore ifc); endinterface endinterface - interface VRAMServer portB; + interface Server portB; interface Put request; method Action put(VRAMRequest req) if (inflight_B[1] matches tagged Invalid); match {.array, .chip, .byteaddr} = split_addr(req.addr);