Project

General

Profile

Download (66.9 KB) Statistics
| Branch: | Tag: | Revision:
1
-------------------------------------------------------------------------------
2
--| @file util.vhd
3
--| @brief A collection of utilities and simple components. The components
4
--| should be synthesizable, and the functions can be used within synthesizable
5
--| components, unless marked with a "_tb" suffix (or is the function n_bits).
6
--| @author         Richard James Howe
7
--| @copyright      Copyright 2017 Richard James Howe
8
--| @license        MIT
9
--| @email          howe.r.j.89@gmail.com
10
-------------------------------------------------------------------------------
11
library ieee;
12
use ieee.std_logic_1164.all;
13
use ieee.numeric_std.all;
14
use std.textio.all;
15

    
16
package util is
17
	component util_tb is
18
		generic(clock_frequency: positive);
19
	end component;
20

    
21
	component clock_source_tb is
22
		generic(clock_frequency: positive; hold_rst: positive := 1);
23
		port(
24
			stop:            in     std_ulogic := '0';
25
			clk:             buffer std_ulogic;
26
			clk_with_jitter: out    std_ulogic := '0';
27
			rst:             out    std_ulogic := '0');
28
	end component;
29

    
30
	component reg
31
		generic(N: positive);
32
		port(
33
			clk: in  std_ulogic;
34
			rst: in  std_ulogic;
35
			we:  in  std_ulogic;
36
			di:  in  std_ulogic_vector(N - 1 downto 0);
37
			do:  out std_ulogic_vector(N - 1 downto 0));
38
	end component;
39

    
40
	component shift_register
41
		generic(N: positive);
42
		port(
43
			clk:     in  std_ulogic;
44
			rst:     in  std_ulogic;
45
			we:      in  std_ulogic;
46
			di:      in  std_ulogic;
47
			do:      out std_ulogic;
48

    
49
			-- optional
50
			load_we: in  std_ulogic := '0';
51
			load_i:  in  std_ulogic_vector(N - 1 downto 0) := (others => '0');
52
			load_o:  out std_ulogic_vector(N - 1 downto 0));
53
	end component;
54

    
55
	component shift_register_tb
56
		generic(clock_frequency: positive);
57
	end component;
58

    
59
	component timer_us
60
		generic(clock_frequency: positive; timer_period_us: natural);
61
		port(
62
			clk: in  std_ulogic;
63
			rst: in  std_ulogic;
64
			co:  out std_ulogic);
65
	end component;
66

    
67
	component timer_us_tb
68
		generic(clock_frequency: positive);
69
	end component;
70

    
71
	component rising_edge_detector is
72
	port(
73
		clk:    in  std_ulogic;
74
		rst:    in  std_ulogic;
75
		di:     in  std_ulogic;
76
       		do:     out std_ulogic);
77
	end component;
78

    
79
	component rising_edge_detector_tb is
80
		generic(clock_frequency: positive);
81
	end component;
82

    
83
	component rising_edge_detectors is
84
	generic(N: positive);
85
	port(
86
		clk:    in  std_ulogic;
87
		rst:    in  std_ulogic;
88
		di:     in  std_ulogic_vector(N - 1 downto 0);
89
       		do:     out std_ulogic_vector(N - 1 downto 0));
90
	end component;
91

    
92

    
93
	-- @note half_adder test bench is folded in to full_adder_tb
94
	component half_adder is
95
		port(
96
			a:     in  std_ulogic;
97
			b:     in  std_ulogic;
98
			sum:   out std_ulogic;
99
			carry: out std_ulogic);
100
	end component;
101

    
102
	component full_adder is
103
		port(
104
			x:     in    std_ulogic;
105
			y:     in    std_ulogic;
106
			z:     in    std_ulogic;
107
			sum:   out   std_ulogic;
108
			carry: out   std_ulogic);
109
	end component;
110

    
111
	component full_adder_tb is
112
		generic(clock_frequency: positive);
113
	end component;
114

    
115
	component fifo is
116
		generic (data_width: positive;
117
			fifo_depth: positive);
118
		port (
119
			clk:   in  std_ulogic;
120
			rst:   in  std_ulogic;
121
			di:    in  std_ulogic_vector(data_width - 1 downto 0);
122
			we:    in  std_ulogic;
123
			re:    in  std_ulogic;
124
			do:    out std_ulogic_vector(data_width - 1 downto 0);
125

    
126
			-- optional
127
			full:  out std_ulogic := '0';
128
			empty: out std_ulogic := '1');
129
	end component;
130

    
131
	component fifo_tb is
132
		generic(clock_frequency: positive);
133
	end component;
134

    
135
	component counter is
136
		generic(
137
			N: positive);
138
		port(
139
			clk:     in  std_ulogic;
140
			rst:     in  std_ulogic;
141
			ce:      in  std_ulogic;
142
			cr:      in  std_ulogic;
143
			dout:    out std_ulogic_vector(N - 1 downto 0);
144

    
145
			-- optional
146
			load_we: in  std_ulogic := '0';
147
			load_i:  in  std_ulogic_vector(N - 1 downto 0) := (others => '0'));
148
	end component;
149

    
150
	component counter_tb is
151
		generic(clock_frequency: positive);
152
	end component;
153

    
154
	component lfsr is
155
		generic(constant tap: std_ulogic_vector);
156
		port
157
		(
158
			clk: in  std_ulogic;
159
			rst: in  std_ulogic;
160
			ce:  in  std_ulogic := '1';
161
			we:  in  std_ulogic;
162
			di:  in  std_ulogic_vector(tap'high + 1 to tap'low);
163
			do:  out std_ulogic_vector(tap'high + 1 to tap'low));
164
	end component;
165

    
166
	component lfsr_tb is
167
		generic(clock_frequency: positive);
168
	end component;
169

    
170
	component io_pins is
171
		generic(
172
			N: positive);
173
		port
174
		(
175
			clk:         in    std_ulogic;
176
			rst:         in    std_ulogic;
177
			control:     in    std_ulogic_vector(N - 1 downto 0);
178
			control_we:  in    std_ulogic;
179
			din:         in    std_ulogic_vector(N - 1 downto 0);
180
			din_we:      in    std_ulogic;
181
			dout:        out   std_ulogic_vector(N - 1 downto 0);
182
			pins:        inout std_logic_vector(N - 1 downto 0));
183
	end component;
184

    
185
	component io_pins_tb is
186
		generic(clock_frequency: positive);
187
	end component;
188

    
189
	type file_format is (FILE_HEX, FILE_BINARY, FILE_NONE);
190

    
191
	component dual_port_block_ram is
192
	generic(addr_length: positive    := 12;
193
		data_length: positive    := 16;
194
		file_name:   string      := "memory.bin";
195
		file_type:   file_format := FILE_BINARY);
196
	port(
197
		-- port A of dual port RAM
198
		a_clk:  in  std_ulogic;
199
		a_dwe:  in  std_ulogic;
200
		a_dre:  in  std_ulogic;
201
		a_addr: in  std_ulogic_vector(addr_length - 1 downto 0);
202
		a_din:  in  std_ulogic_vector(data_length - 1 downto 0);
203
		a_dout: out std_ulogic_vector(data_length - 1 downto 0) := (others => '0');
204
		-- port B of dual port RAM
205
		b_clk:  in  std_ulogic;
206
		b_dwe:  in  std_ulogic;
207
		b_dre:  in  std_ulogic;
208
		b_addr: in  std_ulogic_vector(addr_length - 1 downto 0);
209
		b_din:  in  std_ulogic_vector(data_length - 1 downto 0);
210
		b_dout: out std_ulogic_vector(data_length - 1 downto 0) := (others => '0'));
211
	end component;
212

    
213
	component single_port_block_ram is
214
	generic(addr_length: positive    := 12;
215
		data_length: positive    := 16;
216
		file_name:   string      := "memory.bin";
217
		file_type:   file_format := FILE_BINARY);
218
	port(
219
		clk:  in  std_ulogic;
220
		dwe:  in  std_ulogic;
221
		dre:  in  std_ulogic;
222
		addr: in  std_ulogic_vector(addr_length - 1 downto 0);
223
		din:  in  std_ulogic_vector(data_length - 1 downto 0);
224
		dout: out std_ulogic_vector(data_length - 1 downto 0) := (others => '0'));
225
	end component;
226

    
227
	component data_source is
228
		generic(addr_length: positive    := 12;
229
			data_length: positive    := 16;
230
			file_name:   string      := "memory.bin";
231
			file_type:   file_format := FILE_BINARY);
232
		port(
233
			clk:     in  std_ulogic;
234
			rst:     in  std_ulogic;
235

    
236
			ce:      in  std_ulogic := '1';
237
			cr:      in  std_ulogic;
238

    
239
			load:    in  std_ulogic_vector(addr_length - 1 downto 0) := (others => '0');
240
			load_we: in  std_ulogic := '0';
241

    
242
			dout:    out std_ulogic_vector(data_length - 1 downto 0));
243
	end component;
244

    
245
	component ucpu is
246
		generic(width: positive range 8 to 32 := 8);
247
		port(
248
			clk, rst: in  std_ulogic;
249

    
250
			pc:       out std_ulogic_vector(width - 3 downto 0);
251
			op:       in  std_ulogic_vector(width - 1 downto 0);
252

    
253
			adr:      out std_ulogic_vector(width - 3 downto 0);
254
			di:       in  std_ulogic_vector(width - 1 downto 0);
255
			re, we:   out std_ulogic;
256
			do:       out std_ulogic_vector(width - 1 downto 0));
257
	end component;
258

    
259
	component ucpu_tb is
260
		generic(
261
			clock_frequency: positive;
262
			file_name: string := "ucpu.bin");
263
	end component;
264

    
265
	component restoring_divider is
266
		generic(N: positive);
267
		port(
268
			clk:   in  std_ulogic;
269
			rst:   in  std_ulogic := '0';
270

    
271
			a:     in  std_ulogic_vector(N - 1 downto 0);
272
			b:     in  std_ulogic_vector(N - 1 downto 0);
273
			start: in  std_ulogic;
274
			done:  out std_ulogic;
275
			c:     out std_ulogic_vector(N - 1 downto 0));
276
	end component;
277

    
278
	component restoring_divider_tb is
279
		generic(clock_frequency: positive);
280
	end component;
281

    
282
	component debounce_us is
283
		generic(clock_frequency: positive; timer_period_us: natural);
284
		port(
285
			clk:   in  std_ulogic;
286
			di:    in  std_ulogic;
287
			do:    out std_ulogic);
288
	end component;
289

    
290
	component debounce_block_us is
291
		generic(N: positive; clock_frequency: positive; timer_period_us: natural);
292
		port(
293
			clk:   in  std_ulogic;
294
			di:    in  std_ulogic_vector(N - 1 downto 0);
295
			do:    out std_ulogic_vector(N - 1 downto 0));
296
	end component;
297

    
298
	component debounce_us_tb is
299
		generic(clock_frequency: positive);
300
	end component;
301

    
302
	component state_changed is
303
		port(
304
			clk: in  std_ulogic;
305
			rst: in  std_ulogic;
306
			di:  in  std_ulogic;
307
			do:  out std_ulogic);
308
	end component;
309

    
310
	component state_block_changed is
311
		generic(N: positive);
312
		port(
313
			clk: in  std_ulogic;
314
			rst: in  std_ulogic;
315
			di:  in  std_ulogic_vector(N - 1 downto 0);
316
			do:  out std_ulogic_vector(N - 1 downto 0));
317
	end component;
318

    
319
	function max(a: natural; b: natural) return natural;
