__ _ ____ ___ ___________ ______ _ __________ / /| | / / |/ / / /_ __/ | / ____/ | | / / _/ __ \ / / | | / / /|_/ / __ / / / / / /| |/ / __ | | / // // /_/ / / /__| |/ / / / / / /_/ / / / / ___ / /_/ / | |/ // // ____/ /_____/___/_/ /_/ \____/ /_/ /_/ |_\____/ |___/___/_/ ===================== VIP Configuration ===================== - Support master or slave (build_phase) uvm_config_db#(LVM_ROLE_em)::set(null, "*m_jtag_env*", "lvm_role", LVM_MASTER); uvm_config_db#(LVM_ROLE_em)::set(null, "*s_jtag_env*", "lvm_role", LVM_SLAVE); - Note: the following variables shall be configured at connect phase - Interface setup and hold time .cfg.setup_hold = LVM_CLOCKING; .set_setup_time(3.5 ,"ns"); // example of having 0 delay value .set_hold_time (4.5 ,"ns"); - Reset state .cfg.reset_state = TEST_LOGIC_RESET; - Some TAP is designed to start at RUN_TEST_IDLE , with TMS default value = 0 TEST_LOGIC_RESET, with TMS default value = 1 - instruction code, DUT default instruction code .cfg.idcode = 32'h1288_1689; - DUT has TRST .cfg.has_TRST = 1'b1; - Configurable Instruction Codes .cfg.IR_code_BYPASS = '1 ; .cfg.IR_code_DTMCSR = 'h10; .cfg.IR_code_DMIACCESS = 'h11; .cfg.IR_code_SAMPLE = 'h12; .cfg.IR_code_PRELOAD = 'h13; .cfg.IR_code_EXTEST = 'h14; .cfg.IR_code_INTEST = 'h15; .cfg.IR_code_IDCODE = 'h16; .cfg.IR_code_RUNBIST = 'h17; .cfg.IR_code_CLAMP = 'h18; .cfg.IR_code_HIGHZ = 'h19; .cfg.IR_code_INT = 'h1A; // Placeholder instruction 1 .cfg.IR_code_ISP = 'h1B; // Placeholder instruction 2 - Support daisy chain, user can easily do that by configuring the parameter TOTAL_TAP - TAP's idcode known values, example for 2 TAPs: .cfg.idcode[0] = 32'h1288_1687; .cfg.idcode[1] = 32'h1288_1689; User must configure these values, when VIP shifting out the idcode, it will passively check the correctness when idcode(s) are shifted out Note: When has_riscv_ral is 1, the register riscv_urm[i].idcode will get updated for reset, desired and mirrored values - TAP is a riscv When it is a riscv, then user can set this bit to 1 .cfg.has_riscv_ral = 1'b1; - RISC-V Debug Module printing It will print out the riscv URM map to assist user to know all the registers available in Debug Module during run_phase (Ref: https://riscv.org/wp-content/uploads/2024/12/riscv-debug-release.pdf) .cfg.print_riscv_ral = 1'b1; - Can dump jtag traffic into LVM JTAG API into a designated file The dump file can basically reused to rerun / replay the captured jtag patterns, eg replay the openocd activities .cfg.dump_traffic = 1'b1; // to be done at connect phase .cfg.TrafficName = "jtag_api.sv"; // to be done at connect phase Note: The TrafficName can be done as such as well .cfg.TrafficName = $sformatf("%0s/%0s_%0h.p.jtag_api.sv", testname, testname, seed); Example below shows the dumped API: - variables required to replay the API are added into lvm_jtag_defines.sv - There will be timestamp for the traffic being captured - the general_purpose serves as the numbering you can refer when debugging at the waveform - the checker default is OFF, user can decide to turn them ON, where it will flag error if shifted out data is mismatched //-------------------------------------------------------------------------------------------------------------------------------- // At time 9470.000000 m_jtag_env.cfg.vif.general_purpose = 8; m_jtag_env.shift_DR( .data ({LVM_JTAG_SBADDRESS1, 32'h88888888, LVM_JTAG_DMI_NOOP, 1'h0}), .size (41+1), .data_o (SHIFTED_o) ); if(check_shifted_out == 1'b1 && SHIFTED_o[41: 0] !== 42'h1d111111114) `uvm_error(msg_tag, $sformatf("[Packet 8] Shifted out=42'h%0h while expecting 42'h1d111111114", SHIFTED_o[41: 0])) if(check_shifted_out == 1'b1 && SHIFTED_o[ 0: 0] !== 1'h0) `uvm_error(msg_tag, $sformatf("[Packet 8 TAP 0] Shifted out=1'h%0h while expecting 1'h0", SHIFTED_o[ 0: 0])) if(check_shifted_out == 1'b1 && SHIFTED_o[41: 1] !== 41'he88888888a) `uvm_error(msg_tag, $sformatf("[Packet 8 TAP 1] Shifted out=41'h%0h while expecting 41'he88888888a", SHIFTED_o[41: 1])) //-------------------------------------------------------------------------------------------------------------------------------- // At time 9796.000000 m_jtag_env.cfg.vif.general_purpose = 9; m_jtag_env.shift_IR( .instruction ({m_jtag_env.cfg.IR_code_DTMCSR, m_jtag_env.cfg.IR_code_DTMCSR}), .instruction_o (IR_out) ); if(check_shifted_out == 1'b1 && IR_out[9:0] !== 10'h23f) `uvm_error(msg_tag, $sformatf("[Packet 9] Shifted out=10'h%0h while expecting 10'h23f", IR_out[9:0])) if(check_shifted_out == 1'b1 && IR_out[4:0] !== 5'h1f) `uvm_error(msg_tag, $sformatf("[Packet 9 TAP 0] Shifted out=5'h%0h while expecting 5'h1f", IR_out[4:0])) if(check_shifted_out == 1'b1 && IR_out[9:5] !== 5'h11) `uvm_error(msg_tag, $sformatf("[Packet 9 TAP 1] Shifted out=5'h%0h while expecting 5'h11", IR_out[9:5])) //-------------------------------------------------------------------------------------------------------------------------------- Reusing the api 1. At connect phase, set check_shifted_out to 1 function void connect_phase (uvm_phase phase); super.connect_phase(phase); check_shifted_out = 1'b1; // This will activate the checker endfunction 2. At any point of uvm task phases, include the jtag_api.sv (can be renamed) `include "jtag_api.sv" // The filename can be renamed ===================== API ===================== - Jump to stable state: .go_state() TEST_LOGIC_RESET RUN_TEST_IDLE // DR SHIFT_DR PAUSE_DR // IR SHIFT_IR PAUSE_IR - Shift in instruction code (via TDI), while capturing the shifted out instruction (from TDO) with user defined size .shift_IR( .instruction ( ), .size ( ), .instruction_o ( ) ); Note: This API will be settling down at RUN_TEST_IDLE, after the IR is updated - Shift in data register (via TDI), while capturing the shifted out data (from TDO) with user defined size .shift_DR( .data ( ), .size (), .data_o ( ) ); Note: This API will be settling down at RUN_TEST_IDLE, after the DR is updated - A wrapper of shift_IR and shift_DR .shift_IR_DR ( .instruction ( ), .size_i ( ), .data ( ), .size_d ( ), .instruction_o ( ) .data_o ( ) ); Note: This API will be settling down at RUN_TEST_IDLE, after the DR is updated - drive TDI API .drive_TDI () - drive TMS API .drive_TMS () - drive TRST API .drive_TRST() - Bring TAP to TEST LOGIC RESET state .go_reset () - Return current state in VIP .get_state () Available state names: TEST_LOGIC_RESET RUN_TEST_IDLE // DR SELECT_DR_SCAN CAPTURE_DR SHIFT_DR EXIT_1_DR PAUSE_DR EXIT_2_DR UPDATE_DR // IR SELECT_IR_SCAN CAPTURE_IR SHIFT_IR EXIT_1_IR PAUSE_IR EXIT_2_IR UPDATE_IR - check the user expected state against the current state (inside VIP) .check_state() : - delay 1 clock .posedge_clk(1); ===================== RISCV specific ===================== - The VIP has been enhanced to be riscv friendly, by embedding the riscv debug module as RAL. - Ref : https://riscv.org/wp-content/uploads/2024/12/riscv-debug-release.pdf - Note: make sure .cfg.has_riscv_ral = 1'b1; - For example, user can do the riscv dmiaccess operations below: - Entering the DMI Access mode - DMI write - DMI read For the details of the 3 major operations can refer to test lvm_jtag_10_dmiaccess_test.sv - The address for dmi access can be retrieved from lvm_jtag_pkg.svp - Each JTAG VIP will have embedded RISCV Debug Module UVM Register Model, which you shall see the standard lvm prediction as such: 1: [lvm_jtag_sbd] [TAP 0] DMI Write addr=7'h39 (sbaddress0) data=32'h12345678 status=LVM_JTAG_OP_SUCCESS 2: [REG_PREDICT] 3: [REG_PREDICT] Observed WRITE transaction to register m_jtag_env_riscv_urm[0].sbaddress0 : before='h0 incoming='h12345678 (byte_en='hf) updated_value='h12345678 4: [REG_PREDICT] 5: [REG_PREDICT] m_jtag_env_riscv_urm[0].sbaddress0.address.set(32'h12345678); // before=32'h0 6: [REG_PREDICT] m_jtag_env_riscv_urm[0].sbaddress0.update(status); 7: [REG_PREDICT] 8: [REG_PREDICT] FIRMWARE_WRITE(0x00000039, 0x12345678); 9: [REG_PREDICT] 10: [REG_PREDICT] ADDR VECTOR FIELD_PATH ACCESS RESET BEFORE MIRRORED 11: [REG_PREDICT] 32'h00000039 [31: 0] m_jtag_env_riscv_urm[0].sbaddress0.address RW 32'h0 32'h0 32'h12345678 <------ 12: [REG_PREDICT] Note: - Line 1: - Only when status is LVM_JTAG_OP_SUCCESS, prediction will happen. - Line 3: - Enhanced prediction statement from UVM to LVM version - Line 5 & 6 & 8: - These lines are not directly reusable / not applicable for LVM JTAG UVC, pls take note - Line 10 & 11 - This is the clear indication of RAL prediction activities, you can see each field changes - the <----- will be pointed to the changed field(s) - User can retrieve the mirrored value from the embedded URM, for example: `uvm_info (msg_tag, $sformatf("m_jtag_env.riscv_urm[i].sbaddress0.get_mirrored_value='h%0h", m_jtag_env.riscv_urm[i].sbaddress0.get_mirrored_value), UVM_DEBUG) `uvm_info (msg_tag, $sformatf("m_jtag_env.riscv_urm[i].dtmcs.get_mirrored_value='h%0h", m_jtag_env.riscv_urm[i].dtmcs.get_mirrored_value), UVM_DEBUG) - Note: the prediction only be valid when it is a successful read / write (LVM_JTAG_OP_SUCCESS) - This is matching the spec where DM will reflect a success status for read and write operation ===================== Debug signals ===================== - .tap_fsm_current show the current fsm state - .shifted_value_o[63:0] show the serial data of the shifted out TDO during shiftDR and shiftIR - .shifted[31:0] show the bit position of the data that being shifted out during shiftDR and shiftIR - .ev_sample_output_instruction event that assert when instruction is being shifted out during shiftIR - .ev_sample_output_data event that assert when data is being shifted out during shiftDR - .total_update total of FSM entering UPDATE_IR/UPDATE_DR state - .total_IR_update total of FSM entering UPDATE_IR state - .total_DR_update total of FSM entering UPDATE_DR state - .ev_IR_UPDATE indicate the time where IR is updated - .ev_DR_UPDATE indicate the time where DR is updated - .dmi_addr_name - DMI signal: Showing current access dmi register name - .dmi_addr - DMI signal: hex value of address - .dmi_op - DMI signal: Current operation - .dmi_data - DMI signal: Write Data when it is Write operation. Read Return Data when it is NOOP after the READ operation. - .dmi_access_stat - DMI signal: Write / Read Status ===================== Checker ===================== - While shifting out IDCODE, bit 0 is ensured to be 1 - IDCODE shifted out must be matching the user pre-configured value (as expected IDCODE) - During bypass mode, shifted out data is checked to be matching shifted in data, while the bypass flop is 0 - Checker can be off via .cfg.checker_off = 1'b1; - Scoreboard can be off via .cfg.sbd_on = 1'b1; ===================== OpenOCD mode ===================== - defining LVM_OPENOCD will be activating the openOCD mode - At this mode, the master VIP instance will be set to passive mode, pls refer to base test on its syntax. - OpenOCD program will connect to lvm adapter. - Note: Contact LVM more for details! ===================== Mini Regression ===================== - make mini - Note: the dmi access test is expected to fail because of the slave modelling for riscv debug module can be ignored when you are using VIP as a master [TAP 0] LVM_JTAG_DMI_READ addr=7'h39 has encountered illegal response LVM_JTAG_OP_RSVD (2'h1)!