vram/MemArbiter: rewrite to use client/server idioms
In preparation for making the two Connectable and defining an arbitrated memory client/server for VRAM access.
This commit is contained in:
parent
b2b2c14009
commit
aa048537ef
|
@ -20,26 +20,21 @@ interface Top;
|
||||||
method Bit#(6) grants();
|
method Bit#(6) grants();
|
||||||
endinterface
|
endinterface
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
Bool write;
|
|
||||||
Addr address;
|
|
||||||
} WriteReq deriving (Bits, Eq);
|
|
||||||
|
|
||||||
(* synthesize, clock_prefix="clk_25mhz", reset_prefix="rst_btn" *)
|
(* synthesize, clock_prefix="clk_25mhz", reset_prefix="rst_btn" *)
|
||||||
module mkTop(Top);
|
module mkTop(Top);
|
||||||
Vector#(2, Reg#(Maybe#(WriteReq))) wrin <- replicateM(mkDReg(tagged Invalid));
|
Vector#(2, Reg#(Maybe#(MemArbiterWrite#(Addr)))) wrin <- replicateM(mkDReg(tagged Invalid));
|
||||||
Vector#(4, Reg#(Maybe#(Addr))) rdin <- replicateM(mkDReg(tagged Invalid));
|
Vector#(4, Reg#(Maybe#(Addr))) rdin <- replicateM(mkDReg(tagged Invalid));
|
||||||
|
|
||||||
MemArbiter#(Addr) ret <- mkMemArbiter();
|
MemArbiter#(Addr) ret <- mkMemArbiter();
|
||||||
|
|
||||||
Reg#(Vector#(6, Bool)) ok <- mkReg(replicate(False));
|
Reg#(Vector#(6, Bool)) ok <- mkReg(replicate(False));
|
||||||
|
|
||||||
rule req_cpu (wrin[0] matches tagged Valid .req &&& req matches WriteReq{write: .write, address: .addr});
|
rule req_cpu (wrin[0] matches tagged Valid .req);
|
||||||
ret.cpu.request(write, addr);
|
ret.cpu.request(req);
|
||||||
endrule
|
endrule
|
||||||
|
|
||||||
rule req_debugger (wrin[1] matches tagged Valid .req &&& req matches WriteReq{write: .write, address: .addr});
|
rule req_debugger (wrin[1] matches tagged Valid .req);
|
||||||
ret.debugger.request(write, addr);
|
ret.debugger.request(req);
|
||||||
endrule
|
endrule
|
||||||
|
|
||||||
rule req_palette (rdin[0] matches tagged Valid .addr);
|
rule req_palette (rdin[0] matches tagged Valid .addr);
|
||||||
|
@ -70,11 +65,11 @@ module mkTop(Top);
|
||||||
endrule
|
endrule
|
||||||
|
|
||||||
method Action cpu(Bool write, Addr addr);
|
method Action cpu(Bool write, Addr addr);
|
||||||
wrin[0] <= tagged Valid WriteReq{write: write, address: addr};
|
wrin[0] <= tagged Valid MemArbiterWrite{write: write, addr: addr};
|
||||||
endmethod
|
endmethod
|
||||||
|
|
||||||
method Action debugger(Bool write, Addr addr);
|
method Action debugger(Bool write, Addr addr);
|
||||||
wrin[1] <= tagged Valid WriteReq{write: write, address: addr};
|
wrin[1] <= tagged Valid MemArbiterWrite{write: write, addr: addr};
|
||||||
endmethod
|
endmethod
|
||||||
|
|
||||||
method Action palette(Addr addr);
|
method Action palette(Addr addr);
|
||||||
|
|
|
@ -2,54 +2,53 @@ package MemArbiter;
|
||||||
|
|
||||||
import Vector::*;
|
import Vector::*;
|
||||||
|
|
||||||
export MemArbiterWriter(..);
|
export MemArbiterWrite(..);
|
||||||
export MemArbiterReader(..);
|
export MemArbiterServer(..);
|
||||||
|
export MemArbiterClient(..);
|
||||||
export MemArbiter(..);
|
export MemArbiter(..);
|
||||||
export mkMemArbiter;
|
export mkMemArbiter;
|
||||||
|
|
||||||
// A MemArbiterWriter can request use of a memory port to read or
|
// A MemArbiterServer receives requests for memory access and emits
|
||||||
// write to an address. When a request is feasible, grant() returns
|
// grants.
|
||||||
// True in the same cycle.
|
interface MemArbiterServer#(type request);
|
||||||
(* always_ready *)
|
method Action request(request req);
|
||||||
interface MemArbiterWriter#(type addr);
|
|
||||||
method Action request(Bool write, addr address);
|
|
||||||
method Bool grant();
|
method Bool grant();
|
||||||
endinterface
|
endinterface
|
||||||
|
|
||||||
// MemArbiterReader can request use of a memory port to read from
|
// A MemArbiterClient emits requests for memory access and emits
|
||||||
// an address. When a request is feasible, grant() returns True in the
|
// grants.
|
||||||
// same cycle.
|
interface MemArbiterClient#(type request);
|
||||||
(* always_ready *)
|
method request request();
|
||||||
interface MemArbiterReader#(type addr);
|
method Action grant();
|
||||||
method Action request(addr address);
|
|
||||||
method Bool grant();
|
|
||||||
endinterface
|
endinterface
|
||||||
|
|
||||||
// A MemArbiter manages concurrent access to memory ports. It
|
typedef struct {
|
||||||
// mediates access between 2 writers and 4 readers.
|
Bool write;
|
||||||
|
addr addr;
|
||||||
|
} MemArbiterWrite#(type addr) deriving (Bits, Eq);
|
||||||
|
|
||||||
|
// A MemArbiter manages concurrent access to memory ports.
|
||||||
interface MemArbiter#(type addr);
|
interface MemArbiter#(type addr);
|
||||||
// Assigned to port A.
|
interface MemArbiterServer#(MemArbiterWrite#(addr)) cpu;
|
||||||
interface MemArbiterWriter#(addr) cpu;
|
interface MemArbiterServer#(MemArbiterWrite#(addr)) debugger;
|
||||||
interface MemArbiterWriter#(addr) debugger;
|
interface MemArbiterServer#(addr) palette;
|
||||||
interface MemArbiterReader#(addr) palette;
|
|
||||||
|
|
||||||
// Assigned to port B.
|
interface MemArbiterServer#(addr) tile1;
|
||||||
interface MemArbiterReader#(addr) tile1;
|
interface MemArbiterServer#(addr) tile2;
|
||||||
interface MemArbiterReader#(addr) tile2;
|
interface MemArbiterServer#(addr) sprite;
|
||||||
interface MemArbiterReader#(addr) sprite;
|
|
||||||
endinterface
|
endinterface
|
||||||
|
|
||||||
// mkMemArbiter builds a GARY memory arbiter.
|
// mkMemArbiter builds a GARY memory arbiter.
|
||||||
//
|
//
|
||||||
// Port A arbitrates with strict priority: CPU requests always proceed
|
// Port A arbitrates with strict priority: CPU requests go first, then
|
||||||
// first, followed by debugger requests, then the palette DAC.
|
// the debugger, then the palette DAC.
|
||||||
//
|
//
|
||||||
// Port B does round-robin arbitration, giving each client a fair
|
// Port B does round-robin arbitration, giving each client a fair
|
||||||
// chance of having its requests processed.
|
// share of memory access.
|
||||||
module mkMemArbiter(MemArbiter#(addr) ifc)
|
module mkMemArbiter(MemArbiter#(addr))
|
||||||
provisos(Bits#(addr, _),
|
provisos(Bits#(addr, _),
|
||||||
Eq#(addr),
|
Eq#(addr),
|
||||||
Alias#(write_req, Tuple2#(Bool, addr)));
|
Alias#(write_req, MemArbiterWrite#(addr)));
|
||||||
|
|
||||||
//////
|
//////
|
||||||
// Port A users
|
// Port A users
|
||||||
|
@ -73,16 +72,16 @@ module mkMemArbiter(MemArbiter#(addr) ifc)
|
||||||
(* preempts = "grant_debugger, grant_palette" *)
|
(* preempts = "grant_debugger, grant_palette" *)
|
||||||
|
|
||||||
(* fire_when_enabled *)
|
(* fire_when_enabled *)
|
||||||
rule grant_cpu (cpu_req.wget matches tagged Valid {.write, .addr});
|
rule grant_cpu (cpu_req.wget matches tagged Valid .req);
|
||||||
cpu_ok.send();
|
cpu_ok.send();
|
||||||
if (write)
|
if (req.write)
|
||||||
written_addr.wset(addr);
|
written_addr.wset(req.addr);
|
||||||
endrule
|
endrule
|
||||||
|
|
||||||
rule grant_debugger (debugger_req.wget matches tagged Valid {.write, .addr});
|
rule grant_debugger (debugger_req.wget matches tagged Valid .req);
|
||||||
debugger_ok.send();
|
debugger_ok.send();
|
||||||
if (write)
|
if (req.write)
|
||||||
written_addr.wset(addr);
|
written_addr.wset(req.addr);
|
||||||
endrule
|
endrule
|
||||||
|
|
||||||
rule grant_palette (palette_req);
|
rule grant_palette (palette_req);
|
||||||
|
@ -143,45 +142,35 @@ module mkMemArbiter(MemArbiter#(addr) ifc)
|
||||||
//////
|
//////
|
||||||
// External interface
|
// External interface
|
||||||
|
|
||||||
interface MemArbiterWriter cpu;
|
interface MemArbiterServer cpu;
|
||||||
method Action request(write, addr);
|
method request = cpu_req.wset;
|
||||||
cpu_req.wset(tuple2(write, addr));
|
|
||||||
endmethod
|
|
||||||
method grant = cpu_ok;
|
method grant = cpu_ok;
|
||||||
endinterface
|
endinterface
|
||||||
|
|
||||||
interface MemArbiterWriter debugger;
|
interface MemArbiterServer debugger;
|
||||||
method Action request(write, addr);
|
method request = debugger_req.wset;
|
||||||
debugger_req.wset(tuple2(write, addr));
|
|
||||||
endmethod
|
|
||||||
method grant = debugger_ok;
|
method grant = debugger_ok;
|
||||||
endinterface
|
endinterface
|
||||||
|
|
||||||
interface MemArbiterReader palette;
|
interface MemArbiterServer palette;
|
||||||
method Action request(addr);
|
method Action request(addr);
|
||||||
palette_req.send();
|
palette_req.send();
|
||||||
endmethod
|
endmethod
|
||||||
method grant = palette_ok;
|
method grant = palette_ok;
|
||||||
endinterface
|
endinterface
|
||||||
|
|
||||||
interface MemArbiterReader tile1;
|
interface MemArbiterServer tile1;
|
||||||
method Action request(addr);
|
method request = portB_req[0].wset;
|
||||||
portB_req[0].wset(addr);
|
|
||||||
endmethod
|
|
||||||
method grant = portB_grant[0];
|
method grant = portB_grant[0];
|
||||||
endinterface
|
endinterface
|
||||||
|
|
||||||
interface MemArbiterReader tile2;
|
interface MemArbiterServer tile2;
|
||||||
method Action request(addr);
|
method request = portB_req[1].wset;
|
||||||
portB_req[1].wset(addr);
|
|
||||||
endmethod
|
|
||||||
method grant = portB_grant[1];
|
method grant = portB_grant[1];
|
||||||
endinterface
|
endinterface
|
||||||
|
|
||||||
interface MemArbiterReader sprite;
|
interface MemArbiterServer sprite;
|
||||||
method Action request(addr);
|
method request = portB_req[2].wset;
|
||||||
portB_req[2].wset(addr);
|
|
||||||
endmethod
|
|
||||||
method grant = portB_grant[2];
|
method grant = portB_grant[2];
|
||||||
endinterface
|
endinterface
|
||||||
endmodule
|
endmodule
|
||||||
|
|
|
@ -12,15 +12,10 @@ import MemArbiter::*;
|
||||||
|
|
||||||
typedef UInt#(4) Addr;
|
typedef UInt#(4) Addr;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
Bool write;
|
|
||||||
Addr addr;
|
|
||||||
} WriteReq deriving (Bits, Eq);
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
String name;
|
String name;
|
||||||
Maybe#(WriteReq) cpu;
|
Maybe#(MemArbiterWrite#(Addr)) cpu;
|
||||||
Maybe#(WriteReq) debugger;
|
Maybe#(MemArbiterWrite#(Addr)) debugger;
|
||||||
Maybe#(Addr) palette;
|
Maybe#(Addr) palette;
|
||||||
Maybe#(Addr) tile1;
|
Maybe#(Addr) tile1;
|
||||||
Maybe#(Addr) tile2;
|
Maybe#(Addr) tile2;
|
||||||
|
@ -29,12 +24,12 @@ typedef struct {
|
||||||
Vector#(6, Bool) want;
|
Vector#(6, Bool) want;
|
||||||
} TestCase deriving (Bits, Eq);
|
} TestCase deriving (Bits, Eq);
|
||||||
|
|
||||||
function Maybe#(WriteReq) rwRead(Addr addr);
|
function Maybe#(MemArbiterWrite#(Addr)) rwRead(Addr addr);
|
||||||
return tagged Valid WriteReq{write: False, addr: addr};
|
return tagged Valid MemArbiterWrite{write: False, addr: addr};
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function Maybe#(WriteReq) rwWrite(Addr addr);
|
function Maybe#(MemArbiterWrite#(Addr)) rwWrite(Addr addr);
|
||||||
return tagged Valid WriteReq{write: True, addr: addr};
|
return tagged Valid MemArbiterWrite{write: True, addr: addr};
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function Maybe#(Addr) read(Addr addr);
|
function Maybe#(Addr) read(Addr addr);
|
||||||
|
@ -55,8 +50,8 @@ function Vector#(6, Bool) grant(Integer granted_a, Integer granted_b);
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function TestCase testCase(String name,
|
function TestCase testCase(String name,
|
||||||
Maybe#(WriteReq) cpu,
|
Maybe#(MemArbiterWrite#(Addr)) cpu,
|
||||||
Maybe#(WriteReq) debugger,
|
Maybe#(MemArbiterWrite#(Addr)) debugger,
|
||||||
Maybe#(Addr) palette,
|
Maybe#(Addr) palette,
|
||||||
Maybe#(Addr) tile1,
|
Maybe#(Addr) tile1,
|
||||||
Maybe#(Addr) tile2,
|
Maybe#(Addr) tile2,
|
||||||
|
@ -209,13 +204,13 @@ module mkTB();
|
||||||
endrule
|
endrule
|
||||||
|
|
||||||
(* no_implicit_conditions, fire_when_enabled *)
|
(* no_implicit_conditions, fire_when_enabled *)
|
||||||
rule input_cpu (tests[idx].cpu matches tagged Valid .req &&& req matches WriteReq {write: .write, addr: .addr});
|
rule input_cpu (tests[idx].cpu matches tagged Valid .req);
|
||||||
dut.cpu.request(write, addr);
|
dut.cpu.request(req);
|
||||||
endrule
|
endrule
|
||||||
|
|
||||||
(* no_implicit_conditions, fire_when_enabled *)
|
(* no_implicit_conditions, fire_when_enabled *)
|
||||||
rule input_debugger (tests[idx].debugger matches tagged Valid .req &&& req matches WriteReq {write: .write, addr: .addr});
|
rule input_debugger (tests[idx].debugger matches tagged Valid .req);
|
||||||
dut.debugger.request(write, addr);
|
dut.debugger.request(req);
|
||||||
endrule
|
endrule
|
||||||
|
|
||||||
(* no_implicit_conditions, fire_when_enabled *)
|
(* no_implicit_conditions, fire_when_enabled *)
|
||||||
|
@ -238,7 +233,7 @@ module mkTB();
|
||||||
dut.sprite.request(addr);
|
dut.sprite.request(addr);
|
||||||
endrule
|
endrule
|
||||||
|
|
||||||
function Fmt rw_str(Maybe#(WriteReq) v);
|
function Fmt rw_str(Maybe#(MemArbiterWrite#(Addr)) v);
|
||||||
case (v) matches
|
case (v) matches
|
||||||
tagged Valid .req: begin
|
tagged Valid .req: begin
|
||||||
if (req.write)
|
if (req.write)
|
||||||
|
|
Loading…
Reference in New Issue