320
	function min(a: natural; b: natural) return natural;
321
	function n_bits(x: natural) return natural;
322
	function n_bits(x: std_ulogic_vector) return natural;
323
	function reverse (a: in std_ulogic_vector) return std_ulogic_vector;
324
	function invert(slv:std_ulogic_vector) return std_ulogic_vector;
325
	function parity(slv:std_ulogic_vector; even: boolean) return std_ulogic;
326
	function select_bit(indexed, selector: std_ulogic_vector) return std_ulogic;
327
	function priority(order: std_ulogic_vector; high: boolean) return natural;
328
	function priority(order: std_ulogic_vector; high: boolean) return std_ulogic_vector;
329
	function mux(a: std_ulogic_vector; b: std_ulogic_vector; sel: std_ulogic) return std_ulogic_vector;
330
	function mux(a: std_ulogic; b: std_ulogic; sel: std_ulogic) return std_ulogic;
331
	function mux(a, b : std_ulogic_vector) return std_ulogic;
332
	function decode(encoded: std_ulogic_vector) return std_ulogic_vector;
333
	function hex_char_to_std_ulogic_vector(hc: character) return std_ulogic_vector;
334
	function to_std_ulogic_vector(s: string) return std_ulogic_vector;
335

    
336
	type ulogic_string is array(integer range <>) of std_ulogic_vector(7 downto 0);
337
  	function to_std_ulogic_vector(s: string) return ulogic_string;
338

    
339
	--- Not synthesizable ---
340

    
341
	subtype configuration_name is string(1 to 8);
342

    
343
	type configuration_item is record
344
		name:  configuration_name;
345
		value: integer;
346
	end record;
347

    
348
	type configuration_items is array(integer range <>) of configuration_item;
349

    
350
	function search_configuration_tb(find_me: configuration_name; ci: configuration_items) return integer;
351
	procedure read_configuration_tb(file_name:  string; ci: inout configuration_items);
352
	procedure write_configuration_tb(file_name: string; ci: configuration_items);
353

    
354
end;
355

    
356
package body util is
357

    
358
	function max(a: natural; b: natural) return natural is
359
	begin
360
		if (a > b) then return a; else return b; end if;
361
	end function;
362

    
363
	function min(a: natural; b: natural) return natural is
364
	begin
365
		if (a < b) then return a; else return b; end if;
366
	end function;
367

    
368
	function n_bits(x: natural) return natural is
369
		variable x1: natural := max(x, 1) - 1;
370
		variable n:  natural := 1;
371
	begin
372
		while x1 > 1 loop
373
			x1 := x1 / 2;
374
			n  := n + 1;
375
		end loop;
376
		return n;
377
	end function;
378

    
379
	function n_bits(x: std_ulogic_vector) return natural is
380
	begin
