Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion hw/top_chip/dv/env/seq_lib/top_chip_dv_i2c_host_tx_rx_vseq.sv
Original file line number Diff line number Diff line change
Expand Up @@ -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];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think something can go wrong as the address here is 8 bits but the i2c expects 7 bits. Probably better to add a constraint to this variable?

constraint top_chip_dv_i2c_host_tx_rx_vseq::device_addr_c {
  device_addr[0] inside {[8'h00 : 8'h7F]};
}


extern function new(string name="");
extern task body();
extern virtual task dut_init(string reset_kind = "HARD");
extern task body();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: this change isn't required and it was better before since new and body methods are part of the UVM

endclass : top_chip_dv_i2c_host_tx_rx_vseq

function top_chip_dv_i2c_host_tx_rx_vseq::new(string name = "");
Expand All @@ -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]},
Expand All @@ -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
Expand Down
12 changes: 12 additions & 0 deletions hw/top_chip/dv/env/seq_lib/top_chip_dv_i2c_tx_rx_vseq.sv
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
1 change: 1 addition & 0 deletions hw/top_chip/dv/env/top_chip_dv_env_pkg.sv
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
4 changes: 2 additions & 2 deletions sw/device/examples/i2c.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion sw/device/lib/hal/i2c.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion sw/device/lib/hal/i2c.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
22 changes: 12 additions & 10 deletions sw/device/tests/i2c/host_tx_rx_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
#include <stdbool.h>
#include <stdint.h>

#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;
Expand All @@ -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)
Expand All @@ -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;
}
Expand Down
4 changes: 2 additions & 2 deletions sw/device/tests/i2c/temperature_sensor_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ 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;
}

// Read current temperature
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;
}

Expand Down