mirror of
https://github.com/openhwgroup/cvw
synced 2025-02-11 06:05:49 +00:00
Fix step timing, rewrite jtag to include explicit reset
This commit is contained in:
parent
7dd0182407
commit
5c593c3321
@ -42,105 +42,99 @@ def prog_buff_test(cvw):
|
||||
print()
|
||||
|
||||
|
||||
def flow_control_test():
|
||||
with OpenOCD() as cvw:
|
||||
cvw.reset_dm()
|
||||
cvw.reset_hart()
|
||||
def flow_control_test(cvw):
|
||||
#time.sleep(70) # wait for OpenSBI
|
||||
|
||||
cvw.halt()
|
||||
cvw.read_data("DCSR")
|
||||
for _ in range(50):
|
||||
cvw.step()
|
||||
print(cvw.read_data("PCM"))
|
||||
cvw.resume()
|
||||
cvw.halt()
|
||||
cvw.read_data("DCSR")
|
||||
for _ in range(50):
|
||||
cvw.step()
|
||||
print(cvw.read_data("PCM"))
|
||||
cvw.resume()
|
||||
|
||||
|
||||
def register_rw_test():
|
||||
with OpenOCD() as cvw:
|
||||
registers = dict.fromkeys(cvw.register_translations.keys(),[])
|
||||
reg_addrs = list(registers.keys())
|
||||
def register_rw_test(cvw):
|
||||
registers = dict.fromkeys(cvw.register_translations.keys(),[])
|
||||
reg_addrs = list(registers.keys())
|
||||
|
||||
global XLEN
|
||||
XLEN = cvw.LLEN
|
||||
global nonstandard_register_lengths
|
||||
nonstandard_register_lengths = cvw.nonstandard_register_lengths
|
||||
global XLEN
|
||||
XLEN = cvw.LLEN
|
||||
global nonstandard_register_lengths
|
||||
nonstandard_register_lengths = cvw.nonstandard_register_lengths
|
||||
|
||||
cvw.reset_dm()
|
||||
cvw.reset_hart()
|
||||
#time.sleep(70) # wait for OpenSBI
|
||||
|
||||
#time.sleep(70) # wait for OpenSBI
|
||||
cvw.halt()
|
||||
|
||||
cvw.halt()
|
||||
|
||||
# dump data in all registers
|
||||
for r in reg_addrs:
|
||||
try:
|
||||
data = cvw.read_data(r)
|
||||
registers[r] = data
|
||||
print(f"{r}: {data}")
|
||||
except Exception as e:
|
||||
if e.args[0] == "exception": # Invalid register (not implemented)
|
||||
del registers[r]
|
||||
cvw.clear_abstrcmd_err()
|
||||
else:
|
||||
raise e
|
||||
input("Compare values to ILA, press any key to continue")
|
||||
|
||||
# Write random data to all registers
|
||||
reg_addrs = list(registers.keys())
|
||||
if random_order:
|
||||
random.shuffle(reg_addrs)
|
||||
test_reg_data = {}
|
||||
for r in reg_addrs:
|
||||
test_data = random_hex(r)
|
||||
try:
|
||||
cvw.write_data(r, test_data)
|
||||
test_reg_data[r] = test_data
|
||||
print(f"Writing {test_data} to {r}")
|
||||
except Exception as e:
|
||||
if e.args[0] == "not supported": # Register is read only
|
||||
del registers[r]
|
||||
cvw.clear_abstrcmd_err()
|
||||
else:
|
||||
raise e
|
||||
|
||||
# GPR X0 is always 0
|
||||
test_reg_data["x0"] = "0x" + "0"*(cvw.LLEN//4)
|
||||
|
||||
# Confirm data was written correctly
|
||||
reg_addrs = list(registers.keys())
|
||||
if random_order:
|
||||
random.shuffle(reg_addrs)
|
||||
for r in reg_addrs:
|
||||
try:
|
||||
rdata = cvw.read_data(r)
|
||||
except Exception as e:
|
||||
raise e
|
||||
if rdata != test_reg_data[r]:
|
||||
print(f"Error: register {r} read did not return correct data: {rdata} != {test_reg_data[r]}")
|
||||
# dump data in all registers
|
||||
for r in reg_addrs:
|
||||
try:
|
||||
data = cvw.read_data(r)
|
||||
registers[r] = data
|
||||
print(f"{r}: {data}")
|
||||
except Exception as e:
|
||||
if e.args[0] == "exception": # Invalid register (not implemented)
|
||||
del registers[r]
|
||||
cvw.clear_abstrcmd_err()
|
||||
else:
|
||||
print(f"Reading {rdata} from {r}")
|
||||
raise e
|
||||
input("Compare values to ILA, press any key to continue")
|
||||
|
||||
# Return all registers to original state
|
||||
reg_addrs = list(registers.keys())
|
||||
for r in reg_addrs:
|
||||
print(f"Writing {registers[r]} to {r}")
|
||||
try:
|
||||
cvw.write_data(r, registers[r])
|
||||
except Exception as e:
|
||||
# Write random data to all registers
|
||||
reg_addrs = list(registers.keys())
|
||||
if random_order:
|
||||
random.shuffle(reg_addrs)
|
||||
test_reg_data = {}
|
||||
for r in reg_addrs:
|
||||
test_data = random_hex(r)
|
||||
try:
|
||||
cvw.write_data(r, test_data)
|
||||
test_reg_data[r] = test_data
|
||||
print(f"Writing {test_data} to {r}")
|
||||
except Exception as e:
|
||||
if e.args[0] == "not supported": # Register is read only
|
||||
del registers[r]
|
||||
cvw.clear_abstrcmd_err()
|
||||
else:
|
||||
raise e
|
||||
|
||||
# Confirm data was written correctly
|
||||
for r in reg_addrs:
|
||||
try:
|
||||
rdata = cvw.read_data(r)
|
||||
except Exception as e:
|
||||
raise e
|
||||
if rdata != registers[r]:
|
||||
raise Exception(f"Register {r} read did not return correct data: {rdata} != {registers[r]}")
|
||||
print("All writes successful")
|
||||
# GPR X0 is always 0
|
||||
test_reg_data["x0"] = "0x" + "0"*(cvw.LLEN//4)
|
||||
|
||||
cvw.resume()
|
||||
# Confirm data was written correctly
|
||||
reg_addrs = list(registers.keys())
|
||||
if random_order:
|
||||
random.shuffle(reg_addrs)
|
||||
for r in reg_addrs:
|
||||
try:
|
||||
rdata = cvw.read_data(r)
|
||||
except Exception as e:
|
||||
raise e
|
||||
if rdata != test_reg_data[r]:
|
||||
print(f"Error: register {r} read did not return correct data: {rdata} != {test_reg_data[r]}")
|
||||
else:
|
||||
print(f"Reading {rdata} from {r}")
|
||||
|
||||
# Return all registers to original state
|
||||
reg_addrs = list(registers.keys())
|
||||
for r in reg_addrs:
|
||||
print(f"Writing {registers[r]} to {r}")
|
||||
try:
|
||||
cvw.write_data(r, registers[r])
|
||||
except Exception as e:
|
||||
raise e
|
||||
|
||||
# Confirm data was written correctly
|
||||
for r in reg_addrs:
|
||||
try:
|
||||
rdata = cvw.read_data(r)
|
||||
except Exception as e:
|
||||
raise e
|
||||
if rdata != registers[r]:
|
||||
raise Exception(f"Register {r} read did not return correct data: {rdata} != {registers[r]}")
|
||||
print("All writes successful")
|
||||
|
||||
cvw.resume()
|
||||
|
||||
|
||||
def random_hex(reg_name):
|
||||
@ -160,8 +154,11 @@ def random_hex(reg_name):
|
||||
|
||||
|
||||
with OpenOCD() as cvw:
|
||||
print(cvw.read_dmi("0x16"))
|
||||
cvw.trst()
|
||||
cvw.reset_dm()
|
||||
cvw.reset_hart()
|
||||
#register_rw_test()
|
||||
#flow_control_test()
|
||||
prog_buff_test(cvw)
|
||||
quit()
|
||||
#register_rw_test(cvw)
|
||||
flow_control_test(cvw)
|
||||
#prog_buff_test(cvw)
|
||||
|
@ -98,7 +98,7 @@ module dm import cvw::*; #(parameter cvw_t P) (
|
||||
// [0] = 1
|
||||
localparam JTAG_DEVICE_ID = 32'h1002AC05;
|
||||
|
||||
dtm #(`ADDR_WIDTH, JTAG_DEVICE_ID) dtm (.clk, .tck, .tdi, .tms, .tdo,
|
||||
dtm #(`ADDR_WIDTH, JTAG_DEVICE_ID) dtm (.clk, .rst, .tck, .tdi, .tms, .tdo,
|
||||
.ReqReady, .ReqValid, .ReqAddress, .ReqData, .ReqOP, .RspReady,
|
||||
.RspValid, .RspData, .RspOP);
|
||||
|
||||
@ -253,7 +253,7 @@ module dm import cvw::*; #(parameter cvw_t P) (
|
||||
{2'bx,`HARTINFO},
|
||||
{2'bx,`ABSTRACTAUTO},
|
||||
{2'bx,`NEXTDM} : State <= READ_ZERO;
|
||||
default : State <= INVALID;
|
||||
default : State <= READ_ZERO;//INVALID;
|
||||
endcase
|
||||
end
|
||||
|
||||
@ -388,7 +388,7 @@ module dm import cvw::*; #(parameter cvw_t P) (
|
||||
end
|
||||
|
||||
INVALID : begin
|
||||
RspOP <= `OP_FAILED;
|
||||
RspOP <= `OP_SUCCESS;//`OP_FAILED;
|
||||
State <= ACK;
|
||||
end
|
||||
endcase
|
||||
|
@ -65,7 +65,7 @@ module dmc (
|
||||
assign DebugMode = (State != RUNNING);
|
||||
assign DebugStall = (State == HALTED);
|
||||
|
||||
assign EnterDebugMode = (State == FLUSH) & (Counter == 0);
|
||||
assign EnterDebugMode = (State == FLUSH) & ~|Counter;
|
||||
assign ExitDebugMode = (State == HALTED) & ResumeReq;
|
||||
assign ForceNOP = (State == FLUSH);
|
||||
|
||||
@ -77,7 +77,7 @@ module dmc (
|
||||
case (State)
|
||||
RUNNING : begin
|
||||
if (HaltReq) begin
|
||||
Counter <= 0;
|
||||
Counter <= NOP_CYCLE_DURATION;
|
||||
State <= FLUSH;
|
||||
DebugCause <= `CAUSE_HALTREQ;
|
||||
end
|
||||
@ -87,25 +87,22 @@ module dmc (
|
||||
|
||||
// fill the pipe with NOP before halting
|
||||
FLUSH : begin
|
||||
if (Counter == NOP_CYCLE_DURATION)
|
||||
if (~|Counter)
|
||||
State <= HALTED;
|
||||
else
|
||||
Counter <= Counter + 1;
|
||||
Counter <= Counter - 1;
|
||||
end
|
||||
|
||||
HALTED : begin
|
||||
if (ResumeReq)
|
||||
State <= RESUME;
|
||||
end
|
||||
|
||||
RESUME : begin
|
||||
if (Step) begin
|
||||
Counter <= 0;
|
||||
State <= FLUSH;
|
||||
DebugCause <= `CAUSE_STEP;
|
||||
end else begin
|
||||
State <= RUNNING;
|
||||
ResumeAck <= 1;
|
||||
if (ResumeReq) begin
|
||||
if (Step) begin
|
||||
Counter <= NOP_CYCLE_DURATION;
|
||||
State <= FLUSH;
|
||||
DebugCause <= `CAUSE_STEP;
|
||||
end else begin
|
||||
State <= RUNNING;
|
||||
ResumeAck <= 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
endcase
|
||||
|
@ -31,7 +31,7 @@
|
||||
|
||||
module dtm #(parameter ADDR_WIDTH, parameter JTAG_DEVICE_ID) (
|
||||
// System clock
|
||||
input logic clk,
|
||||
input logic clk, rst,
|
||||
// External JTAG signals
|
||||
input logic tck,
|
||||
input logic tdi,
|
||||
@ -90,7 +90,7 @@ module dtm #(parameter ADDR_WIDTH, parameter JTAG_DEVICE_ID) (
|
||||
// DTMCS
|
||||
assign DtmcsOut = {11'b0, ErrInfo, 3'b0, Idle, DmiStat, ABits, Version};
|
||||
always_ff @(posedge clk) begin
|
||||
if (~resetn | DtmHardReset) begin
|
||||
if (rst | ~resetn | DtmHardReset) begin
|
||||
DtmHardReset <= 0;
|
||||
DmiReset <= 0;
|
||||
end else if (UpdateDtmcs) begin
|
||||
@ -103,7 +103,7 @@ module dtm #(parameter ADDR_WIDTH, parameter JTAG_DEVICE_ID) (
|
||||
|
||||
// DMI
|
||||
always_ff @(posedge clk) begin
|
||||
if (~resetn | DtmHardReset) begin
|
||||
if (rst | ~resetn | DtmHardReset) begin
|
||||
ValRspData <= 0;
|
||||
ValRspOP <= `OP_SUCCESS;
|
||||
//ErrInfo <= 4;
|
||||
|
@ -48,15 +48,10 @@ module ir (
|
||||
assign tdo = shift_reg[0];
|
||||
|
||||
// Shift register
|
||||
always @(posedge clockIR) begin
|
||||
shift_reg[0] <= shift_reg[1] | captureIR;
|
||||
end
|
||||
flop #(1) shift_regmsb (.clk(clockIR), .d(shift_reg[1] | captureIR), .q(shift_reg[0]));
|
||||
genvar i;
|
||||
for (i = INST_REG_WIDTH; i > 1; i = i - 1) begin
|
||||
always @(posedge clockIR) begin
|
||||
shift_reg[i-1] <= shift_reg[i] & ~captureIR;
|
||||
end
|
||||
end
|
||||
for (i = INST_REG_WIDTH; i > 1; i = i - 1)
|
||||
flop #(1) shift_reg (.clk(clockIR), .d(shift_reg[i] & ~captureIR), .q(shift_reg[i-1]));
|
||||
|
||||
// Instruction decoder
|
||||
// 6.1.2
|
||||
|
@ -26,6 +26,7 @@
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
module jtag #(parameter ADDR_WIDTH, parameter DEVICE_ID) (
|
||||
input logic rst,
|
||||
// JTAG signals
|
||||
input logic tck,
|
||||
input logic tdi,
|
||||
@ -79,7 +80,7 @@ module jtag #(parameter ADDR_WIDTH, parameter DEVICE_ID) (
|
||||
assign CaptureDmi = captureDR & DmiInstr;
|
||||
assign UpdateDmi = updateDR & DmiInstr;
|
||||
|
||||
tap tap (.tck, .tms, .resetn, .tdo_en, .captureIR,
|
||||
tap tap (.rst, .tck, .tms, .resetn, .tdo_en, .captureIR,
|
||||
.clockIR, .updateIR, .shiftDR, .captureDR, .clockDR, .updateDR, .select);
|
||||
|
||||
// IR/DR input demux
|
||||
@ -103,34 +104,23 @@ module jtag #(parameter ADDR_WIDTH, parameter DEVICE_ID) (
|
||||
endcase
|
||||
end
|
||||
|
||||
always_ff @(posedge UpdateDtmcs)
|
||||
DtmcsIn <= DtmcsShiftReg[31:0];
|
||||
|
||||
always_ff @(posedge UpdateDmi)
|
||||
DmiIn <= DmiShiftReg[34+ADDR_WIDTH-1:0];
|
||||
flopr #(32) dtmcsreg (.clk(UpdateDtmcs), .reset(rst), .d(DtmcsShiftReg[31:0]), .q(DtmcsIn));
|
||||
flopr #(34+ADDR_WIDTH) dmireg (.clk(UpdateDmi), .reset(rst), .d(DmiShiftReg[34+ADDR_WIDTH-1:0]), .q(DmiIn));
|
||||
|
||||
assign DtmcsShiftReg[32] = tdi_dr;
|
||||
assign tdo_dtmcs = DtmcsShiftReg[0];
|
||||
for (i = 0; i < 32; i = i + 1) begin
|
||||
always_ff @(posedge clockDR) begin
|
||||
DtmcsShiftReg[i] <= captureDR ? DtmcsOut[i] : DtmcsShiftReg[i+1];
|
||||
end
|
||||
end
|
||||
for (i = 0; i < 32; i = i + 1)
|
||||
flopr #(1) dtmcsshiftreg (.clk(clockDR), .reset(rst), .d(captureDR ? DtmcsOut[i] : DtmcsShiftReg[i+1]), .q(DtmcsShiftReg[i]));
|
||||
|
||||
assign DmiShiftReg[34+ADDR_WIDTH] = tdi_dr;
|
||||
assign tdo_dmi = DmiShiftReg[0];
|
||||
for (i = 0; i < 34+ADDR_WIDTH; i = i + 1) begin
|
||||
always_ff @(posedge clockDR) begin
|
||||
DmiShiftReg[i] <= captureDR ? DmiOut[i] : DmiShiftReg[i+1];
|
||||
end
|
||||
end
|
||||
for (i = 0; i < 34+ADDR_WIDTH; i = i + 1)
|
||||
flopr #(1) dmishiftreg (.clk(clockDR), .reset(rst), .d(captureDR ? DmiOut[i] : DmiShiftReg[i+1]), .q(DmiShiftReg[i]));
|
||||
|
||||
// jtag id register
|
||||
idreg #(DEVICE_ID) id (.tdi(tdi_dr), .clockDR, .captureDR, .tdo(tdo_idcode));
|
||||
|
||||
// bypass register
|
||||
always_ff @(posedge clockDR) begin
|
||||
tdo_bypass <= tdi_dr & shiftDR;
|
||||
end
|
||||
flopr #(1) bypassreg (.clk(clockDR), .reset(rst), .d(tdi_dr & shiftDR), .q(tdo_bypass));
|
||||
|
||||
endmodule
|
||||
|
@ -26,6 +26,7 @@
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
module tap (
|
||||
input logic rst,
|
||||
input logic tck,
|
||||
input logic tms,
|
||||
output logic resetn,
|
||||
@ -40,6 +41,8 @@ module tap (
|
||||
output logic select
|
||||
);
|
||||
|
||||
logic tckn;
|
||||
|
||||
enum logic [3:0] {
|
||||
Exit2DR = 4'h0,
|
||||
Exit1DR = 4'h1,
|
||||
@ -59,36 +62,39 @@ module tap (
|
||||
TLReset = 4'hF
|
||||
} State;
|
||||
|
||||
always @(posedge tck) begin
|
||||
case (State)
|
||||
TLReset : State <= tms ? TLReset : RunTestIdle;
|
||||
RunTestIdle : State <= tms ? SelectDR : RunTestIdle;
|
||||
SelectDR : State <= tms ? SelectIR : CaptureDR;
|
||||
CaptureDR : State <= tms ? Exit1DR : ShiftDR;
|
||||
ShiftDR : State <= tms ? Exit1DR : ShiftDR;
|
||||
Exit1DR : State <= tms ? UpdateDR : PauseDR;
|
||||
PauseDR : State <= tms ? Exit2DR : PauseDR;
|
||||
Exit2DR : State <= tms ? UpdateDR : ShiftDR;
|
||||
UpdateDR : State <= tms ? SelectDR : RunTestIdle;
|
||||
SelectIR : State <= tms ? TLReset : CaptureIR;
|
||||
CaptureIR : State <= tms ? Exit1IR : ShiftIR;
|
||||
ShiftIR : State <= tms ? Exit1IR : ShiftIR;
|
||||
Exit1IR : State <= tms ? UpdateIR : PauseIR;
|
||||
PauseIR : State <= tms ? Exit2IR : PauseIR;
|
||||
Exit2IR : State <= tms ? UpdateIR : ShiftIR;
|
||||
UpdateIR : State <= tms ? SelectDR : RunTestIdle;
|
||||
endcase
|
||||
always @(posedge rst, posedge tck) begin
|
||||
if (rst)
|
||||
State <= TLReset;
|
||||
else
|
||||
case (State)
|
||||
TLReset : State <= tms ? TLReset : RunTestIdle;
|
||||
RunTestIdle : State <= tms ? SelectDR : RunTestIdle;
|
||||
SelectDR : State <= tms ? SelectIR : CaptureDR;
|
||||
CaptureDR : State <= tms ? Exit1DR : ShiftDR;
|
||||
ShiftDR : State <= tms ? Exit1DR : ShiftDR;
|
||||
Exit1DR : State <= tms ? UpdateDR : PauseDR;
|
||||
PauseDR : State <= tms ? Exit2DR : PauseDR;
|
||||
Exit2DR : State <= tms ? UpdateDR : ShiftDR;
|
||||
UpdateDR : State <= tms ? SelectDR : RunTestIdle;
|
||||
SelectIR : State <= tms ? TLReset : CaptureIR;
|
||||
CaptureIR : State <= tms ? Exit1IR : ShiftIR;
|
||||
ShiftIR : State <= tms ? Exit1IR : ShiftIR;
|
||||
Exit1IR : State <= tms ? UpdateIR : PauseIR;
|
||||
PauseIR : State <= tms ? Exit2IR : PauseIR;
|
||||
Exit2IR : State <= tms ? UpdateIR : ShiftIR;
|
||||
UpdateIR : State <= tms ? SelectDR : RunTestIdle;
|
||||
endcase
|
||||
end
|
||||
|
||||
always @(negedge tck) begin
|
||||
resetn <= ~(State == TLReset);
|
||||
tdo_en <= State == ShiftIR | State == ShiftDR;
|
||||
captureIR <= State == CaptureIR;
|
||||
updateIR <= State == UpdateIR;
|
||||
shiftDR <= State == ShiftDR;
|
||||
captureDR <= State == CaptureDR;
|
||||
updateDR <= State == UpdateDR;
|
||||
end
|
||||
assign tckn = ~tck;
|
||||
|
||||
flopr #(1) resetnreg (.clk(tckn), .reset(rst), .d(~(State == TLReset)), .q(resetn));
|
||||
flopr #(1) tdo_enreg (.clk(tckn), .reset(rst), .d(State == ShiftIR | State == ShiftDR), .q(tdo_en));
|
||||
flopr #(1) captureIRreg (.clk(tckn), .reset(rst), .d(State == CaptureIR), .q(captureIR));
|
||||
flopr #(1) updateIRreg (.clk(tckn), .reset(rst), .d(State == UpdateIR), .q(updateIR));
|
||||
flopr #(1) shiftDRreg (.clk(tckn), .reset(rst), .d(State == ShiftDR), .q(shiftDR));
|
||||
flopr #(1) captureDRreg (.clk(tckn), .reset(rst), .d(State == CaptureDR), .q(captureDR));
|
||||
flopr #(1) updateDRreg (.clk(tckn), .reset(rst), .d(State == UpdateDR), .q(updateDR));
|
||||
|
||||
assign clockIR = tck | State[0] | ~State[1] | ~State[3];
|
||||
assign clockDR = tck | State[0] | ~State[1] | State[3];
|
||||
|
Loading…
Reference in New Issue
Block a user