381
		return n_bits(x'high);
382
	end function;
383

    
384
	-- https://stackoverflow.com/questions/13584307
385
	function reverse (a: in std_ulogic_vector) return std_ulogic_vector is
386
		variable result: std_ulogic_vector(a'range);
387
		alias aa: std_ulogic_vector(a'reverse_range) is a;
388
	begin
389
		for i in aa'range loop
390
			result(i) := aa(i);
391
		end loop;
392
		return result;
393
	end;
394

    
395
	function invert(slv: std_ulogic_vector) return std_ulogic_vector is
396
		variable z: std_ulogic_vector(slv'range);
397
	begin
398
		for i in slv'range loop
399
			z(i) := not(slv(i));
400
		end loop;
401
		return z;
402
	end;
403

    
404
	function parity(slv: std_ulogic_vector; even: boolean) return std_ulogic is
405
		variable z: std_ulogic := '0';
406
	begin
407
		if not even then
408
			z := '1';
409
		end if;
410
		for i in slv'range loop
411
			z := z xor slv(i);
412
		end loop;
413
		return z;
414
	end;
415

    
416
	function select_bit(indexed, selector: std_ulogic_vector) return std_ulogic is
417
		variable z: std_ulogic := 'X';
418
	begin
419
		assert n_bits(indexed) = selector'high + 1 severity failure;
420
		for i in indexed'range loop
421
			if i = to_integer(unsigned(selector)) then
422
				z := indexed(i);
423
			end if;
424
		end loop;
425
		return z;
426
	end;
427

    
428
	function priority(order: std_ulogic_vector; high: boolean) return natural is
429
		variable p: natural := 0;
430
	begin
431
		if not high then
432
			for i in order'high + 1 downto 1 loop
433
				if order(i-1) = '1' then
434
					p := i - 1;
435
				end if;
436
			end loop;
437
		else
438
			for i in 1 to order'high + 1 loop
439
				if order(i-1) = '1' then
440
					p := i - 1;
441
				end if;
442
			end loop;
443
		end if;
444
		return p;
445
	end;
446

    
447
	function priority(order: std_ulogic_vector; high: boolean) return std_ulogic_vector is
448
		variable length: natural := n_bits(order'length);
449
	begin
450
		return std_ulogic_vector(to_unsigned(priority(order, high), length));
451
	end;
452

    
453
	function mux(a: std_ulogic_vector; b: std_ulogic_vector; sel: std_ulogic) return std_ulogic_vector is
454
		variable m: std_ulogic_vector(a'range) := (others => 'X');
455
	begin
456
		if sel = '0' then m := a; else m := b; end if;
457
		return m;
458
	end;
459

    
460
	function mux(a: std_ulogic; b: std_ulogic; sel: std_ulogic) return std_ulogic is
461
		variable m: std_ulogic := 'X';
462
	begin
463
		if sel = '0' then m := a; else m := b; end if;
464
		return m;
465
	end;
466

    
467
	function mux(a, b : std_ulogic_vector) return std_ulogic is
468
		variable r: std_ulogic_vector(b'length - 1 downto 0) := (others => 'X');
469
		variable i: integer;
470
	begin
471
		r := b;
472
		i := to_integer(unsigned(a));
473
		return r(i);
474
	end;
475

    
476
	function decode(encoded : std_ulogic_vector) return std_ulogic_vector is
477
		variable r: std_ulogic_vector((2 ** encoded'length) - 1 downto 0) := (others => '0');
478
		variable i: natural;
479
	begin
480
		i    := to_integer(unsigned(encoded));
481
		r(i) := '1';
482
		return r;
483
	end;
484

    
485
	function hex_char_to_std_ulogic_vector(hc: character) return std_ulogic_vector is
486
		variable slv: std_ulogic_vector(3 downto 0);
487
	begin
488
		case hc is
489
		when '0' => slv := "0000";
490
		when '1' => slv := "0001";
491
		when '2' => slv := "0010";
492
		when '3' => slv := "0011";
493
		when '4' => slv := "0100";
494
		when '5' => slv := "0101";
495
		when '6' => slv := "0110";
496
		when '7' => slv := "0111";
497
		when '8' => slv := "1000";
498
		when '9' => slv := "1001";
499
		when 'A' => slv := "1010";
500
		when 'a' => slv := "1010";
501
		when 'B' => slv := "1011";
502
		when 'b' => slv := "1011";
503
		when 'C' => slv := "1100";
504
		when 'c' => slv := "1100";
505
		when 'D' => slv := "1101";
506
		when 'd' => slv := "1101";
507
		when 'E' => slv := "1110";
508
		when 'e' => slv := "1110";
509
		when 'F' => slv := "1111";
510
		when 'f' => slv := "1111";
511
		when others => slv := "XXXX";
512
		end case;
513
		assert (slv /= "XXXX") report " not a valid hex character: " & hc  severity failure;
514
		return slv;
515
	end;
516

    
517
	-- <https://stackoverflow.com/questions/30519849/vhdl-convert-string-to-std-logic-vector>
518
	function to_std_ulogic_vector(s: string) return std_ulogic_vector is
519
	    variable ret: std_ulogic_vector(s'length*8-1 downto 0);
520
	begin
521
	    for i in s'range loop
522
		ret(i*8+7 downto i*8) := std_ulogic_vector(to_unsigned(character'pos(s(i)), 8));
523
	    end loop;
524
	    return ret;
525
	end;
526

    
527
	function to_std_ulogic_vector(s: string) return ulogic_string is
528
	    variable ret: ulogic_string(s'range);
529
	begin
530
		for i in s'range loop
531
			ret(i) := std_ulogic_vector(to_unsigned(character'pos(s(i)), 8));
532
		end loop;
533
		return ret;
534
	end;
535

    
536
	--- Not synthesizable ---
537

    
538
	-- Find a string in a configuration items array, or returns -1 on
539
	-- failure to find the string.
540
	function search_configuration_tb(find_me: configuration_name; ci: configuration_items) return integer is
541
	begin
542
		for i in ci'range loop
543
			if ci(i).name = find_me then
544
				return i;
545
			end if;
546
		end loop;
547
		return -1;
548
	end;
549

    
550
	-- VHDL provides quite a limited set of options for dealing with
551
	-- operations that are not synthesizeable but would be useful for
552
	-- in test benches. This method provides a crude way of reading
553
	-- in configurable options. It has a very strict format.
554
	--
555
	-- The format is line oriented, it expects a string on a line
556
	-- with a length equal to the "configuration_name" type, which
557
	-- is a subtype of "string". It finds the corresponding record
558
	-- in configuration_items if it exists. It then reads in an
559
	-- integer from the next line and sets the record for it.
560
	--
561
	-- Any deviation from this format causes an error and the simulation
562
	-- to halt, whilst not a good practice to do error checking with asserts
563
	-- there is no better way in VHDL in this case. The only sensible
564
	-- action on an error would for the configuration file to be fixed
565
	-- anyway.
566
	--
567
	-- Comment lines and variable length strings would be nice, but
568
	-- are too much of a hassle.
569
	--
570
	-- The configuration function only deal with part of the configuration
571
	-- process, it does not deal with deserialization into structures
572
	-- more useful to the user - like into individual signals.
573
	--
574
	procedure read_configuration_tb(file_name: string; ci: inout configuration_items) is
575
		file     in_file: text is in file_name;
576
		variable in_line: line;
577
		variable d:       integer;
578
		variable s:       configuration_name;
579
		variable index:   integer;
580
	begin
581
		while not endfile(in_file) loop
582

    
583
			readline(in_file, in_line);
584
			read(in_line, s);
585
			index := search_configuration_tb(s, ci);
586

    
587
			assert index >= 0 report "Unknown configuration item: " & s severity failure;
588

    
589
			readline(in_file, in_line);
590
			read(in_line, d);
591

    
592
			ci(index).value := d;
593

    
594
			report "Config Item: '" & ci(index).name & "' = " & integer'image(ci(index).value);
595
		end loop;
596
		file_close(in_file);
597
	end procedure;
598

    
599
	procedure write_configuration_tb(file_name: string; ci: configuration_items) is
600
		file     out_file: text is out file_name;
601
		variable out_line: line;
602
	begin
603
		for i in ci'range loop
604
			write(out_line, ci(i).name);
605
			writeline(out_file, out_line);
606
			write(out_line, ci(i).value);
607
			writeline(out_file, out_line);
608
		end loop;
609
	end procedure;
610

    
611
end;
612

    
613
------------------------- Utility Test Bench ----------------------------------------
614
library ieee;
615
use ieee.std_logic_1164.all;
616
use work.util.all;
617

    
618
entity util_tb is
619
	generic(clock_frequency: positive);
620
end entity;
621

    
622
architecture behav of util_tb is
623
begin
624
	uut_shiftReg: work.util.shift_register_tb    generic map(clock_frequency => clock_frequency);
625
	uut_timer_us: work.util.timer_us_tb          generic map(clock_frequency => clock_frequency);
626
	uut_full_add: work.util.full_adder_tb        generic map(clock_frequency => clock_frequency);
627
	uut_fifo:     work.util.fifo_tb              generic map(clock_frequency => clock_frequency);
628
	uut_counter:  work.util.counter_tb           generic map(clock_frequency => clock_frequency);
629
	uut_lfsr:     work.util.lfsr_tb              generic map(clock_frequency => clock_frequency);
630
	uut_ucpu:     work.util.ucpu_tb              generic map(clock_frequency => clock_frequency);
631
	uut_rdivider: work.util.restoring_divider_tb generic map(clock_frequency => clock_frequency);
632
	uut_debounce: work.util.debounce_us_tb       generic map(clock_frequency => clock_frequency);
633
	uut_rising_edge_detector: work.util.rising_edge_detector_tb generic map(clock_frequency => clock_frequency);
634

    
635
	stimulus_process: process
636
	begin
637
		assert max(5, 4)                 =  5      severity failure;
638
		assert work.util.min(5, 4)       =  4      severity failure;
639
		assert n_bits(1)                 =  1      severity failure;
640
		assert n_bits(2)                 =  1      severity failure;
641
		assert n_bits(7)                 =  3      severity failure;
642
		assert n_bits(8)                 =  3      severity failure;
643
		assert n_bits(9)                 =  4      severity failure;
644
		assert reverse("1")              =  "1"    severity failure;
645
		assert reverse("0")              =  "0"    severity failure;
646
		assert reverse("10")             =  "01"   severity failure;
647
		assert reverse("11")             =  "11"   severity failure;
648
		assert reverse("0101")           =  "1010" severity failure;
649
		assert invert("1")               =  "0"    severity failure;
650
		assert invert("0")               =  "1"    severity failure;
651
		assert invert("0101")            =  "1010" severity failure;
652
		assert select_bit("01000", "01") =  '1'    severity failure;
653
		assert parity("0", true)         =  '0'    severity failure;
654
		assert parity("1", true)         =  '1'    severity failure;
655
		assert parity("11", true)        =  '0'    severity failure;
656
		assert parity("1010001", true)   =  '1'    severity failure;
657
		assert parity("0", false)        =  '1'    severity failure;
658
		assert parity("1", false)        =  '0'    severity failure;
659
		assert parity("11", false)       =  '1'    severity failure;
660
		assert parity("1010001", false)  =  '0'    severity failure;
661
		assert priority("01001", false)  =  1      severity failure;
662
		assert mux("1010", "0101", '0')  =  "1010" severity failure;
663
		assert mux("1010", "0101", '1')  =  "0101" severity failure;
664
		assert decode("00")              =  "0001" severity failure;
665
		assert decode("01")              =  "0010" severity failure;
666
		assert decode("10")              =  "0100" severity failure;
667
		assert decode("11")              =  "1000" severity failure;
668
		-- n_bits(x: std_ulogic_vector) return natural;
669
		-- mux(a, b : std_ulogic_vector) return std_ulogic;
670
		wait;
671
	end process;
672
end architecture;
673

    
674
------------------------- Function Test Bench ---------------------------------------
675

    
676
------------------------- Test bench clock source -----------------------------------
677

    
678
library ieee;
679
use ieee.std_logic_1164.all;
680
use ieee.numeric_std.all;
681
use ieee.math_real.all;
682

    
683
entity clock_source_tb is
684
	generic(clock_frequency: positive; hold_rst: positive := 1);
685
	port(
686
		stop:            in     std_ulogic := '0';
687
		clk:             buffer std_ulogic;
688
		clk_with_jitter: out    std_ulogic := '0';
689
		rst:             out    std_ulogic := '0');
690
end entity;
691

    
692
architecture rtl of clock_source_tb is
693
	constant clock_period: time      :=  1000 ms / clock_frequency;
694
	signal jitter_delay:   time      := 0 ns;
695
	signal jitter_clk:     std_ulogic := '0';
696
begin
697
	clk_process: process
698
		variable seed1, seed2 : positive;
699
		variable r : real;
700
	begin
701
		while stop = '0' loop
702
			uniform(seed1, seed2, r);
703
			jitter_delay <= r * 1 ns;
704

    
705
			clk <= '1';
706
			wait for clock_period / 2;
707
			clk <= '0';
708
			wait for clock_period / 2;
709
		end loop;
710
		wait;
711
	end process;
712

    
713
	clk_with_jitter <= transport clk after jitter_delay;
714

    
715
	rst_process: process
716
	begin
717
		rst <= '1';
718
		wait for clock_period * hold_rst;
719
		rst <= '0';
720
		wait;
721
	end process;
722

    
723
end architecture;
724

    
725
------------------------- Generic Register of std_ulogic_vector ----------------------
726

    
727
library ieee;
728
use ieee.std_logic_1164.all;
729
use ieee.numeric_std.all;
730

    
731
entity reg is
732
	generic(
733
		N: positive);
734
	port
735
	(
736
		clk: in  std_ulogic;
737
		rst: in  std_ulogic;
738
		we:  in  std_ulogic;
739
		di:  in  std_ulogic_vector(N - 1 downto 0);
740
		do:  out std_ulogic_vector(N - 1 downto 0));
741
end entity;
742

    
743
architecture rtl of reg is
744
	signal r_c, r_n: std_ulogic_vector(N - 1 downto 0) := (others => '0');
745
begin
746
	do <= r_c;
747

    
748
	process(rst, clk)
749
	begin
750
		if rst = '1' then
751
			r_c <= (others => '0');
752
		elsif rising_edge(clk) then
753
			r_c <= r_n;
754
		end if;
755
	end process;
756

    
757
	process(r_c, di, we)
758
	begin
759
		r_n <= r_c;
760
		if we = '1' then
761
			r_n <= di;
762
		end if;
763
	end process;
764
end;
765

    
766
------------------------- Generic Register of std_ulogic_vector ----------------------
767

    
768
------------------------- Shift register --------------------------------------------
769
library ieee;
770
use ieee.std_logic_1164.all;
771
use ieee.numeric_std.all;
772

    
773
-- https://stackoverflow.com/questions/36342960/optional-ports-in-vhdl
774
entity shift_register is
775
	generic(N: positive);
776
	port
777
	(
778
		clk:     in  std_ulogic;
779
		rst:     in  std_ulogic;
780
		we:      in  std_ulogic;
781
		di:      in  std_ulogic;
782
		do:      out std_ulogic;
783

    
784
		load_we: in  std_ulogic := '0';
785
		load_i:  in  std_ulogic_vector(N - 1 downto 0) := (others => '0');
786
		load_o:  out std_ulogic_vector(N - 1 downto 0));
787
end entity;
788

    
789
architecture rtl of shift_register is
790
	signal r_c, r_n : std_ulogic_vector(N - 1 downto 0) := (others => '0');
791
begin
792
	do     <= r_c(0);
793
	load_o <= r_c;
794

    
795
	process(rst, clk)
796
	begin
797
		if rst = '1' then
798
			r_c <= (others => '0');
799
		elsif rising_edge(clk) then
800
			r_c <= r_n;
801
		end if;
802
	end process;
803

    
804
	process(r_c, di, we, load_i, load_we)
805
	begin
806
		if load_we = '1' then
807
			r_n <= load_i;
808
		else
809
			r_n <= "0" & r_c(N - 1 downto 1);
810
			if we = '1' then
811
				r_n(N-1) <= di;
812
			end if;
813
		end if;
814
	end process;
815
end;
816

    
817
library ieee;
818
use ieee.std_logic_1164.all;
819
use ieee.numeric_std.all;
820

    
821
entity shift_register_tb is
822
	generic(clock_frequency: positive);
823
end entity;
824

    
825
architecture behav of shift_register_tb is
826
	constant N: positive := 8;
827
	constant clock_period: time :=  1000 ms / clock_frequency;
828
	signal we: std_ulogic := '0';
829
	signal di: std_ulogic := '0';
830
	signal do: std_ulogic := '0';
831

    
832
	signal clk, rst: std_ulogic := '0';
833
	signal stop: std_ulogic := '0';
834
begin
835
	cs: entity work.clock_source_tb
836
		generic map(clock_frequency => clock_frequency, hold_rst => 2)
837
		port map(stop => stop, clk => clk, rst => rst);
838

    
839
	uut: entity work.shift_register
840
	generic map(N => N) port map(clk => clk, rst => rst, we => we, di => di, do => do);
841

    
842
	stimulus_process: process
843
	begin
844
		-- put a bit into the shift register and wait
845
		-- for it to come out the other size
846
		wait until rst = '0';
847
		di <= '1';
848
		we <= '1';
849
		wait for clock_period;
850
		di <= '0';
851
		we <= '0';
852
		for I in 0 to 7 loop
853
			assert do = '0' report "bit appeared to quickly";
854
			wait for clock_period;
855
		end loop;
856
		assert do = '1' report "bit disappeared in shift register";
857
		wait for clock_period * 1;
858
		assert do = '0' report "extra bit set in shift register";
859
		stop <= '1';
860
		wait;
861
	end process;
862
end;
863
------------------------- Shift register --------------------------------------------
864

    
865
------------------------- Microsecond Timer -----------------------------------------
866
library ieee;
867
use ieee.std_logic_1164.all;
868
use ieee.numeric_std.all;
869
use work.util.max;
870
use work.util.n_bits;
871

    
872
entity timer_us is
873
	generic(
874
		clock_frequency: positive;
875
		timer_period_us: positive := 1);
876
	port(
877
		clk:  in std_ulogic := 'X';
878
		rst:  in std_ulogic := 'X';
879
		co:  out std_ulogic := '0');
880
end timer_us;
881

    
882
architecture rtl of timer_us is
883
	constant cycles:   natural := (clock_frequency / 1000000) * timer_period_us;
884
	subtype  counter is unsigned(max(1, n_bits(cycles) - 1) downto 0);
885
	signal   c_c, c_n: counter := (others => '0');
886
begin
887
	process (clk, rst)
888
	begin
889
		if rst = '1' then
890
			c_c <= (others => '0');
891
		elsif rising_edge(clk) then
892
			c_c <= c_n;
893
		end if;
894
	end process;
895

    
896
	process (c_c)
897
	begin
898
		if c_c = (cycles - 1) then
899
			c_n <= (others => '0');
900
			co  <= '1';
901
		else
902
			c_n <= c_c + 1;
903
			co  <= '0';
904
		end if;
905
	end process;
906
end;
907

    
908
library ieee;
909
use ieee.std_logic_1164.all;
910
use ieee.numeric_std.all;
911

    
912
entity timer_us_tb is
913
	generic(clock_frequency: positive);
914
end;
915

    
916
architecture behav of timer_us_tb is
917
	constant clock_period: time := 1000 ms / clock_frequency;
918
	signal co: std_ulogic        := 'X';
919
	signal clk, rst: std_ulogic  := '0';
920
	signal stop: std_ulogic      := '0';
921
begin
922
	cs: entity work.clock_source_tb
923
		generic map(clock_frequency => clock_frequency, hold_rst => 2)
924
		port map(stop => stop, clk => clk, rst => rst);
925

    
926
	uut: entity work.timer_us
927
		generic map(clock_frequency => clock_frequency, timer_period_us => 1)
928
		port map(clk => clk, rst => rst, co => co);
929

    
930
	stimulus_process: process
931
	begin
932
		wait for 1 us;
933
		assert co = '0' severity failure;
934
		wait for clock_period;
935
		assert co = '1' severity failure;
936
		stop <= '1';
937
		wait;
938
	end process;
939
end;
940

    
941
------------------------- Microsecond Timer -----------------------------------------
942

    
943
------------------------- Rising Edge Detector --------------------------------------
944
library ieee;
945
use ieee.std_logic_1164.all;
946

    
947
entity rising_edge_detector is
948
port(
949
	clk:    in  std_ulogic;
950
	rst:    in  std_ulogic;
951
	di:     in  std_ulogic;
952
	do:     out std_ulogic);
953
end;
954

    
955
architecture rtl of rising_edge_detector is
956
	signal sin_0: std_ulogic := '0';
957
	signal sin_1: std_ulogic := '0';
958
begin
959
	red: process(clk, rst)
960
	begin
961
		if rst = '1' then
962
			sin_0 <= '0';
963
			sin_1 <= '0';
964
		elsif rising_edge(clk) then
965
			sin_0 <= di;
966
			sin_1 <= sin_0;
967
		end if;
968
	end process;
969
	do <= not sin_1 and sin_0;
970
end architecture;
971

    
972
library ieee;
973
use ieee.std_logic_1164.all;
974
use ieee.numeric_std.all;
975

    
976
entity rising_edge_detector_tb is
977
	generic(clock_frequency: positive);
978
end;
979

    
980
architecture behav of rising_edge_detector_tb is
981
	constant clock_period: time := 1000 ms / clock_frequency;
982
	signal di:  std_ulogic := '0';
983
	signal do: std_ulogic := 'X';
984

    
985
	signal clk, rst: std_ulogic := '0';
986
	signal stop: std_ulogic := '0';
987
begin
988
	cs: entity work.clock_source_tb
989
		generic map(clock_frequency => clock_frequency, hold_rst => 2)
990
		port map(stop => stop, clk => clk, rst => rst);
991

    
992
	uut: entity work.rising_edge_detector
993
		port map(clk => clk, rst => rst, di => di, do => do);
994

    
995
	stimulus_process: process
996
	begin
997
		wait for clock_period * 5;
998
		assert do = '0' severity failure;
999
		wait for clock_period;
1000
		di <= '1';
1001
		wait for clock_period * 0.5;
1002
		assert do = '1' severity failure;
1003
		wait for clock_period * 1.5;
1004
		di <= '0';
1005
		assert do = '0' severity failure;
1006
		wait for clock_period;
1007
		assert do = '0' severity failure;
1008

    
1009
		assert stop = '0' report "Test bench not run to completion";
1010
		stop <= '1';
1011
		wait;
1012
	end process;
1013
end architecture;
1014

    
1015
library ieee;
1016
use ieee.std_logic_1164.all;
1017

    
1018
entity rising_edge_detectors is
1019
generic(N: positive);
1020
port(
1021
	clk:    in  std_ulogic;
1022
	rst:    in  std_ulogic;
1023
	di:     in  std_ulogic_vector(N - 1 downto 0);
1024
	do:     out std_ulogic_vector(N - 1 downto 0));
1025
end entity;
1026

    
1027
architecture structural of rising_edge_detectors is
1028
begin
1029
	changes: for i in N - 1 downto 0 generate
1030
		d_instance: work.util.rising_edge_detector
1031
			port map(clk => clk, rst => rst, di => di(i), do => do(i));
1032
	end generate;
1033
end architecture;
1034

    
1035
------------------------- Rising Edge Detector --------------------------------------
1036

    
1037
------------------------- Half Adder ------------------------------------------------
1038
library ieee;
1039
use ieee.std_logic_1164.all;
1040

    
1041
entity half_adder is
1042
	port(
1043
		a:     in  std_ulogic;
1044
		b:     in  std_ulogic;
1045
		sum:   out std_ulogic;
1046
		carry: out std_ulogic);
1047
end entity;
1048

    
1049
architecture rtl of half_adder is
1050
begin
1051
	sum   <= a xor b;
1052
	carry <= a and b;
1053
end architecture;
1054

    
1055
------------------------- Half Adder ------------------------------------------------
1056

    
1057
------------------------- Full Adder ------------------------------------------------
1058

    
1059
library ieee;
1060
use ieee.std_logic_1164.all;
1061

    
1062
entity full_adder is
1063
	port(
1064
		x:     in    std_ulogic;
1065
		y:     in    std_ulogic;
1066
		z:     in    std_ulogic;
1067
		sum:   out   std_ulogic;
1068
		carry: out   std_ulogic);
1069
end entity;
1070

    
1071
architecture rtl of full_adder is
1072
	signal carry1, carry2, sum1: std_ulogic;
1073
begin
1074
	ha1: entity work.half_adder port map(a => x,    b => y, sum => sum1, carry => carry1);
1075
	ha2: entity work.half_adder port map(a => sum1, b => z, sum => sum,  carry => carry2);
1076
	carry <= carry1 or carry2;
1077
end architecture;
1078

    
1079
library ieee;
1080
use ieee.std_logic_1164.all;
1081

    
1082
entity full_adder_tb is
1083
	generic(clock_frequency: positive);
1084
end entity;
1085

    
1086
architecture behav of full_adder_tb is
1087
	constant clock_period: time  := 1000 ms / clock_frequency;
1088
	signal x, y, z:    std_ulogic := '0';
1089
	signal sum, carry: std_ulogic := '0';
1090

    
1091
	type stimulus_data   is array (0 to 7)              of std_ulogic_vector(2 downto 0);
1092
	type stimulus_result is array (stimulus_data'range) of std_ulogic_vector(0 to     1);
1093

    
1094
	constant data: stimulus_data := (
1095
		0 => "000", 1 => "001",
1096
		2 => "010", 3 => "011",
1097
		4 => "100", 5 => "101",
1098
		6 => "110", 7 => "111");
1099

    
1100
	constant result: stimulus_result := (
1101
		0 => "00",  1 => "10",
1102
		2 => "10",  3 => "01",
1103
		4 => "10",  5 => "01",
1104
		6 => "01",  7 => "11");
1105

    
1106
	signal clk, rst: std_ulogic := '0';
1107
	signal stop: std_ulogic     := '0';
1108
begin
1109
	cs: entity work.clock_source_tb
1110
		generic map(clock_frequency => clock_frequency, hold_rst => 2)
1111
		port map(stop => stop, clk => clk, rst => rst);
1112

    
1113
	uut: entity work.full_adder port map(x => x, y => y, z => z, sum => sum, carry => carry);
1114

    
1115
	stimulus_process: process
1116
	begin
1117
		wait for clock_period;
1118
		for i in data'range loop
1119
			x <= data(i)(0);
1120
			y <= data(i)(1);
1121
			z <= data(i)(2);
1122
			wait for clock_period;
1123
			assert sum = result(i)(0) and carry = result(i)(1)
1124
				report
1125
					"For: "       & std_ulogic'image(x) & std_ulogic'image(y) & std_ulogic'image(z) &
1126
					" Got: "      & std_ulogic'image(sum)          & std_ulogic'image(carry) &
1127
					" Expected: " & std_ulogic'image(result(i)(0)) & std_ulogic'image(result(i)(1))
1128
				severity failure;
1129
			wait for clock_period;
1130
		end loop;
1131

    
1132
		stop <= '1';
1133
		wait;
1134
	end process;
1135
end architecture;
1136

    
1137
------------------------- Full Adder ------------------------------------------------
1138

    
1139
------------------------- FIFO ------------------------------------------------------
1140

    
1141
-- Originally from http://www.deathbylogic.com/2013/07/vhdl-standard-fifo/
1142
-- @copyright Public Domain
1143
-- @todo Add more comments about the FIFOs origin, add assertions test
1144
-- synthesis, make this more generic (with empty FIFO and FIFO count signals)
1145
--
1146
-- The code can be used freely and appears to be public domain, comment
1147
-- from author is: "You can use any code posted here freely, there is no copyright."
1148
--
1149
-- @note The FIFO has been modified from the original to bring it in line with
1150
-- this projects coding standards.
1151

    
1152
library ieee;
1153
use ieee.std_logic_1164.all;
1154
use ieee.numeric_std.all;
1155

    
1156
entity fifo is
1157
	generic(
1158
		data_width: positive;
1159
		fifo_depth: positive);
1160
	port(
1161
		clk:   in  std_ulogic;
1162
		rst:   in  std_ulogic;
1163
		we:    in  std_ulogic;
1164
		di:    in  std_ulogic_vector (data_width - 1 downto 0);
1165
		re:    in  std_ulogic;
1166
		do:    out std_ulogic_vector (data_width - 1 downto 0);
1167
		empty: out std_ulogic := '1';
1168
		full:  out std_ulogic := '0');
1169
end fifo;
1170

    
1171
architecture behavioral of fifo is
1172
begin
1173

    
1174
	-- memory pointer process
1175
	fifo_proc: process (clk, rst)
1176
		type fifo_memory is array (0 to fifo_depth - 1) of std_ulogic_vector (data_width - 1 downto 0);
1177
		variable memory: fifo_memory;
1178

    
1179
		variable head: natural range 0 to fifo_depth - 1;
1180
		variable tail: natural range 0 to fifo_depth - 1;
1181

    
1182
		variable looped: boolean;
1183
	begin
1184
		if rst = '1' then
1185
			head := 0;
1186
			tail := 0;
1187

    
1188
			looped := false;
1189

    
1190
			full  <= '0';
1191
			empty <= '1';
1192
			do    <= (others => '0');
1193
		elsif rising_edge(clk) then
1194
			do    <= (others => '0');
1195
			if re = '1' then
1196
				if looped = true or head /= tail then
1197
					-- update data output
1198
					do <= memory(tail);
1199

    
1200
					-- update tail pointer as needed
1201
					if tail = fifo_depth - 1 then
1202
						tail   := 0;
1203
						looped := false;
1204
					else
1205
						tail := tail + 1;
1206
					end if;
1207
				end if;
1208
			end if;
1209

    
1210
			if we = '1' then
1211
				if looped = false or head /= tail then
1212
					-- write data to memory
1213
					memory(head) := di;
1214

    
1215
					-- increment head pointer as needed
1216
					if head = fifo_depth - 1 then
1217
						head := 0;
1218

    
1219
						looped := true;
1220
					else
1221
						head := head + 1;
1222
					end if;
1223
				end if;
1224
			end if;
1225

    
1226
			-- update empty and full flags
1227
			if head = tail then
1228
				if looped then
1229
					full  <= '1';
1230
				else
1231
					empty <= '1';
1232
				end if;
1233
			else
1234
				empty	<= '0';
1235
				full	<= '0';
1236
			end if;
1237
		end if;
1238
	end process;
1239
end architecture;
1240

    
1241
library ieee;
1242
use ieee.std_logic_1164.all;
1243
use ieee.numeric_std.all;
1244

    
1245
entity fifo_tb is
1246
	generic(clock_frequency: positive);
1247
end entity;
1248

    
1249
architecture behavior of fifo_tb is
1250
	constant clock_period: time  := 1000 ms / clock_frequency;
1251
	constant data_width: positive := 8;
1252
	constant fifo_depth: positive := 16;
1253

    
1254
	signal di:      std_ulogic_vector(data_width - 1 downto 0) := (others => '0');
1255
	signal re:       std_ulogic := '0';
1256
	signal we:       std_ulogic := '0';
1257

    
1258
	signal do:       std_ulogic_vector(data_width - 1 downto 0) := (others => '0');
1259
	signal empty:    std_ulogic := '0';
1260
	signal full:     std_ulogic := '0';
1261

    
1262
	signal clk, rst: std_ulogic := '0';
1263
	signal stop_w:   std_ulogic := '0';
1264
	signal stop_r:   std_ulogic := '0';
1265
	signal stop:     std_ulogic := '0';
1266
begin
1267
	cs: entity work.clock_source_tb
1268
		generic map(clock_frequency => clock_frequency, hold_rst => 2)
1269
		port map(stop => stop, clk => clk, rst => rst);
1270

    
1271
	stop <= '1' when stop_w = '1' and stop_r = '1' else '0';
1272

    
1273
	uut: entity work.fifo
1274
		generic map(data_width => data_width, fifo_depth => fifo_depth)
1275
		port map (
1276
			clk   => clk,
1277
			rst   => rst,
1278
			di    => di,
1279
			we    => we,
1280
			re    => re,
1281
			do    => do,
1282
			full  => full,
1283
			empty => empty);
1284

    
1285
	write_process: process
1286
		variable counter: unsigned (data_width - 1 downto 0) := (others => '0');
1287
	begin
1288
		wait for clock_period * 20;
1289

    
1290
		for i in 1 to 32 loop
1291
			counter := counter + 1;
1292
			di <= std_ulogic_vector(counter);
1293
			wait for clock_period * 1;
1294
			we <= '1';
1295
			wait for clock_period * 1;
1296
			we <= '0';
1297
		end loop;
1298

    
1299
		wait for clock_period * 20;
1300

    
1301
		for i in 1 to 32 loop
1302
			counter := counter + 1;
1303
			di <= std_ulogic_vector(counter);
1304
			wait for clock_period * 1;
1305
			we <= '1';
1306
			wait for clock_period * 1;
1307
			we <= '0';
1308
		end loop;
1309

    
1310
		stop_w <= '1';
1311
		wait;
1312
	end process;
1313

    
1314
	read_process: process
1315
	begin
1316
		wait for clock_period * 60;
1317
		re <= '1';
1318
		wait for clock_period * 60;
1319
		re <= '0';
1320
		wait for clock_period * 256 * 2;
1321
		re <= '1';
1322

    
1323
		stop_r <= '1';
1324
		wait;
1325
	end process;
1326
end architecture;
1327

    
1328
------------------------- FIFO ------------------------------------------------------
1329

    
1330
------------------------- Free running counter --------------------------------------
1331

    
1332
library ieee;
1333
use ieee.std_logic_1164.all;
1334
use ieee.numeric_std.all;
1335

    
1336
entity counter is
1337
	generic(
1338
		N: positive);
1339
	port(
1340
		clk:     in  std_ulogic;
1341
		rst:     in  std_ulogic;
1342
		ce:      in  std_ulogic;
1343
		cr:      in  std_ulogic;
1344
		dout:    out std_ulogic_vector(N - 1 downto 0);
1345

    
1346
		load_we: in  std_ulogic := '0';
1347
		load_i:  in  std_ulogic_vector(N - 1 downto 0) := (others => '0'));
1348
end entity;
1349

    
1350
architecture rtl of counter is
1351
	signal c_c, c_n: unsigned(N - 1 downto 0) := (others => '0');
1352
begin
1353
	dout <= std_ulogic_vector(c_c);
1354

    
1355
	process(clk, rst)
1356
	begin
1357
		if rst = '1' then
1358
			c_c <= (others => '0');
1359
		elsif rising_edge(clk) then
1360
			c_c <= c_n;
1361
		end if;
1362
	end process;
1363

    
1364
	process(c_c, cr, ce, load_we, load_i)
1365
	begin
1366
		c_n <= c_c;
1367
		if load_we = '1' then
1368
			c_n <= unsigned(load_i);
1369
		else
1370
			if cr = '1' then
1371
				c_n <= (others => '0');
1372
			elsif ce = '1' then
1373
				c_n <= c_c + 1;
1374
			end if;
1375
		end if;
1376
	end process;
1377

    
1378
end architecture;
1379

    
1380
library ieee;
1381
use ieee.std_logic_1164.all;
1382
use ieee.numeric_std.all;
1383

    
1384
entity counter_tb is
1385
	generic(clock_frequency: positive);
1386
end entity;
1387

    
1388
architecture behavior of counter_tb is
1389
	constant clock_period: time     := 1000 ms / clock_frequency;
1390
	constant length:       positive := 2;
1391

    
1392
	-- inputs
1393
	signal ce: std_ulogic := '0';
1394
	signal cr: std_ulogic := '0';
1395

    
1396
	-- outputs
1397
	signal dout: std_ulogic_vector(length - 1 downto 0);
1398

    
1399
	-- test data
1400
	type stimulus_data   is array (0 to 16)             of std_ulogic_vector(1 downto 0);
1401
	type stimulus_result is array (stimulus_data'range) of std_ulogic_vector(0 to     1);
1402

    
1403
	constant data: stimulus_data := (
1404
		 0 => "00",  1 => "00",
1405
		 2 => "01",  3 => "01",
1406
		 4 => "00",  5 => "00",
1407
		 6 => "10",  7 => "00",
1408
		 8 => "01",  9 => "01",
1409
		10 => "11", 11 => "00",
1410
		12 => "01", 13 => "01",
1411
		14 => "01", 15 => "01",
1412
		16 => "01");
1413

    
1414
	constant result: stimulus_result := (
1415
		 0 => "00",  1 => "00",
1416
		 2 => "00",  3 => "01",
1417
		 4 => "10",  5 => "10",
1418
		 6 => "10",  7 => "00",
1419
		 8 => "00",  9 => "01",
1420
		10 => "10", 11 => "00",
1421
		12 => "00", 13 => "01",
1422
		14 => "10", 15 => "11",
1423
		16 => "00");
1424

    
1425
	signal clk, rst: std_ulogic := '0';
1426
	signal stop:     std_ulogic := '0';
1427
begin
1428
	cs: entity work.clock_source_tb
1429
		generic map(clock_frequency => clock_frequency, hold_rst => 2)
1430
		port map(stop => stop, clk => clk, rst => rst);
1431

    
1432
	uut: entity work.counter
1433
		generic map(
1434
			N => length)
1435
		port map(
1436
			clk   => clk,
1437
			rst   => rst,
1438
			ce    => ce,
1439
			cr    => cr,
1440
			dout  => dout);
1441

    
1442
	stimulus_process: process
1443
	begin
1444
		wait for clock_period;
1445
		for i in data'range loop
1446
			ce <= data(i)(0);
1447
			cr <= data(i)(1);
1448
			wait for clock_period;
1449
			assert dout = result(i)
1450
				report
1451
					"For: ce("    & std_ulogic'image(ce) & ") cr(" & std_ulogic'image(cr) & ") " &
1452
					" Got: "      & integer'image(to_integer(unsigned(dout))) &
1453
					" Expected: " & integer'image(to_integer(unsigned(result(i))))
1454
				severity failure;
1455
		end loop;
1456
		stop <= '1';
1457
		wait;
1458
	end process;
1459

    
1460
end architecture;
1461

    
1462
------------------------- Free running counter --------------------------------------
1463

    
1464
------------------------- Linear Feedback Shift Register ----------------------------
1465
-- For good sources on LFSR see
1466
-- * https://sites.ualberta.ca/~delliott/ee552/studentAppNotes/1999f/Drivers_Ed/lfsr.html
1467
-- * https://en.wikipedia.org/wiki/Linear-feedback_shift_register
1468
--
1469
-- Some optimal taps
1470
--
1471
-- Taps start at the left most std_ulogic element of tap at '0' and proceed to
1472
-- the highest bit. To instantiate an instance of the LFSR set tap to a
1473
-- standard logic vector one less the size of LFSR that you want. An 8-bit
1474
-- LFSR can be made by setting it 'tap' to "0111001". The LFSR will need to
1475
-- be loaded with a seed value, set 'do' to that value and assert 'we'. The
1476
-- LFSR will only run when 'ce' is asserted, otherwise it will preserve the
1477
-- current value.
1478
--
1479
-- Number of bits   Taps      Cycle Time
1480
--      8           1,2,3,7    255
1481
--      16          1,2,4,15   65535
1482
--      32          1,5,6,31   4294967295
1483
--
1484
-- This component could be improved a lot, and it could also be used to
1485
-- calculate CRCs, which are basically the same computation. Its interface
1486
-- is not the best either, being a free running counter.
1487
--
1488

    
1489
library ieee;
1490
use ieee.std_logic_1164.all;
1491
use ieee.numeric_std.all;
1492

    
1493
entity lfsr is
1494
	generic(constant tap: std_ulogic_vector);
1495
	port
1496
	(
1497
		clk: in  std_ulogic;
1498
		rst: in  std_ulogic;
1499
		we:  in  std_ulogic;
1500
		ce:  in  std_ulogic := '1';
1501
		di:  in  std_ulogic_vector(tap'high + 1 downto tap'low);
1502
		do:  out std_ulogic_vector(tap'high + 1 downto tap'low));
1503
end entity;
1504

    
1505
architecture rtl of lfsr is
1506
	signal r_c, r_n : std_ulogic_vector(di'range) := (others => '0');
1507
begin
1508
	do <= r_c;
1509

    
1510
	process(rst, clk)
1511
	begin
1512
		if rst = '1' then
1513
			r_c <= (others => '0');
1514
		elsif rising_edge(clk) then
1515
			r_c <= r_n;
1516
		end if;
1517
	end process;
1518

    
1519
	process(r_c, di, we, ce)
1520
	begin
1521
		if we = '1' then
1522
			r_n <= di;
1523
		elsif ce = '1' then
1524

    
1525
			r_n(r_n'high) <= r_c(r_c'low);
1526

    
1527
			for i in tap'high downto tap'low loop
1528
				if tap(i) = '1' then
1529
					r_n(i) <= r_c(r_c'low) xor r_c(i+1);
1530
				else
1531
					r_n(i) <= r_c(i+1);
1532
				end if;
1533
			end loop;
1534
		else
1535
			r_n <= r_c;
1536
		end if;
1537
	end process;
1538
end architecture;
1539

    
1540
library ieee;
1541
use ieee.std_logic_1164.all;
1542
use ieee.numeric_std.all;
1543

    
1544
entity lfsr_tb is
1545
	generic(clock_frequency: positive);
1546
end entity;
1547

    
1548
architecture behavior of lfsr_tb is
1549
	constant clock_period: time     := 1000 ms / clock_frequency;
1550
	signal we: std_ulogic := '0';
1551
	signal do, di: std_ulogic_vector(7 downto 0) := (others => '0');
1552

    
1553
	signal clk, rst: std_ulogic := '0';
1554
	signal stop:     std_ulogic := '0';
1555
begin
1556
	cs: entity work.clock_source_tb
1557
		generic map(clock_frequency => clock_frequency, hold_rst => 2)
1558
		port map(stop => stop, clk => clk, rst => rst);
1559

    
1560
	uut: entity work.lfsr
1561
		generic map(tap => "0111001")
1562
		port map(clk => clk,
1563
			 rst => rst,
1564
			 we => we,
1565
			 di => di,
1566
			 do => do);
1567

    
1568
	stimulus_process: process
1569
	begin
1570
		wait for clock_period * 2;
1571
		we   <= '1';
1572
		di   <= "00000001";
1573
		wait for clock_period;
1574
		we   <= '0';
1575
		stop <= '1';
1576
		wait;
1577
	end process;
1578

    
1579
end architecture;
1580

    
1581
------------------------- Linear Feedback Shift Register ----------------------------
1582

    
1583
------------------------- I/O Pin Controller ----------------------------------------
1584
-- @todo Test this in hardware
1585
--
1586
-- This is a simple I/O pin control module, there is a control register which
1587
-- sets whether the pins are to be read in (control = '0') or set to the value written to
1588
-- "din" (control = '1').
1589

    
1590
library ieee;
1591
use ieee.std_logic_1164.all;
1592
use ieee.numeric_std.all;
1593

    
1594
entity io_pins is
1595
	generic(
1596
		N: positive);
1597
	port
1598
	(
1599
		clk:         in    std_ulogic;
1600
		rst:         in    std_ulogic;
1601
		control:     in    std_ulogic_vector(N - 1 downto 0);
1602
		control_we:  in    std_ulogic;
1603
		din:         in    std_ulogic_vector(N - 1 downto 0);
1604
		din_we:      in    std_ulogic;
1605
		dout:        out   std_ulogic_vector(N - 1 downto 0);
1606
		pins:        inout std_logic_vector(N - 1 downto 0));
1607
end entity;
1608

    
1609
architecture rtl of io_pins is
1610
	signal control_o: std_ulogic_vector(control'range) := (others => '0');
1611
	signal din_o:     std_ulogic_vector(din'range)     := (others => '0');
1612
begin
1613

    
1614
	control_r: entity work.reg generic map(N => N) port map(clk => clk, rst => rst, di => control, we => control_we, do => control_o);
1615
	din_r:     entity work.reg generic map(N => N) port map(clk => clk, rst => rst, di => din,     we => din_we,     do => din_o);
1616

    
1617
	pins_i: for i in control_o'range generate
1618
		dout(i) <= pins(i)  when control_o(i) = '0' else '0';
1619
		pins(i) <= din_o(i) when control_o(i) = '1' else 'Z';
1620
	end generate;
1621

    
1622
end architecture;
1623

    
1624
library ieee;
1625
use ieee.std_logic_1164.all;
1626
use ieee.numeric_std.all;
1627

    
1628
entity io_pins_tb is
1629
	generic(clock_frequency: positive);
1630
end entity;
1631

    
1632
architecture behavior of io_pins_tb is
1633
	constant clock_period: time := 1000 ms / clock_frequency;
1634
	constant N: positive := 8;
1635

    
1636
	signal control: std_ulogic_vector(N - 1 downto 0) := (others => '0');
1637
	signal din:     std_ulogic_vector(N - 1 downto 0) := (others => '0');
1638
	signal dout:    std_ulogic_vector(N - 1 downto 0) := (others => '0');
1639
	signal pins:    std_logic_vector(N - 1 downto 0)  := (others => 'L'); -- !
1640

    
1641
	signal control_we: std_ulogic := '0';
1642
	signal din_we: std_ulogic     := '0';
1643

    
1644

    
1645
	signal clk, rst: std_ulogic := '0';
1646
	signal stop:     std_ulogic := '0';
1647
begin
1648
	cs: entity work.clock_source_tb
1649
		generic map(clock_frequency => clock_frequency, hold_rst => 2)
1650
		port map(stop => stop, clk => clk, rst => rst);
1651

    
1652
	uut: entity work.io_pins
1653
		generic map(N => N)
1654
		port map(
1655
			clk         =>  clk,
1656
			rst         =>  rst,
1657
			control     =>  control,
1658
			control_we  =>  control_we,
1659
			din         =>  din,
1660
			din_we      =>  din_we,
1661
			dout        =>  dout,
1662
			pins        =>  pins);
1663

    
1664
	stimulus_process: process
1665
	begin
1666
		wait for clock_period * 2;
1667
		control    <= x"0f"; -- write lower pins
1668
		control_we <= '1';
1669

    
1670
		wait for clock_period;
1671
		din        <= x"AA";
1672
		din_we     <= '1';
1673

    
1674
		wait for clock_period * 2;
1675
		pins <= (others => 'H'); -- !
1676
		wait for clock_period * 2;
1677
		stop <= '1';
1678
		wait;
1679
	end process;
1680

    
1681
end architecture;
1682

    
1683
------------------------- I/O Pin Controller ----------------------------------------
1684

    
1685
------------------------- Single and Dual Port Block RAM ----------------------------
1686
--|
1687
--| @warning The function initialize_ram has to be present in each architecture
1688
--| block ram that uses it (as far as I am aware) which means they could fall
1689
--| out of sync. This could be remedied with VHDL-2008.
1690
---------------------------------------------------------------------------------
1691

    
1692
--- Dual Port Model ---
1693

    
1694
library ieee;
1695
use ieee.std_logic_1164.all;
1696
use ieee.numeric_std.all;
1697
use std.textio.all;
1698
use work.util.all;
1699

    
1700
entity dual_port_block_ram is
1701

    
1702
	-- The dual port Block RAM module can be initialized from a file,
1703
	-- or initialized to all zeros. The model can be synthesized (with
1704
	-- Xilinx's ISE) into BRAM.
1705
	--
1706
	-- Valid file_type options include:
1707
	--
1708
	-- FILE_BINARY - A binary file (ASCII '0' and '1', one number per line)
1709
	-- FILE_HEX    - A Hex file (ASCII '0-9' 'a-f', 'A-F', one number per line)
1710
	-- FILE_NONE   - RAM contents will be defaulted to all zeros, no file will
1711
	--               be read from
1712
	--
1713
	-- @todo Read in actual binary data files, see: https://stackoverflow.com/questions/14173652
1714
	--
1715
	-- The data length must be divisible by 4 if the "hex" option is
1716
	-- given.
1717
	--
1718
	-- These default values for addr_length and data_length have been
1719
	-- chosen so as to fill the block RAM available on a Spartan 6.
1720
	--
1721
	generic(addr_length: positive    := 12;
1722
		data_length: positive    := 16;
1723
		file_name:   string      := "memory.bin";
1724
		file_type:   file_format := FILE_BINARY);
1725
	port(
1726
		--| Port A of dual port RAM
1727
		a_clk:  in  std_ulogic;
1728
		a_dwe:  in  std_ulogic;
1729
		a_dre:  in  std_ulogic;
1730
		a_addr: in  std_ulogic_vector(addr_length - 1 downto 0);
1731
		a_din:  in  std_ulogic_vector(data_length - 1 downto 0);
1732
		a_dout: out std_ulogic_vector(data_length - 1 downto 0) := (others => '0');
1733
		--| Port B of dual port RAM
1734
		b_clk:  in  std_ulogic;
1735
		b_dwe:  in  std_ulogic;
1736
		b_dre:  in  std_ulogic;
1737
		b_addr: in  std_ulogic_vector(addr_length - 1 downto 0);
1738
		b_din:  in  std_ulogic_vector(data_length - 1 downto 0);
1739
		b_dout: out std_ulogic_vector(data_length - 1 downto 0) := (others => '0'));
1740
end entity;
1741

    
1742
architecture behav of dual_port_block_ram is
1743
	constant ram_size: positive := 2 ** addr_length;
1744

    
1745
	type ram_type is array ((ram_size - 1 ) downto 0) of std_ulogic_vector(data_length - 1 downto 0);
1746

    
1747
	impure function initialize_ram(file_name: in string; file_type: in file_format) return ram_type is
1748
		variable ram_data:   ram_type;
1749
		file     in_file:    text is in file_name;
1750
		variable input_line: line;
1751
		variable tmp:        bit_vector(data_length - 1 downto 0);
1752
		variable c:          character;
1753
		variable slv:        std_ulogic_vector(data_length - 1 downto 0);
1754
	begin
1755
		for i in 0 to ram_size - 1 loop
1756
			if file_type = FILE_NONE then
1757
				ram_data(i):=(others => '0');
1758
			elsif not endfile(in_file) then
1759
				readline(in_file,input_line);
1760
				if file_type = FILE_BINARY then
1761
					read(input_line, tmp);
1762
					ram_data(i) := std_ulogic_vector(to_stdlogicvector(tmp));
1763
				elsif file_type = FILE_HEX then
1764
					assert (data_length mod 4) = 0 report "(data_length%4)!=0" severity failure;
1765
					for j in 1 to (data_length/4) loop
1766
						c:= input_line((data_length/4) - j + 1);
1767
						slv((j*4)-1 downto (j*4)-4) := hex_char_to_std_ulogic_vector(c);
1768
					end loop;
1769
					ram_data(i) := slv;
1770
				else
1771
					report "Incorrect file type given: " & file_format'image(file_type) severity failure;
1772
				end if;
1773
			else
1774
				ram_data(i) := (others => '0');
1775
			end if;
1776
		end loop;
1777
		file_close(in_file);
1778
		return ram_data;
1779
	end function;
1780

    
1781
	shared variable ram: ram_type := initialize_ram(file_name, file_type);
1782

    
1783
begin
1784
	a_ram: process(a_clk)
1785
	begin
1786
		if rising_edge(a_clk) then
1787
			if a_dwe = '1' then
1788
				ram(to_integer(unsigned(a_addr))) := a_din;
1789
			end if;
1790
			if a_dre = '1' then
1791
				a_dout <= ram(to_integer(unsigned(a_addr)));
1792
			else
1793
				a_dout <= (others => '0');
1794
			end if;
1795
		end if;
1796
	end process;
1797

    
1798
	b_ram: process(b_clk)
1799
	begin
1800
		if rising_edge(b_clk) then
1801
			if b_dwe = '1' then
1802
				ram(to_integer(unsigned(b_addr))) := b_din;
1803
			end if;
1804
			if b_dre = '1' then
1805
				b_dout <= ram(to_integer(unsigned(b_addr)));
1806
			else
1807
				b_dout <= (others => '0');
1808
			end if;
1809
		end if;
1810
	end process;
1811
end architecture;
1812

    
1813
--- Single Port Model ---
1814

    
1815
library ieee;
1816
use ieee.std_logic_1164.all;
1817
use ieee.numeric_std.all;
1818
use std.textio.all;
1819
use work.util.all;
1820

    
1821
entity single_port_block_ram is
1822
	generic(addr_length: positive    := 12;
1823
		data_length: positive    := 16;
1824
		file_name:   string      := "memory.bin";
1825
		file_type:   file_format := FILE_BINARY);
1826
	port(
1827
		clk:  in  std_ulogic;
1828
		dwe:  in  std_ulogic;
1829
		dre:  in  std_ulogic;
1830
		addr: in  std_ulogic_vector(addr_length - 1 downto 0);
1831
		din:  in  std_ulogic_vector(data_length - 1 downto 0);
1832
		dout: out std_ulogic_vector(data_length - 1 downto 0) := (others => '0'));
1833
end entity;
1834

    
1835
architecture behav of single_port_block_ram is
1836
	constant ram_size: positive := 2 ** addr_length;
1837

    
1838
	type ram_type is array ((ram_size - 1 ) downto 0) of std_ulogic_vector(data_length - 1 downto 0);
1839

    
1840
	impure function initialize_ram(file_name: in string; file_type: in file_format) return ram_type is
1841
		variable ram_data:   ram_type;
1842
		file     in_file:    text is in file_name;
1843
		variable input_line: line;
1844
		variable tmp:        bit_vector(data_length - 1 downto 0);
1845
		variable c:          character;
1846
		variable slv:        std_ulogic_vector(data_length - 1 downto 0);
1847
	begin
1848
		for i in 0 to ram_size - 1 loop
1849
			if file_type = FILE_NONE then
1850
				ram_data(i):=(others => '0');
1851
			elsif not endfile(in_file) then
1852
				readline(in_file,input_line);
1853
				if file_type = FILE_BINARY then
1854
					read(input_line, tmp);
1855
					ram_data(i) := std_ulogic_vector(to_stdlogicvector(tmp));
1856
				elsif file_type = FILE_HEX then -- hexadecimal
1857
					assert (data_length mod 4) = 0 report "(data_length%4)!=0" severity failure;
1858
					for j in 1 to (data_length/4) loop
1859
						c:= input_line((data_length/4) - j + 1);
1860
						slv((j*4)-1 downto (j*4)-4) := hex_char_to_std_ulogic_vector(c);
1861
					end loop;
1862
					ram_data(i) := slv;
1863
				else
1864
					report "Incorrect file type given: " & file_format'image(file_type) severity failure;
1865
				end if;
1866
			else
1867
				ram_data(i) := (others => '0');
1868
			end if;
1869
		end loop;
1870
		file_close(in_file);
1871
		return ram_data;
1872
	end function;
1873

    
1874
	shared variable ram: ram_type := initialize_ram(file_name, file_type);
1875
begin
1876
	block_ram: process(clk)
1877
	begin
1878
		if rising_edge(clk) then
1879
			if dwe = '1' then
1880
				ram(to_integer(unsigned(addr))) := din;
1881
			end if;
1882

    
1883
			if dre = '1' then
1884
				dout <= ram(to_integer(unsigned(addr)));
1885
			else
1886
				dout <= (others => '0');
1887
			end if;
1888
		end if;
1889
	end process;
1890
end architecture;
1891

    
1892
------------------------- Single and Dual Port Block RAM ----------------------------
1893

    
1894
------------------------- Data Source -----------------------------------------------
1895
--|
1896
--| This module spits out a bunch of data
1897
--|
1898
--| @todo Create a single module that can be used to capture and replay data at
1899
--| a configurable rate. This could be used as a logger or as a waveform
1900
--| generator. Depending on the generics used this should synthesize to either
1901
--| logger, or a data source, or both. A pre-divider could also be supplied as
1902
--| generic options, to lower the clock rate.
1903
--|
1904

    
1905
library ieee,work;
1906
use ieee.std_logic_1164.all;
1907
use ieee.numeric_std.all;
1908
use work.util.single_port_block_ram;
1909
use work.util.counter;
1910
use work.util.all;
1911

    
1912
entity data_source is
1913
	generic(addr_length: positive    := 12;
1914
		data_length: positive    := 16;
1915
		file_name:   string      := "memory.bin";
1916
		file_type:   file_format := FILE_BINARY);
1917
	port(
1918
		clk:     in  std_ulogic;
1919
		rst:     in  std_ulogic;
1920

    
1921
		ce:      in  std_ulogic := '1';
1922
		cr:      in  std_ulogic;
1923

    
1924
		load:    in  std_ulogic_vector(addr_length - 1 downto 0) := (others => '0');
1925
		load_we: in  std_ulogic := '0';
1926

    
1927
		dout:    out std_ulogic_vector(data_length - 1 downto 0));
1928
end entity;
1929

    
1930
architecture structural of data_source is
1931
	signal addr: std_ulogic_vector(addr_length - 1 downto 0);
1932
begin
1933
	count: work.util.counter
1934
		generic map(
1935
			N => addr_length)
1936
		port map(
1937
			clk      =>  clk,
1938
			rst      =>  rst,
1939
			ce       =>  ce,
1940
			cr       =>  cr,
1941
			dout     =>  addr,
1942
			load_i   =>  load,
1943
			load_we  =>  load_we);
1944

    
1945
	ram: work.util.single_port_block_ram
1946
		generic map(
1947
			addr_length => addr_length,
1948
			data_length => data_length,
1949
			file_name   => file_name,
1950
			file_type   => file_type)
1951
		port map(
1952
			clk  => clk,
1953
			addr => addr,
1954
			dwe  => '0',
1955
			dre  => '1',
1956
			din  => (others => '0'),
1957
			dout => dout);
1958

    
1959
end architecture;
1960

    
1961
------------------------- Data Source -----------------------------------------------
1962

    
1963
------------------------- uCPU ------------------------------------------------------
1964
-- @brief An incredible simple microcontroller
1965
-- @license MIT
1966
-- @author Richard James Howe
1967
-- @copyright Richard James Howe (2017)
1968
--
1969
-- Based on:
1970
-- https://stackoverflow.com/questions/20955863/vhdl-microprocessor-microcontroller
1971
--
1972
--  INSTRUCTION    CYCLES 87 6543210 OPERATION
1973
--  ADD WITH CARRY   2    00 ADDRESS A = A   + MEM[ADDRESS]
1974
--  NOR              2    01 ADDRESS A = A NOR MEM[ADDRESS]
1975
--  STORE            1    10 ADDRESS MEM[ADDRESS] = A
1976
--  JCC              1    11 ADDRESS IF(CARRY) { PC = ADDRESS, CLEAR CARRY }
1977
--
1978
-- It would be interesting to make a customizable CPU in which the
1979
-- instructions could be customized based upon what. Another interesting
1980
-- possibility is making a simple assembler purely in VHDL, which should
1981
-- be possible, but difficult. A single port version would require another
1982
-- state to fetch the operand and another register, or more states.
1983
--
1984
-- @todo Test in hardware, document, make assembler, and a project that
1985
-- just contains an instantiation of this core.
1986
--
1987

    
1988
library ieee,work;
1989
use ieee.std_logic_1164.all;
1990
use ieee.numeric_std.all;
1991

    
1992
entity ucpu is
1993
	generic(width: positive range 8 to 32 := 8);
1994
	port(
1995
		clk, rst: in  std_ulogic;
1996

    
1997
		pc:       out std_ulogic_vector(width - 3 downto 0);
1998
		op:       in  std_ulogic_vector(width - 1 downto 0);
1999

    
2000
		adr:      out std_ulogic_vector(width - 3 downto 0);
2001
		di:       in  std_ulogic_vector(width - 1 downto 0);
2002
		re, we:   out std_ulogic;
2003
		do:       out std_ulogic_vector(width - 1 downto 0));
2004
end entity;
2005

    
2006
architecture rtl of ucpu is
2007
	signal a_c,   a_n:       unsigned(di'high + 1 downto di'low) := (others => '0'); -- accumulator
2008
	signal pc_c,  pc_n:      unsigned(pc'range)                  := (others => '0');
2009
	signal alu:              std_ulogic_vector(1 downto 0)        := (others => '0');
2010
	signal state_c, state_n: std_ulogic                           := '0'; -- FETCH/Single cycle instruction or EXECUTE
2011
begin
2012
	pc          <= std_ulogic_vector(pc_n);
2013
	do          <= std_ulogic_vector(a_c(do'range));
2014
	alu         <= op(op'high downto op'high - 1);
2015
	adr         <= op(adr'range);
2016
	we          <= '1' when alu = "10" else '0'; -- STORE
2017
	re          <= alu(1) nor state_c;           -- FETCH for ADD and NOR
2018
	state_n     <= alu(1) nor state_c;           -- FETCH not taken or FETCH done
2019
	pc_n        <= unsigned(op(pc_n'range)) when (alu = "11"    and a_c(a_c'high) = '0') else -- Jump when carry set
2020
			pc_c                    when (state_c = '0' and alu(1) = '0')        else -- FETCH
2021
			pc_c + 1; -- EXECUTE
2022

    
2023
	process(clk, rst)
2024
	begin
2025
		if rst = '1' then
2026
			a_c     <= (others => '0');
2027
			pc_c    <= (others => '0');
2028
			state_c <= '0';
2029
		elsif rising_edge(clk) then
2030
			a_c     <= a_n;
2031
			pc_c    <= pc_n;
2032
			state_c <= state_n;
2033
		end if;
2034
	end process;
2035

    
2036
	process(op, alu, di, a_c, state_c)
2037
	begin
2038
		a_n     <= a_c;
2039

    
2040
		if alu = "11" and a_c(a_c'high) = '0' then a_n(a_n'high) <= '0'; end if;
2041

    
2042
		if state_c = '1' then -- EXECUTE for ADD and NOR
2043
			assert alu(1) = '0' severity failure;
2044
			if alu(0) = '0' then a_n <= '0' & a_c(di'range) + unsigned('0' & di); end if;
2045
			if alu(0) = '1' then a_n <= a_c nor '0' & unsigned(di); end if;
2046
		end if;
2047
	end process;
2048
end architecture;
2049

    
2050
library ieee,work;
2051
use ieee.std_logic_1164.all;
2052
use ieee.numeric_std.all;
2053
use ieee.math_real.all;
2054
use work.util.all;
2055

    
2056
entity ucpu_tb is
2057
	generic(
2058
		clock_frequency: positive;
2059
		file_name: string := "ucpu.bin");
2060
end entity;
2061

    
2062
architecture testing of ucpu_tb is
2063
	constant clk_period:      time     := 1000 ms / clock_frequency;
2064

    
2065
	constant data_length: positive := 8;
2066
	constant addr_length: positive := data_length - 2;
2067

    
2068
	signal a_addr: std_ulogic_vector(addr_length - 1 downto 0);
2069
	signal a_dout: std_ulogic_vector(data_length - 1 downto 0) := (others => '0');
2070

    
2071
	signal b_dwe:  std_ulogic;
2072
	signal b_dre:  std_ulogic;
2073
	signal b_addr: std_ulogic_vector(addr_length - 1 downto 0);
2074
	signal b_din:  std_ulogic_vector(data_length - 1 downto 0);
2075
	signal b_dout: std_ulogic_vector(data_length - 1 downto 0) := (others => '0');
2076

    
2077
	signal clk, rst: std_ulogic := '0';
2078
	signal stop:     std_ulogic := '0';
2079
begin
2080
	cs: entity work.clock_source_tb
2081
		generic map(clock_frequency => clock_frequency, hold_rst => 2)
2082
		port map(stop => stop, clk => clk, rst => rst);
2083

    
2084
	bram_0: entity work.dual_port_block_ram
2085
	generic map(
2086
		addr_length => addr_length,
2087
		data_length => data_length,
2088
		file_name   => file_name,
2089
		file_type   => FILE_BINARY)
2090
	port map(
2091
		a_clk   =>  clk,
2092
		a_dwe   =>  '0',
2093
		a_dre   =>  '1',
2094
		a_addr  =>  a_addr,
2095
		a_din   =>  (others => '0'),
2096
		a_dout  =>  a_dout,
2097

    
2098
		b_clk   =>  clk,
2099
		b_dwe   =>  b_dwe,
2100
		b_dre   =>  b_dre,
2101
		b_addr  =>  b_addr,
2102
		b_din   =>  b_din,
2103
		b_dout  =>  b_dout);
2104

    
2105
	ucpu_0: entity work.ucpu
2106
	generic map(width => data_length)
2107
	port map(
2108
		clk => clk,
2109
		rst => rst,
2110
		pc  => a_addr,
2111
		op  => a_dout,
2112

    
2113
		re  => b_dre,
2114
		we  => b_dwe,
2115
		di  => b_dout,
2116
		do  => b_din,
2117
		adr => b_addr);
2118

    
2119
	stimulus_process: process
2120
	begin
2121
		wait for clk_period * 1000;
2122
		stop <= '1';
2123
		wait;
2124
	end process;
2125

    
2126
end architecture;
2127

    
2128
------------------------- uCPU ------------------------------------------------------
2129

    
2130
------------------------- Restoring Division ----------------------------------------
2131
-- @todo Add remainder to output, rename signals, make a
2132
-- better test bench, add non-restoring division, and describe module
2133
--
2134
-- Computes a/b in N cycles
2135
--
2136
-- https://en.wikipedia.org/wiki/Division_algorithm#Restoring_division
2137
--
2138
--
2139
library ieee,work;
2140
use ieee.std_logic_1164.all;
2141
use ieee.numeric_std.all;
2142

    
2143
entity restoring_divider is
2144
	generic(N: positive);
2145
	port(
2146
		clk:   in  std_ulogic;
2147
		rst:   in  std_ulogic := '0';
2148

    
2149
		a:     in  unsigned(N - 1 downto 0);
2150
		b:     in  unsigned(N - 1 downto 0);
2151
		start: in  std_ulogic;
2152
		done:  out std_ulogic;
2153
		c:     out unsigned(N - 1 downto 0));
2154
end entity;
2155

    
2156
architecture rtl of restoring_divider is
2157
	signal a_c, a_n: unsigned(a'range) := (others => '0');
2158
	signal b_c, b_n: unsigned(b'range) := (others => '0');
2159
	signal m_c, m_n: unsigned(b'range) := (others => '0');
2160
	signal o_c, o_n: unsigned(c'range) := (others => '0');
2161
	signal e_c, e_n: std_ulogic         := '0';
2162
	signal count_c, count_n: unsigned(work.util.n_bits(N) downto 0) := (others => '0');
2163
begin
2164
	c <= o_n;
2165

    
2166
	process(clk, rst)
2167
	begin
2168
		if rst = '1' then
2169
			a_c      <=  (others  =>  '0');
2170
			b_c      <=  (others  =>  '0');
2171
			m_c      <=  (others  =>  '0');
2172
			o_c      <=  (others  =>  '0');
2173
			e_c      <=  '0';
2174
			count_c  <=  (others  =>  '0');
2175
		elsif rising_edge(clk) then
2176
			a_c      <=  a_n;
2177
			b_c      <=  b_n;
2178
			m_c      <=  m_n;
2179
			o_c      <=  o_n;
2180
			e_c      <=  e_n;
2181
			count_c  <=  count_n;
2182
		end if;
2183
	end process;
2184

    
2185
	divide: process(a, b, start, a_c, b_c, m_c, e_c, o_c, count_c)
2186
		variable m_v: unsigned(b'range) := (others => '0');
2187
	begin
2188
		done     <=  '0';
2189
		a_n      <=  a_c;
2190
		b_n      <=  b_c;
2191
		m_v      :=  m_c;
2192
		e_n      <=  e_c;
2193
		o_n      <=  o_c;
2194
		count_n  <=  count_c;
2195
		if start = '1' then
2196
			a_n   <= a;
2197
			b_n   <= b;
2198
			m_v   := (others => '0');
2199
			e_n   <= '1';
2200
			o_n   <= (others => '0');
2201
			count_n <= (others => '0');
2202
		elsif e_c = '1' then
2203
			if count_c(count_c'high) = '1' then
2204
				done  <= '1';
2205
				e_n   <= '0';
2206
				o_n   <= a_c;
2207
				count_n <= (others => '0');
2208
			else
2209
				m_v(b'high downto 1) := m_v(b'high - 1 downto 0);
2210
				m_v(0) := a_c(a'high);
2211
				a_n(a'high downto 1) <= a_c(a'high - 1 downto 0);
2212
				m_v := m_v - b_c;
2213
				if m_v(m_v'high) = '1' then
2214
					m_v := m_v + b_c;
2215
					a_n(0) <= '0';
2216
				else
2217
					a_n(0) <= '1';
2218
				end if;
2219
				count_n <= count_c + 1;
2220
			end if;
2221
		else
2222
			count_n <= (others => '0');
2223
		end if;
2224
		m_n <= m_v;
2225
	end process;
2226
end architecture;
2227

    
2228
library ieee,work;
2229
use ieee.std_logic_1164.all;
2230
use ieee.numeric_std.all;
2231
use ieee.math_real.all;
2232

    
2233
entity restoring_divider_tb is
2234
	generic(clock_frequency: positive);
2235
end entity;
2236

    
2237
architecture testing of restoring_divider_tb is
2238
	constant clk_period: time     := 1000 ms / clock_frequency;
2239
	constant N:          positive := 8;
2240

    
2241
	signal a: unsigned(N - 1 downto 0) := (others => '0');
2242
	signal b: unsigned(N - 1 downto 0) := (others => '0');
2243
	signal c: unsigned(N - 1 downto 0) := (others => '0');
2244
	signal start, done: std_ulogic := '0';
2245

    
2246
	signal clk, rst: std_ulogic := '0';
2247
	signal stop:     std_ulogic := '0';
2248
begin
2249
	cs: entity work.clock_source_tb
2250
		generic map(clock_frequency => clock_frequency, hold_rst => 2)
2251
		port map(stop => stop, clk => clk, rst => rst);
2252

    
2253
	uut: entity work.restoring_divider
2254
		generic map(N => N)
2255
		port map(
2256
			clk   => clk,
2257
			rst   => rst,
2258
			a     => a,
2259
			b     => b,
2260
			start => start,
2261
			done  => done,
2262
			c     => c);
2263

    
2264
	stimulus_process: process
2265
	begin
2266
		wait for clk_period * 2;
2267

    
2268
		a <= x"64";
2269
		b <= x"0A";
2270
		start <= '1';
2271
		wait for clk_period * 1;
2272
		start <= '0';
2273
		wait until done = '1';
2274
		--assert c = x"0A" severity failure;
2275

    
2276
		wait for clk_period * 10;
2277
		b     <= x"05";
2278
		start <= '1';
2279
		wait for clk_period * 1;
2280
		start <= '0';
2281
		wait until done = '1';
2282
		--assert c = x"14" severity failure;
2283

    
2284
		stop <= '1';
2285
		wait;
2286
	end process;
2287

    
2288
end architecture;
2289
------------------------- Restoring Divider ---------------------------------------------------
2290

    
2291
------------------------- Debouncer -----------------------------------------------------------
2292

    
2293
library ieee,work;
2294
use ieee.std_logic_1164.all;
2295
use ieee.numeric_std.all;
2296

    
2297
entity debounce_us is
2298
	generic(clock_frequency: positive; timer_period_us: natural);
2299
	port(
2300
		clk:   in  std_ulogic;
2301
		di:    in  std_ulogic;
2302
		do:    out std_ulogic := '0');
2303
end entity;
2304

    
2305
architecture rtl of debounce_us is
2306
	signal ff: std_ulogic_vector(1 downto 0) := (others => '0');
2307
	signal rst, done: std_ulogic             := '0';
2308
begin
2309
	timer: work.util.timer_us
2310
		generic map(
2311
			clock_frequency => clock_frequency,
2312
			timer_period_us => timer_period_us)
2313
		port map(
2314
			clk => clk,
2315
			rst => rst,
2316
			co  => done);
2317

    
2318
	process(clk)
2319
	begin
2320
		if rising_edge(clk) then
2321
			ff(0) <= di;
2322
			ff(1) <= ff(0);
2323
			rst   <= '0';
2324
			if (ff(0) xor ff(1)) = '1' then
2325
				rst <= '1';
2326
			elsif done = '1' then
2327
				do  <= ff(1);
2328
			end if;
2329
		end if;
2330
	end process;
2331
end architecture;
2332

    
2333
library ieee,work;
2334
use ieee.std_logic_1164.all;
2335
use ieee.numeric_std.all;
2336

    
2337
entity debounce_us_tb is
2338
	generic(clock_frequency: positive);
2339
end entity;
2340

    
2341
architecture testing of debounce_us_tb is
2342
	constant clk_period: time     := 1000 ms / clock_frequency;
2343

    
2344
	signal di,  do:  std_ulogic := '0';
2345
	signal clk, rst: std_ulogic := '0';
2346
	signal stop:     std_ulogic := '0';
2347
begin
2348
	cs: entity work.clock_source_tb
2349
		generic map(clock_frequency => clock_frequency, hold_rst => 2)
2350
		port map(stop => stop, clk => clk, rst => rst);
2351

    
2352
	uut: work.util.debounce_us
2353
		generic map(clock_frequency => clock_frequency, timer_period_us => 1)
2354
		port map(clk => clk, di => di, do => do);
2355

    
2356
	stimulus_process: process
2357
	begin
2358
		wait for clk_period * 2;
2359
		di <= '1';
2360

    
2361
		wait for 1.5 us;
2362

    
2363
		stop <= '1';
2364
		wait;
2365
	end process;
2366
end architecture;
2367
------------------------- Debouncer -----------------------------------------------------------
2368

    
2369
------------------------- Debouncer Block -----------------------------------------------------
2370

    
2371
library ieee,work;
2372
use ieee.std_logic_1164.all;
2373
use ieee.numeric_std.all;
2374

    
2375
entity debounce_block_us is
2376
	generic(N: positive; clock_frequency: positive; timer_period_us: natural);
2377
	port(
2378
		clk:   in  std_ulogic;
2379
		di:    in  std_ulogic_vector(N - 1 downto 0);
2380
		do:    out std_ulogic_vector(N - 1 downto 0));
2381
end entity;
2382

    
2383
architecture structural of debounce_block_us is
2384
begin
2385
	debouncer: for i in N - 1 downto 0 generate
2386
		d_instance: work.util.debounce_us
2387
			generic map(
2388
				clock_frequency => clock_frequency,
2389
				timer_period_us => timer_period_us)
2390
			port map(clk => clk, di => di(i), do => do(i));
2391
	end generate;
2392
end architecture;
2393

    
2394
------------------------- Debouncer Block -----------------------------------------------------
2395

    
2396
------------------------- State Changed -------------------------------------------------------
2397
library ieee,work;
2398
use ieee.std_logic_1164.all;
2399
use ieee.numeric_std.all;
2400

    
2401
entity state_changed is
2402
	port(
2403
		clk: in  std_ulogic;
2404
		rst: in  std_ulogic;
2405
		di:  in  std_ulogic;
2406
		do:  out std_ulogic);
2407
end entity;
2408

    
2409
architecture rtl of state_changed is
2410
	signal state_c, state_n: std_ulogic_vector(1 downto 0) := (others => '0');
2411
begin
2412
	process(clk, rst)
2413
	begin
2414
		if rst = '1' then
2415
			state_c <= (others => '0');
2416
		elsif rising_edge(clk) then
2417
			state_c <= state_n;
2418
		end if;
2419
	end process;
2420

    
2421
	do <= '1' when (state_c(0) xor state_c(1)) = '1' else '0';
2422

    
2423
	process(di, state_c)
2424
	begin
2425
		state_n(0) <= state_c(1);
2426
		state_n(1) <= di;
2427
	end process;
2428
end architecture;
2429

    
2430
------------------------- Change State --------------------------------------------------------
2431

    
2432
------------------------- Change State Block --------------------------------------------------
2433
library ieee,work;
2434
use ieee.std_logic_1164.all;
2435
use ieee.numeric_std.all;
2436

    
2437
entity state_block_changed is
2438
	generic(N: positive);
2439
	port(
2440
		clk: in  std_ulogic;
2441
		rst: in  std_ulogic;
2442
		di:  in  std_ulogic_vector(N - 1 downto 0);
2443
		do:  out std_ulogic_vector(N - 1 downto 0));
2444
end entity;
2445

    
2446
architecture structural of state_block_changed is
2447
begin
2448
	changes: for i in N - 1 downto 0 generate
2449
		d_instance: work.util.state_changed
2450
			port map(clk => clk, rst => rst, di => di(i), do => do(i));
2451
	end generate;
2452
end architecture;
2453

    
2454
------------------------- Change State Block --------------------------------------------------
(16-16/21)