|
| 1 | +/* |
| 2 | + * This is a small example showing howto connect an RTL UMI Device |
| 3 | + * to a SystemC/TLM simulation using the TLM-2-UMI bridge. |
| 4 | + * |
| 5 | + * Copyright (c) 2024 Zero ASIC. |
| 6 | + * Written by Edgar E. Iglesias |
| 7 | + * |
| 8 | + * SPDX-License-Identifier: MIT |
| 9 | + */ |
| 10 | + |
| 11 | +#include <sstream> |
| 12 | + |
| 13 | +#define SC_INCLUDE_DYNAMIC_PROCESSES |
| 14 | + |
| 15 | +#include "systemc" |
| 16 | +using namespace sc_core; |
| 17 | +using namespace sc_dt; |
| 18 | +using namespace std; |
| 19 | + |
| 20 | +#include "tlm.h" |
| 21 | +#include "tlm_utils/simple_initiator_socket.h" |
| 22 | +#include "tlm_utils/simple_target_socket.h" |
| 23 | + |
| 24 | +#include "tlm-bridges/tlm2umi-bridge.h" |
| 25 | +#include "traffic-generators/tg-tlm.h" |
| 26 | +#include "traffic-generators/traffic-desc.h" |
| 27 | + |
| 28 | +#include "test-modules/signals-umi.h" |
| 29 | +#include "test-modules/utils.h" |
| 30 | +#include "trace/trace.h" |
| 31 | +#if VM_TRACE |
| 32 | +#include <verilated_vcd_sc.h> |
| 33 | +#endif |
| 34 | + |
| 35 | +#include "Vumi_dev.h" |
| 36 | + |
| 37 | +using namespace utils; |
| 38 | + |
| 39 | +#define DW 64 |
| 40 | + |
| 41 | +#define CONNECT_DUT(DUT, SIGS, SIGNAME) DUT.s00_axi_ ## SIGNAME(SIGS.SIGNAME) |
| 42 | + |
| 43 | +TrafficDesc transactions(merge({ |
| 44 | + // Write something to address 8 |
| 45 | + Write(8, DATA(0x1, 0x2, 0x3, 0x4)), |
| 46 | + // Read it back and check that we get the expected data. |
| 47 | + Read(8, 4), |
| 48 | + Expect(DATA(0x1, 0x2, 0x3, 0x4), 4) |
| 49 | +})); |
| 50 | + |
| 51 | +// Top simulation module. |
| 52 | +SC_MODULE(Top) |
| 53 | +{ |
| 54 | + sc_clock clk; |
| 55 | + sc_signal<bool> rst; |
| 56 | + |
| 57 | + TLMTrafficGenerator tg; |
| 58 | + UMISignals<DW> signals_req; |
| 59 | + UMISignals<DW> signals_resp; |
| 60 | + tlm2umi_bridge<DW> bridge; |
| 61 | + Vumi_dev dut; |
| 62 | + |
| 63 | + void do_reset(void) { |
| 64 | + int i; |
| 65 | + |
| 66 | + rst.write(false); |
| 67 | + for (i = 0; i < 2; i++) { |
| 68 | + wait(clk.posedge_event()); |
| 69 | + } |
| 70 | + rst.write(true); |
| 71 | + for (i = 0; i < 4; i++) { |
| 72 | + wait(clk.posedge_event()); |
| 73 | + } |
| 74 | + rst.write(false); |
| 75 | + } |
| 76 | + |
| 77 | + SC_HAS_PROCESS(Top); |
| 78 | + Top(sc_module_name name) : |
| 79 | + clk("clk", sc_time(1, SC_US)), |
| 80 | + rst("rst"), |
| 81 | + tg("traffic_generator"), |
| 82 | + signals_req("signals_req"), |
| 83 | + signals_resp("signals_resp"), |
| 84 | + bridge("bridge"), |
| 85 | + dut("dut") |
| 86 | + { |
| 87 | + SC_THREAD(do_reset); |
| 88 | + |
| 89 | + // Configure the Traffic generator. |
| 90 | + tg.setStartDelay(sc_time(8, SC_US)); |
| 91 | + tg.enableDebug(); |
| 92 | + tg.addTransfers(transactions); |
| 93 | + tg.socket.bind(bridge.socket); |
| 94 | + |
| 95 | + // Wire up the clock and reset signals. |
| 96 | + bridge.clk(clk); |
| 97 | + bridge.rst(rst); |
| 98 | + dut.clk(clk); |
| 99 | + dut.rst(rst); |
| 100 | + |
| 101 | + // Wire-up the bridge and checker. |
| 102 | + signals_req.connect(bridge, "req_"); |
| 103 | + signals_resp.connect(bridge, "resp_"); |
| 104 | + signals_req.connect(dut, "udev_req_"); |
| 105 | + signals_resp.connect(dut, "udev_resp_"); |
| 106 | + } |
| 107 | +}; |
| 108 | + |
| 109 | +int sc_main(int argc, char *argv[]) |
| 110 | +{ |
| 111 | + Top top("Top"); |
| 112 | + |
| 113 | +#if VM_TRACE |
| 114 | + // Before any evaluation, need to know to calculate those signals only used for tracing |
| 115 | + Verilated::traceEverOn(true); |
| 116 | +#endif |
| 117 | + |
| 118 | + Verilated::commandArgs(argc, argv); |
| 119 | + |
| 120 | + // You must do one evaluation before enabling waves, in order to allow |
| 121 | + // SystemC to interconnect everything for testing. |
| 122 | + sc_start(SC_ZERO_TIME); |
| 123 | + |
| 124 | + sc_trace_file *trace_fp = sc_create_vcd_trace_file(argv[0]); |
| 125 | + trace(trace_fp, top, "top"); |
| 126 | + |
| 127 | +#if VM_TRACE |
| 128 | + // General logfile |
| 129 | + ios::sync_with_stdio(); |
| 130 | + |
| 131 | + // If verilator was invoked with --trace argument, |
| 132 | + // and if at run time passed the +trace argument, turn on tracing |
| 133 | + VerilatedVcdSc* tfp = nullptr; |
| 134 | + const char* flag = Verilated::commandArgsPlusMatch("trace"); |
| 135 | + if (flag && 0 == std::strcmp(flag, "+trace")) { |
| 136 | + std::cout << "Enabling waves into logs/vlt_dump.vcd...\n"; |
| 137 | + tfp = new VerilatedVcdSc; |
| 138 | + top.dut.trace(tfp, 99); // Trace 99 levels of hierarchy |
| 139 | + Verilated::mkdir("logs"); |
| 140 | + tfp->open("logs/vlt_dump.vcd"); |
| 141 | + |
| 142 | + trace_fp = sc_create_vcd_trace_file(argv[0]); |
| 143 | + trace(trace_fp, top, "Top"); |
| 144 | + } |
| 145 | +#endif |
| 146 | + |
| 147 | + sc_start(140, SC_US); |
| 148 | + sc_stop(); |
| 149 | + |
| 150 | +#if VM_TRACE |
| 151 | + // Flush the wave files each cycle so we can immediately see the output |
| 152 | + // Don't do this in "real" programs, do it in an abort() handler instead |
| 153 | + if (tfp) tfp->flush(); |
| 154 | +#endif |
| 155 | + if (trace_fp) { |
| 156 | + sc_close_vcd_trace_file(trace_fp); |
| 157 | + } |
| 158 | + return 0; |
| 159 | +} |
0 commit comments