Skip to content

Commit 7da237d

Browse files
Merge pull request #47 from Milemarco/main
Adding Debug Module of Paranut
2 parents 106ae44 + 3b3a61d commit 7da237d

File tree

8 files changed

+2590
-0
lines changed

8 files changed

+2590
-0
lines changed

examples/dm_paranut/CMakeLists.txt

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# This file is part of the ParaNut project.
2+
3+
# Copyright (C) 2022 Marco Milenkovic <marco.milenkovic@hs-augsburg.de>
4+
# Hochschule Augsburg, University of Applied Sciences
5+
6+
# Redistribution and use in source and binary forms, with or without modification,
7+
# are permitted provided that the following conditions are met:
8+
9+
# 1. Redistributions of source code must retain the above copyright notice, this
10+
# list of conditions and the following disclaimer.
11+
12+
# 2. Redistributions in binary form must reproduce the above copyright notice,
13+
# this list of conditions and the following disclaimer in the documentation and/or
14+
# other materials provided with the distribution.
15+
16+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17+
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
20+
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21+
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22+
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
23+
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26+
27+
28+
# Example Paranut DebugModule
29+
project(DebugModule)
30+
31+
# Add alle the nessesery files here
32+
add_executable(DebugModule dm_tb.cpp dm.cpp base.cpp)
33+
target_include_directories(DebugModule PUBLIC "${PROJECT_SOURCE_DIR}")
34+
35+
# use cmake -DSYN=ON to enable the debug flag or OFF to disable it
36+
OPTION(SYN "set the __SYNTHESIS__ Flag" ON) # Enabled by default
37+
38+
# Add compilation options
39+
# target_compile_options(${PROJECT_NAME} PUBLIC -Wall)
40+
IF(SYN)
41+
target_compile_definitions(DebugModule PUBLIC -D__SYNTHESIS__)
42+
ENDIF(SYN)
43+
44+
# svc_target will create ${PROJECT_NAME}_sctool executable that runs code generation
45+
# and ${PROJECT_NAME} that runs general SystemC simulation
46+
# ELAB_TOP parameter accepts hierarchical name of design
47+
# (that is SystemC name, returned by sc_object::name() method)
48+
svc_target(DebugModule INIT_LOCAL_VARS ELAB_TOP tb.dm)
49+

examples/dm_paranut/base.cpp

