vram/VRAMCore: make simulatable in Bluesim, tidy up
This commit is contained in:
parent
79b54ca86f
commit
fb57903021
|
@ -1,15 +1,9 @@
|
||||||
package VRAMCore;
|
package VRAMCore;
|
||||||
|
|
||||||
import Connectable::*;
|
|
||||||
import GetPut::*;
|
import GetPut::*;
|
||||||
import ClientServer::*;
|
import ClientServer::*;
|
||||||
import DReg::*;
|
import BRAMCore::*;
|
||||||
import BRAM::*;
|
|
||||||
import Vector::*;
|
|
||||||
import FIFOF::*;
|
|
||||||
import SpecialFIFOs::*;
|
|
||||||
import Real::*;
|
import Real::*;
|
||||||
import Printf::*;
|
|
||||||
|
|
||||||
import DelayLine::*;
|
import DelayLine::*;
|
||||||
import ECP5_RAM::*;
|
import ECP5_RAM::*;
|
||||||
|
@ -18,31 +12,71 @@ export VRAMAddr;
|
||||||
export VRAMData;
|
export VRAMData;
|
||||||
export VRAMRequest(..);
|
export VRAMRequest(..);
|
||||||
export VRAMResponse(..);
|
export VRAMResponse(..);
|
||||||
export VRAMClient(..);
|
|
||||||
export VRAMServer(..);
|
|
||||||
export VRAMCore(..);
|
export VRAMCore(..);
|
||||||
export mkVRAMCore;
|
export mkVRAMCore;
|
||||||
|
|
||||||
typedef Bit#(8) VRAMData;
|
typedef Bit#(8) VRAMData;
|
||||||
|
|
||||||
// Each byte RAM we build below can address 4096 bytes, which is 12
|
typedef UInt#(17) VRAMAddr;
|
||||||
// address bits.
|
typedef UInt#(2) ArrayAddr;
|
||||||
typedef UInt#(12) ByteAddr;
|
|
||||||
|
|
||||||
typedef UInt#(3) ChipAddr;
|
typedef UInt#(3) ChipAddr;
|
||||||
|
typedef UInt#(12) ByteAddr;
|
||||||
|
|
||||||
// ByteRAM is two EBRs glued together to make a whole-byte memory.
|
// ByteRAM is two EBRs glued together to make a whole-byte memory.
|
||||||
typedef EBR#(ByteAddr, VRAMData, ByteAddr, VRAMData) ByteRAM;
|
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
|
// mkByteRAM glues two ECP5 EBRs together to make a 4096x8b memory
|
||||||
// block. Like the underlying ECP5 EBRs, callers must bring their own
|
// block. Like the underlying ECP5 EBRs, callers must bring their own
|
||||||
// flow control to read out responses one cycle after putting a read
|
// flow control to read out responses one cycle after putting a read
|
||||||
// request.
|
// request.
|
||||||
module mkByteRAM(ChipAddr chip_addr, ByteRAM ifc);
|
module mkByteRAM(ChipAddr chip_addr, ByteRAM ifc);
|
||||||
EBRPortConfig cfg = defaultValue;
|
EBR#(ByteAddr, Bit#(4), ByteAddr, Bit#(4)) upper <- mkNibbleRAM(chip_addr);
|
||||||
cfg.chip_select_addr = chip_addr;
|
EBR#(ByteAddr, Bit#(4), ByteAddr, Bit#(4)) lower <- mkNibbleRAM(chip_addr);
|
||||||
EBR#(ByteAddr, Bit#(4), ByteAddr, Bit#(4)) upper <- mkEBRCore(cfg, cfg);
|
|
||||||
EBR#(ByteAddr, Bit#(4), ByteAddr, Bit#(4)) lower <- mkEBRCore(cfg, cfg);
|
|
||||||
|
|
||||||
interface EBRPort portA;
|
interface EBRPort portA;
|
||||||
method Action put(ChipAddr chip_select, Bool write, ByteAddr addr, VRAMData data_in);
|
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
|
endinterface
|
||||||
endmodule
|
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 VRAMCore;
|
||||||
interface VRAMServer portA;
|
interface Server#(VRAMRequest, VRAMResponse) portA;
|
||||||
interface VRAMServer portB;
|
interface Server#(VRAMRequest, VRAMResponse) portB;
|
||||||
endinterface
|
endinterface
|
||||||
|
|
||||||
// mkVRAMCore creates a dual port VRAM of the specified size, using
|
// 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);
|
let num_arrays = ceil(fromInteger(num_byterams) / 8);
|
||||||
|
|
||||||
function Tuple3#(ArrayAddr, ChipAddr, ByteAddr) split_addr(VRAMAddr a);
|
function Tuple3#(ArrayAddr, ChipAddr, ByteAddr) split_addr(VRAMAddr a);
|
||||||
if (num_bytes < 128*1024)
|
return unpack(pack(a));
|
||||||
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));
|
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
ByteRAM arrays[num_arrays];
|
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_A[2] <- mkCReg(2, tagged Invalid);
|
||||||
Reg#(Maybe#(ArrayAddr)) inflight_B[2] <- mkCReg(2, tagged Invalid);
|
Reg#(Maybe#(ArrayAddr)) inflight_B[2] <- mkCReg(2, tagged Invalid);
|
||||||
|
|
||||||
interface VRAMServer portA;
|
interface Server portA;
|
||||||
interface Put request;
|
interface Put request;
|
||||||
method Action put(VRAMRequest req) if (inflight_A[1] matches tagged Invalid);
|
method Action put(VRAMRequest req) if (inflight_A[1] matches tagged Invalid);
|
||||||
match {.array, .chip, .byteaddr} = split_addr(req.addr);
|
match {.array, .chip, .byteaddr} = split_addr(req.addr);
|
||||||
|
@ -196,7 +210,7 @@ module mkVRAMCore(Integer num_kilobytes, VRAMCore ifc);
|
||||||
endinterface
|
endinterface
|
||||||
endinterface
|
endinterface
|
||||||
|
|
||||||
interface VRAMServer portB;
|
interface Server portB;
|
||||||
interface Put request;
|
interface Put request;
|
||||||
method Action put(VRAMRequest req) if (inflight_B[1] matches tagged Invalid);
|
method Action put(VRAMRequest req) if (inflight_B[1] matches tagged Invalid);
|
||||||
match {.array, .chip, .byteaddr} = split_addr(req.addr);
|
match {.array, .chip, .byteaddr} = split_addr(req.addr);
|
||||||
|
|
Loading…
Reference in New Issue