diff --git a/Libraries/Misc/Makefile b/Libraries/Misc/Makefile index c233f52..22b5079 100644 --- a/Libraries/Misc/Makefile +++ b/Libraries/Misc/Makefile @@ -15,6 +15,7 @@ build: $(BSC) -u $(BSCFLAGS) EdgeFIFOFs.bsv $(BSC) -u $(BSCFLAGS) GetPut_Aux.bsv $(BSC) -u $(BSCFLAGS) Semi_FIFOF.bsv + $(BSC) -u $(BSCFLAGS) VectorFIFOF.bsv .PHONY: clean full_clean clean full_clean: diff --git a/Libraries/Misc/VectorFIFOF.bsv b/Libraries/Misc/VectorFIFOF.bsv new file mode 100644 index 0000000..f5d1d11 --- /dev/null +++ b/Libraries/Misc/VectorFIFOF.bsv @@ -0,0 +1,104 @@ +// Copyright (c) 2025 Bluespec, Inc. +// +// SPDX-License-Identifier: BSD-3-Clause + +package VectorFIFOF; + +// This package implements a fifo like module with a parameterized +// depth and standard FIFOF interface. The module also provides +// parallel access to all items in the fifo, for example, to allow +// searching for hazards before enqueueing new items. +// +// Due to the use of registers for the head and tail pointer, enq and +// deq should be callable in any order, but cannot both be called in +// the same cycle if the fifo is empty or full. +// +// The clear method conflicts with enq and deq. +// +// The order of the elements in the parallel read interface 'vector' +// is not fifo order. + +import Assert ::*; +import FIFOF ::*; +import Vector ::*; + +interface VectorFIFOF#(numeric type depth, type t); + interface FIFOF#(t) fifo; + interface Vector#(depth, Maybe#(t)) vector; +endinterface + +module mkVectorFIFOF(VectorFIFOF#(depth, t)) + provisos( + Bits#(t, a__) + ); + + staticAssert(valueOf(depth) == valueOf(TExp#(TLog#(depth))), "depth must be a power of 2"); + + Vector#(depth, Reg#(t)) vr_data <- replicateM(mkRegU); + + // The head and tail pointers have a range of 2*depth in order to + // track empty/full and wraparound. Size must be power of 2 due to + // modulo arithmetic. + Reg#(UInt#(TLog#(TMul#(depth,2)))) r_head <- mkReg(0); + Reg#(UInt#(TLog#(TMul#(depth,2)))) r_tail <- mkReg(0); + + function UInt#(TLog#(TMul#(depth,2))) count; + return r_head - r_tail; + endfunction + + function Bool notFull; + return count != fromInteger(valueOf(depth)); + endfunction + + function Bool notEmpty; + return count != 0; + endfunction + + function Maybe#(t) valid(Integer x, t a); + if (r_head >= r_tail) + if (fromInteger(x) < (r_head % fromInteger(valueOf(depth))) && + fromInteger(x) >= (r_tail % fromInteger(valueOf(depth)))) + return tagged Valid a; + else + return tagged Invalid; + else + if (fromInteger(x) < (r_head % fromInteger(valueOf(depth))) || + fromInteger(x) >= (r_tail % fromInteger(valueOf(depth)))) + return tagged Valid a; + else + return tagged Invalid; + endfunction + + interface FIFOF fifo; + method Action enq(t x) if (notFull); + vr_data[r_head % fromInteger(valueOf(depth))] <= x; + r_head <= r_head + 1; + endmethod + + method Action deq if (notEmpty); + r_tail <= r_tail + 1; + endmethod + + method t first if (count > 0); + return vr_data[r_tail % fromInteger(valueOf(depth))]; + endmethod + + method Action clear; + r_head <= 0; + r_tail <= 0; + endmethod + + method Bool notFull; + return notFull; + endmethod + + method Bool notEmpty; + return notEmpty; + endmethod + endinterface + + interface Vector vector = zipWith(valid, genVector, readVReg(vr_data)); + +endmodule + +endpackage