// Copyright (c) 2018-2020 Bluespec, Inc. All Rights Reserved. // //- // RVFI_DII + CHERI modifications: // Copyright (c) 2020 Jonathan Woodruff // All rights reserved. // // This software was developed by SRI International and the University of // Cambridge Computer Laboratory (Department of Computer Science and // Technology) under DARPA contract HR0011-18-C-0016 ("ECATS"), as part of the // DARPA SSITH research programme. // // This work was supported by NCSC programme grant 4212611/RFA 15971 ("SafeBet"). //- package TV_Taps; // ================================================================ // This package defines 'taps' on connections between // - DM and CPU, on which DM accesses CPU GPRs, FPRs and CSRs // - DM and memory bus, on which DM accesses memory // Each tap snoops 'writes', and produces a corresponsing Trace_Data // write-memory command for the Tandem Verifier, so that it keeps its // GPRs, FPRs, CSRs and memories in sync. // ================================================================ // BSV library imports import Assert :: *; import BUtils :: *; import FIFOF :: *; import GetPut :: *; import ClientServer :: *; import Connectable :: *; // ---------------- // BSV additional libs import Semi_FIFOF :: *; import GetPut_Aux :: *; // ================================================================ // Project imports import ISA_Decls :: *; import DM_CPU_Req_Rsp :: *; import TV_Info :: *; import AXI4_Types :: *; import Fabric_Defs :: *; // ================================================================ // DM-to-memory tap interface DM_Mem_Tap_IFC; interface AXI4_Slave_IFC #(Wd_Id, Wd_Addr, Wd_Data, Wd_User) slave; interface AXI4_Master_IFC #(Wd_Id, Wd_Addr, Wd_Data, Wd_User) master; interface Get #(Trace_Data) trace_data_out; endinterface (* synthesize *) module mkDM_Mem_Tap (DM_Mem_Tap_IFC); // Transactor facing DM AXI4_Slave_Xactor_IFC #(Wd_Id, Wd_Addr, Wd_Data, Wd_User) slave_xactor <- mkAXI4_Slave_Xactor; // Transactor facing memory bus AXI4_Master_Xactor_IFC #(Wd_Id, Wd_Addr, Wd_Data, Wd_User) master_xactor <- mkAXI4_Master_Xactor; // Tap output FIFOF #(Trace_Data) f_trace_data <- mkFIFOF; // ---------------- // AXI requests // Snoop write requests rule write_reqs; let wr_addr = slave_xactor.o_wr_addr.first; slave_xactor.o_wr_addr.deq; let wr_data = slave_xactor.o_wr_data.first; slave_xactor.o_wr_data.deq; // Pass-through master_xactor.i_wr_addr.enq (wr_addr); master_xactor.i_wr_data.enq (wr_data); // Tap Bit #(64) paddr = ?; Bit #(64) stval = ?; Integer sh = 0; Fabric_Data mask = 0; MemReqSize sz = ?; case (wr_data.wstrb) `ifdef FABRIC64 'hFF: begin sh= 0; mask = 'hFFFF_FFFF_FFFF_FFFF; sz=f3_SIZE_D; end 'hF0: begin sh=32; mask = 'hFFFF_FFFF; sz=f3_SIZE_W; end 'hC0: begin sh=48; mask = 'hFFFF; sz=f3_SIZE_H; end 'h30: begin sh=32; mask = 'hFFFF; sz=f3_SIZE_H; end 'h80: begin sh=56; mask = 'hFF; sz=f3_SIZE_B; end 'h40: begin sh=48; mask = 'hFF; sz=f3_SIZE_B; end 'h20: begin sh=40; mask = 'hFF; sz=f3_SIZE_B; end 'h10: begin sh=32; mask = 'hFF; sz=f3_SIZE_B; end `endif 'hF: begin sh= 0; mask = 'hFFFF_FFFF; sz=f3_SIZE_W; end 'hC: begin sh=16; mask = 'hFFFF; sz=f3_SIZE_H; end 'h3: begin sh= 0; mask = 'hFFFF; sz=f3_SIZE_H; end 'h8: begin sh=24; mask = 'hFF; sz=f3_SIZE_B; end 'h4: begin sh=16; mask = 'hFF; sz=f3_SIZE_B; end 'h2: begin sh= 8; mask = 'hFF; sz=f3_SIZE_B; end 'h1: begin sh= 0; mask = 'hFF; sz=f3_SIZE_B; end default: dynamicAssert(False, "mkDM_Mem_Tap: unsupported byte enables"); endcase paddr = zeroExtend (wr_addr.awaddr); stval = ((zeroExtend (wr_data.wdata) >> sh) & mask); Trace_Data td = mkTrace_MEM_WRITE (sz, truncate (stval), paddr); f_trace_data.enq (td); endrule // Read requests, write responses and read responses are not snooped mkConnection (slave_xactor.o_rd_addr, master_xactor.i_rd_addr); mkConnection (slave_xactor.i_wr_resp, master_xactor.o_wr_resp); mkConnection (slave_xactor.i_rd_data, master_xactor.o_rd_data); // ================================================================ // INTERFACE // Facing DM interface slave = slave_xactor.axi_side; // Facing bus interface master = master_xactor.axi_side; // Tap towards verifier interface Get trace_data_out = toGet (f_trace_data); endmodule: mkDM_Mem_Tap // ================================================================ // DM-to-CPU GPR tap (for writes to GPRs) interface DM_GPR_Tap_IFC; interface Client #(DM_CPU_Req #(5, XLEN), DM_CPU_Rsp #(XLEN)) client; interface Server #(DM_CPU_Req #(5, XLEN), DM_CPU_Rsp #(XLEN)) server; interface Get #(Trace_Data) trace_data_out; endinterface (* synthesize *) module mkDM_GPR_Tap (DM_GPR_Tap_IFC); // req from DM FIFOF #(DM_CPU_Req #(5, XLEN)) f_req_in <- mkFIFOF; // req to CPU FIFOF #(DM_CPU_Req #(5, XLEN)) f_req_out <- mkFIFOF; // resp CPU->DM FIFOF #(DM_CPU_Rsp #(XLEN)) f_rsp <- mkFIFOF; // Tap to TV FIFOF #(Trace_Data) f_trace_data <- mkFIFOF; rule request; let req <- pop (f_req_in); // Pass-through to CPU f_req_out.enq(req); // Snoop writes and send trace data to TV if (req.write) begin Trace_Data td; td = mkTrace_GPR_WRITE (req.address, req.data); f_trace_data.enq (td); end endrule interface Client client = toGPClient (f_req_out, f_rsp); interface Server server = toGPServer (f_req_in, f_rsp); interface Get trace_data_out = toGet (f_trace_data); endmodule: mkDM_GPR_Tap // ================================================================ // DM-to-CPU FPR tap (for writes to FPRs) `ifdef ISA_F_OR_D interface DM_FPR_Tap_IFC; interface Client #(DM_CPU_Req #(5, XLEN), DM_CPU_Rsp #(XLEN)) client; interface Server #(DM_CPU_Req #(5, XLEN), DM_CPU_Rsp #(XLEN)) server; interface Get #(Trace_Data) trace_data_out; endinterface (* synthesize *) module mkDM_FPR_Tap (DM_FPR_Tap_IFC); // req from DM FIFOF #(DM_CPU_Req #(5, XLEN)) f_req_in <- mkFIFOF; // req to CPU FIFOF #(DM_CPU_Req #(5, XLEN)) f_req_out <- mkFIFOF; // resp CPU->DM FIFOF #(DM_CPU_Rsp #(XLEN)) f_rsp <- mkFIFOF; // Tap to TV FIFOF #(Trace_Data) f_trace_data <- mkFIFOF; rule request; let req <- pop (f_req_in); // Pass-through to CPU f_req_out.enq(req); // Snoop writes and send trace data to TV if (req.write) begin Trace_Data td; td = mkTrace_FPR_WRITE (req.address, req.data); f_trace_data.enq (td); end endrule interface Client client = toGPClient (f_req_out, f_rsp); interface Server server = toGPServer (f_req_in, f_rsp); interface Get trace_data_out = toGet (f_trace_data); endmodule: mkDM_FPR_Tap `endif // ================================================================ // DM-to-CPU CSR tap (for writes to CSRs) interface DM_CSR_Tap_IFC; interface Client #(DM_CPU_Req #(12, XLEN), DM_CPU_Rsp #(XLEN)) client; interface Server #(DM_CPU_Req #(12, XLEN), DM_CPU_Rsp #(XLEN)) server; interface Get #(Trace_Data) trace_data_out; endinterface (* synthesize *) module mkDM_CSR_Tap (DM_CSR_Tap_IFC); // req from DM FIFOF #(DM_CPU_Req #(12, XLEN)) f_req_in <- mkFIFOF; // req to CPU FIFOF #(DM_CPU_Req #(12, XLEN)) f_req_out <- mkFIFOF; // resp CPU->DM FIFOF #(DM_CPU_Rsp #(XLEN)) f_rsp <- mkFIFOF; // Tap to TV FIFOF #(Trace_Data) f_trace_data <- mkFIFOF; rule request; let req <- pop (f_req_in); // Pass-through to CPU f_req_out.enq(req); // Snoop writes and send trace data to TV if (req.write) begin Trace_Data td = mkTrace_CSR_WRITE (req.address, req.data); f_trace_data.enq (td); end endrule interface Client client = toGPClient (f_req_out, f_rsp); interface Server server = toGPServer (f_req_in, f_rsp); interface Get trace_data_out = toGet (f_trace_data); endmodule: mkDM_CSR_Tap // ================================================================ endpackage