-
Notifications
You must be signed in to change notification settings - Fork 0
/
tb_base.cc
189 lines (153 loc) · 5.23 KB
/
tb_base.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
// Copyright 2023 Flavien Solt, ETH Zurich.
// Licensed under the General Public License, Version 3.0, see LICENSE for details.
// SPDX-License-Identifier: GPL-3.0-only
#include "Vtop.h"
#include "verilated.h"
#include "ticks.h"
#include <iostream>
#include <stdlib.h>
#include <chrono>
#include <fstream>
#include <cassert>
#define IN_DATA_WIDTH 96
#define OUT_DATA_WIDTH 96
#define NUM_SUBNETS 1
#define NUM_CLKINS 5
#define PATH_TO_INPUTS_FILE "inputs.txt"
#if VM_TRACE
#if VM_TRACE_FST
#include <verilated_fst_c.h>
#else
#include <verilated_vcd_c.h>
#endif // VM_TRACE_FST
#endif // VM_TRACE
typedef Vtop Module;
#define PATH_TO_METADATA "tmp/metadata.log"
size_t curr_id_in_inputs_from_file = 0;
size_t curr_id_in_actor_id_order = 0;
// For subnets, there are multiple inputs in a row to build the full-width input
std::vector<uint32_t> inputs_from_file;
std::vector<uint32_t> actor_id_order;
#if VM_TRACE
const int kTraceLevel = 6;
#if VM_TRACE_FST
VerilatedFstC *trace_;
#else
VerilatedVcdC *trace_;
#endif // VM_TRACE_FST
#endif // VM_TRACE
int read_inputs_from_file() {
// Make sure we call this function only once
assert(inputs_from_file.size() == 0);
std::ifstream in_file(PATH_TO_INPUTS_FILE);
uint64_t next_in_id, next_input;
std::string next_input_str;
uint64_t num_32bit_inputs;
in_file >> num_32bit_inputs;
uint64_t remaining_lines_to_read = num_32bit_inputs;
int simlen = 0;
while(remaining_lines_to_read--) {
simlen++;
in_file >> next_in_id;
in_file >> next_input_str;
next_input = std::stoul(next_input_str, nullptr, 16);
// std::cout << "Next actor id: " << next_in_id << std::endl;
actor_id_order.push_back(next_in_id);
inputs_from_file.push_back(next_input);
// Check whether we were reading the subnet id or the subnet input
if (next_in_id < NUM_SUBNETS) {
for (int i = 1; i < IN_DATA_WIDTH / 32; i++) {
in_file >> next_in_id; // Only used for assertions
if (next_in_id != actor_id_order.back()) {
std::cout << "Error: subnet id mismatch. Expected: " << actor_id_order.back() << " - Got: " << next_in_id << std::endl;
exit(1);
}
in_file >> next_input_str;
next_input = std::stoul(next_input_str, nullptr, 16);
inputs_from_file.push_back(next_input);
remaining_lines_to_read--;
}
}
}
return simlen;
}
void randomize_inputs(Module *my_module) {
if (actor_id_order.size() == 0) {
std::cout << "Error: actor_id_order is empty." << std::endl;
exit(1);
}
if (curr_id_in_actor_id_order >= actor_id_order.size()) {
std::cout << "Error: curr_id_in_actor_id_order is too big: " << curr_id_in_actor_id_order << " - actor_id_order.size(): " << actor_id_order.size() << std::endl;
exit(1);
}
int curr_actor_id = actor_id_order[curr_id_in_actor_id_order++];
int curr_is_subnet = curr_actor_id < NUM_SUBNETS;
if (curr_is_subnet) {
for (int word_id_in_input = (curr_actor_id * IN_DATA_WIDTH) / 32; word_id_in_input < ((curr_actor_id + 1) * IN_DATA_WIDTH) / 32; word_id_in_input++) {
my_module->in_data[word_id_in_input] = inputs_from_file[curr_id_in_inputs_from_file++];
}
} else {
int curr_clkin_id = curr_actor_id - NUM_SUBNETS;
my_module->clkin_data[curr_clkin_id] = inputs_from_file[curr_id_in_inputs_from_file++];
}
}
/**
* Runs the testbench.
*
* @param tb a pointer to a testbench instance
* @param simlen the number of cycles to run
*/
std::pair<long, uint64_t> run_test(Module *my_module, int simlen, const std::string trace_filename) {
srand(time(NULL)); // set random seed to current time
uint64_t cumulated_output = 0;
auto start = std::chrono::steady_clock::now();
#if VM_TRACE
#if VM_TRACE_FST
trace_ = new VerilatedFstC;
#else
trace_ = new VerilatedVcdC;
#endif // VM_TRACE_FST
my_module->trace(trace_, kTraceLevel);
trace_->open(trace_filename.c_str());
size_t tick_count_ = 0;
#endif // VM_TRACE
for (int tick_id = 0; tick_id < simlen; tick_id++) {
randomize_inputs(my_module);
my_module->eval();
#if VM_TRACE
trace_->dump(tick_count_++);
#endif // VM_TRACE
for (int i = 0; i < OUT_DATA_WIDTH / 32; i++)
cumulated_output += my_module->out_data[i];
}
#if VM_TRACE
trace_->flush();
#endif // VM_TRACE
auto stop = std::chrono::steady_clock::now();
long ret = std::chrono::duration_cast<std::chrono::milliseconds>(stop - start).count();
return std::make_pair(ret, cumulated_output);
}
int main(int argc, char **argv, char **env) {
Verilated::commandArgs(argc, argv);
Verilated::traceEverOn(VM_TRACE);
////////
// Instantiate the module.
////////
Module *my_module = new Module;
////////
// Get the ctx vars.
////////
int simlen = read_inputs_from_file();
std::string vcd_filepath = cl_get_tracefile();
////////
// Run the experiment.
////////
std::pair<long, uint64_t> duration_and_output = run_test(my_module, simlen, vcd_filepath);
long duration = duration_and_output.first;
uint64_t cumulated_output = duration_and_output.second;
std::cout << "Testbench complete!" << std::endl;
std::cout << "Output signature: " << std::dec << cumulated_output << "." << std::endl;
std::cout << "Elapsed time: " << std::dec << duration << "." << std::endl;
delete my_module;
exit(0);
}