vram/VRAM: at last, a video RAM, with all the gubbins
This commit is contained in:
parent
fb57903021
commit
1929bbe3cc
|
@ -0,0 +1,99 @@
|
|||
package VRAM;
|
||||
|
||||
import Connectable::*;
|
||||
import GetPut::*;
|
||||
import ClientServer::*;
|
||||
import Vector::*;
|
||||
import FIFOF::*;
|
||||
import SpecialFIFOs::*;
|
||||
|
||||
import MemArbiter::*;
|
||||
import VRAMCore::*;
|
||||
|
||||
// Re-exports from VRAMCore
|
||||
export VRAMAddr, VRAMData, VRAMRequest(..), VRAMResponse(..);
|
||||
|
||||
export VRAMServer(..);
|
||||
export VRAM(..), mkVRAM;
|
||||
|
||||
typedef Server#(VRAMRequest, VRAMResponse) VRAMServer;
|
||||
|
||||
// mkArbitratedVRAMServers expands a VRAMServer port into multiple
|
||||
// ports through the use of a MemArbiter.
|
||||
module mkArbitratedVRAMServers(VRAMServer ram, MemArbiter#(n, VRAMAddr) arb, Vector#(n, VRAMServer) ifc)
|
||||
provisos (Min#(n, 1, 1),
|
||||
Alias#(port_idx, UInt#(TLog#(n))));
|
||||
Vector#(n, FIFOF#(VRAMRequest)) requests <- replicateM(mkBypassFIFOF());
|
||||
Vector#(n, FIFOF#(VRAMResponse)) responses <- replicateM(mkBypassFIFOF());
|
||||
Reg#(Maybe#(port_idx)) awaiting_response[2] <- mkCReg(2, tagged Invalid);
|
||||
|
||||
(* fire_when_enabled *)
|
||||
rule request_ports;
|
||||
for (Integer i=0; i<valueOf(n); i=i+1)
|
||||
if (requests[i].notEmpty) begin
|
||||
let req = requests[i].first;
|
||||
let arb_req = MemArbiterOp{
|
||||
write: isValid(req.data),
|
||||
addr: req.addr
|
||||
};
|
||||
arb.ports[i].request(arb_req);
|
||||
end
|
||||
endrule
|
||||
|
||||
(* fire_when_enabled *)
|
||||
rule submit (awaiting_response[1] matches tagged Invalid);
|
||||
let port = arb.granted_port();
|
||||
ram.request.put(requests[port].first);
|
||||
requests[port].deq();
|
||||
awaiting_response[1] <= tagged Valid port;
|
||||
endrule
|
||||
|
||||
(* fire_when_enabled *)
|
||||
rule response (awaiting_response[0] matches tagged Valid .port &&& responses[port].notFull);
|
||||
let resp <- ram.response.get();
|
||||
responses[port].enq(resp);
|
||||
awaiting_response[0] <= tagged Invalid;
|
||||
endrule
|
||||
|
||||
return map(uncurry(toGPServer), zip(requests, responses));
|
||||
endmodule
|
||||
|
||||
// VRAM is a GARY video RAM and its memory ports.
|
||||
interface VRAM;
|
||||
interface VRAMServer cpu;
|
||||
interface VRAMServer debugger;
|
||||
interface VRAMServer palette;
|
||||
interface VRAMServer tile1;
|
||||
interface VRAMServer tile2;
|
||||
interface VRAMServer sprite;
|
||||
endinterface
|
||||
|
||||
// mkVRAM constructs a VRAM of the requested size. Memory access is
|
||||
// spread across two internal ports as follows:
|
||||
//
|
||||
// Port A: strict most-important-wins priority: CPU, then debugger,
|
||||
// then palette DAC.
|
||||
// Port B: equal round-robin prioritization between two tile engines
|
||||
// and the sprite engine.
|
||||
module mkVRAM(Integer num_kilobytes, VRAM ifc);
|
||||
VRAMCore ram <- mkVRAMCore(num_kilobytes);
|
||||
|
||||
MemArbiter#(3, VRAMAddr) arbA <- mkPriorityMemArbiter();
|
||||
Vector#(3, VRAMServer) portA <- mkArbitratedVRAMServers(ram.portA, arbA);
|
||||
|
||||
MemArbiter#(3, VRAMAddr) arbB <- mkRoundRobinMemArbiter();
|
||||
Vector#(3, VRAMServer) portB <- mkArbitratedVRAMServers(ram.portB, arbB);
|
||||
|
||||
// Connect up the arbiters so they correctly prevent write-write
|
||||
// and write-read conflicts.
|
||||
mkConnection(arbA, arbB);
|
||||
|
||||
interface cpu = portA[0];
|
||||
interface debugger = portA[1];
|
||||
interface palette = portA[2];
|
||||
interface tile1 = portB[0];
|
||||
interface tile2 = portB[1];
|
||||
interface sprite = portB[2];
|
||||
endmodule
|
||||
|
||||
endpackage
|
Loading…
Reference in New Issue