Kestrel-3

Check-in [b06cdcafc5]
Login

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

Overview
Comment:First cut at a hardware integration test for the SIA
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256:b06cdcafc5bd311d027686afe0ea2c30a73aeeb919e57895ee8d9b2fb4bb0ce1
User & Date: kc5tja 2018-11-26 01:34:58
Context
2018-11-26
05:53
Fucking reset circuitry gets me every time! check-in: 8d2bf519df user: kc5tja tags: trunk
01:34
First cut at a hardware integration test for the SIA check-in: b06cdcafc5 user: kc5tja tags: trunk
2018-11-25
02:29
Forgot to remove debugging change to default loopback settings check-in: 5511953cec user: kc5tja tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

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

23
24
25
26
27
28
29

30
31
32
33
34
35
36
...
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
...
147
148
149
150
151
152
153
154

	o_irq,

	i_rxd,
	o_txd
);
	parameter		DIVISOR_BITS = 20;

	parameter		DIVHB = DIVISOR_BITS - 1;

	input			i_clk;
	input			i_reset;

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

	always @(*)
	case(txd_loopback)
	2'b00:	o_txd = T_txd;
	2'b01:  o_txd = i_rxd;
	2'b10:  o_txd = 1'b0;
	2'b11:  o_txd = 1'b1;
	endcase;

	sia_tilelink io(
		.i_clk(i_clk),
		.i_reset(i_reset),

		.o_txd_data(txd_data),
		.o_txd_valid(txd_valid),
................................................................................
		.o_d_error(o_d_error),
		.o_d_valid(o_d_valid),
		.i_d_ready(i_d_ready),

		.o_irq(o_irq)
	);

endmodule;







>







 







|







 







|
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
...
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
...
148
149
150
151
152
153
154
155

	o_irq,

	i_rxd,
	o_txd
);
	parameter		DIVISOR_BITS = 20;
	parameter		DEFAULT_DIVISOR = 10415;
	parameter		DIVHB = DIVISOR_BITS - 1;

	input			i_clk;
	input			i_reset;

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

	always @(*)
	case(txd_loopback)
	2'b00:	o_txd = T_txd;
	2'b01:  o_txd = i_rxd;
	2'b10:  o_txd = 1'b0;
	2'b11:  o_txd = 1'b1;
	endcase

	sia_tilelink io(
		.i_clk(i_clk),
		.i_reset(i_reset),

		.o_txd_data(txd_data),
		.o_txd_valid(txd_valid),
................................................................................
		.o_d_error(o_d_error),
		.o_d_valid(o_d_valid),
		.i_d_ready(i_d_ready),

		.o_irq(o_irq)
	);

endmodule

Added cores/step-2-dmac-roma-sia-test/Makefile.























































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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

ifeq ($(shell bash -c 'type -p icoprog'),)
SSH_RASPI ?= ssh pi@raspi
else
SSH_RASPI ?= sh -c
endif

help:
	@echo
	@echo "make roma-sia-test.blif      run synthesis, generate BLIF netlist"
	@echo "make roma-sia-test.asc       run place and route, generate IceStorm ASCII file"
	@echo "make roma-sia-test.bin       run timing analysis, generate iCE40 BIN file"
	@echo
	@echo "make prog_sram         FPGA SRAM programming, (re)starts FPGA from SRAM"
	@echo "make prog_flash        serial flash programming, does not touch FPGA"
	@echo "make prog_erase        erase first flash block"
	@echo
	@echo "make reset_halt        stop FPGA and keep in reset"
	@echo "make reset_boot        (re)start FPGA from serial flash"
	@echo
	@echo "make clean             remove output files"
	@echo

.PHONY: roma-sia-test.lint
roma-sia-test.lint: roma-sia-test.v ../dmac/rtl/verilog/dmac.v ../roma/rtl/verilog/roma.v
	verilator --lint-only -y ../include/verilog roma-sia-test.v ../dmac/rtl/verilog/dmac.v ../roma/rtl/verilog/roma.v

roma-sia-test.blif: roma-sia-test.v oclkddr.v ../dmac/rtl/verilog/dmac.v ../roma/rtl/verilog/roma.v
	yosys \
	-p 'read_verilog -I../include/verilog roma-sia-test.v oclkddr.v ../roma/rtl/verilog/roma.v ../sia/rtl/verilog/sia.v ../sia/rtl/verilog/sia_tilelink/sia_tilelink.v ../sia/rtl/verilog/transmit_engine/transmit_engine.v ../sia/rtl/verilog/receiver_engine/receiver_engine.v' \
	-p 'synth_ice40 -blif roma-sia-test.blif -top top'

