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