[spi_device/dv] Test addr 4b mode 1. Update spi agent to support addr_mode - addrDisable, AddrCfg, Addr4b/3b 2. Update sequence to randomly configure en4b and ex4b commands, also send these 2 commands along with others 3. update scb to update addr mode when these 2 commands are received Signed-off-by: Weicai Yang <weicai@google.com>
diff --git a/hw/dv/sv/spi_agent/seq_lib/spi_host_flash_seq.sv b/hw/dv/sv/spi_agent/seq_lib/spi_host_flash_seq.sv index 41d7e0e..55ae6af 100644 --- a/hw/dv/sv/spi_agent/seq_lib/spi_host_flash_seq.sv +++ b/hw/dv/sv/spi_agent/seq_lib/spi_host_flash_seq.sv
@@ -19,7 +19,7 @@ `uvm_object_new virtual task body(); - int addr_bytes, num_lanes, dummy_cycles; + int num_addr_bytes, num_lanes, dummy_cycles; bit write_command; req = spi_item::type_id::create("req"); @@ -27,12 +27,12 @@ cfg.extract_cmd_info_from_opcode(opcode, // output - addr_bytes, write_command, num_lanes, dummy_cycles); + num_addr_bytes, write_command, num_lanes, dummy_cycles); if (address_q.size() == 0) begin `DV_CHECK_MEMBER_RANDOMIZE_WITH_FATAL(address_q, - address_q.size == addr_bytes;) + address_q.size == num_addr_bytes;) end else begin - `DV_CHECK_EQ(address_q.size(), addr_bytes) + `DV_CHECK_EQ(address_q.size(), num_addr_bytes) end `DV_CHECK_RANDOMIZE_WITH_FATAL(req, @@ -41,7 +41,7 @@ write_command == local::write_command; num_lanes == local::num_lanes; dummy_cycles == local::dummy_cycles; - address_q.size() == addr_bytes; + address_q.size() == num_addr_bytes; foreach (address_q[i]) { address_q[i] == local::address_q[i]; }
diff --git a/hw/dv/sv/spi_agent/spi_agent_cfg.sv b/hw/dv/sv/spi_agent/spi_agent_cfg.sv index f28a803..ebbfec6 100644 --- a/hw/dv/sv/spi_agent/spi_agent_cfg.sv +++ b/hw/dv/sv/spi_agent/spi_agent_cfg.sv
@@ -39,7 +39,7 @@ // Cmd info configs spi_flash_cmd_info cmd_infos[bit[7:0]]; bit is_flash_mode; - + bit flash_addr_4b_en; // address width in bytes (default is 4 bytes) int spi_cmd_width = 4; @@ -146,22 +146,22 @@ endfunction : is_opcode_supported virtual function void extract_cmd_info_from_opcode(input bit [7:0] opcode, - output bit [2:0] addr_bytes, + output bit [2:0] num_addr_bytes, output bit write_command, output bit [2:0] num_lanes, output int dummy_cycles); if (cmd_infos.exists(opcode)) begin - addr_bytes = cmd_infos[opcode].addr_bytes; - write_command = cmd_infos[opcode].write_command; - num_lanes = cmd_infos[opcode].num_lanes; - dummy_cycles = cmd_infos[opcode].dummy_cycles; + num_addr_bytes = get_num_addr_byte(opcode); + write_command = cmd_infos[opcode].write_command; + num_lanes = cmd_infos[opcode].num_lanes; + dummy_cycles = cmd_infos[opcode].dummy_cycles; end else begin // if it's invalid opcode, here is the default setting `uvm_info(`gfn, $sformatf("extract invalid opcode: 0x%0h", opcode), UVM_MEDIUM) - write_command = 1; - addr_bytes = 0; - num_lanes = 1; - dummy_cycles = 0; + write_command = 1; + num_addr_bytes = 0; + num_lanes = 1; + dummy_cycles = 0; end endfunction : extract_cmd_info_from_opcode @@ -190,4 +190,15 @@ `uvm_info(`gfn, $sformatf("sampled one byte data for flash: 0x%0h", data), UVM_HIGH) endtask + + virtual function int get_num_addr_byte(bit [7:0] opcode); + `DV_CHECK(cmd_infos.exists(opcode)) + case (cmd_infos[opcode].addr_mode) + SpiFlashAddrDisabled: return 0; + SpiFlashAddrCfg: return flash_addr_4b_en ? 4 : 3; + SpiFlashAddr3b: return 3; + SpiFlashAddr4b: return 4; + default: `uvm_fatal(`gfn, "Impossible value") + endcase + endfunction : get_num_addr_byte endclass : spi_agent_cfg
diff --git a/hw/dv/sv/spi_agent/spi_agent_pkg.sv b/hw/dv/sv/spi_agent/spi_agent_pkg.sv index 97a0794..141839a 100644 --- a/hw/dv/sv/spi_agent/spi_agent_pkg.sv +++ b/hw/dv/sv/spi_agent/spi_agent_pkg.sv
@@ -55,6 +55,16 @@ ReadSfdp = 8'b01011010 } spi_cmd_e; + typedef enum bit [1:0] { + SpiFlashAddrDisabled, + // Configurable 3b or 4b address + SpiFlashAddrCfg, + // Fixed 3b addr + SpiFlashAddr3b, + // Fixed 4b addr + SpiFlashAddr4b + } spi_flash_addr_mode_e; + // forward declare classes to allow typedefs below typedef class spi_item; typedef class spi_agent_cfg;
diff --git a/hw/dv/sv/spi_agent/spi_flash_cmd_info.sv b/hw/dv/sv/spi_agent/spi_flash_cmd_info.sv index b091567..5dfd897 100644 --- a/hw/dv/sv/spi_agent/spi_flash_cmd_info.sv +++ b/hw/dv/sv/spi_agent/spi_flash_cmd_info.sv
@@ -6,16 +6,15 @@ // cmd, it knows how many addr_bytes, direction, dummy_cycles etc class spi_flash_cmd_info extends uvm_sequence_item; rand bit [7:0] opcode; - rand bit [2:0] addr_bytes; + rand spi_flash_addr_mode_e addr_mode; rand bit write_command; // number of lanes when sending payload, set to 0 if no payload is expected rand bit [2:0] num_lanes; rand int dummy_cycles; - constraint addr_bytes_c { - addr_bytes inside {0, 3, 4}; + constraint addr_mode_c { // for dual/quad mode, it always contains address - num_lanes > 1 -> addr_bytes > 0; + num_lanes > 1 -> addr_mode != SpiFlashAddrDisabled; } constraint num_lanes_c { @@ -37,7 +36,7 @@ `uvm_object_utils_begin(spi_flash_cmd_info) `uvm_field_int(opcode, UVM_DEFAULT) - `uvm_field_int(addr_bytes, UVM_DEFAULT) + `uvm_field_enum(spi_flash_addr_mode_e, addr_mode, UVM_DEFAULT) `uvm_field_int(write_command, UVM_DEFAULT) `uvm_field_int(dummy_cycles, UVM_DEFAULT) `uvm_field_int(num_lanes, UVM_DEFAULT)
diff --git a/hw/dv/sv/spi_agent/spi_monitor.sv b/hw/dv/sv/spi_agent/spi_monitor.sv index 1a93274..4f54609 100644 --- a/hw/dv/sv/spi_agent/spi_monitor.sv +++ b/hw/dv/sv/spi_agent/spi_monitor.sv
@@ -195,7 +195,7 @@ wait(cfg.vif.csb[cfg.csb_sel] == 1'b1); end begin: sample_thread - int addr_bytes; + int num_addr_bytes; opcode_received = 0; item.item_type = SpiFlashTrans; // for mode 1 and 3, get the leading edges out of the way @@ -207,10 +207,10 @@ opcode_received = 1; cfg.extract_cmd_info_from_opcode(item.opcode, // output - addr_bytes, item.write_command, item.num_lanes, item.dummy_cycles); + num_addr_bytes, item.write_command, item.num_lanes, item.dummy_cycles); `uvm_info(`gfn, $sformatf("sampled flash opcode: 0x%0h", item.opcode), UVM_MEDIUM) - sample_flash_address(addr_bytes, item.address_q); + sample_flash_address(num_addr_bytes, item.address_q); repeat (item.dummy_cycles) begin cfg.wait_sck_edge(SamplingEdge);
diff --git a/hw/ip/spi_device/data/spi_device_testplan.hjson b/hw/ip/spi_device/data/spi_device_testplan.hjson index 844caf1..fee75b9 100644 --- a/hw/ip/spi_device/data/spi_device_testplan.hjson +++ b/hw/ip/spi_device/data/spi_device_testplan.hjson
@@ -398,7 +398,7 @@ - Issue supported command with required address. - Check proper address propagation.''' milestone: V2 - tests: [] + tests: ["spi_device_cfg_cmd"] } ] covergroups: [
diff --git a/hw/ip/spi_device/dv/env/seq_lib/spi_device_base_vseq.sv b/hw/ip/spi_device/dv/env/seq_lib/spi_device_base_vseq.sv index 1f2c6d6..a6b830b 100644 --- a/hw/ip/spi_device/dv/env/seq_lib/spi_device_base_vseq.sv +++ b/hw/ip/spi_device/dv/env/seq_lib/spi_device_base_vseq.sv
@@ -231,11 +231,12 @@ `uvm_create_on(m_spi_host_seq, p_sequencer.spi_sequencer_h) if (op inside {READ_CMD_LIST} && cfg.spi_host_agent_cfg.is_opcode_supported(op)) begin - int addr_bytes = cfg.spi_host_agent_cfg.cmd_infos[op].addr_bytes; - if (addr_bytes > 0) begin - if (addr_bytes == 4) begin + int num_addr_bytes = cfg.spi_host_agent_cfg.get_num_addr_byte(op); + if (num_addr_bytes > 0) begin + if (num_addr_bytes == 4) begin byte_addr_q.push_back(addr[31:24]); end + // push the lower 3 bytes address byte_addr_q = {byte_addr_q, addr[23:16], addr[15:8], addr[7:0]}; end end @@ -248,6 +249,14 @@ read_size == payload_size;) `uvm_send(m_spi_host_seq) + if (op == `gmv(ral.cmd_info_en4b.opcode) && `gmv(ral.cmd_info_en4b.valid)) begin + cfg.spi_device_agent_cfg.flash_addr_4b_en = 1; + cfg.spi_host_agent_cfg.flash_addr_4b_en = 1; + end else if (op == `gmv(ral.cmd_info_ex4b.opcode) && `gmv(ral.cmd_info_ex4b.valid)) begin + cfg.spi_device_agent_cfg.flash_addr_4b_en = 0; + cfg.spi_host_agent_cfg.flash_addr_4b_en = 0; + end + if (wait_on_busy) begin spi_device_reg_cmd_info cmd_info = get_cmd_info_reg_by_opcode(op, ral); if (cmd_info != null && `gmv(cmd_info.upload) && `gmv(cmd_info.busy)) begin
diff --git a/hw/ip/spi_device/dv/env/seq_lib/spi_device_cfg_cmd_vseq.sv b/hw/ip/spi_device/dv/env/seq_lib/spi_device_cfg_cmd_vseq.sv index 82170d5..ba1badd 100644 --- a/hw/ip/spi_device/dv/env/seq_lib/spi_device_cfg_cmd_vseq.sv +++ b/hw/ip/spi_device/dv/env/seq_lib/spi_device_cfg_cmd_vseq.sv
@@ -8,12 +8,19 @@ `uvm_object_new function void pre_randomize(); - // TODO, 2 more to add - intercept_ops[$] = {WREN, WRDI}; + intercept_ops[$] = {WREN, WRDI, EN4B, EX4B}; endfunction virtual task pre_start(); allow_write_enable_disable = 1; + allow_addr_cfg_cmd = 1; super.pre_start(); endtask + + // randomly set flash_status for every spi transaction + virtual task spi_host_xfer_flash_item(bit [7:0] op, uint payload_size, + bit [31:0] addr, bit wait_on_busy = 1); + super.spi_host_xfer_flash_item(op, payload_size, addr, wait_on_busy); + read_and_check_4b_en(); + endtask endclass : spi_device_cfg_cmd_vseq
diff --git a/hw/ip/spi_device/dv/env/seq_lib/spi_device_pass_all_vseq.sv b/hw/ip/spi_device/dv/env/seq_lib/spi_device_pass_all_vseq.sv index 07805ca..4f53dd6 100644 --- a/hw/ip/spi_device/dv/env/seq_lib/spi_device_pass_all_vseq.sv +++ b/hw/ip/spi_device/dv/env/seq_lib/spi_device_pass_all_vseq.sv
@@ -21,6 +21,7 @@ always_set_busy_when_upload_contain_payload = 1; allow_write_enable_disable = 1; + allow_addr_cfg_cmd = 1; fork // this thread runs until the main_seq completes @@ -57,6 +58,8 @@ random_access_flash_status(.write(0)); end + if ($urandom_range(0, 1)) read_and_check_4b_en(); + randomize_op_addr_size(); `uvm_info(`gfn, $sformatf("Testing op_num %0d/20, op = 0x%0h", j, opcode), UVM_MEDIUM)
diff --git a/hw/ip/spi_device/dv/env/seq_lib/spi_device_pass_base_vseq.sv b/hw/ip/spi_device/dv/env/seq_lib/spi_device_pass_base_vseq.sv index 266972e..c7dd9ed 100644 --- a/hw/ip/spi_device/dv/env/seq_lib/spi_device_pass_base_vseq.sv +++ b/hw/ip/spi_device/dv/env/seq_lib/spi_device_pass_base_vseq.sv
@@ -17,7 +17,7 @@ bit allow_upload; bit allow_write_enable_disable; - + bit allow_addr_cfg_cmd; // we can only hold one payload, set it busy to avoid payload is overwritten before read out. bit always_set_busy_when_upload_contain_payload; @@ -101,7 +101,7 @@ // Configure the first 11 commands which are fixed `DV_CHECK_RANDOMIZE_WITH_FATAL(info, - info.addr_bytes == 0 && + info.addr_mode == SpiFlashAddrDisabled && info.opcode == READ_STATUS_1 && info.num_lanes == 1 && info.dummy_cycles == 0 && @@ -109,7 +109,7 @@ add_cmd_info(info, 0); info = spi_flash_cmd_info::type_id::create("info"); `DV_CHECK_RANDOMIZE_WITH_FATAL(info, - info.addr_bytes == 0 && + info.addr_mode == SpiFlashAddrDisabled && info.opcode == READ_STATUS_2; info.num_lanes == 1 && info.dummy_cycles == 0 && @@ -117,7 +117,7 @@ add_cmd_info(info, 1); info = spi_flash_cmd_info::type_id::create("info"); `DV_CHECK_RANDOMIZE_WITH_FATAL(info, - info.addr_bytes == 0 && + info.addr_mode == SpiFlashAddrDisabled && info.opcode == READ_STATUS_3 && info.num_lanes == 1 && info.dummy_cycles == 0 && @@ -125,7 +125,7 @@ add_cmd_info(info, 2); info = spi_flash_cmd_info::type_id::create("info"); `DV_CHECK_RANDOMIZE_WITH_FATAL(info, - info.addr_bytes == 0 && + info.addr_mode == SpiFlashAddrDisabled && info.opcode == READ_JEDEC && info.num_lanes == 1 && info.dummy_cycles == 0 && @@ -133,49 +133,49 @@ add_cmd_info(info, 3); info = spi_flash_cmd_info::type_id::create("info"); `DV_CHECK_RANDOMIZE_WITH_FATAL(info, - info.addr_bytes == 3 && + info.addr_mode == SpiFlashAddr3b && info.opcode == READ_SFDP; info.num_lanes == 1 && info.write_command == 0;) add_cmd_info(info, 4); info = spi_flash_cmd_info::type_id::create("info"); `DV_CHECK_RANDOMIZE_WITH_FATAL(info, - info.addr_bytes > 0 && + info.addr_mode != SpiFlashAddrDisabled && info.opcode == READ_NORMAL && info.num_lanes == 1 && info.write_command == 0;) add_cmd_info(info, 5); info = spi_flash_cmd_info::type_id::create("info"); `DV_CHECK_RANDOMIZE_WITH_FATAL(info, - info.addr_bytes > 0 && + info.addr_mode != SpiFlashAddrDisabled && info.opcode == READ_FAST && info.num_lanes == 1 && info.write_command == 0;) add_cmd_info(info, 6); info = spi_flash_cmd_info::type_id::create("info"); `DV_CHECK_RANDOMIZE_WITH_FATAL(info, - info.addr_bytes > 0 && + info.addr_mode != SpiFlashAddrDisabled && info.opcode == READ_DUAL && info.write_command == 0 && info.num_lanes == 2;) add_cmd_info(info, 7); info = spi_flash_cmd_info::type_id::create("info"); `DV_CHECK_RANDOMIZE_WITH_FATAL(info, - info.addr_bytes > 0 && + info.addr_mode != SpiFlashAddrDisabled && info.opcode == READ_QUAD && info.write_command == 0 && info.num_lanes == 4;) add_cmd_info(info, 8); info = spi_flash_cmd_info::type_id::create("info"); `DV_CHECK_RANDOMIZE_WITH_FATAL(info, - info.addr_bytes > 0 && + info.addr_mode != SpiFlashAddrDisabled && info.opcode == READ_DUALIO && info.write_command == 0 && info.num_lanes == 2;) add_cmd_info(info, 9); info = spi_flash_cmd_info::type_id::create("info"); `DV_CHECK_RANDOMIZE_WITH_FATAL(info, - info.addr_bytes > 0 && + info.addr_mode != SpiFlashAddrDisabled && info.opcode == READ_QUADIO && info.write_command == 0 && info.num_lanes == 4;) @@ -197,6 +197,21 @@ csr_update(ral.cmd_info_wrdi); end + if (allow_addr_cfg_cmd) begin + bit valid; + randomize_cfg_cmd_info(info, EN4B, valid); + ral.cmd_info_en4b.valid.set(valid); + if (valid) ral.cmd_info_en4b.opcode.set(info.opcode); + else `DV_CHECK_RANDOMIZE_FATAL(ral.cmd_info_en4b.opcode) + csr_update(ral.cmd_info_en4b); + + randomize_cfg_cmd_info(info, EX4B, valid); + ral.cmd_info_ex4b.valid.set(valid); + if (valid) ral.cmd_info_ex4b.opcode.set(info.opcode); + else `DV_CHECK_RANDOMIZE_FATAL(ral.cmd_info_ex4b.opcode) + csr_update(ral.cmd_info_ex4b); + end + for (int i = 11; i < 24; i++) begin info = spi_flash_cmd_info::type_id::create("info"); `DV_CHECK_RANDOMIZE_WITH_FATAL(info, @@ -221,7 +236,7 @@ `DV_CHECK_RANDOMIZE_WITH_FATAL(info, opcode == local::opcode; // no addr, no payload - addr_bytes == 0; + addr_mode == SpiFlashAddrDisabled; num_lanes == 0; write_command == 0; ) @@ -233,10 +248,8 @@ // Task for flash or pass init virtual task spi_device_flash_pass_init(device_mode_e mode); - bit use_addr_4b_enable; // Mode of config spi_device_init(); `uvm_info(`gfn, "Initialize flash/passthrough mode", UVM_MEDIUM) - `DV_CHECK_STD_RANDOMIZE_FATAL(use_addr_4b_enable) // TODO, fixed config for now cfg.spi_host_agent_cfg.sck_polarity[0] = 0; cfg.spi_host_agent_cfg.sck_phase[0] = 0; @@ -255,7 +268,11 @@ cfg.spi_device_agent_cfg.is_flash_mode = 1; ral.cfg.tx_order.set(cfg.spi_host_agent_cfg.host_bit_dir); ral.cfg.rx_order.set(cfg.spi_host_agent_cfg.device_bit_dir); - ral.cfg.addr_4b_en.set(use_addr_4b_enable); + + `DV_CHECK_RANDOMIZE_FATAL(ral.cfg.addr_4b_en) + cfg.spi_host_agent_cfg.flash_addr_4b_en = ral.cfg.addr_4b_en.get(); + cfg.spi_device_agent_cfg.flash_addr_4b_en = ral.cfg.addr_4b_en.get(); + ral.cfg.cpol.set(1'b0); ral.cfg.cpha.set(1'b0); csr_update(.csr(ral.cfg)); // TODO check if randomization possible @@ -351,7 +368,6 @@ // Task for configuring cmd info slot virtual task add_cmd_info(spi_flash_cmd_info info, bit [4:0] idx); bit [3:0] lanes_en; - addr_mode_e addr_size; bit valid; bit swap; @@ -371,19 +387,8 @@ 4: lanes_en = 4'hF; default : `uvm_fatal(`gfn, $sformatf("Unsupported lanes num 0x%0h", info.num_lanes)) endcase - case (info.addr_bytes) - 0: addr_size = AddrDisabled; - 3: addr_size = Addr3B; - 4: addr_size = Addr4B; - default : `uvm_fatal(`gfn, $sformatf("Unsupported addr bytes 0x%0h", info.addr_bytes)) - endcase - // if addr_size is aligned with addr_4b_en, we could use AddrCfg instead of Addr4B/Addr3B - if (`gmv(ral.cfg.addr_4b_en) == 1 && addr_size == Addr4B || - `gmv(ral.cfg.addr_4b_en) == 0 && addr_size == Addr3B) begin - if ($urandom_range(0, 1)) addr_size = AddrCfg; - end - ral.cmd_info[idx].addr_mode.set(addr_size); + ral.cmd_info[idx].addr_mode.set(info.addr_mode); ral.cmd_info[idx].valid.set(valid); // Enable this OPCODE ral.cmd_info[idx].opcode.set(info.opcode); ral.cmd_info[idx].payload_en.set(lanes_en); @@ -520,4 +525,10 @@ // read flash_status for check random_access_flash_status(.write(0)); endtask + + virtual task read_and_check_4b_en(); + cfg.clk_rst_vif.wait_clks(10); + csr_rd_check(.ptr(ral.cfg.addr_4b_en), + .compare_value(cfg.spi_device_agent_cfg.flash_addr_4b_en)); + endtask endclass : spi_device_pass_base_vseq
diff --git a/hw/ip/spi_device/dv/env/spi_device_env_pkg.sv b/hw/ip/spi_device/dv/env/spi_device_env_pkg.sv index 02e677d..500521d 100644 --- a/hw/ip/spi_device/dv/env/spi_device_env_pkg.sv +++ b/hw/ip/spi_device/dv/env/spi_device_env_pkg.sv
@@ -53,13 +53,6 @@ PassthroughMode } device_mode_e; - typedef enum bit [1:0] { - AddrDisabled, - AddrCfg, - Addr3B, - Addr4B - } addr_mode_e; - typedef enum bit { PayloadIn, PayloadOut
diff --git a/hw/ip/spi_device/dv/env/spi_device_scoreboard.sv b/hw/ip/spi_device/dv/env/spi_device_scoreboard.sv index e290168..00a4083 100644 --- a/hw/ip/spi_device/dv/env/spi_device_scoreboard.sv +++ b/hw/ip/spi_device/dv/env/spi_device_scoreboard.sv
@@ -133,7 +133,11 @@ end InternalProcessCfgCmd: begin if (`GET_OPCODE_VALID_AND_MATCH(cmd_info_en4b, item.opcode)) begin + void'(ral.cfg.addr_4b_en.predict(.value(1), .kind(UVM_PREDICT_WRITE))); + `uvm_info(`gfn, "Enable 4b addr due to cmd EN4B", UVM_MEDIUM) end else if (`GET_OPCODE_VALID_AND_MATCH(cmd_info_ex4b, item.opcode)) begin + void'(ral.cfg.addr_4b_en.predict(.value(0), .kind(UVM_PREDICT_WRITE))); + `uvm_info(`gfn, "Disable 4b addr due to cmd EX4B", UVM_MEDIUM) end else if (`GET_OPCODE_VALID_AND_MATCH(cmd_info_wren, item.opcode)) begin update_wel = 1; wel_val = 1;