| // Copyright 2023 Google LLC |
| |
| #include "VVRegfileSegment.h" |
| |
| #include "tests/verilator_sim/kelvin/kelvin_cfg.h" |
| #include "tests/verilator_sim/sysc_tb.h" |
| |
| struct VRegfileSegment_tb : Sysc_tb { |
| sc_out<sc_bv<6> > io_read_0_addr; |
| sc_in<sc_bv<32> > io_read_0_data; |
| sc_out<sc_bv<6> > io_read_1_addr; |
| sc_in<sc_bv<32> > io_read_1_data; |
| sc_out<sc_bv<6> > io_read_2_addr; |
| sc_in<sc_bv<32> > io_read_2_data; |
| sc_out<sc_bv<6> > io_read_3_addr; |
| sc_in<sc_bv<32> > io_read_3_data; |
| sc_out<sc_bv<6> > io_read_4_addr; |
| sc_in<sc_bv<32> > io_read_4_data; |
| sc_out<sc_bv<6> > io_read_5_addr; |
| sc_in<sc_bv<32> > io_read_5_data; |
| sc_out<sc_bv<6> > io_read_6_addr; |
| sc_in<sc_bv<32> > io_read_6_data; |
| sc_out<sc_bv<6> > io_transpose_addr; |
| sc_in<sc_bv<kVector> > io_transpose_data; |
| sc_out<sc_bv<6> > io_internal_addr; |
| sc_in<sc_bv<32> > io_internal_data; |
| sc_out<bool> io_write_0_valid; |
| sc_out<sc_bv<6> > io_write_0_addr; |
| sc_out<sc_bv<32> > io_write_0_data; |
| sc_out<bool> io_write_1_valid; |
| sc_out<sc_bv<6> > io_write_1_addr; |
| sc_out<sc_bv<32> > io_write_1_data; |
| sc_out<bool> io_write_2_valid; |
| sc_out<sc_bv<6> > io_write_2_addr; |
| sc_out<sc_bv<32> > io_write_2_data; |
| sc_out<bool> io_write_3_valid; |
| sc_out<sc_bv<6> > io_write_3_addr; |
| sc_out<sc_bv<32> > io_write_3_data; |
| sc_out<bool> io_write_4_valid; |
| sc_out<sc_bv<6> > io_write_4_addr; |
| sc_out<sc_bv<32> > io_write_4_data; |
| sc_out<bool> io_write_5_valid; |
| sc_out<sc_bv<6> > io_write_5_addr; |
| sc_out<sc_bv<32> > io_write_5_data; |
| sc_out<bool> io_conv_valid; |
| sc_out<sc_bv<32> > io_conv_data_0; |
| sc_out<sc_bv<32> > io_conv_data_1; |
| sc_out<sc_bv<32> > io_conv_data_2; |
| sc_out<sc_bv<32> > io_conv_data_3; |
| #if KELVIN_SIMD >= 256 |
| sc_out<sc_bv<32> > io_conv_data_4; |
| sc_out<sc_bv<32> > io_conv_data_5; |
| sc_out<sc_bv<32> > io_conv_data_6; |
| sc_out<sc_bv<32> > io_conv_data_7; |
| #endif |
| #if KELVIN_SIMD >= 512 |
| sc_out<sc_bv<32> > io_conv_data_8; |
| sc_out<sc_bv<32> > io_conv_data_9; |
| sc_out<sc_bv<32> > io_conv_data_10; |
| sc_out<sc_bv<32> > io_conv_data_11; |
| sc_out<sc_bv<32> > io_conv_data_12; |
| sc_out<sc_bv<32> > io_conv_data_13; |
| sc_out<sc_bv<32> > io_conv_data_14; |
| sc_out<sc_bv<32> > io_conv_data_15; |
| #endif |
| |
| using Sysc_tb::Sysc_tb; |
| |
| void posedge() { |
| if (init_ < 64) { |
| io_write_0_valid = true; |
| io_write_0_addr = init_; |
| io_write_0_data = vreg_[init_] = rand_uint32(); |
| init_++; |
| return; |
| } |
| |
| // Inputs. |
| bool conv = rand_int(0, 3) != 0; |
| |
| io_read_0_addr = rand_uint32(0, 63); |
| io_read_1_addr = rand_uint32(0, 63); |
| io_read_2_addr = rand_uint32(0, 63); |
| io_read_3_addr = rand_uint32(0, 63); |
| io_read_4_addr = rand_uint32(0, 63); |
| io_read_5_addr = rand_uint32(0, 63); |
| io_read_6_addr = rand_uint32(0, 63); |
| |
| io_transpose_addr = rand_uint32(0, 63) & ~15; |
| |
| io_internal_addr = rand_uint32(0, 63); |
| |
| io_write_0_valid = rand_bool(); |
| io_write_1_valid = rand_bool(); |
| io_write_2_valid = rand_bool(); |
| io_write_3_valid = rand_bool(); |
| io_write_4_valid = rand_bool(); |
| io_write_5_valid = rand_bool(); |
| |
| uint8_t waddr[6]; |
| RandWriteAddresses(waddr, conv); |
| io_write_0_addr = waddr[0]; |
| io_write_1_addr = waddr[1]; |
| io_write_2_addr = waddr[2]; |
| io_write_3_addr = waddr[3]; |
| io_write_4_addr = waddr[4]; |
| io_write_5_addr = waddr[5]; |
| |
| io_write_0_data = rand_uint32(); |
| io_write_1_data = rand_uint32(); |
| io_write_2_data = rand_uint32(); |
| io_write_3_data = rand_uint32(); |
| io_write_4_data = rand_uint32(); |
| io_write_5_data = rand_uint32(); |
| |
| io_conv_valid = conv; |
| io_conv_data_0 = rand_uint32(); |
| io_conv_data_1 = rand_uint32(); |
| io_conv_data_2 = rand_uint32(); |
| io_conv_data_3 = rand_uint32(); |
| #if KELVIN_SIMD >= 256 |
| io_conv_data_4 = rand_uint32(); |
| io_conv_data_5 = rand_uint32(); |
| io_conv_data_6 = rand_uint32(); |
| io_conv_data_7 = rand_uint32(); |
| #endif |
| #if KELVIN_SIMD >= 512 |
| io_conv_data_8 = rand_uint32(); |
| io_conv_data_9 = rand_uint32(); |
| io_conv_data_10 = rand_uint32(); |
| io_conv_data_11 = rand_uint32(); |
| io_conv_data_12 = rand_uint32(); |
| io_conv_data_13 = rand_uint32(); |
| io_conv_data_14 = rand_uint32(); |
| io_conv_data_15 = rand_uint32(); |
| #endif |
| |
| // Read. |
| #define READ_CHECK(idx) \ |
| check(io_read_##idx##_data.read().get_word(0) == \ |
| vreg_[io_read_##idx##_addr.read().get_word(0)], \ |
| "read data"); |
| |
| READ_CHECK(0); |
| READ_CHECK(1); |
| READ_CHECK(2); |
| READ_CHECK(3); |
| READ_CHECK(4); |
| READ_CHECK(5); |
| |
| // Transpose. |
| for (int i = 0; i < kVector / 32; ++i) { |
| check(io_transpose_data.read().get_word(i) == |
| vreg_[io_transpose_addr.read().get_word(0) + i], |
| "transpose data"); |
| } |
| |
| // Internal. |
| check(io_internal_data.read().get_word(0) == |
| vreg_[io_internal_addr.read().get_word(0)], |
| "internal data"); |
| |
| // Update model. |
| #define WRITE_DATA(idx) \ |
| if (io_write_##idx##_valid) { \ |
| vreg_[io_write_##idx##_addr.read().get_word(0)] = \ |
| io_write_##idx##_data.read().get_word(0); \ |
| } |
| |
| WRITE_DATA(0); |
| WRITE_DATA(1); |
| WRITE_DATA(2); |
| WRITE_DATA(3); |
| WRITE_DATA(4); |
| WRITE_DATA(5); |
| |
| if (io_conv_valid) { |
| for (int i = 0; i < kVector / 32; ++i) { |
| uint32_t data; |
| if (i == 0) data = io_conv_data_0.read().get_word(0); |
| if (i == 1) data = io_conv_data_1.read().get_word(0); |
| if (i == 2) data = io_conv_data_2.read().get_word(0); |
| if (i == 3) data = io_conv_data_3.read().get_word(0); |
| #if KELVIN_SIMD >= 256 |
| if (i == 4) data = io_conv_data_4.read().get_word(0); |
| if (i == 5) data = io_conv_data_5.read().get_word(0); |
| if (i == 6) data = io_conv_data_6.read().get_word(0); |
| if (i == 7) data = io_conv_data_7.read().get_word(0); |
| #endif |
| #if KELVIN_SIMD >= 512 |
| if (i == 8) data = io_conv_data_8.read().get_word(0); |
| if (i == 9) data = io_conv_data_9.read().get_word(0); |
| if (i == 10) data = io_conv_data_10.read().get_word(0); |
| if (i == 11) data = io_conv_data_11.read().get_word(0); |
| if (i == 12) data = io_conv_data_12.read().get_word(0); |
| if (i == 13) data = io_conv_data_13.read().get_word(0); |
| if (i == 14) data = io_conv_data_14.read().get_word(0); |
| if (i == 15) data = io_conv_data_15.read().get_word(0); |
| #endif |
| vreg_[i + 48] = data; |
| } |
| } |
| } |
| |
| private: |
| int init_ = 0; |
| uint32_t vreg_[64]; |
| |
| void RandWriteAddresses(uint8_t addr[6], bool exclude_accumulators) { |
| uint8_t active[64]; |
| int mark = 0; |
| memset(active, 0, 64); |
| if (exclude_accumulators) { |
| memset(active + 48, 1, 16); |
| } |
| while (mark < 6) { |
| int r = rand_uint32(0, 63); |
| if (active[r]) continue; |
| active[r] = 1; |
| addr[mark] = r; |
| ++mark; |
| } |
| } |
| |
| uint32_t DotProduct(uint32_t adata, uint32_t bdata, uint32_t abias, |
| uint32_t bbias, bool asign, bool bsign) { |
| int32_t dotp = 0; |
| int32_t s_abias = int32_t(abias << 23) >> 23; |
| int32_t s_bbias = int32_t(bbias << 23) >> 23; |
| for (int i = 0; i < 4; ++i) { |
| int32_t s_adata = int32_t(uint8_t(adata >> (8 * i))); |
| int32_t s_bdata = int32_t(uint8_t(bdata >> (8 * i))); |
| if (asign) { |
| s_adata = int8_t(s_adata); |
| } |
| if (bsign) { |
| s_bdata = int8_t(s_bdata); |
| } |
| dotp += (s_adata + s_abias) * (s_bdata + s_bbias); |
| } |
| return dotp; |
| } |
| }; |
| |
| static void VRegfileSegment_test(char* name, int loops, bool trace) { |
| sc_signal<bool> clock; |
| sc_signal<bool> reset; |
| |
| sc_signal<sc_bv<6> > io_read_0_addr; |
| sc_signal<sc_bv<32> > io_read_0_data; |
| sc_signal<sc_bv<6> > io_read_1_addr; |
| sc_signal<sc_bv<32> > io_read_1_data; |
| sc_signal<sc_bv<6> > io_read_2_addr; |
| sc_signal<sc_bv<32> > io_read_2_data; |
| sc_signal<sc_bv<6> > io_read_3_addr; |
| sc_signal<sc_bv<32> > io_read_3_data; |
| sc_signal<sc_bv<6> > io_read_4_addr; |
| sc_signal<sc_bv<32> > io_read_4_data; |
| sc_signal<sc_bv<6> > io_read_5_addr; |
| sc_signal<sc_bv<32> > io_read_5_data; |
| sc_signal<sc_bv<6> > io_read_6_addr; |
| sc_signal<sc_bv<32> > io_read_6_data; |
| sc_signal<sc_bv<6> > io_transpose_addr; |
| sc_signal<sc_bv<kVector> > io_transpose_data; |
| sc_signal<sc_bv<6> > io_internal_addr; |
| sc_signal<sc_bv<32> > io_internal_data; |
| sc_signal<bool> io_write_0_valid; |
| sc_signal<sc_bv<6> > io_write_0_addr; |
| sc_signal<sc_bv<32> > io_write_0_data; |
| sc_signal<bool> io_write_1_valid; |
| sc_signal<sc_bv<6> > io_write_1_addr; |
| sc_signal<sc_bv<32> > io_write_1_data; |
| sc_signal<bool> io_write_2_valid; |
| sc_signal<sc_bv<6> > io_write_2_addr; |
| sc_signal<sc_bv<32> > io_write_2_data; |
| sc_signal<bool> io_write_3_valid; |
| sc_signal<sc_bv<6> > io_write_3_addr; |
| sc_signal<sc_bv<32> > io_write_3_data; |
| sc_signal<bool> io_write_4_valid; |
| sc_signal<sc_bv<6> > io_write_4_addr; |
| sc_signal<sc_bv<32> > io_write_4_data; |
| sc_signal<bool> io_write_5_valid; |
| sc_signal<sc_bv<6> > io_write_5_addr; |
| sc_signal<sc_bv<32> > io_write_5_data; |
| sc_signal<bool> io_conv_valid; |
| sc_signal<sc_bv<32> > io_conv_data_0; |
| sc_signal<sc_bv<32> > io_conv_data_1; |
| sc_signal<sc_bv<32> > io_conv_data_2; |
| sc_signal<sc_bv<32> > io_conv_data_3; |
| #if KELVIN_SIMD >= 256 |
| sc_signal<sc_bv<32> > io_conv_data_4; |
| sc_signal<sc_bv<32> > io_conv_data_5; |
| sc_signal<sc_bv<32> > io_conv_data_6; |
| sc_signal<sc_bv<32> > io_conv_data_7; |
| #endif |
| #if KELVIN_SIMD >= 512 |
| sc_signal<sc_bv<32> > io_conv_data_8; |
| sc_signal<sc_bv<32> > io_conv_data_9; |
| sc_signal<sc_bv<32> > io_conv_data_10; |
| sc_signal<sc_bv<32> > io_conv_data_11; |
| sc_signal<sc_bv<32> > io_conv_data_12; |
| sc_signal<sc_bv<32> > io_conv_data_13; |
| sc_signal<sc_bv<32> > io_conv_data_14; |
| sc_signal<sc_bv<32> > io_conv_data_15; |
| #endif |
| |
| VRegfileSegment_tb tb("VRegfileSegment_tb", loops, true /*random*/); |
| VVRegfileSegment vrf(name); |
| |
| if (trace) { |
| tb.trace(vrf); |
| } |
| |
| vrf.clock(tb.clock); |
| vrf.reset(tb.reset); |
| |
| BIND2(tb, vrf, io_read_0_addr); |
| BIND2(tb, vrf, io_read_0_data); |
| BIND2(tb, vrf, io_read_1_addr); |
| BIND2(tb, vrf, io_read_1_data); |
| BIND2(tb, vrf, io_read_2_addr); |
| BIND2(tb, vrf, io_read_2_data); |
| BIND2(tb, vrf, io_read_3_addr); |
| BIND2(tb, vrf, io_read_3_data); |
| BIND2(tb, vrf, io_read_4_addr); |
| BIND2(tb, vrf, io_read_4_data); |
| BIND2(tb, vrf, io_read_5_addr); |
| BIND2(tb, vrf, io_read_5_data); |
| BIND2(tb, vrf, io_read_6_addr); |
| BIND2(tb, vrf, io_read_6_data); |
| BIND2(tb, vrf, io_transpose_addr); |
| BIND2(tb, vrf, io_transpose_data); |
| BIND2(tb, vrf, io_internal_addr); |
| BIND2(tb, vrf, io_internal_data); |
| BIND2(tb, vrf, io_write_0_valid); |
| BIND2(tb, vrf, io_write_0_addr); |
| BIND2(tb, vrf, io_write_0_data); |
| BIND2(tb, vrf, io_write_1_valid); |
| BIND2(tb, vrf, io_write_1_addr); |
| BIND2(tb, vrf, io_write_1_data); |
| BIND2(tb, vrf, io_write_2_valid); |
| BIND2(tb, vrf, io_write_2_addr); |
| BIND2(tb, vrf, io_write_2_data); |
| BIND2(tb, vrf, io_write_3_valid); |
| BIND2(tb, vrf, io_write_3_addr); |
| BIND2(tb, vrf, io_write_3_data); |
| BIND2(tb, vrf, io_write_4_valid); |
| BIND2(tb, vrf, io_write_4_addr); |
| BIND2(tb, vrf, io_write_4_data); |
| BIND2(tb, vrf, io_write_5_valid); |
| BIND2(tb, vrf, io_write_5_addr); |
| BIND2(tb, vrf, io_write_5_data); |
| BIND2(tb, vrf, io_conv_valid); |
| BIND2(tb, vrf, io_conv_data_0); |
| BIND2(tb, vrf, io_conv_data_1); |
| BIND2(tb, vrf, io_conv_data_2); |
| BIND2(tb, vrf, io_conv_data_3); |
| #if KELVIN_SIMD >= 256 |
| BIND2(tb, vrf, io_conv_data_4); |
| BIND2(tb, vrf, io_conv_data_5); |
| BIND2(tb, vrf, io_conv_data_6); |
| BIND2(tb, vrf, io_conv_data_7); |
| #endif |
| #if KELVIN_SIMD >= 512 |
| BIND2(tb, vrf, io_conv_data_8); |
| BIND2(tb, vrf, io_conv_data_9); |
| BIND2(tb, vrf, io_conv_data_10); |
| BIND2(tb, vrf, io_conv_data_11); |
| BIND2(tb, vrf, io_conv_data_12); |
| BIND2(tb, vrf, io_conv_data_13); |
| BIND2(tb, vrf, io_conv_data_14); |
| BIND2(tb, vrf, io_conv_data_15); |
| #endif |
| |
| tb.start(); |
| } |
| |
| int sc_main(int argc, char* argv[]) { |
| VRegfileSegment_test(Sysc_tb::get_name(argv[0]), 1000000, false); |
| return 0; |
| } |