punk@1: import FIFO::*; punk@1: import FIFOF::*; punk@1: import List::*; punk@1: import Assert::*; punk@1: punk@1: module mkBFIFO1( FIFO#(item_t) ) provisos ( Bits#(item_t,item_sz) ); punk@1: punk@1: RWire#(item_t) inputWire <- mkRWire(); punk@1: PulseWire deqEnabled <- mkPulseWire(); punk@1: PulseWire clearEnabled <- mkPulseWire(); punk@1: punk@1: Reg#(item_t) register <- mkRegU(); punk@1: Reg#(Bool) valid <- mkReg(False); punk@1: punk@1: // If there is an input item on the inputWire wire and dequeue did not punk@1: // execute this cycle then we need to store the item in the register punk@1: punk@1: (*fire_when_enabled*) punk@1: rule update ( True ); punk@1: case (inputWire.wget()) matches punk@1: tagged Invalid: punk@1: if (deqEnabled || clearEnabled) punk@1: valid <= False; punk@1: tagged Valid .x: punk@1: begin punk@1: register <= x; punk@1: valid <= !(deqEnabled || clearEnabled); punk@1: end punk@1: endcase punk@1: endrule punk@1: punk@1: // On enqueue we write the input item to the inputWire wire punk@1: punk@1: method Action enq( item_t item ) if ( !valid ); punk@1: inputWire.wset(item); punk@1: endmethod punk@1: punk@1: // On dequeue we always invalidate the storage register regardless punk@1: // of whether or not the item was actually bypassed or not. We also punk@1: // set a combinational signal so that we know not to move the item punk@1: // into the register this cycle. punk@1: punk@1: method Action deq() if ( valid || isValid(inputWire.wget()) ); punk@1: deqEnabled.send(); punk@1: endmethod punk@1: punk@1: // We get the item either from the register (if register is valid) or punk@1: // from the combinational bypasss (if the rwire is valid). punk@1: punk@1: method item_t first() if ( valid || isValid(inputWire.wget()) ); punk@1: if ( valid ) punk@1: return register; punk@1: else punk@1: return unJust(inputWire.wget()); punk@1: endmethod punk@1: punk@1: method Action clear(); punk@1: clearEnabled.send(); punk@1: endmethod punk@1: punk@1: endmodule punk@1: punk@1: module mkSizedBFIFO#(Integer n) ( FIFO#(item_t) ) provisos ( Bits#(item_t,item_sz) ); punk@1: punk@1: RWire#(item_t) inputWire <- mkRWire(); punk@1: PulseWire deqEnabled <- mkPulseWire(); punk@1: PulseWire clearEnabled <- mkPulseWire(); punk@1: punk@1: List#(Reg#(item_t)) registers <- replicateM(n, mkRegU); punk@1: List#(Reg#(Bool)) valids <- replicateM(n, mkReg(False)); punk@1: punk@1: function Nat getNextFree (List#(Reg#(Bool)) vs); punk@1: punk@1: Nat res = fromInteger(n - 1); punk@1: punk@1: for (Integer x = n - 1; x > -1; x = x - 1) punk@1: res = !vs[x]._read() ? fromInteger(x) : res; punk@1: punk@1: return res; punk@1: punk@1: endfunction punk@1: punk@1: function Bool notFull(); punk@1: punk@1: Bool full = True; punk@1: punk@1: for (Integer x = 0; x < length(valids); x = x + 1) punk@1: full = full && valids[x]._read(); punk@1: punk@1: return !full; punk@1: punk@1: endfunction punk@1: // If there is an input item on the inputWire wire and dequeue did not punk@1: // execute this cycle then we need to store the item in the register punk@1: punk@1: rule update ( True ); punk@1: Nat next = getNextFree(valids); punk@1: punk@1: next = (deqEnabled) ? next - 1 : next; punk@1: punk@1: (valids[next]) <= isValid(inputWire.wget()); punk@1: (registers[next]) <= validValue(inputWire.wget()); punk@1: punk@1: if (deqEnabled && !clearEnabled) punk@1: begin punk@1: punk@1: for (Nat x = 0; x < (next - 1); x = x + 1) punk@1: begin punk@1: (valids[x]) <= valids[x+1]._read(); punk@1: (registers[x]) <= registers[x+1]._read(); punk@1: end punk@1: punk@1: end punk@1: else if (clearEnabled) punk@1: begin punk@1: punk@1: for (Integer x = 0; x < n; x = x + 1) punk@1: (valids[x]) <= False; punk@1: punk@1: end punk@1: endrule punk@1: punk@1: // On enqueue we write the input item to the inputWire wire punk@1: punk@1: method Action enq( item_t item ) if ( notFull ); punk@1: inputWire.wset(item); punk@1: endmethod punk@1: punk@1: // On dequeue we always invalidate the storage register regardless punk@1: // of whether or not the item was actually bypassed or not. We also punk@1: // set a combinational signal so that we know not to move the item punk@1: // into the register this cycle. punk@1: punk@1: method Action deq() if ( valids[0]._read() || isValid(inputWire.wget()) ); punk@1: deqEnabled.send(); punk@1: endmethod punk@1: punk@1: // We get the item either from the register (if register is valid) or punk@1: // from the combinational bypasss (if the rwire is valid). punk@1: punk@1: method item_t first() if ( valids[0]._read() || isValid(inputWire.wget()) ); punk@1: if ( valids[0]._read() ) punk@1: return registers[0]._read(); punk@1: else punk@1: return unJust(inputWire.wget()); punk@1: endmethod punk@1: punk@1: punk@1: method Action clear(); punk@1: clearEnabled.send(); punk@1: endmethod punk@1: punk@1: endmodule punk@1: punk@1: punk@1: module mkBFIFOF1( FIFOF#(item_t) ) provisos ( Bits#(item_t,item_sz) ); punk@1: punk@1: RWire#(item_t) inputWire <- mkRWire(); punk@1: RWire#(Bool) deqEnabled <- mkRWire(); punk@1: punk@1: Reg#(Maybe#(item_t)) register <- mkReg(Invalid); punk@1: punk@1: // If there is an input item on the inputWire wire and dequeue did not punk@1: // execute this cycle then we need to store the item in the register punk@1: punk@1: rule noDeq ( isValid(inputWire.wget()) && !isValid(deqEnabled.wget()) ); punk@1: register <= inputWire.wget(); punk@1: endrule punk@1: punk@1: // On enqueue we write the input item to the inputWire wire punk@1: punk@1: method Action enq( item_t item ) if ( !isValid(register) ); punk@1: inputWire.wset(item); punk@1: endmethod punk@1: punk@1: // On dequeue we always invalidate the storage register regardless punk@1: // of whether or not the item was actually bypassed or not. We also punk@1: // set a combinational signal so that we know not to move the item punk@1: // into the register this cycle. punk@1: punk@1: method Action deq() if ( isValid(register) || isValid(inputWire.wget()) ); punk@1: register <= Invalid; punk@1: deqEnabled.wset(True); punk@1: endmethod punk@1: punk@1: // We get the item either from the register (if register is valid) or punk@1: // from the combinational bypasss (if the rwire is valid). punk@1: punk@1: method item_t first() if ( isValid(register) || isValid(inputWire.wget()) ); punk@1: if ( isValid(register) ) punk@1: return unJust(register); punk@1: else punk@1: return unJust(inputWire.wget()); punk@1: endmethod punk@1: punk@1: // FIFOF adds the following two methods punk@1: punk@1: method Bool notFull(); punk@1: return !isValid(register); punk@1: endmethod punk@1: punk@1: method Bool notEmpty(); punk@1: return (isValid(register) || isValid(inputWire.wget())); punk@1: endmethod punk@1: punk@1: // Not sure about the clear method ... punk@1: punk@1: method Action clear(); punk@1: dynamicAssert( False, "BFIFO.clear() not implemented yet!" ); punk@1: endmethod punk@1: punk@1: endmodule punk@1: punk@1: (* synthesize *) punk@1: module mkBFIFO_16 (FIFO#(Bit#(16))); punk@1: punk@1: let f <- mkBFIFO1(); punk@1: punk@1: return f; punk@1: punk@1: endmodule punk@1: