From 79b54ca86fae01795452ff436db43a2d027f5611 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sun, 8 Sep 2024 09:26:59 -0700 Subject: [PATCH] vram/MemArbiter: add a granted_port method to make downstream wiring easier To implement the mux tree that feeds into RAM ports, we need to know the port index of the grantee to be able to wire it up. In theory we could dispense with the per-port grant signal, but keeping it around allows each client to deal with local concerns separate from the port routing. --- vram/MemArbiter.bsv | 97 +++++++++++++++++++++++----------------- vram/MemArbiter_Test.bsv | 22 ++++----- 2 files changed, 67 insertions(+), 52 deletions(-) diff --git a/vram/MemArbiter.bsv b/vram/MemArbiter.bsv index 1363464..bf61806 100644 --- a/vram/MemArbiter.bsv +++ b/vram/MemArbiter.bsv @@ -14,6 +14,8 @@ typedef struct { addr addr; } MemArbiterOp#(type addr) deriving (Bits, Eq, FShow); +// mem_ops_conflict reports whether memory accesses a and b would +// cause undefined behavior if they proceed simultaneously. function Bool mem_ops_conflict(Maybe#(MemArbiterOp#(addr)) a, Maybe#(MemArbiterOp#(addr)) b) provisos(Eq#(addr)); @@ -35,34 +37,34 @@ interface MemArbiter#(numeric type num_clients, type addr); // ports allow clients to request memory access. interface Vector#(num_clients, MemArbiterServer#(addr)) ports; + // granted_port returns the index in ports of the client that is + // being granted its request. + method UInt#(TLog#(num_clients)) granted_port(); + // The following methods are to support arbiter chaining. // - // Suppose you're arbitrating access to a dual-port - // memory. Typically, such a memory specifies that if one port is - // writing to an address, the other must not concurrently read or - // write that same address. This means the arbiters attached to - // each memory port must cooperate to avoid simultaneously granting + // Suppose you're arbitrating access to a dual-port memory. + // Typically, such a memory specifies that if one port is writing + // to an address, the other must not concurrently read or write + // that same address. This means the arbiters attached to each + // memory port must cooperate to avoid simultaneously granting // conflicting requests from their clients. // - // Calling conflict prevents the arbiter from granting a concurrent - // request that would result in a write-write, read-write or - // write-read conflict. granted_op emits the operation that the - // arbiter is granting, if any. + // conflict_in supplies an already granted operation that this + // arbiter must avoid conflicting with. conflict_out emits the + // operation that the arbiter is granting, if any. // - // MemArbiter intances are Connectable: mkConnection(a, b) gives - // conflict priority to a. That is, b only grants requests that - // don't conflict with a's grant. + // mkConnection(firstArbiter, secondArbiter) gives conflict + // priority to firstArbiter. That is, secondArbiter only grants + // requests that don't conflict with grants made by firstArbiter. (* always_ready *) - method Action conflict(MemArbiterOp#(addr) conflict); - method MemArbiterOp#(addr) granted_op(); + method Action conflict_in(MemArbiterOp#(addr) conflict); + method MemArbiterOp#(addr) conflict_out(); endinterface instance Connectable#(MemArbiter#(m, addr), MemArbiter#(n, addr)); module mkConnection(MemArbiter#(m, addr) a, MemArbiter#(n, addr) b, Empty ifc); - (* fire_when_enabled *) - rule forward_conflict; - b.conflict(a.granted_op); - endrule + mkConnection(a.conflict_out, b.conflict_in); endmodule endinstance @@ -71,13 +73,14 @@ endinstance module mkPriorityMemArbiter(MemArbiter#(num_clients, addr)) provisos (Bits#(addr, _), Eq#(addr), - Min#(num_clients, 1, 1)); + Min#(num_clients, 1, 1), + Alias#(client_idx, UInt#(TLog#(num_clients)))); Vector#(num_clients, RWire#(MemArbiterOp#(addr))) reqs <- replicateM(mkRWire()); Wire#(Vector#(num_clients, Bool)) grants <- mkBypassWire(); - RWire#(MemArbiterOp#(addr)) conflict_in <- mkRWire(); - RWire#(MemArbiterOp#(addr)) granted_op_out <- mkRWire(); + RWire#(MemArbiterOp#(addr)) conflict_op <- mkRWire(); + RWire#(client_idx) granted_idx <- mkRWire(); (* no_implicit_conditions, fire_when_enabled *) rule grant_requests; @@ -86,11 +89,11 @@ module mkPriorityMemArbiter(MemArbiter#(num_clients, addr)) for (Integer i=0; i