Kestrel-3

Check-in [1dd9f6b5cf]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:WIP: Renovate sia_tilelink.v and properties.vf to work better with Verilator. HOWEVER, Verilator now cannot locate "verilated.h" for some reason. Even if I manually include its path as a -I parameter to gcc, it refuses to find it. NOTE: I'll need to apply these kinds of renovations to all the other Verilog sources in the SIA core, and quite possibly throughout the Kestrel-3 repository as well. UUGH! I hate Verilog so much after this. The Verilog spec is total garbage if nobody is going to bother to follow it. Many thanks to ZipCPU (Dan G.) for isolating what could be one of the biggest bugs of the Kestrel-3, and a major source of what's driving me crazy with this project.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256:1dd9f6b5cfb2e6b3c67f77e305dbf3b39388dcb21a5f87831257b6020dbbd246
User & Date: kc5tja 2018-11-01 17:58:44
Context
2018-11-25
02:01
Bug fix: make sure loopback control bits are accounted for in formal assertions. check-in: f047e61a8d user: kc5tja tags: trunk
2018-11-01
17:58
WIP: Renovate sia_tilelink.v and properties.vf to work better with Verilator. HOWEVER, Verilator now cannot locate "verilated.h" for some reason. Even if I manually include its path as a -I parameter to gcc, it refuses to find it. NOTE: I'll need to apply these kinds of renovations to all the other Verilog sources in the SIA core, and quite possibly throughout the Kestrel-3 repository as well. UUGH! I hate Verilog so much after this. The Verilog spec is total garbage if nobody is going to bother to follow it. Many thanks to ZipCPU (Dan G.) for isolating what could be one of the biggest bugs of the Kestrel-3, and a major source of what's driving me crazy with this project. check-in: 1dd9f6b5cf user: kc5tja tags: trunk
2018-10-31
05:59
Revise TB to match structure used by ZipCPU check-in: c72d29e3e8 user: kc5tja tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to cores/sia/Makefile.

7
8
9
10
11
12
13
14
15
16
17
18



19
20
21
22
23
24
25
26
27
28
29
30
	(cd rtl/verilog/transmit_engine && sby -f transmit_engine.sby)

.PHONY: test_receiver_engine
test_receiver_engine:
	(cd rtl/verilog/receiver_engine && sby -f receiver_engine.sby)