roma-sia-test.asc: roma-sia-test.blif icoboard.pcf
	arachne-pnr -m 4096 -d 8k -p icoboard.pcf -o roma-sia-test.asc roma-sia-test.blif

roma-sia-test.bin: roma-sia-test.asc
	icetime -d hx8k -c 25 roma-sia-test.asc
	icepack roma-sia-test.asc roma-sia-test.bin

prog_sram: roma-sia-test.bin
	$(SSH_RASPI) 'icoprog -p' < roma-sia-test.bin

prog_flash: roma-sia-test.bin
	$(SSH_RASPI) 'icoprog -f' < roma-sia-test.bin

prog_erase:
	$(SSH_RASPI) 'icoprog -e'

reset_halt:
	$(SSH_RASPI) 'icoprog -R'

reset_boot:
	$(SSH_RASPI) 'icoprog -b'

clean:
	rm roma-sia-test.blif roma-sia-test.asc roma-sia-test.bin

.PHONY: prog_sram prog_flash reset_halt reset_boot clean

Added cores/step-2-dmac-roma-sia-test/README.md.

































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
This core is an integration test between the SIA and the ROMA cores.

The "DMAC" boots up reading addresses sequentially from flash ROM,
starting at address 1MB and counting up from there, as fast as the SIA will allow it.
Each byte read will be stuffed into the SIA's TXOUT register,
where hopefully it'll appear somewhere on a host PC for testing.

The idea behind this integration test
is that the user generates a pre-made binary image which gets tacked onto the FPGA bitstream at offset 1MB.
That binary is then programmed into the flash.
If all goes well, the FPGA will boot from the flash, and will start reading the preprogrammed image.
The user should recognize the bit-stream being indicated out the PMOD port.

This integration test is manual in nature,
not automated.

Added cores/step-2-dmac-roma-sia-test/icoboard.pcf.

















>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
set_io --warn-no-port i_clk_100MHz R9
set_io --warn-no-port i_reset      K11
set_io --warn-no-port o_txd        C8

set_io --warn-no-port o_spi_mosi P12
set_io --warn-no-port i_spi_miso P11
set_io --warn-no-port o_spi_clk	 R11
set_io --warn-no-port o_spi_cs_n R12

Added cores/step-2-dmac-roma-sia-test/oclkddr.v.











































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
`default_nettype none

module oclkddr(i_clk, i_ddr, o_pin);
 input wire  i_clk;
 input wire [1:0] i_ddr;
 output wire  o_pin;

`ifdef SYNTHESIS
 SB_IO #(.PIN_TYPE(6'b0100_01)) oddr(
  .OUTPUT_CLK(i_clk),
  .CLOCK_ENABLE(1'b1),
  .D_OUT_0(i_ddr[0]),
  .D_OUT_1(i_ddr[1]),
  .OUTPUT_ENABLE(1),
  .PACKAGE_PIN(o_pin)
);
`else
  assign o_pin = i_clk ? i_ddr[0] : i_ddr[1];
`endif
endmodule

Added cores/step-2-dmac-roma-sia-test/roma-sia-test.v.



























































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
`default_nettype none

`include "tilelink.vh"

