diff --git a/src_Core/CPU/Core.bsv b/src_Core/CPU/Core.bsv index ffe7360..248d4d4 100644 --- a/src_Core/CPU/Core.bsv +++ b/src_Core/CPU/Core.bsv @@ -179,6 +179,9 @@ module mkCore#(CoreId coreId)(Core); `ifdef RVFI_DII Toooba_RVFI_DII_Bridge_IFC rvfi_bridge <- mkTooobaRVFIDIIBridge; mkConnection(rvfi_bridge.dii, fetchStage.dii); + rule rl_passLastId; + fetchStage.lastTraceId(rvfi_bridge.lastId); + endrule `endif // back end diff --git a/src_Core/RISCY_OOO/procs/RV64G_OOO/CommitStage.bsv b/src_Core/RISCY_OOO/procs/RV64G_OOO/CommitStage.bsv index 40a6da9..06dd7bd 100644 --- a/src_Core/RISCY_OOO/procs/RV64G_OOO/CommitStage.bsv +++ b/src_Core/RISCY_OOO/procs/RV64G_OOO/CommitStage.bsv @@ -40,7 +40,7 @@ import VerificationPacket::*; import RenameDebugIF::*; `ifdef RVFI -import RVFI_DII :: *; +import RVFI_DII_Types::*; `endif typedef struct { @@ -131,41 +131,47 @@ typedef struct { } CommitTrap deriving(Bits, Eq, FShow); `ifdef RVFI -function RVFI_DII_Execution#(DataSz,DataSz) genRVFI(ToReorderBuffer rot); - Addr addr = 0; - Addr next_pc = rot.pc + 4; - Data data = rot.traceBundle.regWriteData; - case (rot.ppc_vaddr_csrData) matches - tagged VAddr .vaddr: addr = vaddr; - tagged PPC .ppc: next_pc = ppc; - tagged CSRData .csrdata: data = csrdata; - endcase - ByteEn rmask = replicate(False); - ByteEn wmask = replicate(False); - case (rot.lsqTag) matches - tagged Ld .l: rmask = rot.traceBundle.memByteEn; - tagged St .s: wmask = rot.traceBundle.memByteEn; - endcase - return RVFI_DII_Execution { - rvfi_order: 0, // Instruction number? InstID maybe? - rvfi_trap: isValid(rot.trap), - rvfi_halt: False, - rvfi_intr: ?, - rvfi_insn: rot.orig_inst, - rvfi_rs1_addr: rot.orig_inst[19:15], - rvfi_rs2_addr: rot.orig_inst[24:20], - rvfi_rs1_data: ?, - rvfi_rs2_data: ?, - rvfi_pc_rdata: rot.pc, - rvfi_pc_wdata: next_pc, - rvfi_mem_wdata: 0, - rvfi_rd_addr: rot.orig_inst[11:7], - rvfi_rd_wdata: ((rot.orig_inst[11:7]==0) ? 0:data), - rvfi_mem_addr: addr, - rvfi_mem_rmask: pack(rmask), - rvfi_mem_wmask: pack(wmask), - rvfi_mem_rdata: data - }; +function Maybe#(RVFI_DII_Execution#(DataSz,DataSz)) genRVFI(ToReorderBuffer rot, Dii_Id traceCnt); + Addr addr = 0; + Addr next_pc = 0; + Data data = 0; + ByteEn rmask = replicate(False); + ByteEn wmask = replicate(False); + if (!isValid(rot.trap)) begin + next_pc = rot.pc + 4; + data = rot.traceBundle.regWriteData; + case (rot.ppc_vaddr_csrData) matches + tagged VAddr .vaddr: begin + addr = vaddr; + case (rot.lsqTag) matches + tagged Ld .l: rmask = rot.traceBundle.memByteEn; + tagged St .s: wmask = rot.traceBundle.memByteEn; + endcase + end + tagged PPC .ppc: next_pc = ppc; + tagged CSRData .csrdata: data = csrdata; + endcase + end + return tagged Valid RVFI_DII_Execution { + rvfi_order: zeroExtend(pack(traceCnt)), + rvfi_trap: isValid(rot.trap), + rvfi_halt: False, + rvfi_intr: ?, + rvfi_insn: rot.orig_inst, + rvfi_rs1_addr: rot.orig_inst[19:15], + rvfi_rs2_addr: rot.orig_inst[24:20], + rvfi_rs1_data: ?, + rvfi_rs2_data: ?, + rvfi_pc_rdata: rot.pc, + rvfi_pc_wdata: next_pc, + rvfi_mem_wdata: 0, + rvfi_rd_addr: rot.orig_inst[11:7], + rvfi_rd_wdata: ((rot.orig_inst[11:7]==0) ? 0:data), + rvfi_mem_addr: addr, + rvfi_mem_rmask: pack(rmask), + rvfi_mem_wmask: pack(wmask), + rvfi_mem_rdata: data + }; endfunction `endif @@ -230,6 +236,7 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage); `ifdef RVFI // RVFI trace report. Not an input? FIFO#(Rvfi_Traces) rvfiQ <- mkFIFO; + Reg#(Dii_Id) traceCnt <- mkReg(0); `endif // deadlock check @@ -428,9 +435,10 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage); $display ("CommitStage.doCommitTrap_flush: commitTrap: ", fshow (commitTrap_val)); end `ifdef RVFI - Rvfi_Traces rvfis = replicate(RVFI_DII_Execution{rvfi_order: -1}); - rvfis[0] = genRVFI(x); + Rvfi_Traces rvfis = replicate(tagged Invalid); + rvfis[0] = genRVFI(x, traceCnt); rvfiQ.enq(rvfis); + traceCnt <= traceCnt + 1; `endif // flush everything. Only increment epoch and stall fetch when we haven @@ -469,6 +477,7 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage); if(trap.trap matches tagged Interrupt .inter) begin inIfc.commitCsrInstOrInterrupt; end + if (verbose) $display ("CommitStage.doCommitTrap_handle: ", fshow (commitTrap)); // trap handling & redirect let new_pc <- csrf.trap(trap.trap, trap.pc, trap.addr); @@ -533,9 +542,10 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage); rg_instret <= rg_instret + 1; end `ifdef RVFI - Rvfi_Traces rvfis = replicate(RVFI_DII_Execution{rvfi_order: -1}); - rvfis[0] = genRVFI(x); + Rvfi_Traces rvfis = replicate(tagged Invalid); + rvfis[0] = genRVFI(x, traceCnt); rvfiQ.enq(rvfis); + traceCnt <= traceCnt + 1; `endif // we claim a phy reg for every inst, so commit its renaming @@ -679,7 +689,8 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage); `endif `ifdef RVFI - Rvfi_Traces rvfis = replicate(RVFI_DII_Execution{rvfi_order: -1}); + Rvfi_Traces rvfis = replicate(tagged Invalid); + SupCnt whichTrace = 0; `endif Bit #(64) instret = 0; @@ -698,7 +709,8 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage); else begin if (verbose) $display("[doCommitNormalInst - %d] ", i, fshow(inst_tag), " ; ", fshow(x)); `ifdef RVFI - rvfis[i] = genRVFI(x); + rvfis[i] = genRVFI(x, traceCnt + zeroExtend(whichTrace)); + whichTrace = whichTrace + 1; `endif if (verbosity > 0) begin @@ -805,6 +817,7 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage); `endif `ifdef RVFI rvfiQ.enq(rvfis); + traceCnt <= traceCnt + zeroExtend(whichTrace); `endif endrule diff --git a/src_Core/RISCY_OOO/procs/lib/Types.bsv b/src_Core/RISCY_OOO/procs/lib/Types.bsv index e6f0a34..cccdf06 100644 --- a/src_Core/RISCY_OOO/procs/lib/Types.bsv +++ b/src_Core/RISCY_OOO/procs/lib/Types.bsv @@ -80,18 +80,18 @@ function Action doAssert(Bool b, String s) = dynamicAssert(b, s); `endif `ifdef RVFI_DII -typedef 8 SEQ_LEN; -typedef UInt#(SEQ_LEN) Dii_Id; -typedef Vector#(`sizeSup, RVFI_DII_Execution #(DataSz,DataSz)) Rvfi_Traces; +typedef Vector#(`sizeSup, Maybe#(RVFI_DII_Execution #(DataSz,DataSz))) Rvfi_Traces; +typedef Vector#(`sizeSup, Maybe#(Dii_Id)) Dii_Ids; +typedef Vector#(`sizeSup, Maybe#(Bit#(32))) Dii_Insts; typedef struct { - Vector#(`sizeSup, Maybe#(Instruction)) insts; - Vector#(`sizeSup, Dii_Id) ids; + Dii_Insts insts; + Dii_Ids ids; } InstsAndIDs deriving(Bits, Eq, FShow); interface Toooba_RVFI_DII_Server; - interface Get#(Dii_Id) seqReq; - interface Put#(Tuple2#(Bit#(32), Dii_Id)) inst; - interface Get#(RVFI_DII_Execution#(DataSz, DataSz)) trace_report; + interface Get#(Dii_Ids) seqReq; + interface Put#(InstsAndIDs) inst; + interface Get#(Rvfi_Traces) trace_report; endinterface `endif diff --git a/src_Testbench/SoC/SoC_Top.bsv b/src_Testbench/SoC/SoC_Top.bsv index 1668dbd..cc24dd1 100644 --- a/src_Testbench/SoC/SoC_Top.bsv +++ b/src_Testbench/SoC/SoC_Top.bsv @@ -72,7 +72,7 @@ import TV_Info :: *; `endif `ifdef RVFI_DII -import RVFI_DII :: *; +import RVFI_DII_Types :: *; import Types :: *; `endif diff --git a/src_Testbench/Top/Top_HW_Side.bsv b/src_Testbench/Top/Top_HW_Side.bsv index 1c55a53..40e8e8e 100644 --- a/src_Testbench/Top/Top_HW_Side.bsv +++ b/src_Testbench/Top/Top_HW_Side.bsv @@ -31,6 +31,8 @@ package Top_HW_Side; // ================================================================ // BSV lib imports +`include "ProcConfig.bsv" + import GetPut :: *; import ClientServer :: *; import Connectable :: *; @@ -300,6 +302,7 @@ endmodule (* synthesize *) module mkTop_HW_Side(Empty) + provisos (Add#(a__, TDiv#(DataSz,8), 8), Add#(b__, DataSz, 64), Add#(c__, TDiv#(DataSz,8), 8), Add#(d__, DataSz, 64)); Reg #(Bool) rg_banner_printed <- mkReg (False); @@ -314,15 +317,14 @@ module mkTop_HW_Side(Empty) rg_banner_printed <= True; endrule - RVFI_DII_Bridge #(DataSz, DataSz, SEQ_LEN) bridge <- mkRVFI_DII_Bridge("", 5001); + RVFI_DII_Bridge #(DataSz, DataSz, `sizeSup) bridge <- mkRVFI_DII_Bridge("", 5001); let dut <- mkPre_Top_HW_Side(reset_by bridge.new_rst); mkConnection(bridge.client.report, dut.trace_report); - (* descending_urgency = "bridge.handleReset, rl_provide_instr" *) rule rl_provide_instr; - Dii_Id req <- dut.seqReq.get; - Bit#(32) inst <- bridge.client.getInst(req); - dut.inst.put(tuple2(inst, req)); + Dii_Ids reqs <- dut.seqReq.get; + Dii_Insts insts <- bridge.client.getInst(reqs); + dut.inst.put(InstsAndIDs{insts: insts, ids: reqs}); endrule endmodule diff --git a/src_Verifier/BSV-RVFI-DII b/src_Verifier/BSV-RVFI-DII index 380f77d..b64f7a5 160000 --- a/src_Verifier/BSV-RVFI-DII +++ b/src_Verifier/BSV-RVFI-DII @@ -1 +1 @@ -Subproject commit 380f77da5bbed8ce2b34fd177f4f4dee3cecfa67 +Subproject commit b64f7a532d229f18baa58651f4066b7373c20ec1 diff --git a/src_Verifier/Toooba_RVFI_DII_Bridge.bsv b/src_Verifier/Toooba_RVFI_DII_Bridge.bsv index 0f7e654..b6c56fd 100644 --- a/src_Verifier/Toooba_RVFI_DII_Bridge.bsv +++ b/src_Verifier/Toooba_RVFI_DII_Bridge.bsv @@ -43,8 +43,10 @@ import ConfigReg :: *; // ================================================================ // Project imports +`include "ProcConfig.bsv" + import Types::*; -import ProcTypes::*; +import ProcTypes::*; //import Verifier :: *; import RVFI_DII :: *; @@ -53,74 +55,51 @@ import RVFI_DII :: *; interface Toooba_RVFI_DII_Bridge_IFC; interface Toooba_RVFI_DII_Server rvfi_dii_server; - interface Server#(Dii_Id, InstsAndIDs) dii; + interface Server#(Dii_Ids, InstsAndIDs) dii; interface Put#(Rvfi_Traces) rvfi; + method Dii_Id lastId; endinterface module mkTooobaRVFIDIIBridge(Toooba_RVFI_DII_Bridge_IFC); // DII state - FIFOF#(Tuple2#(Bit#(32), Dii_Id)) dii_in <- mkUGFIFOF; - Reg#(InstsAndIDs) buff <- mkConfigRegU; FIFOF#(InstsAndIDs) instrs <- mkSizedFIFOF(2048); - PulseWire putFromBridge <- mkPulseWire; // RVFI state FIFO#(Rvfi_Traces) report_vectors <- mkSizedFIFO(2048); - FIFO#(RVFI_DII_Execution#(DataSz,DataSz)) reports <- mkFIFO; // Request ID - FIFO#(Dii_Id) seq_req <- mkFIFO; - - Bit#(32) nop = 'h01FFF033; + FIFO#(Dii_Ids) seq_req <- mkFIFO; + Reg#(Dii_Id) last_id <- mkReg(0); Bool verbose = True; function Bool validReport(RVFI_DII_Execution#(DataSz,DataSz) trace); - return (trace.rvfi_order != -1 && trace.rvfi_insn != nop); + return (trace.rvfi_insn != dii_nop); endfunction - Reg#(SupWaySel) report_select <- mkReg(0); - rule split_report_vectors; - RVFI_DII_Execution#(DataSz,DataSz) report = report_vectors.first[report_select]; - if (verbose) - $display("%t RVFI response: ", $time, - fshow(report_vectors.first[report_select]) - ); - if (validReport(report)) reports.enq(report); - if (report_select == -1) report_vectors.deq(); - report_select <= report_select + 1; - endrule + // These two functions convert beteween "Invalid" instructions and "nops". + // This is because the pipeline currently isn't able to handle Invalid injections, + // so we replace them with special nops in the bridge that we can filter out in the rvfi trace stream. + function Maybe#(Bit#(32)) maybeToNop(Maybe#(Bit#(32)) in); + return tagged Valid fromMaybe(dii_nop, in); + endfunction - Reg#(SupWaySel) buffLvl <- mkConfigReg(0); - rule bufferInsts(buffLvl != 0 || dii_in.notEmpty); - InstsAndIDs cb = buff; - Bit#(32) ins = nop; - Dii_Id id = ?; - if (dii_in.notEmpty) {ins, id} <- toGet(dii_in).get; - cb.insts[buffLvl] = tagged Valid ins; - cb.ids[buffLvl] = id; - if (buffLvl == -1) begin - instrs.enq(cb); - cb.insts = replicate(tagged Invalid); - end - buff <= cb; - buffLvl <= buffLvl + 1; - endrule + function Maybe#(RVFI_DII_Execution #(DataSz,DataSz)) nopToMaybe(Maybe#(RVFI_DII_Execution #(DataSz,DataSz)) in); + Maybe#(RVFI_DII_Execution #(DataSz,DataSz)) ret = in; + if (ret matches tagged Valid .val &&& !validReport(val)) ret = tagged Invalid; + return (ret); + endfunction interface Toooba_RVFI_DII_Server rvfi_dii_server; interface Get seqReq = toGet(seq_req); - interface Put inst; - method Action put(Tuple2#(Bit#(32), Dii_Id) in) if (dii_in.notFull); - dii_in.enq(in); - putFromBridge.send(); - endmethod - endinterface - interface Get trace_report = toGet(reports); + interface Put inst = toPut(instrs); + interface Get trace_report = toGet(report_vectors); endinterface interface Server dii; interface Put request = toPut(seq_req); interface Get response; - method ActionValue#(InstsAndIDs) get if (!putFromBridge); + method ActionValue#(InstsAndIDs) get; InstsAndIDs insts = instrs.first(); + insts.insts = map(maybeToNop, insts.insts); instrs.deq(); if (verbose) $display("%t DII injection: ", $time, @@ -131,7 +110,21 @@ module mkTooobaRVFIDIIBridge(Toooba_RVFI_DII_Bridge_IFC); endinterface endinterface - interface Put rvfi = toPut(report_vectors); + interface Put rvfi; + method Action put(Rvfi_Traces in); + Rvfi_Traces out = map(nopToMaybe,in); + report_vectors.enq(out); + Dii_Id next_id = last_id; + for (Integer i = 0; i < `sizeSup; i = i + 1) begin + if (out[i] matches tagged Valid .rpt) begin + Dii_Id this_id = unpack(truncate(rpt.rvfi_order)); + if (this_id > next_id) next_id = this_id; + end + end + last_id <= next_id; + endmethod + endinterface + method Dii_Id lastId = last_id; endmodule endpackage diff --git a/src_bsc_lib_RTL/SyncFIFOLevel.v b/src_bsc_lib_RTL/SyncFIFOLevel.v deleted file mode 100644 index 8ca1331..0000000 --- a/src_bsc_lib_RTL/SyncFIFOLevel.v +++ /dev/null @@ -1,519 +0,0 @@ - -// Copyright (c) 2000-2012 Bluespec, Inc. - -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: - -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. - -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// -// $Revision$ -// $Date$ - -`ifdef BSV_ASSIGNMENT_DELAY -`else - `define BSV_ASSIGNMENT_DELAY -`endif - -`ifdef BSV_POSITIVE_RESET - `define BSV_RESET_VALUE 1'b1 - `define BSV_RESET_EDGE posedge -`else - `define BSV_RESET_VALUE 1'b0 - `define BSV_RESET_EDGE negedge -`endif - -`ifdef BSV_RESET_FIFO_HEAD - `define BSV_RESET_EDGE_HEAD or `BSV_RESET_EDGE dRST -`else - `define BSV_RESET_EDGE_HEAD -`endif - - -// A clock synchronization FIFO where the enqueue and dequeue sides are in -// different clock domains. -// There are no restrictions w.r.t. clock frequencies -// The depth of the FIFO must be a power of 2 (2,4,8,...) since the -// indexing uses a Gray code counter. -// FULL and EMPTY signal are pessimistic, that is, they are asserted -// immediately when the FIFO becomes FULL or EMPTY, but their deassertion -// is delayed due to synchronization latency. -// dCount and sCount are also delayed and may differ because of latency -// from the synchronization logic -module SyncFIFOLevel( - sCLK, - sRST, - dCLK, - sENQ, - sD_IN, - sFULL_N, - dDEQ, - dD_OUT, - dEMPTY_N, - dCOUNT, - sCOUNT, - sCLR, - sCLR_RDY, - dCLR, - dCLR_RDY - ) ; - - - parameter dataWidth = 1 ; - parameter depth = 2 ; // minimum 2 - parameter indxWidth = 1 ; // minimum 1 - - // input clock domain ports - input sCLK ; - input sRST ; - input sENQ ; - input [dataWidth -1 : 0] sD_IN ; - output sFULL_N ; - - // destination clock domain ports - input dCLK ; - input dDEQ ; - output dEMPTY_N ; - output [dataWidth -1 : 0] dD_OUT ; - - // Counts of capacity need extra bit to show full, e.g., range is 0 to 32 - output [indxWidth : 0] dCOUNT; - output [indxWidth : 0] sCOUNT; - - // Clear signals on both domains - input sCLR; - output sCLR_RDY; - input dCLR; - output dCLR_RDY; - - // constants for bit masking of the gray code - wire [indxWidth : 0] msbset = ~({(indxWidth + 1){1'b1}} >> 1) ; - wire [indxWidth - 1 : 0] msb2set = ~({(indxWidth + 0){1'b1}} >> 1) ; - wire [indxWidth : 0] msb12set = msbset | {1'b0, msb2set} ; // 'b11000... - - // FIFO Memory - reg [dataWidth -1 : 0] fifoMem [0: depth -1 ] ; - reg [dataWidth -1 : 0] dDoutReg ; - - // Enqueue Pointer - reg [indxWidth : 0] sGEnqPtr, sBEnqPtr ; // Flops - reg sNotFullReg ; - wire [indxWidth : 0] sNextGEnqPtr, sNextBEnqPtr ; - wire [indxWidth : 0] sNextCnt, sFutureCnt ; - wire sNextNotFull, sFutureNotFull ; - - // Dequeue Pointer - reg [indxWidth : 0] dGDeqPtr, dBDeqPtr ; // Flops - reg dNotEmptyReg ; - wire [indxWidth : 0] dNextGDeqPtr, dNextBDeqPtr ; - wire [indxWidth : 0] dNextCnt ; - wire dNextNotEmpty; - - - // Rgisters needed for capacity counts - reg [indxWidth : 0] sCountReg, dCountReg ; - - // Note for Timing improvement: - // These signals can be registers to improve a long path from the - // second stage of the synchronizer to the input of the - // CountReg. The path includes a Gray to Binary conversion and a - // subtraction, which can easily be a long path. - // The effect is that the count is delayed one additional cycle. - wire [indxWidth : 0] sBDeqPtr, dBEnqPtr ; - - // flops to sychronize enqueue and dequeue point across domains - reg [indxWidth : 0] dSyncReg1, dEnqPtr ; - reg [indxWidth : 0] sSyncReg1, sDeqPtr ; - - // Indexes for fifo memory is one bit smaller than indexes - wire [indxWidth - 1 :0] sEnqPtrIndx, dDeqPtrIndx ; - - // wires needed for clear processing - wire dRST; - wire sCLRSynced; // dCLR synced to sCLK - wire sCLR_RDY_int; - - wire dCLRSynced; // sCLR synced to dCLK - wire dCLR_RDY_int; - - wire sClear; - wire dClear; - - // Clear processing requires the use of 2 handshake synchronizers - SyncHandshake #(.delayreturn(1)) - sClrSync ( .sCLK(sCLK), - .sRST(sRST), - .dCLK(dCLK), - .sEN(sCLR), - .sRDY(sCLR_RDY_int), - .dPulse(dCLRSynced)); - - SyncHandshake #(.delayreturn(1)) - dClrSync ( .sCLK(dCLK), - .sRST(sRST), - .dCLK(sCLK), - .sEN(dCLR), - .sRDY(dCLR_RDY_int), - .dPulse(sCLRSynced)); - - // Outputs - assign dD_OUT = dDoutReg; - assign dEMPTY_N = dNotEmptyReg ; - assign sFULL_N = sNotFullReg ; - assign sCOUNT = sCountReg; - assign dCOUNT = dCountReg; - assign sCLR_RDY = sCLR_RDY_int; - assign dCLR_RDY = dCLR_RDY_int; - - // Indexes are truncated from the Binary counter - assign sEnqPtrIndx = sBEnqPtr[indxWidth-1:0] ; - assign dDeqPtrIndx = dBDeqPtr[indxWidth-1:0] ; - - // clear signals - assign sClear = sCLR || !sCLR_RDY_int || sCLRSynced; - assign dClear = dCLR || !dCLR_RDY_int || dCLRSynced; - assign dRST = sRST; - - // Fifo memory write - always @(posedge sCLK) - begin - if ( sENQ ) - fifoMem[sEnqPtrIndx] <= `BSV_ASSIGNMENT_DELAY sD_IN ; - end // always @ (posedge sCLK) - - //////////////////////////////////////////////////////////////////////// - // Enqueue Pointer and increment logic - assign sNextBEnqPtr = sBEnqPtr + 1'b1 ; - assign sNextGEnqPtr = sNextBEnqPtr ^ (sNextBEnqPtr >> 1) ; - assign sNextNotFull = (sGEnqPtr ^ msb12set) != sDeqPtr ; - assign sFutureNotFull = (sNextGEnqPtr ^ msb12set) != sDeqPtr ; - assign sNextCnt = sBEnqPtr - sBDeqPtr ; - assign sFutureCnt = sNextBEnqPtr - sBDeqPtr ; - assign sBDeqPtr = grayToBinary( sDeqPtr ) ; - - - always @(posedge sCLK or `BSV_RESET_EDGE sRST) - begin - if (sRST == `BSV_RESET_VALUE) - begin - sBEnqPtr <= `BSV_ASSIGNMENT_DELAY {(indxWidth +1 ) {1'b0}} ; - sGEnqPtr <= `BSV_ASSIGNMENT_DELAY {(indxWidth +1 ) {1'b0}} ; - sNotFullReg <= `BSV_ASSIGNMENT_DELAY 1'b0 ; // Mark as full during reset - sCountReg <= `BSV_ASSIGNMENT_DELAY {(indxWidth +1 ) {1'b0}} ; - end // if (sRST == `BSV_RESET_VALUE) - else - begin - if (sClear) - begin - sBEnqPtr <= `BSV_ASSIGNMENT_DELAY {(indxWidth +1 ) {1'b0}} ; - sGEnqPtr <= `BSV_ASSIGNMENT_DELAY {(indxWidth +1 ) {1'b0}} ; - sNotFullReg <= `BSV_ASSIGNMENT_DELAY 1'b0 ; - sCountReg <= `BSV_ASSIGNMENT_DELAY {(indxWidth +1 ) {1'b0}} ; - end - else if ( sENQ ) - begin - sBEnqPtr <= `BSV_ASSIGNMENT_DELAY sNextBEnqPtr ; - sGEnqPtr <= `BSV_ASSIGNMENT_DELAY sNextGEnqPtr ; - sNotFullReg <= `BSV_ASSIGNMENT_DELAY sFutureNotFull ; - sCountReg <= `BSV_ASSIGNMENT_DELAY sFutureCnt ; - end - else - begin - sNotFullReg <= `BSV_ASSIGNMENT_DELAY sNextNotFull ; - sCountReg <= `BSV_ASSIGNMENT_DELAY sNextCnt ; - end // else: !if( sENQ ) - end // else: !if(sRST == `BSV_RESET_VALUE) - end // always @ (posedge sCLK or `BSV_RESET_EDGE sRST) - - // Enqueue pointer synchronizer to dCLK - always @(posedge dCLK or `BSV_RESET_EDGE sRST) - begin - if (sRST == `BSV_RESET_VALUE) - begin - dSyncReg1 <= `BSV_ASSIGNMENT_DELAY {(indxWidth + 1) {1'b0}} ; - dEnqPtr <= `BSV_ASSIGNMENT_DELAY {(indxWidth + 1) {1'b0}} ; - end // if (sRST == `BSV_RESET_VALUE) - else - begin - dSyncReg1 <= `BSV_ASSIGNMENT_DELAY sGEnqPtr ; // Clock domain crossing - dEnqPtr <= `BSV_ASSIGNMENT_DELAY dSyncReg1 ; - end // else: !if(sRST == `BSV_RESET_VALUE) - end // always @ (posedge dCLK or `BSV_RESET_EDGE sRST) - //////////////////////////////////////////////////////////////////////// - - //////////////////////////////////////////////////////////////////////// - // Enqueue Pointer and increment logic - assign dNextBDeqPtr = dBDeqPtr + 1'b1 ; - assign dNextGDeqPtr = dNextBDeqPtr ^ (dNextBDeqPtr >> 1) ; - assign dNextNotEmpty = dGDeqPtr != dEnqPtr ; - assign dNextCnt = dBEnqPtr - dBDeqPtr ; - assign dBEnqPtr = grayToBinary( dEnqPtr ) ; - - always @(posedge dCLK or `BSV_RESET_EDGE dRST) - begin - if (dRST == `BSV_RESET_VALUE) - begin - dBDeqPtr <= `BSV_ASSIGNMENT_DELAY {(indxWidth + 1) {1'b0}} ; - dGDeqPtr <= `BSV_ASSIGNMENT_DELAY {(indxWidth + 1) {1'b0}} ; - dNotEmptyReg <= `BSV_ASSIGNMENT_DELAY 1'b0 ; // Mark as empty to avoid dequeues until after reset - dCountReg <= `BSV_ASSIGNMENT_DELAY {(indxWidth + 1) {1'b0}} ; - end // if (sRST == `BSV_RESET_VALUE) - else - begin - if (dClear) begin - dBDeqPtr <= `BSV_ASSIGNMENT_DELAY {(indxWidth + 1) {1'b0}} ; - dGDeqPtr <= `BSV_ASSIGNMENT_DELAY {(indxWidth + 1) {1'b0}} ; - dNotEmptyReg <= `BSV_ASSIGNMENT_DELAY 1'b0 ; - dCountReg <= `BSV_ASSIGNMENT_DELAY {(indxWidth + 1) {1'b0}} ; - end - else if (!dNotEmptyReg && dNextNotEmpty) begin - dBDeqPtr <= `BSV_ASSIGNMENT_DELAY dNextBDeqPtr ; - dGDeqPtr <= `BSV_ASSIGNMENT_DELAY dNextGDeqPtr ; - dNotEmptyReg <= `BSV_ASSIGNMENT_DELAY 1'b1 ; - dCountReg <= `BSV_ASSIGNMENT_DELAY dNextCnt ; - end - else if (dDEQ && dNextNotEmpty) begin - dBDeqPtr <= `BSV_ASSIGNMENT_DELAY dNextBDeqPtr ; - dGDeqPtr <= `BSV_ASSIGNMENT_DELAY dNextGDeqPtr ; - dNotEmptyReg <= `BSV_ASSIGNMENT_DELAY 1'b1 ; - dCountReg <= `BSV_ASSIGNMENT_DELAY dNextCnt ; - end - else if (dDEQ && !dNextNotEmpty) begin - dNotEmptyReg <= `BSV_ASSIGNMENT_DELAY 1'b0 ; - dCountReg <= `BSV_ASSIGNMENT_DELAY {(indxWidth + 1) {1'b0}} ; - end - else begin - dCountReg <= `BSV_ASSIGNMENT_DELAY dNextCnt ; - end - end // else: !if(sRST == `BSV_RESET_VALUE) - end // always @ (posedge dCLK or `BSV_RESET_EDGE sRST) - - always @(posedge dCLK `BSV_RESET_EDGE_HEAD) - begin -`ifdef BSV_RESET_FIFO_HEAD - if (dRST == `BSV_RESET_VALUE) - begin - dDoutReg <= `BSV_ASSIGNMENT_DELAY { dataWidth { 1'b0 }} ; - end // if (dRST == `BSV_RESET_VALUE) - else -`endif - begin - if ((!dNotEmptyReg || dDEQ) && dNextNotEmpty) begin - dDoutReg <= `BSV_ASSIGNMENT_DELAY fifoMem[dDeqPtrIndx] ; - end - end - end - - // Dequeue pointer synchronized to sCLK - always @(posedge sCLK or `BSV_RESET_EDGE sRST) - begin - if (sRST == `BSV_RESET_VALUE) - begin - sSyncReg1 <= `BSV_ASSIGNMENT_DELAY {(indxWidth + 1) {1'b0}} ; - sDeqPtr <= `BSV_ASSIGNMENT_DELAY {(indxWidth + 1) {1'b0}} ; - end // if (sRST == `BSV_RESET_VALUE) - else - begin - sSyncReg1 <= `BSV_ASSIGNMENT_DELAY dGDeqPtr ; // clock domain crossing - sDeqPtr <= `BSV_ASSIGNMENT_DELAY sSyncReg1 ; - // sBDeqPtr <= `BSV_ASSIGNMENT_DELAY grayToBinary( sDeqPtr ) ; - end // else: !if(sRST == `BSV_RESET_VALUE) - end // always @ (posedge sCLK or `BSV_RESET_EDGE sRST) - //////////////////////////////////////////////////////////////////////// - - // synopsys translate_off - // Run time assertion check - always @(posedge sCLK) - begin - if ( sENQ && ! sNotFullReg ) $display ("Warning: SyncFIFOLevel: %m -- Enqueing to a full fifo"); - end - always @(posedge dCLK) - begin - if ( dDEQ && ! dNotEmptyReg ) $display ("Warning: SyncFIFOLevel: %m -- Dequeuing from empty fifo"); - end - // synopsys translate_on - -`ifdef BSV_NO_INITIAL_BLOCKS -`else // not BSV_NO_INITIAL_BLOCKS - // synopsys translate_off - initial - begin : initBlock - integer i ; - - // initialize the FIFO memory with aa's - for (i = 0; i < depth; i = i + 1) - begin - fifoMem[i] = {((dataWidth + 1)/2){2'b10}} ; - end - dDoutReg = {((dataWidth + 1)/2){2'b10}} ; - - // initialize the pointer - sGEnqPtr = {((indxWidth + 1)/2){2'b10}} ; - sBEnqPtr = sGEnqPtr ; - sNotFullReg = 1'b0 ; - - dGDeqPtr = sGEnqPtr ; - dBDeqPtr = sGEnqPtr ; - dNotEmptyReg = 1'b0; - - - // initialize other registers - sSyncReg1 = sGEnqPtr ; - sDeqPtr = sGEnqPtr ; - dSyncReg1 = sGEnqPtr ; - dEnqPtr = sGEnqPtr ; - end // initial begin - // synopsys translate_on - - // synopsys translate_off - initial - begin : parameter_assertions - integer ok ; - integer i, expDepth ; - - ok = 1; - expDepth = 1 ; - - // calculate x = 2 ** (indxWidth - 1) - for( i = 0 ; i < indxWidth ; i = i + 1 ) - begin - expDepth = expDepth * 2 ; - end - if ( expDepth != depth ) - begin - ok = 0; - $display ( "ERROR SyncFiFOLevel.v: index size and depth do not match;" ) ; - $display ( "\tdepth must equal 2 ** index size. expected %0d", expDepth ); - end - - #0 - if ( ok == 0 ) $finish ; - - end // initial begin - // synopsys translate_on -`endif // BSV_NO_INITIAL_BLOCKS - - function [indxWidth:0] grayToBinary ; - input [indxWidth:0] grayin; - begin: grayToBinary_block - reg [indxWidth:0] binary ; - integer i ; - for ( i = 0 ; i <= indxWidth ; i = i+1 ) - begin - binary[i] = ^( grayin >> i ) ; - end - grayToBinary = binary ; - end - endfunction - -endmodule // FIFOSync - - - - -`ifdef testBluespec -module testSyncFIFOLevel() ; - parameter dsize = 8; - parameter fifodepth = 32; - parameter fifoidx = 5; - - wire sCLK, dCLK, dRST ; - wire sENQ, dDEQ; - wire sFULL_N, dEMPTY_N ; - wire [dsize -1:0] sDIN, dDOUT ; - - reg [dsize -1:0] sCNT, dCNT ; - reg sRST ; - - wire [fifoidx:0] dItemCnt, sItemCnt ; - wire sCLR_RDY; - wire dCLR_RDY; - wire sCLR; - wire dCLR; - reg [31:0] count ; - reg started ; - reg ddeq ; - - - ClockGen#(14,15,10) sc( sCLK ); - ClockGen#(11,12,2600) dc( dCLK ); // Pause the generation of the destination side clock - - initial - begin - sCNT = 0; - dCNT = 0; - sRST = `BSV_RESET_VALUE ; - count = 0; - started = 0; - ddeq = 0; - - $display( "running test" ) ; - - $dumpfile("SyncFIFOLevel.vcd"); - $dumpvars(10,testSyncFIFOLevel) ; - #1 - $dumpon ; - #200 ; - sRST = !`BSV_RESET_VALUE ; - - - #50000 $finish ; - end - - SyncFIFOLevel #(dsize,fifodepth,fifoidx) - dut( sCLK, sRST, dCLK, sENQ, sDIN, - sFULL_N, dDEQ, dDOUT, dEMPTY_N, dItemCnt, sItemCnt, - sCLR, sCLR_RDY, dCLR, dCLR_RDY ); - - assign sDIN = sCNT ; - assign sENQ = sFULL_N ; - - assign dCLR = ((count[7:0] == 8'b0010_0011) && dCLR_RDY); - assign sCLR = ((count[7:0] == 8'b0000_0001) && sCLR_RDY); - - always @(posedge sCLK) - begin - count <= count + 1 ; - $display( "scount is %d", sItemCnt ) ; - if (sENQ ) - begin - sCNT <= `BSV_ASSIGNMENT_DELAY sCNT + 1; - $display( "enqueuing is %d", sCNT ) ; - end // if (sENQ ) - end // always @ (posedge sCLK) - - assign dDEQ = ddeq ; - - always @(dItemCnt or dEMPTY_N or started or count) - begin - ddeq = (count > 40) && dEMPTY_N && (started || dItemCnt > 4); - end // always @ (dItemCnt or dEMPTY_N or started) - - always @(posedge dCLK) - begin - $display( "dcount is %d", dItemCnt ) ; - if (ddeq) - begin - started <= 1; - $display( "dequeing %d", dDOUT ) ; - end // if (dDEQ ) - else - begin - started <= 0; - end - end // always @ (posedge dCLK) - -endmodule // testSyncFIFO -`endif diff --git a/src_bsc_lib_RTL/SyncRegister.v b/src_bsc_lib_RTL/SyncRegister.v new file mode 100644 index 0000000..e34908a --- /dev/null +++ b/src_bsc_lib_RTL/SyncRegister.v @@ -0,0 +1,175 @@ + +// Copyright (c) 2000-2013 Bluespec, Inc. + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// $Revision$ +// $Date$ + +`ifdef BSV_ASSIGNMENT_DELAY +`else + `define BSV_ASSIGNMENT_DELAY +`endif + +`ifdef BSV_POSITIVE_RESET + `define BSV_RESET_VALUE 1'b1 + `define BSV_RESET_EDGE posedge +`else + `define BSV_RESET_VALUE 1'b0 + `define BSV_RESET_EDGE negedge +`endif + + +// A register synchronization module across clock domains. +// Uses a Handshake Pulse protocol to trigger the load on +// destination side registers +// Transfer takes 3 dCLK for destination side to see data, +// sRDY recovers takes 3 dCLK + 3 sCLK +module SyncRegister( + sCLK, + sRST, + dCLK, + sEN, + sRDY, + sD_IN, + dD_OUT + ); + parameter width = 1 ; + parameter init = { width {1'b0 }} ; + + // Source clock domain ports + input sCLK ; + input sRST ; + input sEN ; + input [width -1 : 0] sD_IN ; + output sRDY ; + + // Destination clock domain ports + input dCLK ; + output [width -1 : 0] dD_OUT ; + + wire dPulse ; + reg [width -1 : 0] sDataSyncIn ; + reg [width -1 : 0] dD_OUT ; + + // instantiate a Handshake Sync + SyncHandshake #(.init(0),.delayreturn(1)) + sync( .sCLK(sCLK), .sRST(sRST), + .dCLK(dCLK), + .sEN(sEN), .sRDY(sRDY), + .dPulse(dPulse) ) ; + + always @(posedge sCLK or `BSV_RESET_EDGE sRST) + begin + if (sRST == `BSV_RESET_VALUE) + begin + sDataSyncIn <= `BSV_ASSIGNMENT_DELAY init ; + end // if (sRST == `BSV_RESET_VALUE) + else + begin + if ( sEN ) + begin + sDataSyncIn <= `BSV_ASSIGNMENT_DELAY sD_IN ; + end // if ( sEN ) + end // else: !if(sRST == `BSV_RESET_VALUE) + end // always @ (posedge sCLK or `BSV_RESET_EDGE sRST) + + + // Transfer the data to destination domain when dPulsed is asserted. + // Setup and hold time are assured since at least 2 dClks occured since + // sDataSyncIn have been written. + always @(posedge dCLK or `BSV_RESET_EDGE sRST) + begin + if (sRST == `BSV_RESET_VALUE) + begin + dD_OUT <= `BSV_ASSIGNMENT_DELAY init ; + end // if (sRST == `BSV_RESET_VALUE) + else + begin + if ( dPulse ) + begin + dD_OUT <= `BSV_ASSIGNMENT_DELAY sDataSyncIn ;// clock domain crossing + end // if ( dPulse ) + end // else: !if(sRST == `BSV_RESET_VALUE) + end // always @ (posedge dCLK or `BSV_RESET_EDGE sRST) + + +`ifdef BSV_NO_INITIAL_BLOCKS +`else // not BSV_NO_INITIAL_BLOCKS + // synopsys translate_off + initial + begin + sDataSyncIn = {((width + 1)/2){2'b10}} ; + dD_OUT = {((width + 1)/2){2'b10}} ; + end // initial begin + // synopsys translate_on +`endif // BSV_NO_INITIAL_BLOCKS + + +endmodule // RegisterSync + + + +`ifdef testBluespec +module testSyncRegister() ; + parameter dsize = 8; + + wire sCLK, sRST, dCLK ; + wire sEN ; + wire sRDY ; + + reg [dsize -1:0] sCNT ; + wire [dsize -1:0] sDIN, dDOUT ; + + ClockGen#(20,9,10) sc( sCLK ); + ClockGen#(11,12,26) dc( dCLK ); + + initial + begin + sCNT = 0; + + $dumpfile("SyncRegister.dump"); + $dumpvars(5) ; + $dumpon ; + #100000 $finish ; + end + + SyncRegister #(dsize) + dut( sCLK, sRST, dCLK, + sEN, sRDY, sDIN, + dDOUT ) ; + + + assign sDIN = sCNT ; + assign sEN = sRDY ; + + always @(posedge sCLK) + begin + if (sRDY ) + begin + sCNT <= `BSV_ASSIGNMENT_DELAY sCNT + 1; + end + end // always @ (posedge sCLK) + + + +endmodule // testSyncFIFO +`endif + +