diff --git a/hw/top_chip/dv/env/seq_lib/top_chip_dv_i2c_host_tx_rx_vseq.sv b/hw/top_chip/dv/env/seq_lib/top_chip_dv_i2c_host_tx_rx_vseq.sv index 712f51ee0..21f2cc0b0 100644 --- a/hw/top_chip/dv/env/seq_lib/top_chip_dv_i2c_host_tx_rx_vseq.sv +++ b/hw/top_chip/dv/env/seq_lib/top_chip_dv_i2c_host_tx_rx_vseq.sv @@ -11,9 +11,13 @@ class top_chip_dv_i2c_host_tx_rx_vseq extends top_chip_dv_i2c_tx_rx_vseq; `uvm_object_utils(top_chip_dv_i2c_host_tx_rx_vseq) + // Declare the device_addr as a byte size array because sw_symbol_backdoor_overwrite() expects the + // data that is going to overwrite the SW symbol to be an array + local rand bit [7:0] device_addr[1]; + extern function new(string name=""); - extern task body(); extern virtual task dut_init(string reset_kind = "HARD"); + extern task body(); endclass : top_chip_dv_i2c_host_tx_rx_vseq function top_chip_dv_i2c_host_tx_rx_vseq::new(string name = ""); @@ -28,6 +32,10 @@ task top_chip_dv_i2c_host_tx_rx_vseq::dut_init(string reset_kind = "HARD"); sw_symbol_backdoor_read("scl_low_time_ns", sw_scl_low_time_ns); sw_symbol_backdoor_read("hold_data_time_ns", sw_data_hold_time_ns); + // Overwrite the SW symbol with the randomized value + sw_symbol_backdoor_overwrite("byte_count", xfer_bytes); + sw_symbol_backdoor_overwrite("device_addr", device_addr); + scl_low_cycles = round_up_divide({sw_scl_low_time_ns[1], sw_scl_low_time_ns[0]}, sw_sys_clk_period_ns[0]); sda_hold_cycles = round_up_divide({sw_data_hold_time_ns[1], sw_data_hold_time_ns[0]}, @@ -47,6 +55,7 @@ task top_chip_dv_i2c_host_tx_rx_vseq::body(); configure_agent_timing(); print_i2c_timing_cfg(); + fork seq.start(p_sequencer.i2c_sqr); join_none diff --git a/hw/top_chip/dv/env/seq_lib/top_chip_dv_i2c_tx_rx_vseq.sv b/hw/top_chip/dv/env/seq_lib/top_chip_dv_i2c_tx_rx_vseq.sv index 666e17633..8059ed96f 100644 --- a/hw/top_chip/dv/env/seq_lib/top_chip_dv_i2c_tx_rx_vseq.sv +++ b/hw/top_chip/dv/env/seq_lib/top_chip_dv_i2c_tx_rx_vseq.sv @@ -17,6 +17,12 @@ class top_chip_dv_i2c_tx_rx_vseq extends top_chip_dv_base_vseq; protected bit [15:0] scl_low_cycles; protected bit [15:0] sda_hold_cycles; + // Number of bytes to read / write in a transfer. This is going to overwrite a SW symbol so that + // the SW will read / write bytes based on the xfer_bytes count + protected rand bit [7:0] xfer_bytes[1]; + + extern constraint xfer_bytes_c; + extern function new(string name=""); // Returns the ceiling of (a / b), converting a timing parameter "a" in nanoseconds to an integer @@ -28,6 +34,12 @@ class top_chip_dv_i2c_tx_rx_vseq extends top_chip_dv_base_vseq; extern protected function void print_i2c_timing_cfg(); endclass : top_chip_dv_i2c_tx_rx_vseq +// SW will perform a comparison on each byte that was read and written. To do this accurately, +// the number of bytes should be within the depth of TX / RX FIFO of target and host respectively. +constraint top_chip_dv_i2c_tx_rx_vseq::xfer_bytes_c { + xfer_bytes[0] inside {[1 : FifoDepth]}; +} + function top_chip_dv_i2c_tx_rx_vseq::new(string name = ""); super.new(name); endfunction diff --git a/hw/top_chip/dv/env/top_chip_dv_env_pkg.sv b/hw/top_chip/dv/env/top_chip_dv_env_pkg.sv index e65aaab3d..ad8a50d44 100644 --- a/hw/top_chip/dv/env/top_chip_dv_env_pkg.sv +++ b/hw/top_chip/dv/env/top_chip_dv_env_pkg.sv @@ -10,6 +10,7 @@ package top_chip_dv_env_pkg; import sw_test_status_pkg::*; import uart_agent_pkg::*; import gpio_env_pkg::NUM_GPIOS; + import i2c_reg_pkg::FifoDepth; // Macro includes `include "uvm_macros.svh" diff --git a/sw/device/examples/i2c.c b/sw/device/examples/i2c.c index 5824158d5..3d3c0aaba 100644 --- a/sw/device/examples/i2c.c +++ b/sw/device/examples/i2c.c @@ -31,9 +31,9 @@ int main(void) uint8_t w_data = 0; // Read current temperature from an AS6212 I^2C-bus sensor and print the value i2c_write_bytes(i2c, 0x48u, &w_data, 1); - if (i2c_wait_transfer_finish(i2c)) { // select TVAL reg; also a presence check + if (i2c_host_wait_transfer_finish(i2c)) { // select TVAL reg; also a presence check i2c_read_bytes(i2c, 0x48u, 1); - if (i2c_wait_transfer_finish(i2c)) { + if (i2c_host_wait_transfer_finish(i2c)) { uint16_t sensor_reading = i2c_rdata_byte(i2c); // read TVAl reg uprintf(uart, "Temperature: 0x%x degC\n", (sensor_reading << 1)); // no decimal printf diff --git a/sw/device/lib/hal/i2c.c b/sw/device/lib/hal/i2c.c index c854da576..0d880343b 100644 --- a/sw/device/lib/hal/i2c.c +++ b/sw/device/lib/hal/i2c.c @@ -184,7 +184,7 @@ void i2c_read_bytes(i2c_t i2c, uint8_t addr, uint8_t num_bytes) VOLATILE_WRITE(i2c->fdata, fdata_reg); } -bool i2c_wait_transfer_finish(i2c_t i2c) +bool i2c_host_wait_transfer_finish(i2c_t i2c) { // Wait for transaction to complete and report simple succeed / fail while (true) { diff --git a/sw/device/lib/hal/i2c.h b/sw/device/lib/hal/i2c.h index ac7190c44..d64f4b53f 100644 --- a/sw/device/lib/hal/i2c.h +++ b/sw/device/lib/hal/i2c.h @@ -120,7 +120,7 @@ void i2c_read_bytes(i2c_t i2c, uint8_t addr, uint8_t num_bytes); // Wait for the write / read transfer to complete by checking interrupt state and status register // fields. -bool i2c_wait_transfer_finish(i2c_t i2c); +bool i2c_host_wait_transfer_finish(i2c_t i2c); // Enable I2C in controller mode void i2c_enable_controller_mode(i2c_t i2c); diff --git a/sw/device/tests/i2c/host_tx_rx_test.c b/sw/device/tests/i2c/host_tx_rx_test.c index 9e9808caf..3cbddf5d2 100644 --- a/sw/device/tests/i2c/host_tx_rx_test.c +++ b/sw/device/tests/i2c/host_tx_rx_test.c @@ -8,6 +8,8 @@ #include #include +#define TX_FIFO_DEPTH (64) + // The const variables below are treated as symbols read by top_chip_dv_i2c_host_tx_rx_vseq in order // to calculate agent timing parameters. const uint8_t sys_clk_period_ns = SYSCLK_NS; @@ -17,23 +19,23 @@ const uint8_t sys_clk_period_ns = SYSCLK_NS; const uint16_t scl_low_time_ns = 4700; const uint16_t hold_data_time_ns = 1; -enum : uint8_t { - device_addr = 0x3A, - num_bytes = 0x8, -}; +// The symbols below are going to be overwritten through sw_symbol_backdoor_overwrite() in +// top_chip_dv_i2c_host_tx_rx_vseq.sv +volatile const uint8_t byte_count = TX_FIFO_DEPTH; +volatile const uint8_t device_addr = 0x0; static bool write_transfer(i2c_t i2c, uint8_t addr, const uint8_t *data, uint8_t num_bytes) { // Start a write transfer i2c_write_bytes(i2c, addr, data, num_bytes); - return i2c_wait_transfer_finish(i2c); + return i2c_host_wait_transfer_finish(i2c); } static bool read_transfer(i2c_t i2c, uint8_t addr, uint8_t num_bytes) { // Start a read transfer i2c_read_bytes(i2c, addr, num_bytes); - return i2c_wait_transfer_finish(i2c); + return i2c_host_wait_transfer_finish(i2c); } static bool drive_transfer(i2c_t i2c, uint8_t addr, const uint8_t *data, uint8_t num_bytes) @@ -47,18 +49,18 @@ static bool drive_transfer(i2c_t i2c, uint8_t addr, const uint8_t *data, uint8_t static bool host_tx_rx_test(i2c_t i2c) { // Data bytes to send to the target's receiver. - uint8_t data_bytes[num_bytes]; + uint8_t data_bytes[byte_count]; // Write walking 1's pattern - for (uint8_t i = 0; i < num_bytes; i++) { + for (uint8_t i = 0; i < byte_count; i++) { data_bytes[i] = 1u << (i % 8); } - if (!drive_transfer(i2c, device_addr, data_bytes, num_bytes)) { + if (!drive_transfer(i2c, device_addr, data_bytes, byte_count)) { return false; } - for (uint8_t i = 0; i < num_bytes; i++) { + for (uint8_t i = 0; i < byte_count; i++) { if (data_bytes[i] != i2c_rdata_byte(i2c)) { return false; } diff --git a/sw/device/tests/i2c/temperature_sensor_test.c b/sw/device/tests/i2c/temperature_sensor_test.c index 191ca6c5d..a1513a355 100644 --- a/sw/device/tests/i2c/temperature_sensor_test.c +++ b/sw/device/tests/i2c/temperature_sensor_test.c @@ -17,7 +17,7 @@ static bool as6212_test(i2c_t i2c) i2c_write_bytes(i2c, 0x48u, &w_data, 1); // Check if the write was successful - if (!i2c_wait_transfer_finish(i2c)) { + if (!i2c_host_wait_transfer_finish(i2c)) { return false; } @@ -25,7 +25,7 @@ static bool as6212_test(i2c_t i2c) i2c_read_bytes(i2c, 0x48u, 1); // Check if the read was successful - if (!i2c_wait_transfer_finish(i2c)) { + if (!i2c_host_wait_transfer_finish(i2c)) { return false; }