obj_dir: rtl/verilog/sia_tilelink/*.v rtl/verilog/receiver_engine/*.v rtl/verilog/transmit_engine/*.v rtl/verilog/sia.v bench/cpp/*.cpp
	verilator -CFLAGS "-I../../include/cpp" -y ../include/verilog --cc \
	rtl/verilog/sia_tilelink/*.v \
	rtl/verilog/receiver_engine/*.v \
	rtl/verilog/transmit_engine/*.v \
	rtl/verilog/sia.v \



	--top-module sia \
	--exe bench/cpp/sia.cpp

driver: obj_dir
	make -j -C obj_dir -f Vsia.mk Vsia

.PHONY:
verilator_test: driver
	obj_dir/Vsia

.PHONY: test
test: test_sia_tilelink test_transmit_engine test_receiver_engine verilator_test







<
|
|
|
|
>
>
>
|











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
	(cd rtl/verilog/transmit_engine && sby -f transmit_engine.sby)

.PHONY: test_receiver_engine
test_receiver_engine:
	(cd rtl/verilog/receiver_engine && sby -f receiver_engine.sby)

obj_dir: rtl/verilog/sia_tilelink/*.v rtl/verilog/receiver_engine/*.v rtl/verilog/transmit_engine/*.v rtl/verilog/sia.v bench/cpp/*.cpp

	verilator -Wall --trace -y rtl/verilog/sia_tilelink	\
	-y rtl/verilog/receiver_engine			\
	-y rtl/verilog/transmit_engine			\
	-y rtl/verilog					\
	-y ../include/verilog				\
	-CFLAGS "-I../../include/cpp"			\
	-cc sia.v					\
	--top-module sia				\
	--exe bench/cpp/sia.cpp

driver: obj_dir
	make -j -C obj_dir -f Vsia.mk Vsia

.PHONY:
verilator_test: driver
	obj_dir/Vsia

.PHONY: test
test: test_sia_tilelink test_transmit_engine test_receiver_engine verilator_test

Changes to cores/sia/bench/cpp/sia.cpp.

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
#include <iostream>

#include "Vsia.h"
#include "verilated.h"


#include "tilelink.h"


static VerilatedVcdC *trace;


template<class MODULE> struct TESTBENCH {
	unsigned long	m_ticks;		// needed for dumping to the VCD
	MODULE *	m_core;


	TESTBENCH() {
		m_core = new MODULE;


		m_ticks = 0;
	}

	~TESTBENCH() {
		delete m_core;
		m_core = NULL;
	}

















	virtual void reset() {

		m_core->i_reset = 1;
		this->tick();
		m_core->i_reset = 0;

	}

	virtual void tick() {
		m_ticks++;

		m_core->i_clk = 0;
		m_core->eval();





		m_core->i_clk = 1;
		m_core->eval();





		m_core->i_clk = 0;
		m_core->eval();










	}

	virtual bool is_done() {
		return Verilated::gotFinish();
	}
};





>










>

|

>
>








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

>



>







>
>
>
>



>
>
>
>



>
>
>
>
>
>
>
>
>
>







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
#include <iostream>

#include "Vsia.h"
#include "verilated.h"
#include "verilated_vcd_c.h"

#include "tilelink.h"


static VerilatedVcdC *trace;


template<class MODULE> struct TESTBENCH {
	unsigned long	m_ticks;		// needed for dumping to the VCD
	MODULE *	m_core;
	VerilatedVcdC	*m_trace;

	TESTBENCH() : m_trace(NULL) {
		m_core = new MODULE;
		Verilated::traceEverOn(true);
		opentrace("dump.vcd");
		m_ticks = 0;
	}

	~TESTBENCH() {
		delete m_core;
		m_core = NULL;
	}

	virtual	void	opentrace(const char *vcdname) {
		if (!m_trace) {
			m_trace = new VerilatedVcdC;
			m_core->trace(m_trace, 99);
			m_trace->open(vcdname);
		}
	}

	virtual	void	closetrace(void) {
		if (m_trace) {
			m_trace->close();
			delete m_trace;
			m_trace = NULL;
		}
	}

	virtual void reset() {
printf("Reset tick()\n");
		m_core->i_reset = 1;
		this->tick();
		m_core->i_reset = 0;
printf("Reset complete()\n");
	}

	virtual void tick() {
		m_ticks++;

		m_core->i_clk = 0;
		m_core->eval();
		if (m_trace) {
printf("Pre edge trace\n");
			m_trace->dump((vluint64_t)(10*m_ticks-2));
		}

		m_core->i_clk = 1;
		m_core->eval();
		if (m_trace) {
printf("Rising edge trace\n");
			m_trace->dump((vluint64_t)(10*m_ticks));
		}

		m_core->i_clk = 0;
		m_core->eval();
		if (m_trace) {
printf("Falling edge trace\n");
			m_trace->dump((vluint64_t)(10*m_ticks+5));
			m_trace->flush();
fflush(stdout);
		}
	}

	virtual	void	eval(void) {
		m_core->eval();
	}

	virtual bool is_done() {
		return Verilated::gotFinish();
	}
};

Changes to cores/sia/rtl/verilog/sia_tilelink/properties.vf.

224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
// O: Enable interrupt on overrun
// P: Enable interrupt on fresh receipt of a byte

always @(posedge i_clk)
if(&{
	f_past_valid,
	$stable(i_reset) && !i_reset,
	$past(rd_dword_0)
}) begin
	assert(o_d_data[63:32] == {
		{
			$past(o_txd_loopback),
			$past(o_rxd_loopback),
			5'd0
		},







|







224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
// O: Enable interrupt on overrun
// P: Enable interrupt on fresh receipt of a byte

always @(posedge i_clk)
if(&{
	f_past_valid,
	$stable(i_reset) && !i_reset,
	$past(is_get)
}) begin
	assert(o_d_data[63:32] == {
		{
			$past(o_txd_loopback),
			$past(o_rxd_loopback),
			5'd0
		},

Changes to cores/sia/rtl/verilog/sia_tilelink/sia_tilelink.v.

43
44
45
46
47
48
49

50
51

52


53
54

55

56

57
58
59
60
61
62
63
64
..
88
89
90
91
92
93
94

95
96
97

98
99
100

101
102
103

104
105
106
107
108
109
110
111
...
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
...
168
169
170
171
172
173
174

175
176
177
178
179
180
181
182
...
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
...
256
257
258
259
260
261
262

263
264

265
266

267
268
269
270
271
272
273
274
...
295
296
297
298
299
300
301

302
303
304
305
306
307
308
309
);
	input i_clk;
	input i_reset;

	input [2:0] i_a_opcode;
	input [1:0] i_a_source;
	input [1:0] i_a_size;

	input [7:0] i_a_mask;
	input [63:0] i_a_data;

	input i_a_valid;


	output o_a_ready = slave_ready;


	output [1:0] o_d_param = 0;

	output o_d_error = 0;

	output o_d_valid = slave_ack;
	input i_d_ready;

	// The SIA sits in one of three states at any given time.
	//
	// slave_ready is the state in which the core can receive
	// new operations on the TL-UL A channel.
	//
................................................................................

	// When working on a request sent from a host, we will
	// acknowledge the request by copying some attributes
	// into the TL-UL D Channel.  These attributes allow the
	// switching fabric to route messages back to the
	// originating host processor.
	reg [1:0] txn_size;

	output [1:0] o_d_size = txn_size;

	reg [1:0] txn_source;

	output [1:0] o_d_source = txn_source;

	reg [63:0] txn_data;

	output [63:0] o_d_data = txn_data;

	reg [2:0] txn_opcode;

	output [2:0] o_d_opcode = txn_opcode;

	// is_put is asserted when the host is attempting to write
	// a value to one or more SIA registers.
	//
	// is_get is asserted when the host is attempting to read
	// a value from one or more SIA registers.
	wire is_put = (
................................................................................
	};

	// The SIA only has 8 bytes of registers, so we don't actually
	// need any register-select logic.  The i_a_mask input provides
	// everything we need to select which bytes of the register set
	// are selected for writing new values.  When reading, all 8
	// bytes are placed on the bus at a time; i_a_mask is ignored.
	wire rd_dword_0 = is_get;

	wire addr_txout = i_a_mask[0];
	wire addr_stat = i_a_mask[1];
	wire addr_rxinp = i_a_mask[2];
	wire addr_intena = i_a_mask[3];
	wire addr_baud = |{i_a_mask[7:4]};

	// o_txd_valid is asserted when we have a data byte for the
	// transmitter to send.
	//
................................................................................
	// i_txd_ready is asserted when the transmitter engine is
	// available for the next byte.
	//
	// Only when these two are asserted at the same time will
	// the data byte be loaded into the transmitter.  Since we
	// want to block the host processor until the transfer
	// completes, we just draw the data from i_a_data directly.

	output o_txd_valid = slave_txout;
	input i_txd_ready;

	output [7:0] o_txd_data = r_txd_data;
	reg [7:0] r_txd_data;

	always @(posedge i_clk) begin
		r_txd_data <= r_txd_data;

		if(is_put && addr_txout) begin
			r_txd_data <= i_a_data[7:0];
		end
	end
................................................................................
	// processor is done in the slave_txout state.

	input [9:0] i_rxd_data;
	input i_rxd_idle;
	input i_rxd_overrun;
	input i_rxd_valid;


	output o_rxd_ready = (is_get & i_a_mask[2]);

	wire frame_error = (i_rxd_data[0] != 1'b0) && (i_rxd_data[9] != 1'b1);

	always @(posedge i_clk) begin
		slave_ready <= slave_ready;
		slave_ack <= slave_ack;
		slave_txout <= slave_txout;
................................................................................
			slave_ready <= 0;
			slave_ack <= 1;
			slave_txout <= 0;

			txn_size <= i_a_size;
			txn_source <= i_a_source;
			txn_data <= {
				o_txd_loopback,
				o_rxd_loopback,
				5'd0,
				4'd0, r_baud,
				{
					3'd0,
					r_ie_frame_error,
					r_ie_rxd_idle,
................................................................................
		end
	end

	// The SIA is a configurable UART.  You are free to set
	// the data rate via the BAUD register.  See the Kestrel-3
	// wiki for details on how to calculate the value.
	wire wr_baud = is_put & addr_baud;

	output [19:0] o_divisor = r_baud;
	reg [19:0] r_baud;

	output [1:0] o_txd_loopback = r_txd_loopback;
	reg [1:0] r_txd_loopback;

	output o_rxd_loopback = r_rxd_loopback;
	reg r_rxd_loopback;

	always @(posedge i_clk) begin
		r_baud <= r_baud;
		r_txd_loopback <= r_txd_loopback;
		r_rxd_loopback <= r_rxd_loopback;

................................................................................

	reg r_ie_rxd_valid;
	reg r_ie_rxd_overrun;
	reg r_ie_txd_ready;
	reg r_ie_rxd_idle;
	reg r_ie_frame_error;


	output o_irq = |{
		r_ie_rxd_valid & i_rxd_valid,
		r_ie_rxd_overrun & i_rxd_overrun,
		r_ie_txd_ready & i_txd_ready,
		r_ie_rxd_idle & i_rxd_idle,
		r_ie_frame_error & frame_error
	};








>


>

>
>
|

>
|
>
|
>
|







 







>
|


>
|


>
|


>
|







 







<


<







 







>
|


|

>







 







>
|







 







|







 







>
|

>
|

>
|







 







>
|







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
..
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
...
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
...
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
...
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
...
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
...
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
);
	input i_clk;
	input i_reset;

	input [2:0] i_a_opcode;
	input [1:0] i_a_source;
	input [1:0] i_a_size;
	// verilator lint_off UNUSED
	input [7:0] i_a_mask;
	input [63:0] i_a_data;
	// verilator lint_on UNUSED
	input i_a_valid;
	output wire o_a_ready;

	assign	o_a_ready = slave_ready;

	output wire [1:0] o_d_param;
	assign o_d_param = 0;
	output wire o_d_error;
	assign o_d_error = 0;
	output wire o_d_valid;
	assign o_d_valid = slave_ack;
	input i_d_ready;

	// The SIA sits in one of three states at any given time.
	//
	// slave_ready is the state in which the core can receive
	// new operations on the TL-UL A channel.
	//
................................................................................

	// When working on a request sent from a host, we will
	// acknowledge the request by copying some attributes
	// into the TL-UL D Channel.  These attributes allow the
	// switching fabric to route messages back to the
	// originating host processor.
	reg [1:0] txn_size;
	output wire [1:0] o_d_size;
	assign o_d_size = txn_size;

	reg [1:0] txn_source;
	output wire [1:0] o_d_source;
	assign o_d_source = txn_source;

	reg [63:0] txn_data;
	output wire [63:0] o_d_data;
	assign o_d_data = txn_data;

	reg [2:0] txn_opcode;
	output wire [2:0] o_d_opcode;
	assign o_d_opcode = txn_opcode;

	// is_put is asserted when the host is attempting to write
	// a value to one or more SIA registers.
	//
	// is_get is asserted when the host is attempting to read
	// a value from one or more SIA registers.
	wire is_put = (
................................................................................
	};

	// The SIA only has 8 bytes of registers, so we don't actually
	// need any register-select logic.  The i_a_mask input provides
	// everything we need to select which bytes of the register set
	// are selected for writing new values.  When reading, all 8
	// bytes are placed on the bus at a time; i_a_mask is ignored.


	wire addr_txout = i_a_mask[0];

	wire addr_rxinp = i_a_mask[2];
	wire addr_intena = i_a_mask[3];
	wire addr_baud = |{i_a_mask[7:4]};

	// o_txd_valid is asserted when we have a data byte for the
	// transmitter to send.
	//
................................................................................
	// i_txd_ready is asserted when the transmitter engine is
	// available for the next byte.
	//
	// Only when these two are asserted at the same time will
	// the data byte be loaded into the transmitter.  Since we
	// want to block the host processor until the transfer
	// completes, we just draw the data from i_a_data directly.
	output wire o_txd_valid;
	assign o_txd_valid = slave_txout;
	input i_txd_ready;

	output wire [7:0] o_txd_data;
	reg [7:0] r_txd_data;
	assign o_txd_data = r_txd_data;
	always @(posedge i_clk) begin
		r_txd_data <= r_txd_data;

		if(is_put && addr_txout) begin
			r_txd_data <= i_a_data[7:0];
		end
	end
................................................................................
	// processor is done in the slave_txout state.

	input [9:0] i_rxd_data;
	input i_rxd_idle;
	input i_rxd_overrun;
	input i_rxd_valid;

	output wire o_rxd_ready;
	assign o_rxd_ready = (is_get & addr_rxinp);

	wire frame_error = (i_rxd_data[0] != 1'b0) && (i_rxd_data[9] != 1'b1);

	always @(posedge i_clk) begin
		slave_ready <= slave_ready;
		slave_ack <= slave_ack;
		slave_txout <= slave_txout;
................................................................................
			slave_ready <= 0;
			slave_ack <= 1;
			slave_txout <= 0;

			txn_size <= i_a_size;
			txn_source <= i_a_source;
			txn_data <= {
				o_txd_loopback,  // Remember: 2 bits wide!
				o_rxd_loopback,
				5'd0,
				4'd0, r_baud,
				{
					3'd0,
					r_ie_frame_error,
					r_ie_rxd_idle,
................................................................................
		end
	end

	// The SIA is a configurable UART.  You are free to set
	// the data rate via the BAUD register.  See the Kestrel-3
	// wiki for details on how to calculate the value.
	wire wr_baud = is_put & addr_baud;
	output wire [19:0] o_divisor;
	assign o_divisor = r_baud;
	reg [19:0] r_baud;
	output wire [1:0] o_txd_loopback;
	assign o_txd_loopback = r_txd_loopback;
	reg [1:0] r_txd_loopback;
	output wire o_rxd_loopback;
	assign o_rxd_loopback = r_rxd_loopback;
	reg r_rxd_loopback;

	always @(posedge i_clk) begin
		r_baud <= r_baud;
		r_txd_loopback <= r_txd_loopback;
		r_rxd_loopback <= r_rxd_loopback;

................................................................................

	reg r_ie_rxd_valid;
	reg r_ie_rxd_overrun;
	reg r_ie_txd_ready;
	reg r_ie_rxd_idle;
	reg r_ie_frame_error;

	output wire o_irq;
	assign o_irq = |{
		r_ie_rxd_valid & i_rxd_valid,
		r_ie_rxd_overrun & i_rxd_overrun,
		r_ie_txd_ready & i_txd_ready,
		r_ie_rxd_idle & i_rxd_idle,
		r_ie_frame_error & frame_error
	};