| // Copyright 2023 Google LLC |
| |
| #include "VDBus2Axi.h" |
| #include "tests/verilator_sim/sysc_tb.h" |
| |
| struct DBus2Axi_tb : Sysc_tb { |
| sc_out<bool> io_dbus_valid; |
| sc_in<bool> io_dbus_ready; |
| sc_out<bool> io_dbus_write; |
| sc_out<bool> io_axi_write_addr_ready; |
| sc_in<bool> io_axi_write_addr_valid; |
| sc_out<bool> io_axi_write_data_ready; |
| sc_in<bool> io_axi_write_data_valid; |
| sc_in<bool> io_axi_write_resp_ready; |
| sc_out<bool> io_axi_write_resp_valid; |
| sc_out<bool> io_axi_read_addr_ready; |
| sc_in<bool> io_axi_read_addr_valid; |
| sc_in<bool> io_axi_read_data_ready; |
| sc_out<bool> io_axi_read_data_valid; |
| sc_out<sc_bv<32> > io_dbus_addr; |
| sc_out<sc_bv<32> > io_dbus_adrx; |
| sc_out<sc_bv<6> > io_dbus_size; |
| sc_out<sc_bv<256> > io_dbus_wdata; |
| sc_out<sc_bv<32> > io_dbus_wmask; |
| sc_in<sc_bv<256> > io_dbus_rdata; |
| sc_in<sc_bv<32> > io_axi_write_addr_bits_addr; |
| sc_in<sc_bv<6> > io_axi_write_addr_bits_id; |
| sc_in<sc_bv<256> > io_axi_write_data_bits_data; |
| sc_in<sc_bv<32> > io_axi_write_data_bits_strb; |
| sc_out<sc_bv<6> > io_axi_write_resp_bits_id; |
| sc_out<sc_bv<2> > io_axi_write_resp_bits_resp; |
| sc_in<sc_bv<32> > io_axi_read_addr_bits_addr; |
| sc_in<sc_bv<6> > io_axi_read_addr_bits_id; |
| sc_out<sc_bv<2> > io_axi_read_data_bits_resp; |
| sc_out<sc_bv<6> > io_axi_read_data_bits_id; |
| sc_out<sc_bv<256> > io_axi_read_data_bits_data; |
| |
| using Sysc_tb::Sysc_tb; |
| |
| void posedge() { |
| sc_bv<32> dbus_wmask; |
| sc_bv<256> dbus_wdata; |
| for (int i = 0; i < 8; ++i) dbus_wdata.set_word(i, rand_uint32()); |
| dbus_wmask.set_word(0, rand_uint32()); |
| |
| if (!(io_dbus_valid && !io_dbus_ready && !io_dbus_write)) { |
| io_dbus_valid = rand_bool(); |
| io_dbus_write = rand_bool(); |
| io_dbus_addr = rand_uint32(); |
| io_dbus_adrx = rand_uint32(); |
| io_dbus_size = rand_uint32(); |
| io_dbus_wdata = dbus_wdata; |
| io_dbus_wmask = dbus_wmask; |
| } |
| |
| io_axi_read_addr_ready = rand_bool(); |
| |
| const bool write_ready = rand_bool(); |
| io_axi_write_addr_ready = write_ready; |
| io_axi_write_data_ready = write_ready; |
| |
| // ************************************************************************* |
| // DBus Addr. |
| if (io_dbus_valid && !io_dbus_write && !dbus_read_ready_) { |
| dbus_read_ready_ = true; |
| axi_read_addr_t r; |
| r.addr = io_dbus_addr.read().get_word(0) & ~31; |
| r.id = 0x00; // from RTL |
| axi_read_addr_.write(r); |
| } |
| |
| if (io_dbus_valid && io_dbus_ready && io_dbus_write) { |
| axi_write_addr_t w; |
| sc_bv<256> data; |
| sc_bv<32> strb; |
| w.addr = io_dbus_addr.read().get_word(0) & ~31; |
| w.id = 0x00; // from RTL |
| w.strb = io_dbus_wmask; |
| w.data = io_dbus_wdata; |
| axi_write_addr_.write(w); |
| } |
| |
| // ************************************************************************* |
| // DBus Read Data. |
| if (dbus_read_active_) { |
| dbus_read_active_ = false; |
| dbus_read_data_t ref, dut; |
| check(dbus_read_data_.read(ref), "dbus read data"); |
| dut.data = io_dbus_rdata; |
| if (ref != dut) { |
| ref.print("ref::dbus_read_addr"); |
| dut.print("dut::dbus_read_addr"); |
| check(false); |
| } |
| } |
| |
| if (io_dbus_valid && io_dbus_ready && !io_dbus_write) { |
| dbus_read_ready_ = false; |
| dbus_read_active_ = true; |
| } |
| |
| // ************************************************************************* |
| // AXI Read Addr. |
| if (io_axi_read_addr_valid && io_axi_read_addr_ready) { |
| axi_read_addr_t dut, ref; |
| check(axi_read_addr_.read(ref), "axi read addr"); |
| dut.addr = io_axi_read_addr_bits_addr.read().get_word(0); |
| dut.id = io_axi_read_addr_bits_id.read().get_word(0); |
| if (ref != dut) { |
| ref.print("ref::axi_read_addr"); |
| dut.print("dut::axi_read_addr"); |
| check(false); |
| } |
| |
| sc_bv<256> data; |
| for (int i = 0; i < 8; ++i) data.set_word(i, rand_uint32()); |
| axi_read_data_t raxi; |
| raxi.id = dut.id; |
| raxi.data = data; |
| raxi.resp = rand_int(); |
| axi_read_data_.write(raxi); |
| |
| dbus_read_data_t dbus; |
| dbus.data = data; |
| dbus_read_data_.write(dbus); |
| } |
| |
| // ************************************************************************* |
| // AXI Read Data. |
| if (io_axi_read_data_valid && io_axi_read_data_ready) { |
| check(axi_read_data_.remove(), "axi read data"); |
| } |
| |
| axi_read_data_t rdata; |
| bool read_data_valid = axi_read_data_.next(rdata); |
| io_axi_read_data_valid = read_data_valid && rand_bool(); |
| io_axi_read_data_bits_id = rdata.id; |
| io_axi_read_data_bits_data = rdata.data; |
| io_axi_read_data_bits_resp = rdata.resp; |
| |
| // ************************************************************************* |
| // AXI Write Addr. |
| if (io_axi_write_addr_valid && io_axi_write_addr_ready) { |
| assert(io_axi_write_data_valid && io_axi_write_data_ready); |
| axi_write_addr_t dut, ref; |
| check(axi_write_addr_.read(ref), "axi write addr"); |
| dut.addr = io_axi_write_addr_bits_addr.read().get_word(0); |
| dut.id = io_axi_write_addr_bits_id.read().get_word(0); |
| dut.data = io_axi_write_data_bits_data; |
| dut.strb = io_axi_write_data_bits_strb; |
| if (ref != dut) { |
| ref.print("ref::axi_write_addr"); |
| dut.print("dut::axi_write_addr"); |
| check(false); |
| } |
| |
| axi_write_resp_t resp; |
| resp.id = dut.id; |
| resp.resp = rand_int(); |
| axi_write_resp_.write(resp); |
| } |
| |
| // ************************************************************************* |
| // AXI Write Resp. |
| if (io_axi_write_resp_valid && io_axi_write_resp_ready) { |
| check(axi_write_resp_.remove(), "axi write resp"); |
| } |
| |
| axi_write_resp_t wresp; |
| bool write_resp_valid = axi_write_resp_.next(wresp); |
| io_axi_write_resp_valid = write_resp_valid; |
| io_axi_write_resp_bits_id = wresp.id; |
| io_axi_write_resp_bits_resp = wresp.resp; |
| } |
| |
| |
| private: |
| struct axi_read_addr_t { |
| uint32_t addr; |
| uint32_t id : 7; |
| |
| bool operator!=(const axi_read_addr_t& rhs) const { |
| if (addr != rhs.addr) return true; |
| if (id != rhs.id) return true; |
| return false; |
| } |
| |
| void print(const char* name) { |
| printf("[%s]: id=%x addr=%08x\n", name, id, addr); |
| } |
| }; |
| |
| struct axi_read_data_t { |
| uint32_t id : 7; |
| uint32_t resp : 7; |
| sc_bv<256> data; |
| |
| bool operator!=(const axi_read_data_t& rhs) const { |
| if (id != rhs.id) return true; |
| if (data != rhs.data) return true; |
| return false; |
| } |
| |
| void print(const char* name) { |
| printf("[%s]: id=%x data=", name, id); |
| for (int i = 0; i < 256 / 32; ++i) { |
| printf("%08x ", data.get_word(i)); |
| } |
| printf("\n"); |
| } |
| }; |
| |
| struct axi_write_addr_t { |
| uint32_t addr; |
| uint32_t id : 7; |
| sc_bv<256> data; |
| sc_bv<32> strb; |
| |
| bool operator!=(const axi_write_addr_t& rhs) const { |
| if (addr != rhs.addr) return true; |
| if (id != rhs.id) return true; |
| if (strb != rhs.strb) return true; |
| if (data != rhs.data) return true; |
| return false; |
| } |
| |
| void print(const char* name) { |
| printf("[%s]: id=%x addr=%08x strb=%08x data=", name, id, addr, strb.get_word(0)); |
| for (int i = 0; i < 256 / 32; ++i) { |
| printf("%08x ", data.get_word(0)); |
| } |
| printf("\n"); |
| } |
| }; |
| |
| struct axi_write_resp_t { |
| uint32_t id : 7; |
| uint32_t resp : 2; |
| }; |
| |
| struct dbus_read_data_t { |
| sc_bv<256> data; |
| |
| bool operator!=(const dbus_read_data_t& rhs) const { |
| if (data != rhs.data) return true; |
| return false; |
| } |
| |
| void print(const char* name) { |
| printf("[%s]: data=", name); |
| for (int i = 0; i < 256 / 32; ++i) { |
| printf("%08x ", data.get_word(i)); |
| } |
| printf("\n"); |
| } |
| }; |
| |
| bool dbus_read_ready_ = false; |
| bool dbus_read_active_ = false; |
| fifo_t<axi_read_addr_t> axi_read_addr_; |
| fifo_t<axi_read_data_t> axi_read_data_; |
| fifo_t<axi_write_addr_t> axi_write_addr_; |
| fifo_t<axi_write_resp_t> axi_write_resp_; |
| fifo_t<dbus_read_data_t> dbus_read_data_; |
| }; |
| |
| static void DBus2Axi_test(char* name, int loops, bool trace) { |
| sc_signal<bool> io_dbus_valid; |
| sc_signal<bool> io_dbus_ready; |
| sc_signal<bool> io_dbus_write; |
| sc_signal<bool> io_axi_write_addr_ready; |
| sc_signal<bool> io_axi_write_addr_valid; |
| sc_signal<bool> io_axi_write_data_ready; |
| sc_signal<bool> io_axi_write_data_valid; |
| sc_signal<bool> io_axi_write_resp_ready; |
| sc_signal<bool> io_axi_write_resp_valid; |
| sc_signal<bool> io_axi_read_addr_ready; |
| sc_signal<bool> io_axi_read_addr_valid; |
| sc_signal<bool> io_axi_read_data_ready; |
| sc_signal<bool> io_axi_read_data_valid; |
| sc_signal<sc_bv<32> > io_dbus_addr; |
| sc_signal<sc_bv<32> > io_dbus_adrx; |
| sc_signal<sc_bv<6> > io_dbus_size; |
| sc_signal<sc_bv<256> > io_dbus_wdata; |
| sc_signal<sc_bv<32> > io_dbus_wmask; |
| sc_signal<sc_bv<256> > io_dbus_rdata; |
| sc_signal<sc_bv<32> > io_axi_write_addr_bits_addr; |
| sc_signal<sc_bv<6> > io_axi_write_addr_bits_id; |
| sc_signal<sc_bv<256> > io_axi_write_data_bits_data; |
| sc_signal<sc_bv<32> > io_axi_write_data_bits_strb; |
| sc_signal<sc_bv<6> > io_axi_write_resp_bits_id; |
| sc_signal<sc_bv<2> > io_axi_write_resp_bits_resp; |
| sc_signal<sc_bv<32> > io_axi_read_addr_bits_addr; |
| sc_signal<sc_bv<6> > io_axi_read_addr_bits_id; |
| sc_signal<sc_bv<2> > io_axi_read_data_bits_resp; |
| sc_signal<sc_bv<6> > io_axi_read_data_bits_id; |
| sc_signal<sc_bv<256> > io_axi_read_data_bits_data; |
| |
| DBus2Axi_tb tb("DBus2Axi_tb", loops, true /*random*/); |
| VDBus2Axi d2a(name); |
| |
| d2a.clock(tb.clock); |
| d2a.reset(tb.reset); |
| BIND2(tb, d2a, io_dbus_valid); |
| BIND2(tb, d2a, io_dbus_ready); |
| BIND2(tb, d2a, io_dbus_write); |
| BIND2(tb, d2a, io_axi_write_addr_ready); |
| BIND2(tb, d2a, io_axi_write_addr_valid); |
| BIND2(tb, d2a, io_axi_write_data_ready); |
| BIND2(tb, d2a, io_axi_write_data_valid); |
| BIND2(tb, d2a, io_axi_write_resp_ready); |
| BIND2(tb, d2a, io_axi_write_resp_valid); |
| BIND2(tb, d2a, io_axi_read_addr_ready); |
| BIND2(tb, d2a, io_axi_read_addr_valid); |
| BIND2(tb, d2a, io_axi_read_data_ready); |
| BIND2(tb, d2a, io_axi_read_data_valid); |
| BIND2(tb, d2a, io_dbus_addr); |
| BIND2(tb, d2a, io_dbus_adrx); |
| BIND2(tb, d2a, io_dbus_size); |
| BIND2(tb, d2a, io_dbus_wdata); |
| BIND2(tb, d2a, io_dbus_wmask); |
| BIND2(tb, d2a, io_dbus_rdata); |
| BIND2(tb, d2a, io_axi_write_addr_bits_addr); |
| BIND2(tb, d2a, io_axi_write_addr_bits_id); |
| BIND2(tb, d2a, io_axi_write_data_bits_data); |
| BIND2(tb, d2a, io_axi_write_data_bits_strb); |
| BIND2(tb, d2a, io_axi_write_resp_bits_id); |
| BIND2(tb, d2a, io_axi_write_resp_bits_resp); |
| BIND2(tb, d2a, io_axi_read_addr_bits_addr); |
| BIND2(tb, d2a, io_axi_read_addr_bits_id); |
| BIND2(tb, d2a, io_axi_read_data_bits_resp); |
| BIND2(tb, d2a, io_axi_read_data_bits_id); |
| BIND2(tb, d2a, io_axi_read_data_bits_data); |
| |
| if (trace) { |
| tb.trace(d2a); |
| } |
| |
| tb.start(); |
| } |
| |
| int sc_main(int argc, char* argv[]) { |
| DBus2Axi_test(Sysc_tb::get_name(argv[0]), 1000000, false); |
| return 0; |
| } |