Add JTAG DTM and test support in simulation
Initial cut checkpoint which compiles and runs but there is some off-by-1 in the protocol Debugging the clock crossing logic checkpoint which works Clean up the AsyncMailbox black box
This commit is contained in:
271
vsrc/AsyncFifo.v
Normal file
271
vsrc/AsyncFifo.v
Normal file
@ -0,0 +1,271 @@
|
||||
|
||||
|
||||
module AsyncFifo (
|
||||
// Write Interface
|
||||
|
||||
enq_clock
|
||||
, enq_reset
|
||||
, enq_ready
|
||||
, enq_valid
|
||||
, enq_bits
|
||||
|
||||
// Read Interface
|
||||
, deq_clock
|
||||
, deq_reset
|
||||
, deq_ready
|
||||
, deq_valid
|
||||
, deq_bits
|
||||
|
||||
);
|
||||
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Parameter Declarations
|
||||
|
||||
parameter DEPTH_LG_2 = 0; // default is 'mailbox'.
|
||||
parameter WIDTH = 64;
|
||||
|
||||
localparam DEPTH = 2**DEPTH_LG_2;
|
||||
|
||||
//--------------------------------------------------------
|
||||
// I/O Declarations
|
||||
|
||||
// Write Interface
|
||||
input enq_clock;
|
||||
wire w_clock = enq_clock;
|
||||
|
||||
input enq_reset;
|
||||
wire w_reset = enq_reset;
|
||||
|
||||
output enq_ready;
|
||||
wire w_ready;
|
||||
assign enq_ready = w_ready;
|
||||
|
||||
input enq_valid;
|
||||
wire w_valid = enq_valid;
|
||||
|
||||
input [WIDTH - 1 : 0 ] enq_bits;
|
||||
wire [WIDTH - 1 : 0 ] w_bits = enq_bits;
|
||||
|
||||
// Read Interface
|
||||
input deq_clock;
|
||||
wire r_clock = deq_clock;
|
||||
|
||||
input deq_reset;
|
||||
wire r_reset = deq_reset;
|
||||
|
||||
output deq_valid;
|
||||
wire r_valid;
|
||||
assign deq_valid = r_valid;
|
||||
|
||||
input deq_ready;
|
||||
wire r_ready = deq_ready;
|
||||
|
||||
output [WIDTH - 1 : 0] deq_bits;
|
||||
wire [WIDTH - 1 : 0] r_bits;
|
||||
assign deq_bits = r_bits;
|
||||
|
||||
//--------------------------------------------------------
|
||||
// FIFO Memory Declaration
|
||||
|
||||
generate
|
||||
if (DEPTH > 1) begin : mem1_scope
|
||||
reg [WIDTH - 1 : 0] fifoMem [ 0 : DEPTH - 1];
|
||||
end else begin : mem2_scope
|
||||
reg [WIDTH - 1 :0] fifoMem;
|
||||
end
|
||||
endgenerate
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Reg and Wire Declarations
|
||||
|
||||
wire w_full;
|
||||
wire w_fire;
|
||||
|
||||
wire r_empty;
|
||||
wire r_fire;
|
||||
|
||||
|
||||
// Read & Write Address Pointers
|
||||
generate
|
||||
if (DEPTH_LG_2 > 0) begin : reg1_scope
|
||||
reg [DEPTH_LG_2 : 0 ] w_wrAddrReg;
|
||||
wire [DEPTH_LG_2 : 0] w_wrAddrNxt;
|
||||
reg [DEPTH_LG_2 : 0 ] w_wrAddrGrayReg;
|
||||
wire [DEPTH_LG_2 : 0] w_wrAddrGrayNxt;
|
||||
|
||||
reg [DEPTH_LG_2 : 0 ] r_rdAddrReg;
|
||||
wire [DEPTH_LG_2 : 0] r_rdAddrNxt;
|
||||
reg [DEPTH_LG_2 : 0 ] r_rdAddrGrayReg;
|
||||
wire [DEPTH_LG_2 : 0] r_rdAddrGrayNxt;
|
||||
|
||||
reg [DEPTH_LG_2 : 0 ] wrAddrGrayReg_sync;
|
||||
reg [DEPTH_LG_2 : 0 ] rdAddrGrayReg_sync;
|
||||
|
||||
reg [DEPTH_LG_2 : 0 ] r_wrAddrGrayReg;
|
||||
reg [DEPTH_LG_2 : 0 ] w_rdAddrGrayReg;
|
||||
end else begin : reg2_scope
|
||||
|
||||
reg w_wrAddrReg;
|
||||
wire w_wrAddrNxt;
|
||||
reg r_rdAddrReg;
|
||||
wire r_rdAddrNxt;
|
||||
|
||||
|
||||
reg wrAddrReg_sync;
|
||||
reg rdAddrReg_sync;
|
||||
|
||||
reg r_wrAddrReg;
|
||||
reg w_rdAddrReg;
|
||||
end
|
||||
endgenerate
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Reg and Wire Declarations
|
||||
|
||||
|
||||
// Pointer Logic
|
||||
generate
|
||||
if (DEPTH_LG_2 > 0) begin : ptr_logic_scope
|
||||
assign w_full = ~(reg1_scope.w_wrAddrGrayReg[DEPTH_LG_2] == reg1_scope.w_rdAddrGrayReg[DEPTH_LG_2]) &
|
||||
(reg1_scope.w_wrAddrGrayReg[DEPTH_LG_2 - 1 : 0] == reg1_scope.w_rdAddrGrayReg[DEPTH_LG_2 - 1 : 0 ]);
|
||||
|
||||
assign reg1_scope.w_wrAddrNxt = reg1_scope.w_wrAddrReg + 1'b1; // OK / expected to overflow
|
||||
assign reg1_scope.w_wrAddrGrayNext = reg1_scope.w_wrAddrNxt ^ (reg1_scope.w_wrAddrNxt >> 1);
|
||||
|
||||
assign reg1_scope.r_rdAddrNxt = reg1_scope.r_rdAddrReg + 1'b1; // OK / expected to overflow
|
||||
assign reg1_scope.r_rdAddrGrayNext = reg1_scope.r_rdAddrNxt ^ (reg1_scope.r_rdAddrNxt >> 1);
|
||||
|
||||
assign r_empty = (reg1_scope.r_wrAddrGrayReg == reg1_scope.r_rdAddrGrayReg);
|
||||
|
||||
end else begin : ptr_logic_scope
|
||||
assign w_full = ~(reg2_scope.w_wrAddrReg == reg2_scope.r_rdAddrReg);
|
||||
|
||||
assign reg2_scope.w_wrAddrNxt = ~reg2_scope.w_wrAddrReg ;
|
||||
|
||||
assign reg2_scope.r_rdAddrNxt = ~reg2_scope.r_rdAddrReg;
|
||||
|
||||
assign r_empty = (reg2_scope.r_wrAddrReg == reg2_scope.r_rdAddrReg);
|
||||
|
||||
end
|
||||
endgenerate
|
||||
|
||||
assign w_ready = ~w_full;
|
||||
assign w_fire = w_ready & w_valid;
|
||||
|
||||
// Read Logic
|
||||
assign r_valid = ~r_empty;
|
||||
assign r_fire = r_ready & r_valid;
|
||||
|
||||
generate
|
||||
if (DEPTH > 1) begin : rw_scope1
|
||||
if (DEPTH > 2) begin : rw_scope2
|
||||
|
||||
assign r_bits = mem1_scope.fifoMem[reg1_scope.r_rdAddrReg[DEPTH_LG_2-1:0]];
|
||||
|
||||
always @(posedge w_clock) begin
|
||||
if (w_fire) begin
|
||||
mem1_scope.fifoMem[reg1_scope.w_wrAddrReg[DEPTH_LG_2-1:0]] <= w_bits;
|
||||
end
|
||||
end
|
||||
|
||||
end else begin
|
||||
|
||||
assign r_bits = mem1_scope.fifoMem[reg1_scope.r_rdAddrReg[0]];
|
||||
|
||||
always @(posedge w_clock) begin
|
||||
if (w_fire) begin
|
||||
mem1_scope.fifoMem[reg1_scope.w_wrAddrReg[0]] <= w_bits;
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end else begin
|
||||
|
||||
assign r_bits = mem2_scope.fifoMem;
|
||||
|
||||
always @(posedge w_clock) begin
|
||||
if (w_fire) begin
|
||||
mem2_scope.fifoMem <= w_bits;
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
endgenerate
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Sequential logic
|
||||
//
|
||||
generate
|
||||
if (DEPTH_LG_2 > 0) begin : seq1_scope
|
||||
always @(posedge w_clock or posedge w_reset) begin
|
||||
if (w_reset) begin
|
||||
reg1_scope.w_wrAddrReg <= 'b0;
|
||||
reg1_scope.w_wrAddrGrayReg <= 'b0;
|
||||
|
||||
reg1_scope.rdAddrGrayReg_sync <= 'b0;
|
||||
reg1_scope.w_rdAddrGrayReg <= 'b0;
|
||||
end else begin
|
||||
if (w_fire) begin
|
||||
reg1_scope.w_wrAddrReg <= reg1_scope.w_wrAddrNxt;
|
||||
reg1_scope.w_wrAddrGrayReg <= reg1_scope.w_wrAddrGrayNxt;
|
||||
end
|
||||
reg1_scope.rdAddrGrayReg_sync <= reg1_scope.r_rdAddrGrayReg;
|
||||
reg1_scope.w_rdAddrGrayReg <= reg1_scope.rdAddrGrayReg_sync;
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge r_clock or posedge r_reset) begin
|
||||
if (r_reset) begin
|
||||
reg1_scope.r_rdAddrReg <= 'b0;
|
||||
reg1_scope.r_rdAddrGrayReg <= 'b0;
|
||||
|
||||
reg1_scope.reg1_scope.wrAddrGrayReg_sync <= 'b0;
|
||||
reg1_scope.reg1_scope.r_wrAddrGrayReg <= 'b0;
|
||||
end else begin
|
||||
if (r_fire) begin
|
||||
reg1_scope.r_rdAddrReg <= reg1_scope.r_rdAddrNxt;
|
||||
reg1_scope.r_rdAddrGrayReg <= reg1_scope.r_rdAddrGrayNxt;
|
||||
end
|
||||
reg1_scope.wrAddrGrayReg_sync <= reg1_scope.w_wrAddrGrayReg;
|
||||
reg1_scope.r_wrAddrGrayReg <= reg1_scope.wrAddrGrayReg_sync;
|
||||
end
|
||||
end // always @ (posedge r_clock)
|
||||
|
||||
end else begin : seq2_scope // block: seq1_scope
|
||||
always @(posedge w_clock or posedge w_reset) begin
|
||||
if (w_reset ) begin
|
||||
reg2_scope.w_wrAddrReg <= 1'b0;
|
||||
|
||||
reg2_scope.rdAddrReg_sync <= 1'b0;
|
||||
reg2_scope.w_rdAddrReg <= 1'b0;
|
||||
end else begin
|
||||
if (w_fire) begin
|
||||
reg2_scope.w_wrAddrReg <= reg2_scope.w_wrAddrNxt;
|
||||
end
|
||||
reg2_scope.rdAddrReg_sync <= reg2_scope.r_rdAddrReg;
|
||||
reg2_scope.w_rdAddrReg <= reg2_scope.rdAddrReg_sync;
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge r_clock or posedge r_reset) begin
|
||||
if (r_reset) begin
|
||||
reg2_scope.r_rdAddrReg <= 1'b0;
|
||||
|
||||
reg2_scope.wrAddrReg_sync <= 1'b0;
|
||||
reg2_scope.r_wrAddrReg <= 1'b0;
|
||||
end else begin
|
||||
if (r_fire) begin
|
||||
reg2_scope.r_rdAddrReg <= reg2_scope.r_rdAddrNxt;
|
||||
end
|
||||
reg2_scope.wrAddrReg_sync <= reg2_scope.w_wrAddrReg;
|
||||
reg2_scope.r_wrAddrReg <= reg2_scope.wrAddrReg_sync;
|
||||
end
|
||||
end // always @ (posedge r_clock)
|
||||
end // block: seq2_scope
|
||||
|
||||
endgenerate
|
||||
|
||||
|
||||
|
||||
endmodule // AsyncFifo
|
301
vsrc/DebugTransportModuleJtag.v
Executable file
301
vsrc/DebugTransportModuleJtag.v
Executable file
@ -0,0 +1,301 @@
|
||||
|
||||
|
||||
module DebugTransportModuleJtag (
|
||||
|
||||
//JTAG Interface
|
||||
|
||||
jtag_TDI,
|
||||
jtag_TDO,
|
||||
jtag_TCK,
|
||||
jtag_TMS,
|
||||
jtag_TRST,
|
||||
|
||||
jtag_DRV_TDO,
|
||||
|
||||
dtm_req_valid,
|
||||
dtm_req_ready,
|
||||
dtm_req_bits,
|
||||
|
||||
dtm_resp_valid,
|
||||
dtm_resp_ready,
|
||||
dtm_resp_bits
|
||||
|
||||
);
|
||||
//--------------------------------------------------------
|
||||
// Parameter Declarations
|
||||
|
||||
parameter DEBUG_DATA_BITS = 34;
|
||||
parameter DEBUG_ADDR_BITS = 5; // Spec allows values are 5-7
|
||||
parameter DEBUG_OP_BITS = 2; // OP and RESP are the same size.
|
||||
|
||||
parameter JTAG_VERSION = 4'h1;
|
||||
parameter JTAG_PART_NUM = 16'h0E31; // E31
|
||||
parameter JTAG_MANUF_ID = 11'h489; // As Assigned by JEDEC
|
||||
|
||||
localparam IR_BITS = 5;
|
||||
|
||||
localparam DEBUG_VERSION = 0;
|
||||
|
||||
// JTAG State Machine
|
||||
localparam TEST_LOGIC_RESET = 4'h0;
|
||||
localparam RUN_TEST_IDLE = 4'h1;
|
||||
localparam SELECT_DR = 4'h2;
|
||||
localparam CAPTURE_DR = 4'h3;
|
||||
localparam SHIFT_DR = 4'h4;
|
||||
localparam EXIT1_DR = 4'h5;
|
||||
localparam PAUSE_DR = 4'h6;
|
||||
localparam EXIT2_DR = 4'h7;
|
||||
localparam UPDATE_DR = 4'h8;
|
||||
localparam SELECT_IR = 4'h9;
|
||||
localparam CAPTURE_IR = 4'hA;
|
||||
localparam SHIFT_IR = 4'hB;
|
||||
localparam EXIT1_IR = 4'hC;
|
||||
localparam PAUSE_IR = 4'hD;
|
||||
localparam EXIT2_IR = 4'hE;
|
||||
localparam UPDATE_IR = 4'hF;
|
||||
|
||||
//RISCV DTM Registers (see RISC-V Debug Specification)
|
||||
// All others are treated as 'BYPASS'.
|
||||
localparam REG_BYPASS = 5'b11111;
|
||||
localparam REG_IDCODE = 5'b00001;
|
||||
localparam REG_DEBUG_ACCESS = 5'b10001;
|
||||
localparam REG_DTM_INFO = 5'b10000;
|
||||
|
||||
localparam DBUS_REG_BITS = DEBUG_OP_BITS + DEBUG_ADDR_BITS + DEBUG_DATA_BITS;
|
||||
localparam DBUS_REQ_BITS = DEBUG_OP_BITS + DEBUG_ADDR_BITS + DEBUG_DATA_BITS;
|
||||
localparam DBUS_RESP_BITS = DEBUG_OP_BITS + DEBUG_DATA_BITS;
|
||||
|
||||
|
||||
localparam SHIFT_REG_BITS = DBUS_REG_BITS;
|
||||
|
||||
//--------------------------------------------------------
|
||||
// I/O Declarations
|
||||
|
||||
//JTAG SIDE
|
||||
input jtag_TDI;
|
||||
output reg jtag_TDO;
|
||||
input jtag_TCK;
|
||||
input jtag_TMS;
|
||||
input jtag_TRST;
|
||||
|
||||
|
||||
// To allow tri-state outside of this block.
|
||||
output reg jtag_DRV_TDO;
|
||||
|
||||
// RISC-V Core Side
|
||||
|
||||
output dtm_req_valid;
|
||||
input dtm_req_ready;
|
||||
output [DBUS_REQ_BITS - 1 :0] dtm_req_bits;
|
||||
|
||||
input dtm_resp_valid;
|
||||
output dtm_resp_ready;
|
||||
input [DBUS_RESP_BITS - 1 : 0] dtm_resp_bits;
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Reg and Wire Declarations
|
||||
|
||||
reg [IR_BITS -1 : 0 ] irReg;
|
||||
|
||||
wire [31:0] idcode;
|
||||
wire [31:0] dtminfo;
|
||||
reg [DBUS_REG_BITS - 1 : 0] dbusReg;
|
||||
reg dbusValidReg;
|
||||
|
||||
reg [3:0] jtagStateReg;
|
||||
|
||||
reg [SHIFT_REG_BITS -1 : 0] shiftReg;
|
||||
|
||||
reg doDbusWriteReg;
|
||||
reg doDbusReadReg;
|
||||
|
||||
reg busyReg;
|
||||
reg skipOpReg; // Skip op because we're busy.
|
||||
reg downgradeOpReg; // Downgrade op because prev. op failed.
|
||||
|
||||
|
||||
wire busy;
|
||||
wire nonzeroResp;
|
||||
|
||||
wire [SHIFT_REG_BITS -1 : 0] busyResponse;
|
||||
wire [SHIFT_REG_BITS -1 : 0] nonbusyResponse;
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Combo Logic
|
||||
|
||||
assign idcode = {JTAG_VERSION, JTAG_PART_NUM, JTAG_MANUF_ID, 1'h1};
|
||||
|
||||
wire [3:0] debugAddrBits = DEBUG_ADDR_BITS;
|
||||
wire [3:0] debugVersion = DEBUG_VERSION;
|
||||
|
||||
assign dtminfo = {24'b0, debugAddrBits, debugVersion};
|
||||
|
||||
//busy, dtm_resp* is only valid during CAPTURE_DR,
|
||||
// so these signals should only be used at that time.
|
||||
// This assumes there is only one transaction in flight at a time.
|
||||
assign busy = busyReg & ~dtm_resp_valid;
|
||||
// This is needed especially for the first request.
|
||||
assign nonzeroResp = dtm_resp_valid ? |{dtm_resp_bits[DEBUG_OP_BITS-1:0]} : 1'b0;
|
||||
|
||||
// Interface to DM.
|
||||
// Note that this means dtm_resp_bits must only be used during CAPTURE_DR.
|
||||
assign dtm_resp_ready = (jtagStateReg == CAPTURE_DR) &&
|
||||
(irReg == REG_DEBUG_ACCESS) &&
|
||||
dtm_resp_valid;
|
||||
|
||||
assign dtm_req_valid = dbusValidReg;
|
||||
assign dtm_req_bits = dbusReg;
|
||||
|
||||
assign busyResponse = {{(DEBUG_ADDR_BITS + DEBUG_DATA_BITS){1'b0}},
|
||||
{(DEBUG_OP_BITS){1'b1}}}; // Generalizing 'busy' to 'all-1'
|
||||
|
||||
assign nonbusyResponse = {dbusReg[(DEBUG_DATA_BITS + DEBUG_OP_BITS) +: DEBUG_ADDR_BITS] , // retain address bits from Req.
|
||||
dtm_resp_bits[DEBUG_OP_BITS +: DEBUG_DATA_BITS] , // data
|
||||
dtm_resp_bits[0 +: DEBUG_OP_BITS] // response
|
||||
};
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Sequential Logic
|
||||
|
||||
// JTAG STATE MACHINE
|
||||
|
||||
always @(posedge jtag_TCK or posedge jtag_TRST) begin
|
||||
if (jtag_TRST) begin
|
||||
jtagStateReg <= TEST_LOGIC_RESET;
|
||||
end else begin
|
||||
case (jtagStateReg)
|
||||
TEST_LOGIC_RESET : jtagStateReg <= jtag_TMS ? TEST_LOGIC_RESET : RUN_TEST_IDLE;
|
||||
RUN_TEST_IDLE : jtagStateReg <= jtag_TMS ? SELECT_DR : RUN_TEST_IDLE;
|
||||
SELECT_DR : jtagStateReg <= jtag_TMS ? SELECT_IR : CAPTURE_DR;
|
||||
CAPTURE_DR : jtagStateReg <= jtag_TMS ? EXIT1_DR : SHIFT_DR;
|
||||
SHIFT_DR : jtagStateReg <= jtag_TMS ? EXIT1_DR : SHIFT_DR;
|
||||
EXIT1_DR : jtagStateReg <= jtag_TMS ? UPDATE_DR : PAUSE_DR;
|
||||
PAUSE_DR : jtagStateReg <= jtag_TMS ? EXIT2_DR : PAUSE_DR;
|
||||
EXIT2_DR : jtagStateReg <= jtag_TMS ? UPDATE_DR : SHIFT_DR;
|
||||
UPDATE_DR : jtagStateReg <= jtag_TMS ? SELECT_DR : RUN_TEST_IDLE;
|
||||
SELECT_IR : jtagStateReg <= jtag_TMS ? TEST_LOGIC_RESET : CAPTURE_IR;
|
||||
CAPTURE_IR : jtagStateReg <= jtag_TMS ? EXIT1_IR : SHIFT_IR;
|
||||
SHIFT_IR : jtagStateReg <= jtag_TMS ? EXIT1_IR : SHIFT_IR;
|
||||
EXIT1_IR : jtagStateReg <= jtag_TMS ? UPDATE_IR : PAUSE_IR;
|
||||
PAUSE_IR : jtagStateReg <= jtag_TMS ? EXIT2_IR : PAUSE_IR;
|
||||
EXIT2_IR : jtagStateReg <= jtag_TMS ? UPDATE_IR : SHIFT_IR;
|
||||
UPDATE_IR : jtagStateReg <= jtag_TMS ? SELECT_DR : RUN_TEST_IDLE;
|
||||
endcase // case (jtagStateReg)
|
||||
end // else: !if(jtag_TRST)
|
||||
end // always @ (posedge jtag_TCK or posedge jtag_TRST)
|
||||
|
||||
// SHIFT REG
|
||||
always @(posedge jtag_TCK) begin
|
||||
case (jtagStateReg)
|
||||
CAPTURE_IR : shiftReg <= {{(SHIFT_REG_BITS-1){1'b0}}, 1'b1}; //JTAG spec only says must end with 'b01.
|
||||
SHIFT_IR : shiftReg <= {{(SHIFT_REG_BITS-IR_BITS){1'b0}}, jtag_TDI, shiftReg[IR_BITS-1 : 1]};
|
||||
CAPTURE_DR : case (irReg)
|
||||
REG_BYPASS : shiftReg <= {(SHIFT_REG_BITS){1'b0}};
|
||||
REG_IDCODE : shiftReg <= {{(SHIFT_REG_BITS-32){1'b0}}, idcode};
|
||||
REG_DTM_INFO : shiftReg <= {{(SHIFT_REG_BITS-32){1'b0}}, dtminfo};
|
||||
REG_DEBUG_ACCESS : shiftReg <= busy ? busyResponse : nonbusyResponse;
|
||||
default : //BYPASS
|
||||
shiftReg <= {(SHIFT_REG_BITS){1'b0}};
|
||||
endcase
|
||||
SHIFT_DR : case (irReg)
|
||||
REG_BYPASS : shiftReg <= {{(SHIFT_REG_BITS- 1){1'b0}}, jtag_TDI};
|
||||
REG_IDCODE : shiftReg <= {{(SHIFT_REG_BITS-32){1'b0}}, jtag_TDI, shiftReg[31:1]};
|
||||
REG_DTM_INFO : shiftReg <= {{(SHIFT_REG_BITS-32){1'b0}}, jtag_TDI, shiftReg[31:1]};
|
||||
REG_DEBUG_ACCESS : shiftReg <= {jtag_TDI, shiftReg[SHIFT_REG_BITS -1 : 1 ]};
|
||||
default: // BYPASS
|
||||
shiftReg <= {{(SHIFT_REG_BITS- 1){1'b0}} , jtag_TDI};
|
||||
endcase // case (irReg)
|
||||
endcase // case (jtagStateReg)
|
||||
end
|
||||
|
||||
// IR
|
||||
always @(negedge jtag_TCK or posedge jtag_TRST) begin
|
||||
if (jtag_TRST) begin
|
||||
irReg <= REG_IDCODE;
|
||||
end else if (jtagStateReg == TEST_LOGIC_RESET) begin
|
||||
irReg <= REG_IDCODE;
|
||||
end else if (jtagStateReg == UPDATE_IR) begin
|
||||
irReg <= shiftReg[IR_BITS-1:0];
|
||||
end
|
||||
end
|
||||
|
||||
// Busy. We become busy when we first try to send a request.
|
||||
// We stop being busy when we accept a response.
|
||||
// This means that busyReg will still be set when we check it,
|
||||
// so the logic for checking busy looks ahead.
|
||||
|
||||
always @(posedge jtag_TCK or posedge jtag_TRST) begin
|
||||
if (jtag_TRST) begin
|
||||
busyReg <= 1'b0;
|
||||
end else if (dtm_req_valid) begin //UPDATE_DR onwards
|
||||
busyReg <= 1'b1;
|
||||
end else if (dtm_resp_valid & dtm_resp_ready) begin //only in CAPTURE_DR
|
||||
busyReg <= 1'b0;
|
||||
end
|
||||
end // always @ (posedge jtag_TCK or posedge jtag_TRST)
|
||||
|
||||
|
||||
// Downgrade/Skip. We make the decision to downgrade or skip
|
||||
// during every CAPTURE_DR, and use the result in UPDATE_DR.
|
||||
always @(posedge jtag_TCK or posedge jtag_TRST) begin
|
||||
if (jtag_TRST) begin
|
||||
skipOpReg <= 1'b0;
|
||||
downgradeOpReg <= 1'b0;
|
||||
end else if (irReg == REG_DEBUG_ACCESS) begin
|
||||
case(jtagStateReg)
|
||||
CAPTURE_DR: begin
|
||||
skipOpReg <= busy;
|
||||
downgradeOpReg <= (~busy & nonzeroResp);
|
||||
end
|
||||
UPDATE_DR: begin
|
||||
skipOpReg <= 1'b0;
|
||||
downgradeOpReg <= 1'b0;
|
||||
end
|
||||
endcase // case (jtagStateReg)
|
||||
end
|
||||
end // always @ (posedge jtag_TCK or posedge jtag_TRST)
|
||||
|
||||
|
||||
//dbusReg, dbusValidReg.
|
||||
always @(posedge jtag_TCK or posedge jtag_TRST) begin
|
||||
if (jtag_TRST) begin
|
||||
dbusReg <= {(DBUS_REG_BITS) {1'b0}};
|
||||
dbusValidReg <= 1'b0;
|
||||
end else if (jtagStateReg == UPDATE_DR) begin
|
||||
if (irReg == REG_DEBUG_ACCESS) begin
|
||||
if (skipOpReg) begin
|
||||
// do nothing.
|
||||
end else if (downgradeOpReg) begin
|
||||
dbusReg <= {(DBUS_REG_BITS){1'b0}}; // NOP has encoding 2'b00.
|
||||
dbusValidReg <= 1'b1;
|
||||
end else begin
|
||||
dbusReg <= shiftReg[DBUS_REG_BITS-1:0];
|
||||
dbusValidReg <= 1'b1;
|
||||
end
|
||||
end
|
||||
end else if (dtm_req_ready) begin
|
||||
dbusValidReg <= 1'b0;
|
||||
end
|
||||
end // always @ (negedge jtag_TCK or posedge jtag_TRST)
|
||||
|
||||
//TDO
|
||||
always @(negedge jtag_TCK or posedge jtag_TRST) begin
|
||||
if (jtag_TRST) begin
|
||||
jtag_TDO <= 1'b0;
|
||||
jtag_DRV_TDO <= 1'b0;
|
||||
end else if (jtagStateReg == SHIFT_IR) begin
|
||||
jtag_TDO <= shiftReg[0];
|
||||
jtag_DRV_TDO <= 1'b1;
|
||||
end else if (jtagStateReg == SHIFT_DR) begin
|
||||
jtag_TDO <= shiftReg[0];
|
||||
jtag_DRV_TDO <= 1'b1;
|
||||
end else begin
|
||||
jtag_TDO <= 1'b0;
|
||||
jtag_DRV_TDO <= 1'b0;
|
||||
end
|
||||
end // always @ (negedge jtag_TCK or posedge jtag_TRST)
|
||||
|
||||
|
||||
endmodule
|
||||
|
||||
|
2
vsrc/jtag_vpi.tab
Normal file
2
vsrc/jtag_vpi.tab
Normal file
@ -0,0 +1,2 @@
|
||||
$send_result_to_server call=send_result_to_server
|
||||
$check_for_command call=check_for_command
|
302
vsrc/jtag_vpi.v
Normal file
302
vsrc/jtag_vpi.v
Normal file
@ -0,0 +1,302 @@
|
||||
/*
|
||||
* TCP/IP controlled VPI JTAG Interface.
|
||||
* Based on Julius Baxter's work on jp_vpi.c
|
||||
*
|
||||
* Copyright (C) 2012 Franck Jullien, <franck.jullien@gmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the names of the copyright holders nor the names of any
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
`define CMD_RESET 0
|
||||
`define CMD_TMS_SEQ 1
|
||||
`define CMD_SCAN_CHAIN 2
|
||||
`define CMD_SCAN_CHAIN_FLIP_TMS 3
|
||||
`define CMD_STOP_SIMU 4
|
||||
|
||||
module JtagVpi
|
||||
#( parameter DEBUG_INFO = 0,
|
||||
parameter TP = 1,
|
||||
parameter TCK_HALF_PERIOD = 2,// 50, // Clock half period (Clock period = 100 ns => 10 MHz)
|
||||
parameter CMD_DELAY = 2 // 1000
|
||||
)
|
||||
(
|
||||
output jtag_TMS,
|
||||
output jtag_TCK,
|
||||
output jtag_TDI,
|
||||
input jtag_TDO,
|
||||
input jtag_TRST, // unused
|
||||
input enable,
|
||||
input init_done);
|
||||
|
||||
reg tms;
|
||||
reg tck;
|
||||
reg tdi;
|
||||
wire tdo;
|
||||
|
||||
assign jtag_TMS = tms;
|
||||
assign jtag_TCK = tck;
|
||||
assign jtag_TDI = tdi;
|
||||
assign tdo = jtag_TDO;
|
||||
|
||||
|
||||
integer cmd;
|
||||
integer length;
|
||||
integer nb_bits;
|
||||
|
||||
reg [31:0] buffer_out [0:4095]; // Data storage from the jtag server
|
||||
reg [31:0] buffer_in [0:4095]; // Data storage to the jtag server
|
||||
|
||||
integer flip_tms;
|
||||
|
||||
reg [31:0] data_out;
|
||||
reg [31:0] data_in;
|
||||
|
||||
integer debug;
|
||||
|
||||
assign tms_o = tms;
|
||||
assign tck_o = tck;
|
||||
assign tdi_o = tdi;
|
||||
|
||||
initial
|
||||
begin
|
||||
tck <= #TP 1'b0;
|
||||
tdi <= #TP 1'bz;
|
||||
tms <= #TP 1'b0;
|
||||
|
||||
data_out <= 32'h0;
|
||||
data_in <= 32'h0;
|
||||
|
||||
// Insert a #delay here because we need to
|
||||
// wait until the PC isn't pointing to flash anymore
|
||||
// (this is around 20k ns if the flash_crash boot code
|
||||
// is being booted from, else much bigger, around 10mil ns)
|
||||
wait(init_done)
|
||||
if($test$plusargs("jtag_vpi_enable")) main;
|
||||
end
|
||||
|
||||
task main;
|
||||
begin
|
||||
$display("JTAG debug module with VPI interface enabled\n");
|
||||
|
||||
reset_tap;
|
||||
goto_run_test_idle_from_reset;
|
||||
|
||||
while (1) begin
|
||||
|
||||
// Check for incoming command
|
||||
// wait until a command is sent
|
||||
// poll with a delay here
|
||||
cmd = -1;
|
||||
|
||||
while (cmd == -1)
|
||||
begin
|
||||
#CMD_DELAY $check_for_command(cmd, length, nb_bits, buffer_out);
|
||||
end
|
||||
|
||||
// now switch on the command
|
||||
case (cmd)
|
||||
|
||||
`CMD_RESET :
|
||||
begin
|
||||
if (DEBUG_INFO)
|
||||
$display("%t ----> CMD_RESET %h\n", $time, length);
|
||||
reset_tap;
|
||||
goto_run_test_idle_from_reset;
|
||||
end
|
||||
|
||||
`CMD_TMS_SEQ :
|
||||
begin
|
||||
if (DEBUG_INFO)
|
||||
$display("%t ----> CMD_TMS_SEQ\n", $time);
|
||||
do_tms_seq;
|
||||
end
|
||||
|
||||
`CMD_SCAN_CHAIN :
|
||||
begin
|
||||
if (DEBUG_INFO)
|
||||
$display("%t ----> CMD_SCAN_CHAIN\n", $time);
|
||||
flip_tms = 0;
|
||||
do_scan_chain;
|
||||
$send_result_to_server(length, buffer_in);
|
||||
end
|
||||
|
||||
`CMD_SCAN_CHAIN_FLIP_TMS :
|
||||
begin
|
||||
if(DEBUG_INFO)
|
||||
$display("%t ----> CMD_SCAN_CHAIN\n", $time);
|
||||
flip_tms = 1;
|
||||
do_scan_chain;
|
||||
$send_result_to_server(length, buffer_in);
|
||||
end
|
||||
|
||||
`CMD_STOP_SIMU :
|
||||
begin
|
||||
if(DEBUG_INFO)
|
||||
$display("%t ----> End of simulation\n", $time);
|
||||
$finish();
|
||||
end
|
||||
|
||||
default:
|
||||
begin
|
||||
$display("Somehow got to the default case in the command case statement.");
|
||||
$display("Command was: %x", cmd);
|
||||
$display("Exiting...");
|
||||
$finish();
|
||||
end
|
||||
|
||||
endcase // case (cmd)
|
||||
|
||||
end // while (1)
|
||||
end
|
||||
|
||||
endtask // main
|
||||
|
||||
|
||||
// Generation of the TCK signal
|
||||
task gen_clk;
|
||||
input [31:0] number;
|
||||
integer i;
|
||||
|
||||
begin
|
||||
for (i = 0; i < number; i = i + 1)
|
||||
begin
|
||||
#TCK_HALF_PERIOD tck <= 1;
|
||||
#TCK_HALF_PERIOD tck <= 0;
|
||||
end
|
||||
end
|
||||
|
||||
endtask
|
||||
|
||||
// TAP reset
|
||||
task reset_tap;
|
||||
begin
|
||||
if (DEBUG_INFO)
|
||||
$display("(%0t) Task reset_tap", $time);
|
||||
tms <= #1 1'b1;
|
||||
gen_clk(5);
|
||||
end
|
||||
|
||||
endtask
|
||||
|
||||
|
||||
// Goes to RunTestIdle state
|
||||
task goto_run_test_idle_from_reset;
|
||||
begin
|
||||
if (DEBUG_INFO)
|
||||
$display("(%0t) Task goto_run_test_idle_from_reset", $time);
|
||||
tms <= #1 1'b0;
|
||||
gen_clk(1);
|
||||
end
|
||||
|
||||
endtask
|
||||
|
||||
//
|
||||
task do_tms_seq;
|
||||
|
||||
integer i,j;
|
||||
reg [31:0] data;
|
||||
integer nb_bits_rem;
|
||||
integer nb_bits_in_this_byte;
|
||||
|
||||
begin
|
||||
if (DEBUG_INFO)
|
||||
$display("(%0t) Task do_tms_seq of %d bits (length = %d)", $time, nb_bits, length);
|
||||
|
||||
// Number of bits to send in the last byte
|
||||
nb_bits_rem = nb_bits % 8;
|
||||
|
||||
for (i = 0; i < length; i = i + 1)
|
||||
begin
|
||||
// If we are in the last byte, we have to send only
|
||||
// nb_bits_rem bits. If not, we send the whole byte.
|
||||
nb_bits_in_this_byte = (i == (length - 1)) ? nb_bits_rem : 8;
|
||||
|
||||
data = buffer_out[i];
|
||||
for (j = 0; j < nb_bits_in_this_byte; j = j + 1)
|
||||
begin
|
||||
tms <= #1 1'b0;
|
||||
if (data[j] == 1) begin
|
||||
tms <= #1 1'b1;
|
||||
end
|
||||
gen_clk(1);
|
||||
end
|
||||
end
|
||||
|
||||
tms <= #1 1'b0;
|
||||
end
|
||||
|
||||
endtask
|
||||
|
||||
|
||||
//
|
||||
task do_scan_chain;
|
||||
|
||||
integer _bit;
|
||||
integer nb_bits_rem;
|
||||
integer nb_bits_in_this_byte;
|
||||
integer index;
|
||||
|
||||
begin
|
||||
if(DEBUG_INFO)
|
||||
$display("(%0t) Task do_scan_chain of %d bits (length = %d)", $time, nb_bits, length);
|
||||
|
||||
// Number of bits to send in the last byte
|
||||
nb_bits_rem = nb_bits % 8;
|
||||
|
||||
for (index = 0; index < length; index = index + 1)
|
||||
begin
|
||||
// If we are in the last byte, we have to send only
|
||||
// nb_bits_rem bits if it's not zero.
|
||||
// If not, we send the whole byte.
|
||||
nb_bits_in_this_byte = (index == (length - 1)) ? ((nb_bits_rem == 0) ? 8 : nb_bits_rem) : 8;
|
||||
|
||||
data_out = buffer_out[index];
|
||||
for (_bit = 0; _bit < nb_bits_in_this_byte; _bit = _bit + 1)
|
||||
begin
|
||||
tdi <= 1'b0;
|
||||
if (data_out[_bit] == 1'b1) begin
|
||||
tdi <= 1'b1;
|
||||
end
|
||||
|
||||
// On the last bit, set TMS to '1'
|
||||
if (((_bit == (nb_bits_in_this_byte - 1)) && (index == (length - 1))) && (flip_tms == 1)) begin
|
||||
tms <= 1'b1;
|
||||
end
|
||||
|
||||
#TCK_HALF_PERIOD tck <= 1;
|
||||
data_in[_bit] <= tdo;
|
||||
#TCK_HALF_PERIOD tck <= 0;
|
||||
end
|
||||
buffer_in[index] = data_in;
|
||||
end
|
||||
|
||||
tdi <= 1'b0;
|
||||
tms <= 1'b0;
|
||||
end
|
||||
|
||||
endtask
|
||||
|
||||
endmodule
|
293
vsrc/rocketDTMTestHarness.v
Normal file
293
vsrc/rocketDTMTestHarness.v
Normal file
@ -0,0 +1,293 @@
|
||||
// See LICENSE for license details.
|
||||
|
||||
extern "A" void memory_tick
|
||||
(
|
||||
input reg [31:0] channel,
|
||||
|
||||
input reg ar_valid,
|
||||
output reg ar_ready,
|
||||
input reg [`MEM_ADDR_BITS-1:0] ar_addr,
|
||||
input reg [`MEM_ID_BITS-1:0] ar_id,
|
||||
input reg [2:0] ar_size,
|
||||
input reg [7:0] ar_len,
|
||||
|
||||
input reg aw_valid,
|
||||
output reg aw_ready,
|
||||
input reg [`MEM_ADDR_BITS-1:0] aw_addr,
|
||||
input reg [`MEM_ID_BITS-1:0] aw_id,
|
||||
input reg [2:0] aw_size,
|
||||
input reg [7:0] aw_len,
|
||||
|
||||
input reg w_valid,
|
||||
output reg w_ready,
|
||||
input reg [`MEM_STRB_BITS-1:0] w_strb,
|
||||
input reg [`MEM_DATA_BITS-1:0] w_data,
|
||||
input reg w_last,
|
||||
|
||||
output reg r_valid,
|
||||
input reg r_ready,
|
||||
output reg [1:0] r_resp,
|
||||
output reg [`MEM_ID_BITS-1:0] r_id,
|
||||
output reg [`MEM_DATA_BITS-1:0] r_data,
|
||||
output reg r_last,
|
||||
|
||||
output reg b_valid,
|
||||
input reg b_ready,
|
||||
output reg [1:0] b_resp,
|
||||
output reg [`MEM_ID_BITS-1:0] b_id
|
||||
);
|
||||
|
||||
module rocketDTMTestHarness;
|
||||
|
||||
reg [31:0] seed;
|
||||
initial seed = $get_initial_random_seed();
|
||||
|
||||
//-----------------------------------------------
|
||||
// Instantiate the processor
|
||||
|
||||
reg clk = 1'b0;
|
||||
reg reset = 1'b1;
|
||||
reg r_reset = 1'b1;
|
||||
reg start = 1'b0;
|
||||
|
||||
always #`CLOCK_PERIOD clk = ~clk;
|
||||
|
||||
reg [ 31:0] n_mem_channel = `N_MEM_CHANNELS;
|
||||
reg [ 31:0] mem_width = `MEM_DATA_BITS;
|
||||
reg [ 63:0] max_cycles = 0;
|
||||
reg [ 63:0] trace_count = 0;
|
||||
reg [1023:0] loadmem = 0;
|
||||
reg [1023:0] vcdplusfile = 0;
|
||||
reg [1023:0] vcdfile = 0;
|
||||
reg verbose = 0;
|
||||
wire printf_cond = verbose && !reset;
|
||||
integer stderr = 32'h80000002;
|
||||
|
||||
`include `TBVFRAG
|
||||
|
||||
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
r_reset <= reset;
|
||||
end
|
||||
|
||||
reg [31:0] exit = 0;
|
||||
|
||||
//-----------------------------------------------
|
||||
// Instantiate DTM and Synchronizers
|
||||
|
||||
// JTAG Interface
|
||||
|
||||
wire debug_TDI;
|
||||
wire debug_TDO;
|
||||
wire debug_TCK;
|
||||
wire debug_TMS;
|
||||
wire debug_TRST;
|
||||
wire debug_DRV_TDO;
|
||||
|
||||
//=================================================
|
||||
// JTAG VPI Server
|
||||
|
||||
wire cheater_TCK;
|
||||
|
||||
|
||||
jtag_vpi #(
|
||||
.DEBUG_INFO(0),
|
||||
//parameter TP = 1,
|
||||
.TCK_HALF_PERIOD(5),
|
||||
.CMD_DELAY(10)
|
||||
) // Clock half period (Clock period = 10 ns => 100 MHz)
|
||||
jtag_vpi (
|
||||
.tms(debug_TMS),
|
||||
.tck(debug_TCK),
|
||||
.tdi(debug_TDI),
|
||||
.tdo(debug_TDO),
|
||||
.enable(~reset),
|
||||
.init_done(~reset)
|
||||
);
|
||||
|
||||
|
||||
//=================================================
|
||||
// DTM <-> Synchronizers Interface
|
||||
|
||||
localparam DEBUG_ADDR_BITS = 5;
|
||||
localparam DEBUG_DATA_BITS = 34;
|
||||
localparam DEBUG_OP_BITS = 2;
|
||||
|
||||
|
||||
wire dtm_req_ready;
|
||||
wire dtm_req_valid;
|
||||
wire [DEBUG_OP_BITS + DEBUG_ADDR_BITS + DEBUG_DATA_BITS - 1 : 0 ] dtm_req_data;
|
||||
|
||||
wire dtm_resp_ready;
|
||||
wire dtm_resp_valid;
|
||||
wire [DEBUG_OP_BITS + DEBUG_DATA_BITS - 1 :0 ] dtm_resp_data;
|
||||
|
||||
|
||||
DebugTransportModuleJtag #(.DEBUG_OP_BITS(DEBUG_OP_BITS),
|
||||
.DEBUG_ADDR_BITS(DEBUG_ADDR_BITS),
|
||||
.DEBUG_DATA_BITS(DEBUG_DATA_BITS)
|
||||
) debugTransportModuleJtag0 (
|
||||
|
||||
//JTAG Interface
|
||||
|
||||
.TDI(debug_TDI),
|
||||
.TDO(debug_TDO),
|
||||
.TCK(debug_TCK),
|
||||
.TMS(debug_TMS),
|
||||
.TRST(debug_TRST),
|
||||
|
||||
.DRV_TDO(debug_DRV_TDO),
|
||||
|
||||
.dtm_req_ready(dtm_req_ready),
|
||||
.dtm_req_valid(dtm_req_valid),
|
||||
.dtm_req_data(dtm_req_data),
|
||||
|
||||
.dtm_resp_ready(dtm_resp_ready),
|
||||
.dtm_resp_valid(dtm_resp_valid),
|
||||
.dtm_resp_data(dtm_resp_data)
|
||||
|
||||
);
|
||||
|
||||
`ifdef VERILOG_DEBUG_SYNC
|
||||
|
||||
AsyncFifo #(.DEPTH_LG_2(0),
|
||||
.WIDTH(DEBUG_OP_BITS + DEBUG_ADDR_BITS + DEBUG_DATA_BITS))
|
||||
debugBusReqFifo(
|
||||
// Write Interface
|
||||
|
||||
.clk_w(~debug_TCK),
|
||||
.reset_w(debug_TRST),
|
||||
.ready_w(dtm_req_ready),
|
||||
.valid_w(dtm_req_valid),
|
||||
.data_w(dtm_req_data),
|
||||
|
||||
.clk_r(clk),
|
||||
.reset_r(reset),
|
||||
.ready_r(debug_req_ready),
|
||||
.valid_r(debug_req_valid),
|
||||
.data_r({debug_req_bits_addr, debug_req_bits_data, debug_req_bits_op})
|
||||
|
||||
);
|
||||
|
||||
AsyncFifo #(.DEPTH_LG_2(0),
|
||||
.WIDTH(DEBUG_OP_BITS + DEBUG_DATA_BITS))
|
||||
debugBusRespFifo(
|
||||
.clk_w(clk),
|
||||
.reset_w(reset),
|
||||
.ready_w(debug_resp_ready),
|
||||
.valid_w(debug_resp_valid),
|
||||
.data_w({debug_resp_bits_data, debug_resp_bits_resp}),
|
||||
|
||||
.clk_r(debug_TCK),
|
||||
.reset_r(debug_TRST),
|
||||
.ready_r(dtm_resp_ready),
|
||||
.valid_r(dtm_resp_valid),
|
||||
.data_r(dtm_resp_data)
|
||||
);
|
||||
|
||||
|
||||
// This is cheating / potentially incorrect!!! It needs to be more
|
||||
// clearly specified as to what the behavior of TRST is.
|
||||
assign debug_TRST = reset;
|
||||
|
||||
// The TCK cheat is not needed for this side of the ifdef
|
||||
// because both DTM and synchronizer
|
||||
// logic is asynchronously reset as needed.
|
||||
|
||||
`else // !`ifdef VERILOG_DEBUG_SYNC
|
||||
|
||||
// This is cheating / potentially incorrect!!! It needs to be more
|
||||
// clearly specified as to what the behavior of TRST is.
|
||||
assign debug_TRST = reset;
|
||||
|
||||
// This is TOTAL cheating!!! The synchronizer
|
||||
// logic should be asynchronously reset, or we should
|
||||
// specify the TCK/TRST requirements for a synchronous reset.
|
||||
assign debug_clk = reset ? clk : debug_TCK;
|
||||
|
||||
assign debug_reset = debug_TRST;
|
||||
|
||||
assign debug_req_valid = dtm_req_valid;
|
||||
assign {debug_req_bits_addr, debug_req_bits_data, debug_req_bits_op} = dtm_req_data;
|
||||
|
||||
assign dtm_req_ready = debug_req_ready;
|
||||
|
||||
assign dtm_resp_valid = debug_resp_valid;
|
||||
assign dtm_resp_data = {debug_resp_bits_data, debug_resp_bits_resp};
|
||||
|
||||
assign debug_resp_ready = dtm_resp_ready;
|
||||
|
||||
`endif // !`ifdef VERILOG_DEBUG_SYNC
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------
|
||||
// Start the simulation
|
||||
|
||||
// Read input arguments and initialize
|
||||
initial
|
||||
begin
|
||||
$value$plusargs("max-cycles=%d", max_cycles);
|
||||
verbose = $test$plusargs("verbose");
|
||||
`ifdef DEBUG
|
||||
if ($value$plusargs("vcdplusfile=%s", vcdplusfile))
|
||||
begin
|
||||
$vcdplusfile(vcdplusfile);
|
||||
$vcdpluson(0);
|
||||
$vcdplusmemon(0);
|
||||
end
|
||||
|
||||
if ($value$plusargs("vcdfile=%s", vcdfile))
|
||||
begin
|
||||
$dumpfile(vcdfile);
|
||||
$dumpvars(0, dut);
|
||||
$dumpon;
|
||||
end
|
||||
`define VCDPLUSCLOSE $vcdplusclose; $dumpoff;
|
||||
`else
|
||||
`define VCDPLUSCLOSE
|
||||
`endif
|
||||
|
||||
// Strobe reset
|
||||
#777.7 reset = 0;
|
||||
|
||||
end
|
||||
|
||||
reg [255:0] reason = 0;
|
||||
always @(posedge clk)
|
||||
begin
|
||||
if (max_cycles > 0 && trace_count > max_cycles)
|
||||
reason = "timeout";
|
||||
if (exit > 1)
|
||||
$sformat(reason, "tohost = %d", exit >> 1);
|
||||
|
||||
if (reason)
|
||||
begin
|
||||
$fdisplay(stderr, "*** FAILED *** (%s) after %d simulation cycles", reason, trace_count);
|
||||
`VCDPLUSCLOSE
|
||||
$fatal;
|
||||
end
|
||||
|
||||
if (exit == 1)
|
||||
begin
|
||||
if (verbose)
|
||||
$fdisplay(stderr, "Completed after %d simulation cycles", trace_count);
|
||||
`VCDPLUSCLOSE
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
trace_count = trace_count + 1;
|
||||
`ifdef GATE_LEVEL
|
||||
if (verbose)
|
||||
begin
|
||||
$fdisplay(stderr, "C: %10d", trace_count-1);
|
||||
end
|
||||
`endif
|
||||
end
|
||||
|
||||
endmodule
|
Reference in New Issue
Block a user