Lines changed: 337 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,337 @@
1+
/*************************************************************************
2+
3+
This file is part of the ParaNut project.
4+
5+
Copyright (C) 2010-2022 Alexander Bahle <alexander.bahle@hs-augsburg.de>
6+
Gundolf Kiefer <gundolf.kiefer@hs-augsburg.de>
7+
Christian H. Meyer <christian.meyer@hs-augsburg.de>
8+
Hochschule Augsburg, University of Applied Sciences
9+
10+
Redistribution and use in source and binary forms, with or without modification,
11+
are permitted provided that the following conditions are met:
12+
13+
1. Redistributions of source code must retain the above copyright notice, this
14+
list of conditions and the following disclaimer.
15+
16+
2. Redistributions in binary form must reproduce the above copyright notice,
17+
this list of conditions and the following disclaimer in the documentation and/or
18+
other materials provided with the distribution.
19+
20+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
21+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
24+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
27+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30+
31+
*************************************************************************/
32+
33+
34+
#include "base.h"
35+
36+
#include <float.h>
37+
#include <stdarg.h>
38+
#include <stdio.h>
39+
#include <string.h>
40+
41+
#include <systemc.h>
42+
43+
// *********** Dynamic Configuration ************
44+
45+
46+
int pn_cfg_vcd_level = 0;
47+
int pn_cfg_insn_trace = 0;
48+
bool pn_cfg_disable_cache = 0;
49+
bool pn_cfg_debug_mode = 0;
50+
51+
52+
// **************** Tracing *********************
53+
54+
55+
bool pn_trace_verbose = false;
56+
57+
58+
std::string pn_GetTraceName (sc_object *obj, const char *name, int dim, int arg1, int arg2) {
59+
std::string ret;
60+
61+
if (dim < 0 || dim > 2)
62+
PN_ERRORF (("pn_GetTraceName: Parameter dim outside of range (0-2): %d", dim));
63+
64+
// Read full object name and get the base module name
65+
ret = obj->name ();
66+
ret = ret.substr (0, ret.find_last_of ('.') + 1);
67+
68+
// Add name...
69+
ret += name;
70+
71+
// Add first dimension...
72+
if (dim > 0)
73+
ret += "(" + std::to_string (arg1) + ")";
74+
75+
// Add second dimension...
76+
if (dim == 2)
77+
ret += "(" + std::to_string (arg2) + ")";
78+
79+
return ret;
80+
}
81+
82+
83+
// **************** Testbench helpers ***********
84+
85+
86+
sc_trace_file *pn_trace_file = NULL;
87+
88+
89+
char *pn_TbPrintf (const char *format, ...) {
90+
static char buf[200];
91+
92+
va_list ap;
93+
va_start (ap, format);
94+
vsprintf (buf, format, ap);
95+
return buf;
96+
}
97+
98+
99+
void pn_TbAssert (bool cond, const char *msg, const char *filename, const int line) {
100+
if (!cond) {
101+
fprintf (stderr, "ASSERTION FAILURE: %s, %s:%i", sc_time_stamp ().to_string ().c_str (), filename, line);
102+
if (msg)
103+
fprintf (stderr, ": %s\n", msg);
104+
else
105+
fprintf (stderr, "\n");
106+
if (pn_trace_file) sc_close_vcd_trace_file (pn_trace_file);
107+
abort ();
108+
}
109+
}
110+
111+
112+
void pn_TbInfo (const char *msg, const char *filename, const int line) {
113+
int time_size = sc_time_stamp ().to_double () == 0.0 ? 1 : 15;
114+
fprintf (stderr, "(INFO): %*s, %s:%i: %s\n", time_size, sc_time_stamp ().to_string ().c_str (), filename, line, msg);
115+
}
116+
117+
118+
void pn_TbWarning (const char *msg, const char *filename, const int line) {
119+
int time_size = sc_time_stamp ().to_double () == 0.0 ? 1 : 12;
120+
fprintf (stderr, "(WARNING): %*s, %s:%i: %s\n", time_size, sc_time_stamp ().to_string ().c_str (), filename, line, msg);
121+
}
122+
123+
124+
void pn_TbError (const char *msg, const char *filename, const int line) {
125+
int time_size = sc_time_stamp ().to_double () == 0.0 ? 1 : 14;
126+
fprintf (stderr, "(ERROR): %*s, %s:%i: %s\n", time_size, sc_time_stamp ().to_string ().c_str (), filename, line, msg);
127+
if (pn_trace_file) sc_close_vcd_trace_file (pn_trace_file);
128+
exit (3);
129+
}
130+
131+
132+
// **************** DisAss **********************
133+
134+
135+
char *pn_DisAss (TWord insn) {
136+
static char ret[80] = "";
137+
TWord opcode, funct3, funct7, rs1, rs2, rd, bit30, bit20, bit21, bit25, bit28, bit29, itype, utype, btype, jtype, stype;
138+
sc_uint<32> inst = insn;
139+
140+
opcode = insn & 0x7f;
141+
funct3 = (insn >> 12) & 0x7;
142+
funct7 = (insn >> 25);
143+
144+
rd = (insn >> 7) & 0x1f;
145+
rs1 = (insn >> 15) & 0x1f;
146+
rs2 = (insn >> 20) & 0x1f;
147+
148+
bit20 = (insn >> 20) & 0x1;
149+
bit21 = (insn >> 21) & 0x1;
150+
bit25 = (insn >> 25) & 0x1;
151+
bit28 = (insn >> 28) & 0x1;
152+
bit29 = (insn >> 28) & 0x1;
153+
bit30 = (insn >> 30) & 0x1;
154+
155+
itype = ((insn >> 20) ^ 0x800) - 0x800;
156+
utype = insn & 0xFFFFF000;
157+
btype = ((sc_uint<32>)(inst[31], inst[7], inst (30, 25), inst (11, 8), 0) ^ 0x1000) - 0x1000;
158+
jtype = ((sc_uint<32>)(inst[31], inst (19, 12), inst[20], inst (30, 25), inst (24, 21), 0) ^ 0x100000) - 0x100000;
159+
stype = ((((sc_uint<32>)(inst (31, 25), 0, 0, 0, 0, 0)).value () + rd) ^ 0x800) - 0x800;
160+
161+
strcpy (ret, " ");
162+
163+
// ALU instructions...
164+
if (opcode == 0x13) { // OP_IMM
165+
const char *table[] = { "addi", "slli", "slti", "sltiu", "xori", "srli", "ori", "andi" };
166+
if (funct3 == 5 || funct3 == 1) {
167+
if (bit30) table[funct3] = "srai";
168+
itype &= 0x1F; // shamt
169+
}
170+
sprintf (ret + 2, "%s r%i, r%i, 0x%x", table[funct3], rd, rs1, itype);
171+
} else if (opcode == 0x33 && !bit25) { // OP (Bit 25 is on for M-Extension (DIV/MUL...)
172+
const char *table[] = { "add", "sll", "slt", "sltu", "xor", "srl", "or", "and" };
173+
if (funct3 == 0) {
174+
if (bit30) table[funct3] = "sub";
175+
} else if (funct3 == 5) {
176+
if (bit30) table[funct3] = "sra";
177+
}
178+
sprintf (ret + 2, "%s r%i, r%i, r%i", table[funct3], rd, rs1, rs2);
179+
} else if ((opcode == 0x33 && bit25)) { // OP - M-Extension
180+
static const char *table[] = { "mul", "mulh", "mulhsu", "mulhu",
181+
"div", "divu", "rem", "remu" };
182+
sprintf (ret + 2, "%s r%i, r%i, r%i", table[funct3], rd, rs1, rs2);
183+
} else if (opcode == 0x17) { // AUIPC
184+
sprintf (ret + 2, "auipc r%i, 0x%x", rd, utype);
185+
} else if (opcode == 0x37) { // LUI
186+
sprintf (ret + 2, "lui r%i, 0x%x", rd, utype);
187+
} else if (opcode == 0x63) { // BRANCH
188+
const char *table[] = { "beq", "bneq", "INV_SUB", "INV_SUB", "blt", "bge", "bltu", "bgeu" };
189+
sprintf (ret + 2, "%s r%i, r%i, 0x%x", table[funct3], rs1, rs2, btype);
190+
} else if (opcode == 0x6F) { // JAL
191+
sprintf (ret + 2, "jal r%i, 0x%x", rd, jtype);
192+
} else if (opcode == 0x67) { // JALR
193+
sprintf (ret + 2, "jalr r%i, r%i, 0x%x", rd, rs1, itype);
194+
} else if (opcode == 0x03) { // LOAD
195+
static const char *table[] = { "lb", "lh", "lw", "INV_SUB", "lbu", "lhu" };
196+
sprintf (ret + 2, "%s r%i, 0x%x(r%i)", table[funct3], rd, itype, rs1);
197+
} else if (opcode == 0x23) { // STORE
198+
static const char *table[] = { "sb", "sh", "sw" };
199+
sprintf (ret + 2, "%s r%i, 0x%x(r%i)", table[funct3], rs2, stype, rs1);
200+
} else if (opcode == 0x73) { // SYSTEM
201+
const char *table[] = { "ecall", "csrrw", "csrrs", "csrrc",
202+
"INV_SUB", "csrrwi", "csrrsi", "csrrci" };
203+
if (bit25 && bit28) table[0] = "sfence.vma";
204+
if (bit21) table[0] = bit28 ? bit29 ? "mret" : "sret" : "uret";
205+
if (bit20) table[0] = "ebreak";
206+
if (funct3 == 0)
207+
sprintf (ret + 2, "%s", table[funct3]);
208+
else if (funct3 < 4)
209+
sprintf (ret + 2, "%s r%i, 0x%x, r%i", table[funct3], rd, itype, rs1);
210+
else
211+
sprintf (ret + 2, "%s r%i, 0x%x, 0x%x", table[funct3], rd, itype, rs1);
212+
} else if (opcode == 0x0F) {
213+
sprintf (ret + 2, "fence");
214+
} else if (opcode == 0xB) { // PARA
215+
static const char *table[] = { "halt", "cinvalidate", "cwriteback", "cflush" };
216+
if (funct3 == 0)
217+
sprintf (ret + 2, "%s", table[funct3]);
218+
else
219+
sprintf (ret + 2, "%s 0x%x(r%i) ", table[funct3], itype, rs1);
220+
} else if (opcode == 0x2F) { // AMO
221+
if (funct3 == 2 && (funct7 >> 2) == 2) // LR.W
222+
sprintf (ret + 2, "lr.w r%i, (r%i)", rd, rs1);
223+
else if (funct3 == 2 && (funct7 >> 2) == 3) // SC.W
224+
sprintf (ret + 2, "sc.w r%i, r%i, (r%i) ", rd, rs2, rs1);
225+
else
226+
sprintf (ret + 2, "AMO_INVALID r%i, r%i, (r%i) ", rd, rs2, rs1);
227+
} else
228+
sprintf (ret, "? 0x%08x ?", insn);
229+
230+
return ret;
231+
}
232+
233+
234+
// **************** Performance measuring *****************
235+
236+
237+
void CPerfMon::Init (int events, CEventDef *ev_tab) {
238+
events_ = events;
239+
ev_tab_ = ev_tab;
240+
count_tab_ = new int[events];
241+
time_tab_ = new double[events];
242+
min_tab_ = new double[events];
243+
max_tab_ = new double[events];
244+
Reset ();
245+
}
246+
247+
248+
void CPerfMon::Done () {
249+
if (events_ > 0) {
250+
delete[] count_tab_;
251+
delete[] time_tab_;
252+
delete[] min_tab_;
253+
delete[] max_tab_;
254+
}
255+
}
256+
257+
258+
void CPerfMon::Reset () {
259+
last_no_ = -1;
260+
for (int n = 0; n < events_; n++) {
261+
count_tab_[n] = 0;
262+
time_tab_[n] = max_tab_[n] = 0.0;
263+
min_tab_[n] = DBL_MAX;
264+
}
265+
}
266+
267+
268+
void CPerfMon::Count (int ev_no) {
269+
double curStamp = sc_time_stamp ().to_double ();
270+
271+
if (last_no_ >= 0) {
272+
if (ev_tab_[last_no_].is_timed) {
273+
double t = curStamp - last_stamp_;
274+
if (t == 0) // Time of 0 between two events is not plausible
275+
return;
276+
time_tab_[last_no_] += t;
277+
if (t < min_tab_[last_no_])
278+
min_tab_[last_no_] = t;
279+
if (t > max_tab_[last_no_])
280+
max_tab_[last_no_] = t;
281+
}
282+
}
283+
284+
count_tab_[ev_no]++;
285+
if (ev_tab_[ev_no].is_timed) last_stamp_ = curStamp;
286+
last_no_ = ev_no;
287+
}
288+
289+
290+
static void DisplayLine (const char *name, int count, int avg_count, double total, double min, double max, bool is_timed) {
291+
if (avg_count > 0 && is_timed)
292+
fprintf (stderr, "(PERF): %-10s %7i %8.1lf %8.1lf %8.1lf %11.1lf\n", name, count, min,
293+
total / avg_count, max, total);
294+
else
295+
fprintf (stderr, "(PERF): %-10s %7i\n", name, count);
296+
}
297+
298+
299+
void CPerfMon::Display (const char *name) {
300+
double time_total, min_total, max_total;
301+
int count_total, avg_count_total;
302+
303+
fprintf (stderr, "(PERF):\n"
304+
"(PERF): ********** Performance statics ");
305+
if (name) fprintf (stderr, "of unit '%s'", name);
306+
fprintf (stderr, "\n"
307+
"(PERF):\n"
308+
"(PERF): Time [ns]\n"
309+
"(PERF): Event Count min avg max Total\n"
310+
"(PERF): -----------------------------------------------------------\n");
311+
count_total = avg_count_total = 0;
312+
time_total = max_total = 0.0;
313+
min_total = DBL_MAX;
314+
for (int n = 0; n < events_; n++) {
315+
DisplayLine (ev_tab_[n].name, count_tab_[n], count_tab_[n], time_tab_[n], min_tab_[n],
316+
max_tab_[n], ev_tab_[n].is_timed);
317+
count_total += count_tab_[n];
318+
if (ev_tab_[n].is_timed) avg_count_total += count_tab_[n];
319+
time_total += time_tab_[n];
320+
if (min_tab_[n] < min_total) min_total = min_tab_[n];
321+
if (max_tab_[n] > max_total) max_total = max_tab_[n];
322+
}
323+
fprintf (stderr, "(PERF): -----------------------------------------------------------\n");
324+
DisplayLine ("Total", count_total, avg_count_total, time_total, min_total, max_total, true);
325+
fprintf (stderr, "(PERF):\n");
326+
}
327+
328+
329+
// ***** CPerfMonCPU *****
330+
331+
332+
void CPerfMonCPU::Init () {
333+
static CEventDef CPU_events[] = {
334+
{ "ALU", true }, { "Load", true }, { "Store", true }, { "Jump", true }, { "Other", true }, { "IFetch", true }
335+
};
336+
CPerfMon::Init (6, CPU_events);
337+
}

0 commit comments

Comments
 (0)