module top (
	i_clk_100MHz,
	i_reset,

	// Serial Interface (to PC)

	o_txd,

	// Flash ROM interface

	o_spi_mosi,
	i_spi_miso,
	o_spi_clk,
	o_spi_cs_n
);
	input wire i_reset;

	// The ROMA cannot be driven any faster than 50MHz.  Therefore,
	// we drive the whole system at 50MHz just to keep things simple.

	input wire i_clk_100MHz;
	reg clk_50MHz;

	always @(posedge i_clk_100MHz) begin
		clk_50MHz <= clk_50MHz;

		if(i_reset) begin
			clk_50MHz <= 0;
		end
		else begin
			clk_50MHz <= ~clk_50MHz;
		end
	end

	// Here's our make-shift DMA controller.
	//
	// The RP register (Read Pointer) is a 24-bit address counter.
	// It's used to read through the flash ROM byte by byte.
	
	wire increment_read_pointer;
	wire issue_rom_read;

	reg [23:0] read_pointer;

	always @(posedge clk_50MHz) begin
		if(i_reset) begin
			read_pointer <= 24'h100000;	// Start at 1MB mark
		end
		else if(increment_read_pointer) begin
			read_pointer <= read_pointer + 1;
		end
	end

	// Here's where we drive the ROMA's private A-channel with the
	// RP register.

	wire [2:0] roma_a_opcode = `A_OPC_GET;
	wire [20:0] roma_a_address; // actually a word address!
	assign roma_a_address = read_pointer[23:3];
	reg roma_a_valid;
	wire roma_a_ready;

	always @(posedge clk_50MHz) begin
		roma_a_valid <= 0;

		if(issue_rom_read) begin
			roma_a_valid <= 1;
		end
	end

	// Here's where we capture the data returned by the ROMA core.

	wire [63:0] roma_d_data;
	wire roma_d_valid;
	reg roma_d_ready;
	reg [7:0] fetched_byte;

	always @(posedge clk_50MHz) begin
		fetched_byte <= fetched_byte;
		roma_d_ready <= 0;

		if(read_rom_byte) begin
			roma_d_ready <= 1;
			if(roma_d_valid) begin
				case(read_pointer[2:0])
				0: fetched_byte <= roma_d_data[7:0];
				1: fetched_byte <= roma_d_data[15:8];
				2: fetched_byte <= roma_d_data[23:16];
				3: fetched_byte <= roma_d_data[31:23];
				4: fetched_byte <= roma_d_data[39:32];
				5: fetched_byte <= roma_d_data[47:40];
				6: fetched_byte <= roma_d_data[55:48];
				7: fetched_byte <= roma_d_data[63:56];
				endcase
			end
		end
	end

	// When writing to the SIA, we always write to the TXOUT
	// register.  Everything else is assumed to be default.
	// As I write this, this means no loopback, and 9600bps 8N1.

	reg sia_a_valid;
	wire sia_a_ready;
	wire sia_d_valid;
	wire sia_d_ready = wait_sia_ack;

	always @(posedge clk_50MHz) begin
		sia_a_valid <= 0;

		if(issue_sia_write) begin
			sia_a_valid <= 1;
		end
	end


	// Here's our state machine to drive the DMAC loop.
	
	reg [2:0] state;

	always @(posedge clk_50MHz) begin
		state <= state;

		if(i_reset) begin
			state <= 0;
		end
		else if(goto_1) begin
			state <= 1;
		end
		else if(issue_rom_read && roma_a_ready) begin
			state <= 2;
		end
		else if(read_rom_byte && roma_d_valid) begin
			state <= 3;
		end
		else if(issue_sia_write && sia_a_ready) begin
			state <= 4;
		end
		else if(wait_sia_ack && sia_d_valid) begin
			state <= 5;
		end
		else begin
			state <= 1;
		end
	end

	wire issue_rom_read;
	wire increment_read_pointer;
	wire read_rom_byte;
	wire issue_sia_write;
	wire wait_sia_ack;
	wire goto_1;

        assign issue_rom_read = (state == 1);
	assign increment_read_pointer = (state == 2);
	assign read_rom_byte = (state == 2);
	assign issue_sia_write = (state == 3);
	assign wait_sia_ack = (state == 4);
	assign goto_1 = (state == 5);

	// The ROMA core interfaces to the flash ROM on the icoBoard Gamma.

	wire flash_clk;
	wire flash_cs;

	output wire o_spi_mosi;
	input wire i_spi_miso;
	output wire o_spi_cs_n;
	output wire o_spi_clk;

	roma ROMA(
		.i_clk(clk_50MHz),
		.i_reset(i_reset),

		.i_a_opcode(roma_a_opcode),
		.i_a_address(roma_a_address),
		.i_a_source(2'd0),
		.i_a_valid(roma_a_valid),
		.o_a_ready(roma_a_ready),

		.o_d_opcode(),
		.o_d_data(roma_d_data),
		.o_d_size(),
		.o_d_source(),
		.o_d_valid(roma_d_valid),
		.i_d_ready(roma_d_ready),

		.o_spi_mosi(o_spi_mosi),
		.i_spi_miso(i_spi_miso),
		.o_spi_clk(flash_clk),
		.o_spi_cs(flash_cs)
	);

	oclkddr spi_ddr_clk(
		.i_clk(clk_50MHz),
		.i_ddr({1'b1, o_spi_cs_n}),
		.o_pin(o_spi_clk)
	);

	assign o_spi_cs_n = ~flash_cs;

	// The SIA core interfaces to the host PC.

	output wire o_txd;

	sia SIA(
		.i_clk(clk_50MHz),
		.i_reset(i_reset),

		.i_a_opcode(`A_OPC_PUT_FULL),
		.i_a_source(2'd0),
		.i_a_size(`A_SIZ_BYTE),
		.i_a_mask(8'h01),
		.i_a_data({56'd0, fetched_byte}),
		.i_a_valid(sia_a_valid),
		.o_a_ready(sia_a_ready),

		.o_d_opcode(),
		.o_d_size(),
		.o_d_source(),
		.o_d_data(),
		.o_d_param(),
		.o_d_error(),
		.o_d_valid(sia_d_valid),
		.i_d_ready(sia_d_ready),

		.o_irq(),

		.i_rxd(1'b1),
		.o_txd(o_txd)
	);

endmodule