forth-cpu
/
util.vhd
4102 строки · 120.5 Кб
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 if the function n_bits).
6--|
7--| Other modules to implement; CRC core (reuse LFSR), Count
8--| Leading Zeros, Count Trailing Zeros, Manchester CODEC, Wishbone interface
9--| types and Wishbone Bus Arbitrator. Also SPI, a H2 core with an eForth image
10--| read to go, and UART.
11--|
12--| More exotic modules would include; encryption, compression, sorting networks,
13--| switching networks, Reed-Solomon CODEC, Discrete Fourier Transform/Discrete
14--| Cosine Transform, Pulse Width/Code/Position Modulation modules, so long as
15--| they are fairly generic and synthesizable.
16--|
17--| Potential improvements to the library:
18--| - Optional registers on either input or output, selectable by a generic
19--| - Better timing models
20--| - More assertions
21--| - See 'A Structured VHDL design' by Jiri Gaisler,
22--| <http://gaisler.com/doc/vhdl2proc.pdf> and apply methodology.
23--|
24--| @author Richard James Howe
25--| @copyright Copyright 2017, 2019 Richard James Howe
26--| @license MIT
27--| @email howe.r.j.89@gmail.com
28-------------------------------------------------------------------------------
29library ieee, work;
30use ieee.std_logic_1164.all;
31use ieee.numeric_std.all;
32use std.textio.all;
33
34package util is
35-- Not all modules will need every generic specified here, even so it
36-- is easier to group the common generics in one structure.
37type common_generics is record
38clock_frequency: positive; -- clock frequency of module clock
39delay: time; -- gate delay for simulation purposes
40asynchronous_reset: boolean; -- use asynchronous reset if true
41end record;
42
43constant default_settings: common_generics := (
44clock_frequency => 100_000_000,
45delay => 10 ns,
46asynchronous_reset => true
47);
48
49component util_tb is
50generic (g: common_generics);
51end component;
52
53component clock_source_tb is
54generic (g: common_generics; hold_rst: positive := 1);
55port (
56stop: in std_ulogic := '0';
57clk: out std_ulogic;
58clk_with_jitter: out std_ulogic := '0';
59rst: out std_ulogic := '0');
60end component;
61
62component reg
63generic (g: common_generics; N: positive);
64port (
65clk: in std_ulogic;
66rst: in std_ulogic;
67we: in std_ulogic;
68di: in std_ulogic_vector(N - 1 downto 0);
69do: out std_ulogic_vector(N - 1 downto 0));
70end component;
71
72component shift_register
73generic (g: common_generics; N: positive);
74port (
75clk: in std_ulogic;
76rst: in std_ulogic;
77we: in std_ulogic;
78di: in std_ulogic;
79do: out std_ulogic;
80
81-- optional
82load_we: in std_ulogic := '0';
83load_i: in std_ulogic_vector(N - 1 downto 0) := (others => '0');
84load_o: out std_ulogic_vector(N - 1 downto 0));
85end component;
86
87component shift_register_tb
88generic (g: common_generics);
89end component;
90
91component timer_us
92generic (g: common_generics; timer_period_us: natural);
93port (
94clk: in std_ulogic;
95rst: in std_ulogic;
96co: out std_ulogic);
97end component;
98
99component timer_us_tb
100generic (g: common_generics);
101end component;
102
103component rising_edge_detector is
104generic (g: common_generics);
105port (
106clk: in std_ulogic;
107rst: in std_ulogic;
108di: in std_ulogic;
109do: out std_ulogic);
110end component;
111
112component rising_edge_detector_tb is
113generic (g: common_generics);
114end component;
115
116component rising_edge_detectors is
117generic (g: common_generics; N: positive);
118port (
119clk: in std_ulogic;
120rst: in std_ulogic;
121di: in std_ulogic_vector(N - 1 downto 0);
122do: out std_ulogic_vector(N - 1 downto 0));
123end component;
124
125-- NB. 'half_adder' test bench is folded in to 'full_adder_tb'
126component half_adder is
127generic (g: common_generics); -- simulation only
128port (
129a: in std_ulogic;
130b: in std_ulogic;
131sum: out std_ulogic;
132carry: out std_ulogic);
133end component;
134
135component full_adder is
136generic (g: common_generics); -- simulation only
137port (
138x: in std_ulogic;
139y: in std_ulogic;
140z: in std_ulogic;
141sum: out std_ulogic;
142carry: out std_ulogic);
143end component;
144
145component full_adder_tb is
146generic (g: common_generics);
147end component;
148
149component fifo is
150generic (g: common_generics;
151data_width: positive;
152fifo_depth: positive;
153read_first: boolean := true);
154port (
155clk: in std_ulogic;
156rst: in std_ulogic;
157di: in std_ulogic_vector(data_width - 1 downto 0);
158we: in std_ulogic;
159re: in std_ulogic;
160do: out std_ulogic_vector(data_width - 1 downto 0);
161
162-- optional
163full: out std_ulogic := '0';
164empty: out std_ulogic := '1');
165end component;
166
167component fifo_tb is
168generic (g: common_generics);
169end component;
170
171component counter is
172generic (g: common_generics; N: positive);
173port (
174clk: in std_ulogic;
175rst: in std_ulogic;
176ce: in std_ulogic;
177cr: in std_ulogic;
178dout: out std_ulogic_vector(N - 1 downto 0);
179
180-- optional
181load_we: in std_ulogic := '0';
182load_i: in std_ulogic_vector(N - 1 downto 0) := (others => '0'));
183end component;
184
185component counter_tb is
186generic (g: common_generics);
187end component;
188
189component lfsr is
190generic (g: common_generics; constant tap: std_ulogic_vector);
191port (
192clk: in std_ulogic;
193rst: in std_ulogic;
194ce: in std_ulogic := '1';
195we: in std_ulogic;
196di: in std_ulogic_vector(tap'high + 1 downto tap'low);
197do: out std_ulogic_vector(tap'high + 1 downto tap'low));
198end component;
199
200component lfsr_tb is
201generic (g: common_generics);
202end component;
203
204component io_pins is
205generic (g: common_generics; N: positive);
206port (
207clk: in std_ulogic;
208rst: in std_ulogic;
209control: in std_ulogic_vector(N - 1 downto 0);
210control_we: in std_ulogic;
211din: in std_ulogic_vector(N - 1 downto 0);
212din_we: in std_ulogic;
213dout: out std_ulogic_vector(N - 1 downto 0);
214pins: inout std_logic_vector(N - 1 downto 0)); -- NB!
215end component;
216
217component io_pins_tb is
218generic (g: common_generics);
219end component;
220
221type file_format is (FILE_HEX, FILE_BINARY, FILE_NONE);
222
223component dual_port_block_ram is
224generic (g: common_generics;
225addr_length: positive := 12;
226data_length: positive := 16;
227file_name: string := "memory.bin";
228file_type: file_format := FILE_BINARY);
229port (
230-- port A of dual port RAM
231a_clk: in std_ulogic;
232a_dwe: in std_ulogic;
233a_dre: in std_ulogic;
234a_addr: in std_ulogic_vector(addr_length - 1 downto 0);
235a_din: in std_ulogic_vector(data_length - 1 downto 0);
236a_dout: out std_ulogic_vector(data_length - 1 downto 0) := (others => '0');
237-- port B of dual port RAM
238b_clk: in std_ulogic;
239b_dwe: in std_ulogic;
240b_dre: in std_ulogic;
241b_addr: in std_ulogic_vector(addr_length - 1 downto 0);
242b_din: in std_ulogic_vector(data_length - 1 downto 0);
243b_dout: out std_ulogic_vector(data_length - 1 downto 0) := (others => '0'));
244end component;
245
246component single_port_block_ram is
247generic (g: common_generics;
248addr_length: positive := 12;
249data_length: positive := 16;
250file_name: string := "memory.bin";
251file_type: file_format := FILE_BINARY);
252port (
253clk: in std_ulogic;
254dwe: in std_ulogic;
255dre: in std_ulogic;
256addr: in std_ulogic_vector(addr_length - 1 downto 0);
257din: in std_ulogic_vector(data_length - 1 downto 0);
258dout: out std_ulogic_vector(data_length - 1 downto 0) := (others => '0'));
259end component;
260
261component data_source is
262generic (g: common_generics;
263addr_length: positive := 12;
264data_length: positive := 16;
265file_name: string := "memory.bin";
266file_type: file_format := FILE_BINARY);
267port (
268clk: in std_ulogic;
269rst: in std_ulogic;
270
271ce: in std_ulogic := '1';
272cr: in std_ulogic;
273
274load: in std_ulogic_vector(addr_length - 1 downto 0) := (others => '0');
275load_we: in std_ulogic := '0';
276
277dout: out std_ulogic_vector(data_length - 1 downto 0));
278end component;
279
280component ucpu is
281generic (
282asynchronous_reset: boolean := true; -- use asynchronous reset if true, synchronous if false
283delay: time := 0 ns; -- simulation only
284
285width: positive range 8 to 32 := 8);
286port (
287clk, rst: in std_ulogic;
288
289pc: out std_ulogic_vector(width - 3 downto 0);
290op: in std_ulogic_vector(width - 1 downto 0);
291
292adr: out std_ulogic_vector(width - 3 downto 0);
293di: in std_ulogic_vector(width - 1 downto 0);
294re, we: out std_ulogic;
295do: out std_ulogic_vector(width - 1 downto 0));
296end component;
297
298component ucpu_tb is
299generic (g: common_generics; file_name: string := "ucpu.bin");
300end component;
301
302component restoring_divider is
303generic (g: common_generics; N: positive);
304port (
305clk: in std_ulogic;
306rst: in std_ulogic := '0';
307
308a: in std_ulogic_vector(N - 1 downto 0);
309b: in std_ulogic_vector(N - 1 downto 0);
310start: in std_ulogic;
311done: out std_ulogic;
312c: out std_ulogic_vector(N - 1 downto 0));
313end component;
314
315component restoring_divider_tb is
316generic (g: common_generics);
317end component;
318
319component debounce_us is
320generic (g: common_generics; timer_period_us: natural);
321port (
322clk: in std_ulogic;
323di: in std_ulogic;
324do: out std_ulogic);
325end component;
326
327component debounce_block_us is
328generic (g: common_generics; N: positive; timer_period_us: natural);
329port (
330clk: in std_ulogic;
331di: in std_ulogic_vector(N - 1 downto 0);
332do: out std_ulogic_vector(N - 1 downto 0));
333end component;
334
335component debounce_us_tb is
336generic (g: common_generics);
337end component;
338
339component state_changed is
340generic (g: common_generics);
341port (
342clk: in std_ulogic;
343rst: in std_ulogic;
344di: in std_ulogic;
345do: out std_ulogic);
346end component;
347
348component state_block_changed is
349generic (g: common_generics; N: positive);
350port (
351clk: in std_ulogic;
352rst: in std_ulogic;
353di: in std_ulogic_vector(N - 1 downto 0);
354do: out std_ulogic_vector(N - 1 downto 0));
355end component;
356
357component reset_generator is
358generic (g: common_generics; reset_period_us: natural := 1);
359port (
360clk: in std_logic := 'X';
361rst: out std_logic := '0'); -- reset out!
362end component;
363
364component reset_generator_tb is
365generic (g: common_generics);
366end component;
367
368function n_bits(x: natural) return natural; -- Not synthesizable
369function n_bits(x: std_ulogic_vector) return natural; -- Not synthesizable
370
371component bit_count is
372generic (g: common_generics; N: positive);
373port (
374bits: in std_ulogic_vector(N - 1 downto 0);
375count: out std_ulogic_vector(n_bits(N) downto 0));
376end component;
377
378component bit_count_tb is
379generic (g: common_generics);
380end component;
381
382component majority is
383generic (g: common_generics; N: positive; even_wins: boolean := false);
384port (
385bits: in std_ulogic_vector(N - 1 downto 0);
386vote: out std_ulogic;
387tie: out std_ulogic);
388end component;
389
390component majority_tb is
391generic (g: common_generics);
392end component;
393
394component delay_line is
395generic (g: common_generics; width: positive; depth: natural);
396port (
397clk: in std_ulogic;
398rst: in std_ulogic;
399ce: in std_ulogic := '1';
400di: in std_ulogic_vector(width - 1 downto 0);
401do: out std_ulogic_vector(width - 1 downto 0));
402end component;
403
404component delay_line_tb is
405generic (g: common_generics);
406end component;
407
408component gray_encoder is
409generic (g: common_generics; N: positive);
410port (di: in std_ulogic_vector(N - 1 downto 0);
411do: out std_ulogic_vector(N - 1 downto 0));
412end component;
413
414component gray_decoder is
415generic (g: common_generics; N: positive);
416port (di: in std_ulogic_vector(N - 1 downto 0);
417do: out std_ulogic_vector(N - 1 downto 0));
418end component;
419
420component gray_tb is
421generic (g: common_generics);
422end component;
423
424component parity_module is
425generic (g: common_generics; N: positive; even: boolean);
426port (di: in std_ulogic_vector(N - 1 downto 0);
427do: out std_ulogic);
428end component;
429
430component hamming_7_4_encoder is
431generic (g: common_generics);
432port (
433di: in std_ulogic_vector(3 downto 0);
434do: out std_ulogic_vector(6 downto 0);
435parity: out std_ulogic -- parity over 'di'
436);
437end component;
438
439component hamming_7_4_decoder is
440generic (g: common_generics; secdec: boolean := true);
441port (
442di: in std_ulogic_vector(6 downto 0);
443parity: in std_ulogic;
444do: out std_ulogic_vector(3 downto 0);
445single, double: out std_ulogic);
446end component;
447
448component hamming_7_4_tb is
449generic (g: common_generics);
450end component;
451
452type vga_configuration is record
453clock_frequency: positive; -- pixel clock frequency
454h_pulse: integer; -- horizontal sync pulse width in pixels
455h_back_porch: integer; -- horizontal back porch width in pixels
456h_pixels: integer; -- horizontal display width in pixels
457h_front_porch: integer; -- horizontal front porch width in pixels
458h_polarity: std_ulogic; -- horizontal sync pulse polarity (1 = positive, 0 = negative)
459
460v_pulse: integer; -- vertical sync pulse width in rows
461v_back_porch: integer; -- vertical back porch width in rows
462v_pixels: integer; -- vertical display width in rows
463v_front_porch: integer; -- vertical front porch width in rows
464v_polarity: std_ulogic; -- vertical sync pulse polarity (1 = positive, 0 = negative)
465end record;
466
467constant vga_640x480: vga_configuration := (
468clock_frequency => 25_175_000,
469h_pulse => 96, h_back_porch => 48, h_pixels => 640, h_front_porch => 16, h_polarity => '0',
470v_pulse => 2, v_back_porch => 33, v_pixels => 480, v_front_porch => 10, v_polarity => '0');
471
472constant vga_800x600: vga_configuration := (
473clock_frequency => 40_000_000,
474h_pulse => 128, h_back_porch => 88, h_pixels => 800, h_front_porch => 40, h_polarity => '1',
475v_pulse => 4, v_back_porch => 23, v_pixels => 600, v_front_porch => 1, v_polarity => '1');
476
477constant vga_1024x768: vga_configuration := (
478clock_frequency => 44_900_000,
479h_pulse => 176, h_back_porch => 56, h_pixels => 1024, h_front_porch => 8, h_polarity => '1',
480v_pulse => 8, v_back_porch => 41, v_pixels => 800, v_front_porch => 0, v_polarity => '1');
481
482constant vga_1920x1200: vga_configuration := (
483clock_frequency => 193_160_000,
484h_pulse => 208, h_back_porch => 336, h_pixels => 1920, h_front_porch => 128, h_polarity => '0',
485v_pulse => 3, v_back_porch => 38, v_pixels => 1200, v_front_porch => 1, v_polarity => '1');
486
487component vga_controller is
488generic (
489g: common_generics;
490pixel_clock_frequency: positive := 25_000_000;
491constant cfg: vga_configuration := vga_640x480);
492port (
493clk, rst: in std_ulogic; -- pixel clock, must run at configured frequency
494h_sync, v_sync: out std_ulogic; -- sync pulses
495h_blank, v_blank: out std_ulogic;
496column, row: out integer); -- pixel coordinates
497end component;
498
499component vga_tb is
500generic (g: common_generics; pixel_clock_frequency: positive := 25_000_000; simulation_us: time := 20000 us);
501end component;
502
503constant led_7_segment_character_length: positive := 4;
504subtype led_7_segment_character is std_ulogic_vector(led_7_segment_character_length - 1 downto 0);
505subtype led_7_segment is std_ulogic_vector(7 downto 0);
506
507component led_7_segment_display is
508generic (g: common_generics;
509use_bcd_not_hex: boolean := true;
510refresh_rate_us: natural := 1500;
511number_of_led_displays: positive := 4);
512port (
513clk: in std_ulogic;
514rst: in std_ulogic;
515
516leds_we: in std_ulogic;
517leds: in std_ulogic_vector((number_of_led_displays * led_7_segment_character_length) - 1 downto 0);
518
519-- Physical outputs
520an: out std_ulogic_vector(number_of_led_displays - 1 downto 0); -- anodes, controls on/off
521ka: out std_ulogic_vector(7 downto 0)); -- cathodes, data on display
522end component;
523
524component led_7_segment_display_tb is
525generic (g: common_generics);
526end component;
527
528component sine is
529generic (g: common_generics; pipeline: boolean := true);
530port (
531clk, rst, xwe: in std_ulogic;
532x: in std_ulogic_vector(15 downto 0);
533s: out std_ulogic_vector(15 downto 0));
534end component;
535
536component cosine is
537generic (g: common_generics; pipeline: boolean := true);
538port (
539clk, rst, xwe: in std_ulogic;
540x: in std_ulogic_vector(15 downto 0);
541s: out std_ulogic_vector(15 downto 0));
542end component;
543
544component sine_tb is
545generic (g: common_generics);
546end component;
547
548function max(a: natural; b: natural) return natural;
549function min(a: natural; b: natural) return natural;
550function reverse (a: in std_ulogic_vector) return std_ulogic_vector;
551function invert(slv:std_ulogic_vector) return std_ulogic_vector;
552function parity(slv:std_ulogic_vector; even: boolean) return std_ulogic;
553function parity(slv:std_ulogic_vector; even: std_ulogic) return std_ulogic;
554function or_reduce(slv:std_ulogic_vector) return std_ulogic;
555function and_reduce(slv:std_ulogic_vector) return std_ulogic;
556function select_bit(indexed, selector: std_ulogic_vector) return std_ulogic;
557function priority(order: std_ulogic_vector; high: boolean) return natural;
558function priority(order: std_ulogic_vector; high: boolean) return std_ulogic_vector;
559function mux(a: std_ulogic_vector; b: std_ulogic_vector; sel: std_ulogic) return std_ulogic_vector;
560function mux(a: std_ulogic; b: std_ulogic; sel: std_ulogic) return std_ulogic;
561function mux(a, b : std_ulogic_vector) return std_ulogic;
562function decode(encoded: std_ulogic_vector) return std_ulogic_vector;
563function to_std_ulogic_vector(s: string) return std_ulogic_vector;
564function logical(b: boolean) return std_ulogic;
565function bit_count_f(s: std_ulogic_vector) return integer;
566function hex_char_to_std_ulogic_vector_tb(hc: character) return std_ulogic_vector;
567
568type ulogic_string is array(integer range <>) of std_ulogic_vector(7 downto 0);
569function to_std_ulogic_vector(s: string) return ulogic_string;
570
571-- synthesis translate_off
572subtype configuration_name is string(1 to 8);
573
574type configuration_item is record
575name: configuration_name;
576value: integer;
577end record;
578
579type configuration_items is array(integer range <>) of configuration_item;
580
581function search_configuration_tb(find_me: configuration_name; ci: configuration_items) return integer;
582procedure read_configuration_tb(file_name: string; ci: inout configuration_items);
583procedure write_configuration_tb(file_name: string; ci: configuration_items);
584-- synthesis translate_on
585end;
586
587package body util is
588
589function max(a: natural; b: natural) return natural is
590begin
591if (a > b) then return a; else return b; end if;
592end function;
593
594function min(a: natural; b: natural) return natural is
595begin
596if (a < b) then return a; else return b; end if;
597end function;
598
599function n_bits(x: natural) return natural is -- Not synthesizable
600variable x1: natural := max(x, 1) - 1;
601variable n: natural := 1;
602begin
603while x1 > 1 loop
604x1 := x1 / 2;
605n := n + 1;
606end loop;
607return n;
608end function;
609
610function n_bits(x: std_ulogic_vector) return natural is -- Not synthesizable
611begin
612return n_bits(x'high);
613end function;
614
615-- <https://stackoverflow.com/questions/13584307>
616function reverse (a: in std_ulogic_vector) return std_ulogic_vector is
617variable result: std_ulogic_vector(a'range);
618alias aa: std_ulogic_vector(a'reverse_range) is a;
619begin
620for i in aa'range loop
621result(i) := aa(i);
622end loop;
623return result;
624end;
625
626function invert(slv: std_ulogic_vector) return std_ulogic_vector is
627variable z: std_ulogic_vector(slv'range);
628begin
629for i in slv'range loop
630z(i) := not(slv(i));
631end loop;
632return z;
633end;
634
635function parity(slv: std_ulogic_vector; even: boolean) return std_ulogic is
636variable z: std_ulogic := '0';
637begin
638if not even then
639z := '1';
640end if;
641for i in slv'range loop
642z := z xor slv(i);
643end loop;
644return z;
645end;
646
647function parity(slv:std_ulogic_vector; even: std_ulogic) return std_ulogic is
648variable z: boolean := false;
649begin
650if even = '1' then
651z := true;
652end if;
653return parity(slv, z);
654end;
655
656function or_reduce(slv:std_ulogic_vector) return std_ulogic is
657variable z: std_ulogic := '0';
658begin
659for i in slv'range loop
660z := z or slv(i);
661end loop;
662return z;
663end;
664
665function and_reduce(slv:std_ulogic_vector) return std_ulogic is
666variable z: std_ulogic := '1';
667begin
668for i in slv'range loop
669z := z and slv(i);
670end loop;
671return z;
672end;
673
674function select_bit(indexed, selector: std_ulogic_vector) return std_ulogic is
675variable z: std_ulogic := 'X';
676begin
677assert n_bits(indexed) = selector'high + 1 severity failure;
678for i in indexed'range loop
679if i = to_integer(unsigned(selector)) then
680z := indexed(i);
681end if;
682end loop;
683return z;
684end;
685
686function priority(order: std_ulogic_vector; high: boolean) return natural is
687variable p: natural := 0;
688begin
689if not high then
690for i in order'high + 1 downto 1 loop
691if order(i-1) = '1' then
692p := i - 1;
693end if;
694end loop;
695else
696for i in 1 to order'high + 1 loop
697if order(i-1) = '1' then
698p := i - 1;
699end if;
700end loop;
701end if;
702return p;
703end;
704
705function priority(order: std_ulogic_vector; high: boolean) return std_ulogic_vector is
706variable length: natural := n_bits(order'length);
707begin
708return std_ulogic_vector(to_unsigned(priority(order, high), length));
709end;
710
711function mux(a: std_ulogic_vector; b: std_ulogic_vector; sel: std_ulogic) return std_ulogic_vector is
712variable m: std_ulogic_vector(a'range) := (others => 'X');
713begin
714if sel = '0' then m := a; else m := b; end if;
715return m;
716end;
717
718function mux(a: std_ulogic; b: std_ulogic; sel: std_ulogic) return std_ulogic is
719variable m: std_ulogic := 'X';
720begin
721if sel = '0' then m := a; else m := b; end if;
722return m;
723end;
724
725function mux(a, b : std_ulogic_vector) return std_ulogic is
726variable r: std_ulogic_vector(b'length - 1 downto 0) := (others => 'X');
727variable i: integer;
728begin
729r := b;
730i := to_integer(unsigned(a));
731return r(i);
732end;
733
734function decode(encoded : std_ulogic_vector) return std_ulogic_vector is
735variable r: std_ulogic_vector((2 ** encoded'length) - 1 downto 0) := (others => '0');
736variable i: natural;
737begin
738i := to_integer(unsigned(encoded));
739r(i) := '1';
740return r;
741end;
742
743function logical(b: boolean) return std_ulogic is
744begin
745if b then return '1'; else return '0'; end if;
746end;
747
748function hex_char_to_std_ulogic_vector_tb(hc: character) return std_ulogic_vector is
749variable slv: std_ulogic_vector(3 downto 0);
750begin
751case hc is
752when '0' => slv := "0000";
753when '1' => slv := "0001";
754when '2' => slv := "0010";
755when '3' => slv := "0011";
756when '4' => slv := "0100";
757when '5' => slv := "0101";
758when '6' => slv := "0110";
759when '7' => slv := "0111";
760when '8' => slv := "1000";
761when '9' => slv := "1001";
762when 'A' => slv := "1010";
763when 'a' => slv := "1010";
764when 'B' => slv := "1011";
765when 'b' => slv := "1011";
766when 'C' => slv := "1100";
767when 'c' => slv := "1100";
768when 'D' => slv := "1101";
769when 'd' => slv := "1101";
770when 'E' => slv := "1110";
771when 'e' => slv := "1110";
772when 'F' => slv := "1111";
773when 'f' => slv := "1111";
774when others => slv := "XXXX";
775end case;
776assert (slv /= "XXXX") report " not a valid hex character: " & hc severity failure;
777return slv;
778end;
779
780function bit_count_f(s : std_ulogic_vector) return integer is
781variable count: natural := 0;
782begin
783for i in s'range loop
784if s(i) = '1' then
785count := count + 1;
786end if;
787end loop;
788return count;
789end;
790
791-- <https://stackoverflow.com/questions/30519849/vhdl-convert-string-to-std-logic-vector>
792function to_std_ulogic_vector(s: string) return std_ulogic_vector is
793variable ret: std_ulogic_vector(s'length*8-1 downto 0);
794begin
795for i in s'range loop
796ret(i*8+7 downto i*8) := std_ulogic_vector(to_unsigned(character'pos(s(i)), 8));
797end loop;
798return ret;
799end;
800
801function to_std_ulogic_vector(s: string) return ulogic_string is
802variable ret: ulogic_string(s'range);
803begin
804for i in s'range loop
805ret(i) := std_ulogic_vector(to_unsigned(character'pos(s(i)), 8));
806end loop;
807return ret;
808end;
809
810-- synthesis translate_off
811
812-- Find a string in a configuration items array, or returns -1 on
813-- failure to find the string.
814function search_configuration_tb(find_me: configuration_name; ci: configuration_items) return integer is
815begin
816for i in ci'range loop
817if ci(i).name = find_me then
818return i;
819end if;
820end loop;
821return -1;
822end;
823
824-- VHDL provides quite a limited set of options for dealing with
825-- operations that are not synthesizeable but would be useful for
826-- in test benches. This method provides a crude way of reading
827-- in configurable options. It has a very strict format.
828--
829-- The format is line oriented, it expects a string on a line
830-- with a length equal to the "configuration_name" type, which
831-- is a subtype of "string". It finds the corresponding record
832-- in configuration_items if it exists. It then reads in an
833-- integer from the next line and sets the record for it.
834--
835-- Any deviation from this format causes an error and the simulation
836-- to halt, whilst not a good practice to do error checking with asserts
837-- there is no better way in VHDL in this case. The only sensible
838-- action on an error would for the configuration file to be fixed
839-- anyway.
840--
841-- Comment lines and variable length strings would be nice, but
842-- are too much of a hassle.
843--
844-- The configuration function only deal with part of the configuration
845-- process, it does not deal with deserialization into structures
846-- more useful to the user - like into individual signals.
847--
848procedure read_configuration_tb(file_name: string; ci: inout configuration_items) is
849file in_file: text is in file_name;
850variable in_line: line;
851variable d: integer;
852variable s: configuration_name;
853variable index: integer;
854begin
855while not endfile(in_file) loop
856
857readline(in_file, in_line);
858read(in_line, s);
859index := search_configuration_tb(s, ci);
860
861assert index >= 0 report "Unknown configuration item: " & s severity failure;
862
863readline(in_file, in_line);
864read(in_line, d);
865
866ci(index).value := d;
867
868report "Config Item: '" & ci(index).name & "' = " & integer'image(ci(index).value);
869end loop;
870file_close(in_file);
871end procedure;
872
873procedure write_configuration_tb(file_name: string; ci: configuration_items) is
874file out_file: text is out file_name;
875variable out_line: line;
876begin
877for i in ci'range loop
878write(out_line, ci(i).name);
879writeline(out_file, out_line);
880write(out_line, ci(i).value);
881writeline(out_file, out_line);
882end loop;
883end procedure;
884
885-- synthesis translate_on
886end;
887
888------------------------- Utility Test Bench ----------------------------------------
889library ieee, work;
890use ieee.std_logic_1164.all;
891use work.util.all;
892
893entity util_tb is
894generic (g: common_generics);
895end entity;
896
897architecture behav of util_tb is
898begin
899-- The "io_pins_tb" works correctly, however in GHDL 0.29, compiled under
900-- Windows, fails to simulate this component correctly, resulting
901-- in a crash. This does not affect the Linux build of GHDL. It has
902-- something to do with 'Z' values for std_logic types.
903uut_io_pins: work.util.io_pins_tb generic map (g => g);
904uut_timer_us: work.util.timer_us_tb generic map (g => g);
905uut_full_add: work.util.full_adder_tb generic map (g => g);
906uut_fifo: work.util.fifo_tb generic map (g => g);
907uut_counter: work.util.counter_tb generic map (g => g);
908uut_ucpu: work.util.ucpu_tb generic map (g => g);
909uut_rdivider: work.util.restoring_divider_tb generic map (g => g);
910uut_debounce: work.util.debounce_us_tb generic map (g => g);
911uut_rst_gen: work.util.reset_generator_tb generic map (g => g);
912uut_bit_cnt: work.util.bit_count_tb generic map (g => g);
913uut_majority: work.util.majority_tb generic map (g => g);
914uut_delay_ln: work.util.delay_line_tb generic map (g => g);
915uut_rising: work.util.rising_edge_detector_tb generic map (g => g);
916uut_shiftReg: work.util.shift_register_tb generic map (g => g);
917uut_lfsr: work.util.lfsr_tb generic map (g => g);
918uut_gray: work.util.gray_tb generic map (g => g);
919uut_ham: work.util.hamming_7_4_tb generic map (g => g); -- Oink!
920uut_vga: work.util.vga_tb generic map (g => g, simulation_us => 1 us);
921uut_sine: work.util.sine_tb generic map (g => g);
922uut_7_seg: work.util.led_7_segment_display_tb generic map (g => g);
923
924stimulus_process: process
925begin
926assert max(5, 4) = 5 severity failure;
927assert work.util.min(5, 4) = 4 severity failure;
928assert n_bits(1) = 1 severity failure;
929assert n_bits(2) = 1 severity failure;
930assert n_bits(7) = 3 severity failure;
931assert n_bits(8) = 3 severity failure;
932assert n_bits(9) = 4 severity failure;
933assert reverse("1") = "1" severity failure;
934assert reverse("0") = "0" severity failure;
935assert reverse("10") = "01" severity failure;
936assert reverse("11") = "11" severity failure;
937assert reverse("0101") = "1010" severity failure;
938assert invert("1") = "0" severity failure;
939assert invert("0") = "1" severity failure;
940assert invert("0101") = "1010" severity failure;
941assert select_bit("01000", "01") = '1' severity failure;
942assert parity("0", true) = '0' severity failure;
943assert parity("1", true) = '1' severity failure;
944assert parity("11", true) = '0' severity failure;
945assert parity("1010001", true) = '1' severity failure;
946assert parity("0", false) = '1' severity failure;
947assert parity("1", false) = '0' severity failure;
948assert parity("11", false) = '1' severity failure;
949assert parity("1010001", false) = '0' severity failure;
950assert or_reduce("0000") = '0' severity failure;
951assert or_reduce("0") = '0' severity failure;
952assert or_reduce("1") = '1' severity failure;
953assert or_reduce("11") = '1' severity failure;
954assert or_reduce("10") = '1' severity failure;
955assert or_reduce("01") = '1' severity failure;
956assert and_reduce("01") = '0' severity failure;
957assert and_reduce("11") = '1' severity failure;
958assert and_reduce("1") = '1' severity failure;
959assert and_reduce("0") = '0' severity failure;
960assert and_reduce("10") = '0' severity failure;
961assert priority("01001", false) = 1 severity failure;
962assert mux("1010", "0101", '0') = "1010" severity failure;
963assert mux("1010", "0101", '1') = "0101" severity failure;
964assert decode("00") = "0001" severity failure;
965assert decode("01") = "0010" severity failure;
966assert decode("10") = "0100" severity failure;
967assert decode("11") = "1000" severity failure;
968wait;
969end process;
970end architecture;
971
972------------------------- Function Test Bench ---------------------------------------
973
974------------------------- Test bench clock source -----------------------------------
975
976library ieee, work;
977use ieee.std_logic_1164.all;
978use ieee.numeric_std.all;
979use ieee.math_real.all;
980use work.util.common_generics;
981
982entity clock_source_tb is
983generic (g: common_generics; hold_rst: positive);
984port (
985stop: in std_ulogic := '0';
986clk: out std_ulogic;
987clk_with_jitter: out std_ulogic := '0';
988rst: out std_ulogic := '0');
989end entity;
990
991architecture rtl of clock_source_tb is
992constant clock_period: time := 1000 ms / g.clock_frequency;
993signal jitter_delay: time := 0 ns;
994signal jitter_clk: std_ulogic := '0';
995begin
996jitter_clk_process: process
997variable seed1, seed2: positive;
998variable r: real;
999variable jit_high, jit_low: time := 0 ns;
1000begin
1001while stop = '0' loop
1002uniform(seed1, seed2, r);
1003jit_high := r * g.delay;
1004uniform(seed1, seed2, r);
1005jit_low := r * g.delay;
1006uniform(seed1, seed2, r);
1007if r < 0.5 then jit_high := -jit_high; end if;
1008uniform(seed1, seed2, r);
1009if r < 0.5 then jit_low := -jit_low; end if;
1010clk_with_jitter <= '1';
1011wait for (clock_period / 2) + jit_high;
1012clk_with_jitter <= '0';
1013wait for (clock_period / 2) + jit_low;
1014end loop;
1015wait;
1016end process;
1017
1018clk_process: process
1019begin
1020while stop = '0' loop
1021clk <= '1';
1022wait for clock_period / 2;
1023clk <= '0';
1024wait for clock_period / 2;
1025end loop;
1026wait;
1027end process;
1028
1029rst_process: process
1030begin
1031rst <= '1';
1032wait for clock_period * hold_rst;
1033rst <= '0';
1034wait;
1035end process;
1036
1037end architecture;
1038
1039------------------------- Generic Register of std_ulogic_vector ----------------------
1040
1041library ieee, work;
1042use ieee.std_logic_1164.all;
1043use ieee.numeric_std.all;
1044use work.util.common_generics;
1045
1046entity reg is
1047generic (g: common_generics; N: positive);
1048port (
1049clk: in std_ulogic;
1050rst: in std_ulogic;
1051we: in std_ulogic;
1052di: in std_ulogic_vector(N - 1 downto 0);
1053do: out std_ulogic_vector(N - 1 downto 0));
1054end entity;
1055
1056architecture rtl of reg is
1057signal r_c, r_n: std_ulogic_vector(N - 1 downto 0) := (others => '0');
1058begin
1059do <= r_c after g.delay;
1060
1061process(rst, clk)
1062begin
1063if rst = '1' and g.asynchronous_reset then
1064r_c <= (others => '0') after g.delay;
1065elsif rising_edge(clk) then
1066if rst = '1' and not g.asynchronous_reset then
1067r_c <= (others => '0') after g.delay;
1068else
1069r_c <= r_n after g.delay;
1070end if;
1071end if;
1072end process;
1073
1074process(r_c, di, we)
1075begin
1076if we = '1' then
1077r_n <= di after g.delay;
1078else
1079r_n <= r_c after g.delay;
1080end if;
1081end process;
1082end;
1083
1084------------------------- Generic Register of std_ulogic_vector ----------------------
1085
1086------------------------- Shift register --------------------------------------------
1087library ieee, work;
1088use ieee.std_logic_1164.all;
1089use work.util.common_generics;
1090
1091-- https://stackoverflow.com/questions/36342960/optional-ports-in-vhdl
1092entity shift_register is
1093generic (g: common_generics; N: positive);
1094port (
1095clk: in std_ulogic;
1096rst: in std_ulogic;
1097we: in std_ulogic;
1098di: in std_ulogic;
1099do: out std_ulogic;
1100
1101-- optional
1102load_we: in std_ulogic := '0';
1103load_i: in std_ulogic_vector(N - 1 downto 0) := (others => '0');
1104load_o: out std_ulogic_vector(N - 1 downto 0));
1105end entity;
1106
1107architecture rtl of shift_register is
1108signal r_c, r_n : std_ulogic_vector(N - 1 downto 0) := (others => '0');
1109begin
1110do <= r_c(0);
1111load_o <= r_c;
1112
1113process(rst, clk)
1114begin
1115if rst = '1' and g.asynchronous_reset then
1116r_c <= (others => '0') after g.delay;
1117elsif rising_edge(clk) then
1118if rst = '1' and not g.asynchronous_reset then
1119r_c <= (others => '0') after g.delay;
1120else
1121r_c <= r_n after g.delay;
1122end if;
1123end if;
1124end process;
1125
1126process(r_c, di, we, load_i, load_we)
1127begin
1128if load_we = '1' then
1129r_n <= load_i after g.delay;
1130else
1131r_n <= "0" & r_c(N - 1 downto 1) after g.delay;
1132if we = '1' then
1133r_n(N-1) <= di after g.delay;
1134end if;
1135end if;
1136end process;
1137end;
1138
1139library ieee, work;
1140use ieee.std_logic_1164.all;
1141use work.util.common_generics;
1142
1143entity shift_register_tb is
1144generic (g: common_generics);
1145end entity;
1146
1147architecture behav of shift_register_tb is
1148constant N: positive := 8;
1149constant clock_period: time := 1000 ms / g.clock_frequency;
1150signal we: std_ulogic := '0';
1151signal di: std_ulogic := '0';
1152signal do: std_ulogic := '0';
1153
1154signal clk, rst: std_ulogic := '0';
1155signal stop: std_ulogic := '0';
1156begin
1157cs: entity work.clock_source_tb
1158generic map (g => g, hold_rst => 2)
1159port map (stop => stop, clk => clk, rst => rst);
1160
1161uut: entity work.shift_register
1162generic map (g => g, N => N) port map (clk => clk, rst => rst, we => we, di => di, do => do);
1163
1164stimulus_process: process
1165begin
1166-- Put a bit into the shift register and wait
1167-- for it to come out the other size.
1168wait until rst = '0';
1169di <= '1';
1170we <= '1';
1171wait for clock_period;
1172di <= '0';
1173we <= '0';
1174for I in 0 to 7 loop
1175assert do = '0' report "bit appeared to quickly";
1176wait for clock_period;
1177end loop;
1178assert do = '1' report "bit disappeared in shift register";
1179wait for clock_period * 1;
1180assert do = '0' report "extra bit set in shift register";
1181stop <= '1';
1182wait;
1183end process;
1184end;
1185------------------------- Shift register --------------------------------------------
1186
1187------------------------- Microsecond Timer -----------------------------------------
1188library ieee, work;
1189use ieee.std_logic_1164.all;
1190use ieee.numeric_std.all;
1191use work.util.max;
1192use work.util.n_bits;
1193use work.util.common_generics;
1194
1195entity timer_us is
1196generic (g: common_generics; timer_period_us: natural);
1197port (
1198clk: in std_ulogic;
1199rst: in std_ulogic;
1200co: out std_ulogic);
1201end timer_us;
1202
1203architecture rtl of timer_us is
1204constant cycles: natural := (g.clock_frequency / 1000000) * timer_period_us;
1205subtype counter is unsigned(max(1, n_bits(cycles) - 1) downto 0);
1206signal c_c, c_n: counter := (others => '0');
1207begin
1208process (clk, rst)
1209begin
1210if rst = '1' and g.asynchronous_reset then
1211c_c <= (others => '0') after g.delay;
1212elsif rising_edge(clk) then
1213if rst = '1' and not g.asynchronous_reset then
1214c_c <= (others => '0') after g.delay;
1215else
1216c_c <= c_n after g.delay;
1217end if;
1218end if;
1219end process;
1220
1221process (c_c)
1222begin
1223if c_c = (cycles - 1) then
1224c_n <= (others => '0') after g.delay;
1225co <= '1' after g.delay;
1226else
1227c_n <= c_c + 1 after g.delay;
1228co <= '0' after g.delay;
1229end if;
1230end process;
1231end;
1232
1233library ieee, work;
1234use ieee.std_logic_1164.all;
1235use ieee.numeric_std.all;
1236use work.util.common_generics;
1237
1238entity timer_us_tb is
1239generic (g: common_generics);
1240end;
1241
1242architecture behav of timer_us_tb is
1243constant clock_period: time := 1000 ms / g.clock_frequency;
1244signal co: std_ulogic := 'X';
1245signal clk, rst: std_ulogic := '0';
1246signal stop: std_ulogic := '0';
1247begin
1248cs: entity work.clock_source_tb
1249generic map (g => g, hold_rst => 2)
1250port map (stop => stop, clk => clk, rst => rst);
1251
1252uut: entity work.timer_us
1253generic map (g => g, timer_period_us => 1)
1254port map (clk => clk, rst => rst, co => co);
1255
1256stimulus_process: process
1257begin
1258wait for 1 us;
1259assert co = '0' severity failure;
1260wait for clock_period;
1261assert co = '1' severity failure;
1262stop <= '1';
1263wait;
1264end process;
1265end;
1266
1267------------------------- Microsecond Timer -----------------------------------------
1268
1269------------------------- Rising Edge Detector --------------------------------------
1270library ieee, work;
1271use ieee.std_logic_1164.all;
1272use work.util.common_generics;
1273
1274entity rising_edge_detector is
1275generic (g: common_generics);
1276port (
1277clk: in std_ulogic;
1278rst: in std_ulogic;
1279di: in std_ulogic;
1280do: out std_ulogic);
1281end;
1282
1283architecture rtl of rising_edge_detector is
1284signal sin_0: std_ulogic := '0';
1285signal sin_1: std_ulogic := '0';
1286begin
1287red: process(clk, rst)
1288begin
1289if rst = '1' and g.asynchronous_reset then
1290sin_0 <= '0' after g.delay;
1291sin_1 <= '0' after g.delay;
1292elsif rising_edge(clk) then
1293if rst = '1' and not g.asynchronous_reset then
1294sin_0 <= '0' after g.delay;
1295sin_1 <= '0' after g.delay;
1296else
1297sin_0 <= di after g.delay;
1298sin_1 <= sin_0 after g.delay;
1299end if;
1300end if;
1301end process;
1302do <= not sin_1 and sin_0;
1303end architecture;
1304
1305library ieee, work;
1306use ieee.std_logic_1164.all;
1307use work.util.common_generics;
1308
1309entity rising_edge_detector_tb is
1310generic (g: common_generics);
1311end;
1312
1313architecture behav of rising_edge_detector_tb is
1314constant clock_period: time := 1000 ms / g.clock_frequency;
1315signal di: std_ulogic := '0';
1316signal do: std_ulogic := 'X';
1317
1318signal clk, rst: std_ulogic := '0';
1319signal stop: std_ulogic := '0';
1320begin
1321cs: entity work.clock_source_tb
1322generic map (g => g, hold_rst => 2)
1323port map (stop => stop, clk => clk, rst => rst);
1324
1325uut: entity work.rising_edge_detector
1326generic map (g => g)
1327port map (clk => clk, rst => rst, di => di, do => do);
1328
1329stimulus_process: process
1330begin
1331wait for clock_period * 5;
1332assert do = '0' severity failure;
1333wait for clock_period;
1334di <= '1';
1335wait for clock_period * 0.5;
1336assert do = '1' severity failure;
1337wait for clock_period * 1.5;
1338di <= '0';
1339assert do = '0' severity failure;
1340wait for clock_period;
1341assert do = '0' severity failure;
1342
1343assert stop = '0' report "Test bench not run to completion";
1344stop <= '1';
1345wait;
1346end process;
1347end architecture;
1348
1349library ieee, work;
1350use ieee.std_logic_1164.all;
1351use work.util.common_generics;
1352
1353entity rising_edge_detectors is
1354generic (g: common_generics; N: positive);
1355port (
1356clk: in std_ulogic;
1357rst: in std_ulogic;
1358di: in std_ulogic_vector(N - 1 downto 0);
1359do: out std_ulogic_vector(N - 1 downto 0));
1360end entity;
1361
1362architecture structural of rising_edge_detectors is
1363begin
1364changes: for i in N - 1 downto 0 generate
1365d_instance: work.util.rising_edge_detector
1366generic map (g => g)
1367port map (clk => clk, rst => rst, di => di(i), do => do(i));
1368end generate;
1369end architecture;
1370
1371------------------------- Rising Edge Detector --------------------------------------
1372
1373------------------------- Half Adder ------------------------------------------------
1374library ieee, work;
1375use ieee.std_logic_1164.all;
1376use work.util.common_generics;
1377
1378entity half_adder is
1379generic (g: common_generics);
1380port (
1381a: in std_ulogic;
1382b: in std_ulogic;
1383sum: out std_ulogic;
1384carry: out std_ulogic);
1385end entity;
1386
1387architecture rtl of half_adder is
1388begin
1389sum <= a xor b after g.delay;
1390carry <= a and b after g.delay;
1391end architecture;
1392
1393------------------------- Half Adder ------------------------------------------------
1394
1395------------------------- Full Adder ------------------------------------------------
1396
1397library ieee, work;
1398use ieee.std_logic_1164.all;
1399use work.util.common_generics;
1400
1401entity full_adder is
1402generic (g: common_generics);
1403port (
1404x: in std_ulogic;
1405y: in std_ulogic;
1406z: in std_ulogic;
1407sum: out std_ulogic;
1408carry: out std_ulogic);
1409end entity;
1410
1411architecture rtl of full_adder is
1412signal carry1, carry2, sum1: std_ulogic;
1413begin
1414ha1: entity work.half_adder generic map (g => g) port map (a => x, b => y, sum => sum1, carry => carry1);
1415ha2: entity work.half_adder generic map (g => g) port map (a => sum1, b => z, sum => sum, carry => carry2);
1416carry <= carry1 or carry2 after g.delay;
1417end architecture;
1418
1419library ieee, work;
1420use ieee.std_logic_1164.all;
1421use work.util.common_generics;
1422
1423entity full_adder_tb is
1424generic (g: common_generics);
1425end entity;
1426
1427architecture behav of full_adder_tb is
1428constant clock_period: time := 1000 ms / g.clock_frequency;
1429signal x, y, z: std_ulogic := '0';
1430signal sum, carry: std_ulogic := '0';
1431
1432type stimulus_data is array (0 to 7) of std_ulogic_vector(2 downto 0);
1433type stimulus_result is array (stimulus_data'range) of std_ulogic_vector(0 to 1);
1434
1435constant data: stimulus_data := (
14360 => "000", 1 => "001",
14372 => "010", 3 => "011",
14384 => "100", 5 => "101",
14396 => "110", 7 => "111");
1440
1441constant result: stimulus_result := (
14420 => "00", 1 => "10",
14432 => "10", 3 => "01",
14444 => "10", 5 => "01",
14456 => "01", 7 => "11");
1446
1447signal clk, rst: std_ulogic := '0';
1448signal stop: std_ulogic := '0';
1449begin
1450cs: entity work.clock_source_tb
1451generic map (g => g, hold_rst => 2)
1452port map (stop => stop, clk => clk, rst => rst);
1453
1454uut: entity work.full_adder
1455generic map (g => g)
1456port map (x => x, y => y, z => z, sum => sum, carry => carry);
1457
1458stimulus_process: process
1459begin
1460wait for clock_period;
1461for i in data'range loop
1462x <= data(i)(0);
1463y <= data(i)(1);
1464z <= data(i)(2);
1465wait for clock_period;
1466assert sum = result(i)(0) and carry = result(i)(1)
1467report
1468"For: " & std_ulogic'image(x) & std_ulogic'image(y) & std_ulogic'image(z) &
1469" Got: " & std_ulogic'image(sum) & std_ulogic'image(carry) &
1470" Expected: " & std_ulogic'image(result(i)(0)) & std_ulogic'image(result(i)(1))
1471severity failure;
1472wait for clock_period;
1473end loop;
1474
1475stop <= '1';
1476wait;
1477end process;
1478end architecture;
1479
1480------------------------- Full Adder ------------------------------------------------
1481
1482------------------------- FIFO ------------------------------------------------------
1483library ieee, work;
1484use ieee.std_logic_1164.all;
1485use ieee.numeric_std.all;
1486use work.util.common_generics;
1487
1488entity fifo is
1489generic (g: common_generics;
1490data_width: positive;
1491fifo_depth: positive;
1492read_first: boolean := true);
1493port (
1494clk: in std_ulogic;
1495rst: in std_ulogic;
1496di: in std_ulogic_vector(data_width - 1 downto 0);
1497we: in std_ulogic;
1498re: in std_ulogic;
1499do: out std_ulogic_vector(data_width - 1 downto 0);
1500
1501-- optional
1502full: out std_ulogic := '0';
1503empty: out std_ulogic := '1');
1504end fifo;
1505
1506architecture behavior of fifo is
1507type fifo_data_t is array (0 to fifo_depth - 1) of std_ulogic_vector(di'range);
1508signal data: fifo_data_t := (others => (others => '0'));
1509function rindex_init return integer is
1510begin
1511if read_first then
1512return 0;
1513end if;
1514return fifo_depth - 1;
1515end function;
1516
1517signal count: integer range 0 to fifo_depth := 0;
1518signal windex: integer range 0 to fifo_depth - 1 := 0;
1519signal rindex: integer range 0 to fifo_depth - 1 := rindex_init;
1520
1521signal is_full: std_ulogic := '0';
1522signal is_empty: std_ulogic := '1';
1523begin
1524do <= data(rindex) after g.delay;
1525full <= is_full after g.delay; -- buffer these bad boys
1526empty <= is_empty after g.delay;
1527is_full <= '1' when count = fifo_depth else '0' after g.delay;
1528is_empty <= '1' when count = 0 else '0' after g.delay;
1529
1530process (rst, clk) is
1531begin
1532if rst = '1' and g.asynchronous_reset then
1533windex <= 0 after g.delay;
1534count <= 0 after g.delay;
1535rindex <= rindex_init after g.delay;
1536elsif rising_edge(clk) then
1537if rst = '1' and not g.asynchronous_reset then
1538windex <= 0 after g.delay;
1539count <= 0 after g.delay;
1540rindex <= rindex_init after g.delay;
1541else
1542if we = '1' and re = '0' then
1543if is_full = '0' then
1544count <= count + 1 after g.delay;
1545end if;
1546elsif we = '0' and re = '1' then
1547if is_empty = '0' then
1548count <= count - 1 after g.delay;
1549end if;
1550end if;
1551
1552if re = '1' and is_empty = '0' then
1553if rindex = (fifo_depth - 1) then
1554rindex <= 0 after g.delay;
1555else
1556rindex <= rindex + 1 after g.delay;
1557end if;
1558end if;
1559
1560if we = '1' and is_full = '0' then
1561if windex = (fifo_depth - 1) then
1562windex <= 0 after g.delay;
1563else
1564windex <= windex + 1 after g.delay;
1565end if;
1566data(windex) <= di after g.delay;
1567end if;
1568end if;
1569end if;
1570end process;
1571end behavior;
1572
1573library ieee, work;
1574use ieee.std_logic_1164.all;
1575use ieee.numeric_std.all;
1576use work.util.common_generics;
1577
1578entity fifo_tb is
1579generic (g: common_generics);
1580end entity;
1581
1582architecture behavior of fifo_tb is
1583constant clock_period: time := 1000 ms / g.clock_frequency;
1584constant data_width: positive := 8;
1585constant fifo_depth: positive := 16;
1586
1587signal di: std_ulogic_vector(data_width - 1 downto 0) := (others => '0');
1588signal re: std_ulogic := '0';
1589signal we: std_ulogic := '0';
1590
1591signal do: std_ulogic_vector(data_width - 1 downto 0) := (others => '0');
1592signal empty: std_ulogic := '0';
1593signal full: std_ulogic := '0';
1594
1595signal clk, rst: std_ulogic := '0';
1596signal stop_w: std_ulogic := '0';
1597signal stop_r: std_ulogic := '0';
1598signal stop: std_ulogic := '0';
1599begin
1600cs: entity work.clock_source_tb
1601generic map (g => g, hold_rst => 2)
1602port map (stop => stop, clk => clk, rst => rst);
1603
1604stop <= '1' when stop_w = '1' and stop_r = '1' else '0';
1605
1606uut: entity work.fifo
1607generic map (g => g, data_width => data_width, fifo_depth => fifo_depth)
1608port map (
1609clk => clk,
1610rst => rst,
1611di => di,
1612we => we,
1613re => re,
1614do => do,
1615full => full,
1616empty => empty);
1617
1618write_process: process
1619variable counter: unsigned (data_width - 1 downto 0) := (others => '0');
1620begin
1621wait for clock_period * 20;
1622
1623for i in 1 to 32 loop
1624counter := counter + 1;
1625di <= std_ulogic_vector(counter);
1626wait for clock_period * 1;
1627we <= '1';
1628wait for clock_period * 1;
1629we <= '0';
1630end loop;
1631
1632wait for clock_period * 20;
1633
1634for i in 1 to 32 loop
1635counter := counter + 1;
1636di <= std_ulogic_vector(counter);
1637wait for clock_period * 1;
1638we <= '1';
1639wait for clock_period * 1;
1640we <= '0';
1641end loop;
1642
1643stop_w <= '1';
1644wait;
1645end process;
1646
1647read_process: process
1648begin
1649wait for clock_period * 60;
1650re <= '1';
1651wait for clock_period * 60;
1652re <= '0';
1653wait for clock_period * 256 * 2;
1654re <= '1';
1655
1656stop_r <= '1';
1657wait;
1658end process;
1659end architecture;
1660
1661------------------------- FIFO ------------------------------------------------------
1662
1663------------------------- Free running counter --------------------------------------
1664
1665library ieee, work;
1666use ieee.std_logic_1164.all;
1667use ieee.numeric_std.all;
1668use work.util.common_generics;
1669
1670entity counter is
1671generic (g: common_generics;
1672N: positive);
1673port (
1674clk: in std_ulogic;
1675rst: in std_ulogic;
1676ce: in std_ulogic;
1677cr: in std_ulogic;
1678dout: out std_ulogic_vector(N - 1 downto 0);
1679
1680-- optional
1681load_we: in std_ulogic := '0';
1682load_i: in std_ulogic_vector(N - 1 downto 0) := (others => '0'));
1683end entity;
1684
1685architecture rtl of counter is
1686signal c_c, c_n: unsigned(N - 1 downto 0) := (others => '0');
1687begin
1688dout <= std_ulogic_vector(c_c) after g.delay;
1689
1690process(clk, rst)
1691begin
1692if rst = '1' and g.asynchronous_reset then
1693c_c <= (others => '0') after g.delay;
1694elsif rising_edge(clk) then
1695if rst = '1' and not g.asynchronous_reset then
1696c_c <= (others => '0') after g.delay;
1697else
1698c_c <= c_n after g.delay;
1699end if;
1700end if;
1701end process;
1702
1703process(c_c, cr, ce, load_we, load_i)
1704begin
1705c_n <= c_c;
1706if load_we = '1' then
1707c_n <= unsigned(load_i) after g.delay;
1708else
1709if cr = '1' then
1710c_n <= (others => '0') after g.delay;
1711elsif ce = '1' then
1712c_n <= c_c + 1 after g.delay;
1713end if;
1714end if;
1715end process;
1716
1717end architecture;
1718
1719library ieee, work;
1720use ieee.std_logic_1164.all;
1721use ieee.numeric_std.all;
1722use work.util.common_generics;
1723
1724entity counter_tb is
1725generic (g: common_generics);
1726end entity;
1727
1728architecture behavior of counter_tb is
1729constant clock_period: time := 1000 ms / g.clock_frequency;
1730constant length: positive := 2;
1731
1732-- inputs
1733signal ce: std_ulogic := '0';
1734signal cr: std_ulogic := '0';
1735
1736-- outputs
1737signal dout: std_ulogic_vector(length - 1 downto 0);
1738
1739-- test data
1740type stimulus_data is array (0 to 16) of std_ulogic_vector(1 downto 0);
1741type stimulus_result is array (stimulus_data'range) of std_ulogic_vector(0 to 1);
1742
1743constant data: stimulus_data := (
17440 => "00", 1 => "00",
17452 => "01", 3 => "01",
17464 => "00", 5 => "00",
17476 => "10", 7 => "00",
17488 => "01", 9 => "01",
174910 => "11", 11 => "00",
175012 => "01", 13 => "01",
175114 => "01", 15 => "01",
175216 => "01");
1753
1754constant result: stimulus_result := (
17550 => "00", 1 => "00",
17562 => "00", 3 => "01",
17574 => "10", 5 => "10",
17586 => "10", 7 => "00",
17598 => "00", 9 => "01",
176010 => "10", 11 => "00",
176112 => "00", 13 => "01",
176214 => "10", 15 => "11",
176316 => "00");
1764
1765signal clk, rst: std_ulogic := '0';
1766signal stop: std_ulogic := '0';
1767begin
1768cs: entity work.clock_source_tb
1769generic map (g => g, hold_rst => 2)
1770port map (stop => stop, clk => clk, rst => rst);
1771
1772uut: entity work.counter
1773generic map (g => g, N => length)
1774port map (
1775clk => clk,
1776rst => rst,
1777ce => ce,
1778cr => cr,
1779dout => dout);
1780
1781stimulus_process: process
1782begin
1783wait for clock_period;
1784for i in data'range loop
1785ce <= data(i)(0);
1786cr <= data(i)(1);
1787wait for clock_period;
1788assert dout = result(i)
1789report
1790"For: ce(" & std_ulogic'image(ce) & ") cr(" & std_ulogic'image(cr) & ") " &
1791" Got: " & integer'image(to_integer(unsigned(dout))) &
1792" Expected: " & integer'image(to_integer(unsigned(result(i))))
1793severity failure;
1794end loop;
1795stop <= '1';
1796wait;
1797end process;
1798
1799end architecture;
1800
1801------------------------- Free running counter --------------------------------------
1802
1803------------------------- Linear Feedback Shift Register ----------------------------
1804-- For good sources on LFSR see
1805-- * https://sites.ualberta.ca/~delliott/ee552/studentAppNotes/1999f/Drivers_Ed/lfsr.html
1806-- * https://en.wikipedia.org/wiki/Linear-feedback_shift_register
1807--
1808-- Some optimal taps
1809--
1810-- Taps start at the left most std_ulogic element of tap at '0' and proceed to
1811-- the highest bit. To instantiate an instance of the LFSR set tap to a
1812-- standard logic vector one less the size of LFSR that you want. An 8-bit
1813-- LFSR can be made by setting it 'tap' to "0111001". The LFSR will need to
1814-- be loaded with a seed value, set 'do' to that value and assert 'we'. The
1815-- LFSR will only run when 'ce' is asserted, otherwise it will preserve the
1816-- current value.
1817--
1818-- Number of bits Taps Cycle Time
1819-- 8 1,2,3,7 255
1820-- 16 1,2,4,15 65535
1821-- 32 1,5,6,31 4294967295
1822--
1823-- This component could also be used to calculate CRCs, which are basically
1824-- the same computation.
1825--
1826
1827library ieee, work;
1828use ieee.std_logic_1164.all;
1829use work.util.common_generics;
1830
1831entity lfsr is
1832generic (g: common_generics; constant tap: std_ulogic_vector);
1833port
1834(
1835clk: in std_ulogic;
1836rst: in std_ulogic;
1837ce: in std_ulogic := '1';
1838we: in std_ulogic;
1839di: in std_ulogic_vector(tap'high + 1 downto tap'low);
1840do: out std_ulogic_vector(tap'high + 1 downto tap'low));
1841end entity;
1842
1843architecture rtl of lfsr is
1844signal r_c, r_n : std_ulogic_vector(di'range) := (others => '0');
1845begin
1846do <= r_c after g.delay;
1847
1848process(rst, clk)
1849begin
1850if rst = '1' and g.asynchronous_reset then
1851r_c <= (others => '0') after g.delay;
1852elsif rising_edge(clk) then
1853if rst = '1' and not g.asynchronous_reset then
1854r_c <= (others => '0') after g.delay;
1855else
1856r_c <= r_n after g.delay;
1857end if;
1858end if;
1859end process;
1860
1861process(r_c, di, we, ce)
1862begin
1863if we = '1' then
1864r_n <= di after g.delay;
1865elsif ce = '1' then
1866r_n(r_n'high) <= r_c(r_c'low);
1867for i in tap'high downto tap'low loop
1868if tap(i) = '1' then
1869r_n(i) <= r_c(r_c'low) xor r_c(i+1) after g.delay;
1870else
1871r_n(i) <= r_c(i+1) after g.delay;
1872end if;
1873end loop;
1874else
1875r_n <= r_c;
1876end if;
1877end process;
1878end architecture;
1879
1880library ieee, work;
1881use ieee.std_logic_1164.all;
1882use work.util.common_generics;
1883
1884entity lfsr_tb is
1885generic (g: common_generics);
1886end entity;
1887
1888architecture behavior of lfsr_tb is
1889constant clock_period: time := 1000 ms / g.clock_frequency;
1890signal we: std_ulogic := '0';
1891signal do, di: std_ulogic_vector(7 downto 0) := (others => '0');
1892
1893signal clk, rst: std_ulogic := '0';
1894signal stop: std_ulogic := '0';
1895begin
1896cs: entity work.clock_source_tb
1897generic map (g => g, hold_rst => 2)
1898port map (stop => stop, clk => clk, rst => rst);
1899
1900uut: entity work.lfsr
1901generic map (g => g, tap => "0111001")
1902port map (clk => clk,
1903rst => rst,
1904we => we,
1905di => di,
1906do => do);
1907
1908stimulus_process: process
1909begin
1910wait for clock_period * 2;
1911we <= '1';
1912di <= "00000001";
1913wait for clock_period;
1914we <= '0';
1915stop <= '1';
1916wait;
1917end process;
1918
1919end architecture;
1920
1921------------------------- Linear Feedback Shift Register ----------------------------
1922
1923------------------------- I/O Pin Controller ----------------------------------------
1924--
1925-- This is a simple I/O pin control module, there is a control register which
1926-- sets whether the pins are to be read in (control = '0') or set to the value written to
1927-- "din" (control = '1').
1928
1929library ieee, work;
1930use ieee.std_logic_1164.all;
1931use work.util.common_generics;
1932
1933entity io_pins is
1934generic (g: common_generics; N: positive);
1935port
1936(
1937clk: in std_ulogic;
1938rst: in std_ulogic;
1939control: in std_ulogic_vector(N - 1 downto 0);
1940control_we: in std_ulogic;
1941din: in std_ulogic_vector(N - 1 downto 0);
1942din_we: in std_ulogic;
1943dout: out std_ulogic_vector(N - 1 downto 0);
1944pins: inout std_logic_vector(N - 1 downto 0));
1945end entity;
1946
1947architecture rtl of io_pins is
1948signal control_o: std_ulogic_vector(control'range) := (others => '0');
1949signal din_o: std_ulogic_vector(din'range) := (others => '0');
1950begin
1951
1952control_r: entity work.reg generic map (g => g, N => N)
1953port map (clk => clk, rst => rst, di => control, we => control_we, do => control_o);
1954din_r: entity work.reg generic map (g => g, N => N)
1955port map (clk => clk, rst => rst, di => din, we => din_we, do => din_o);
1956
1957pins_i: for i in control_o'range generate
1958dout(i) <= pins(i) when control_o(i) = '0' else '0' after g.delay;
1959pins(i) <= din_o(i) when control_o(i) = '1' else 'Z' after g.delay;
1960end generate;
1961
1962end architecture;
1963
1964library ieee, work;
1965use ieee.std_logic_1164.all;
1966use work.util.common_generics;
1967
1968entity io_pins_tb is
1969generic (g: common_generics);
1970end entity;
1971
1972architecture behavior of io_pins_tb is
1973constant clock_period: time := 1000 ms / g.clock_frequency;
1974constant N: positive := 8;
1975
1976signal control: std_ulogic_vector(N - 1 downto 0) := (others => '0');
1977signal din: std_ulogic_vector(N - 1 downto 0) := (others => '0');
1978signal dout: std_ulogic_vector(N - 1 downto 0) := (others => '0');
1979signal pins: std_logic_vector(N - 1 downto 0) := (others => 'L'); -- !
1980
1981signal control_we: std_ulogic := '0';
1982signal din_we: std_ulogic := '0';
1983
1984
1985signal clk, rst: std_ulogic := '0';
1986signal stop: std_ulogic := '0';
1987begin
1988cs: entity work.clock_source_tb
1989generic map (g => g, hold_rst => 2)
1990port map (stop => stop, clk => clk, rst => rst);
1991
1992uut: entity work.io_pins
1993generic map (g => g, N => N)
1994port map (
1995clk => clk,
1996rst => rst,
1997control => control,
1998control_we => control_we,
1999din => din,
2000din_we => din_we,
2001dout => dout,
2002pins => pins);
2003
2004stimulus_process: process
2005begin
2006wait for clock_period * 2;
2007control <= x"0f"; -- write lower pins
2008control_we <= '1';
2009
2010wait for clock_period;
2011din <= x"AA";
2012din_we <= '1';
2013
2014wait for clock_period * 2;
2015pins <= (others => 'H'); -- !
2016wait for clock_period * 2;
2017stop <= '1';
2018wait;
2019end process;
2020
2021end architecture;
2022
2023------------------------- I/O Pin Controller ----------------------------------------
2024
2025------------------------- Single and Dual Port Block RAM ----------------------------
2026--| @warning The function initialize_ram has to be present in each architecture
2027--| block ram that uses it (as far as I am aware) which means they could fall
2028--| out of sync. This could be remedied with VHDL-2008.
2029---------------------------------------------------------------------------------
2030
2031--- Dual Port Model ---
2032
2033library ieee, work;
2034use ieee.std_logic_1164.all;
2035use ieee.numeric_std.all;
2036use std.textio.all;
2037use work.util.all;
2038
2039entity dual_port_block_ram is
2040
2041-- The dual port Block RAM module can be initialized from a file,
2042-- or initialized to all zeros. The model can be synthesized (with
2043-- Xilinx's ISE) into BRAM.
2044--
2045-- Valid file_type options include:
2046--
2047-- FILE_BINARY - A binary file (ASCII '0' and '1', one number per line)
2048-- FILE_HEX - A Hex file (ASCII '0-9' 'a-f', 'A-F', one number per line)
2049-- FILE_NONE - RAM contents will be defaulted to all zeros, no file will
2050-- be read from
2051--
2052-- The data length must be divisible by 4 if the "hex" option is
2053-- given.
2054--
2055-- These default values for addr_length and data_length have been
2056-- chosen so as to fill the block RAM available on a Spartan 6.
2057--
2058generic (g: common_generics;
2059addr_length: positive := 12;
2060data_length: positive := 16;
2061file_name: string := "memory.bin";
2062file_type: file_format := FILE_BINARY);
2063port (
2064--| Port A of dual port RAM
2065a_clk: in std_ulogic;
2066a_dwe: in std_ulogic;
2067a_dre: in std_ulogic;
2068a_addr: in std_ulogic_vector(addr_length - 1 downto 0);
2069a_din: in std_ulogic_vector(data_length - 1 downto 0);
2070a_dout: out std_ulogic_vector(data_length - 1 downto 0) := (others => '0');
2071--| Port B of dual port RAM
2072b_clk: in std_ulogic;
2073b_dwe: in std_ulogic;
2074b_dre: in std_ulogic;
2075b_addr: in std_ulogic_vector(addr_length - 1 downto 0);
2076b_din: in std_ulogic_vector(data_length - 1 downto 0);
2077b_dout: out std_ulogic_vector(data_length - 1 downto 0) := (others => '0'));
2078end entity;
2079
2080architecture behav of dual_port_block_ram is
2081constant ram_size: positive := 2 ** addr_length;
2082
2083type ram_type is array ((ram_size - 1 ) downto 0) of std_ulogic_vector(data_length - 1 downto 0);
2084
2085impure function initialize_ram(the_file_name: in string; the_file_type: in file_format) return ram_type is
2086variable ram_data: ram_type;
2087file in_file: text is in the_file_name;
2088variable input_line: line;
2089variable tmp: bit_vector(data_length - 1 downto 0);
2090variable c: character;
2091variable slv: std_ulogic_vector(data_length - 1 downto 0);
2092begin
2093for i in 0 to ram_size - 1 loop
2094if the_file_type = FILE_NONE then
2095ram_data(i):=(others => '0');
2096elsif not endfile(in_file) then
2097readline(in_file,input_line);
2098if the_file_type = FILE_BINARY then
2099read(input_line, tmp);
2100ram_data(i) := std_ulogic_vector(to_stdlogicvector(tmp));
2101elsif the_file_type = FILE_HEX then
2102assert (data_length mod 4) = 0 report "(data_length%4)!=0" severity failure;
2103for j in 1 to (data_length/4) loop
2104c:= input_line((data_length/4) - j + 1);
2105slv((j*4)-1 downto (j*4)-4) := hex_char_to_std_ulogic_vector_tb(c);
2106end loop;
2107ram_data(i) := slv;
2108else
2109report "Incorrect file type given: " & file_format'image(the_file_type) severity failure;
2110end if;
2111else
2112ram_data(i) := (others => '0');
2113end if;
2114end loop;
2115file_close(in_file);
2116return ram_data;
2117end function;
2118
2119shared variable ram: ram_type := initialize_ram(file_name, file_type);
2120
2121begin
2122a_ram: process(a_clk)
2123begin
2124if rising_edge(a_clk) then
2125if a_dwe = '1' then
2126ram(to_integer(unsigned(a_addr))) := a_din;
2127end if;
2128if a_dre = '1' then
2129a_dout <= ram(to_integer(unsigned(a_addr))) after g.delay;
2130else
2131a_dout <= (others => '0') after g.delay;
2132end if;
2133end if;
2134end process;
2135
2136b_ram: process(b_clk)
2137begin
2138if rising_edge(b_clk) then
2139if b_dwe = '1' then
2140ram(to_integer(unsigned(b_addr))) := b_din;
2141end if;
2142if b_dre = '1' then
2143b_dout <= ram(to_integer(unsigned(b_addr))) after g.delay;
2144else
2145b_dout <= (others => '0') after g.delay;
2146end if;
2147end if;
2148end process;
2149end architecture;
2150
2151--- Single Port Model ---
2152
2153library ieee, work;
2154use ieee.std_logic_1164.all;
2155use ieee.numeric_std.all;
2156use std.textio.all;
2157use work.util.all;
2158
2159entity single_port_block_ram is
2160generic (g: common_generics;
2161addr_length: positive := 12;
2162data_length: positive := 16;
2163file_name: string := "memory.bin";
2164file_type: file_format := FILE_BINARY);
2165port (
2166clk: in std_ulogic;
2167dwe: in std_ulogic;
2168dre: in std_ulogic;
2169addr: in std_ulogic_vector(addr_length - 1 downto 0);
2170din: in std_ulogic_vector(data_length - 1 downto 0);
2171dout: out std_ulogic_vector(data_length - 1 downto 0) := (others => '0'));
2172end entity;
2173
2174architecture behav of single_port_block_ram is
2175constant ram_size: positive := 2 ** addr_length;
2176
2177type ram_type is array ((ram_size - 1 ) downto 0) of std_ulogic_vector(data_length - 1 downto 0);
2178
2179impure function initialize_ram(the_file_name: in string; the_file_type: in file_format) return ram_type is
2180variable ram_data: ram_type;
2181file in_file: text is in the_file_name;
2182variable input_line: line;
2183variable tmp: bit_vector(data_length - 1 downto 0);
2184variable c: character;
2185variable slv: std_ulogic_vector(data_length - 1 downto 0);
2186begin
2187for i in 0 to ram_size - 1 loop
2188if the_file_type = FILE_NONE then
2189ram_data(i):=(others => '0');
2190elsif not endfile(in_file) then
2191readline(in_file,input_line);
2192if the_file_type = FILE_BINARY then
2193read(input_line, tmp);
2194ram_data(i) := std_ulogic_vector(to_stdlogicvector(tmp));
2195elsif the_file_type = FILE_HEX then -- hexadecimal
2196assert (data_length mod 4) = 0 report "(data_length%4)!=0" severity failure;
2197for j in 1 to (data_length/4) loop
2198c:= input_line((data_length/4) - j + 1);
2199slv((j*4)-1 downto (j*4)-4) := hex_char_to_std_ulogic_vector_tb(c);
2200end loop;
2201ram_data(i) := slv;
2202else
2203report "Incorrect file type given: " & file_format'image(the_file_type) severity failure;
2204end if;
2205else
2206ram_data(i) := (others => '0');
2207end if;
2208end loop;
2209file_close(in_file);
2210return ram_data;
2211end function;
2212
2213shared variable ram: ram_type := initialize_ram(file_name, file_type);
2214
2215begin
2216block_ram: process(clk)
2217begin
2218if rising_edge(clk) then
2219if dwe = '1' then
2220ram(to_integer(unsigned(addr))) := din;
2221end if;
2222
2223if dre = '1' then
2224dout <= ram(to_integer(unsigned(addr))) after g.delay;
2225else
2226dout <= (others => '0') after g.delay;
2227end if;
2228end if;
2229end process;
2230end architecture;
2231
2232------------------------- Single and Dual Port Block RAM ----------------------------
2233
2234------------------------- Data Source -----------------------------------------------
2235--|
2236--| This module spits out a bunch of data.
2237--|
2238
2239library ieee, work;
2240use ieee.std_logic_1164.all;
2241use ieee.numeric_std.all;
2242use work.util.single_port_block_ram;
2243use work.util.counter;
2244use work.util.all;
2245
2246entity data_source is
2247generic (g: common_generics;
2248addr_length: positive := 12;
2249data_length: positive := 16;
2250file_name: string := "memory.bin";
2251file_type: file_format := FILE_BINARY);
2252port (
2253clk: in std_ulogic;
2254rst: in std_ulogic;
2255
2256ce: in std_ulogic := '1';
2257cr: in std_ulogic;
2258
2259load: in std_ulogic_vector(addr_length - 1 downto 0) := (others => '0');
2260load_we: in std_ulogic := '0';
2261
2262dout: out std_ulogic_vector(data_length - 1 downto 0));
2263end entity;
2264
2265architecture structural of data_source is
2266signal addr: std_ulogic_vector(addr_length - 1 downto 0);
2267begin
2268count: work.util.counter
2269generic map (g => g, N => addr_length)
2270port map (
2271clk => clk,
2272rst => rst,
2273ce => ce,
2274cr => cr,
2275dout => addr,
2276load_i => load,
2277load_we => load_we);
2278
2279ram: work.util.single_port_block_ram
2280generic map (
2281g => g,
2282addr_length => addr_length,
2283data_length => data_length,
2284file_name => file_name,
2285file_type => file_type)
2286port map (
2287clk => clk,
2288addr => addr,
2289dwe => '0',
2290dre => '1',
2291din => (others => '0'),
2292dout => dout);
2293
2294end architecture;
2295
2296------------------------- Data Source -----------------------------------------------
2297
2298------------------------- uCPU ------------------------------------------------------
2299-- @brief An incredible simple microcontroller
2300-- @license MIT
2301-- @author Richard James Howe
2302-- @copyright Richard James Howe (2017)
2303--
2304-- Based on:
2305-- https://stackoverflow.com/questions/20955863/vhdl-microprocessor-microcontroller
2306--
2307-- INSTRUCTION CYCLES 87 6543210 OPERATION
2308-- ADD WITH CARRY 2 00 ADDRESS A = A + MEM[ADDRESS]
2309-- NOR 2 01 ADDRESS A = A NOR MEM[ADDRESS]
2310-- STORE 1 10 ADDRESS MEM[ADDRESS] = A
2311-- JCC 1 11 ADDRESS IF(CARRY) { PC = ADDRESS, CLEAR CARRY }
2312--
2313-- It would be interesting to make a customizable CPU in which the
2314-- instructions could be customized based upon generics. Another interesting
2315-- possibility is making a simple assembler purely in VHDL, which should
2316-- be possible, but difficult. A single port version would require another
2317-- state to fetch the operand and another register, or more states.
2318--
2319-- I have another small, bit serial CPU, available at:
2320-- <https://github.com/howerj/bit-serial>
2321-- Which is also tiny, but potentially much more useful.
2322--
2323
2324library ieee, work;
2325use ieee.std_logic_1164.all;
2326use ieee.numeric_std.all;
2327
2328entity ucpu is
2329generic (
2330asynchronous_reset: boolean := true; -- use asynchronous reset if true, synchronous if false
2331delay: time := 0 ns; -- simulation only
2332
2333width: positive range 8 to 32 := 8);
2334port (
2335clk, rst: in std_ulogic;
2336
2337pc: out std_ulogic_vector(width - 3 downto 0);
2338op: in std_ulogic_vector(width - 1 downto 0);
2339
2340adr: out std_ulogic_vector(width - 3 downto 0);
2341di: in std_ulogic_vector(width - 1 downto 0);
2342re, we: out std_ulogic;
2343do: out std_ulogic_vector(width - 1 downto 0));
2344end entity;
2345
2346architecture rtl of ucpu is
2347signal a_c, a_n: unsigned(di'high + 1 downto di'low) := (others => '0'); -- accumulator
2348signal pc_c, pc_n: unsigned(pc'range) := (others => '0');
2349signal alu: std_ulogic_vector(1 downto 0) := (others => '0');
2350signal state_c, state_n: std_ulogic := '0'; -- FETCH/Single cycle instruction or EXECUTE
2351begin
2352pc <= std_ulogic_vector(pc_n) after delay;
2353do <= std_ulogic_vector(a_c(do'range)) after delay;
2354alu <= op(op'high downto op'high - 1) after delay;
2355adr <= op(adr'range) after delay;
2356we <= '1' when alu = "10" else '0' after delay; -- STORE
2357re <= alu(1) nor state_c after delay; -- FETCH for ADD and NOR
2358state_n <= alu(1) nor state_c after delay; -- FETCH not taken or FETCH done
2359pc_n <= unsigned(op(pc_n'range)) when (alu = "11" and a_c(a_c'high) = '0') else -- Jump when carry set
2360pc_c when (state_c = '0' and alu(1) = '0') else -- FETCH
2361(pc_c + 1) after delay; -- EXECUTE
2362
2363process(clk, rst)
2364begin
2365if rst = '1' and asynchronous_reset then
2366a_c <= (others => '0') after delay;
2367pc_c <= (others => '0') after delay;
2368state_c <= '0' after delay;
2369elsif rising_edge(clk) then
2370if rst = '1' and not asynchronous_reset then
2371a_c <= (others => '0') after delay;
2372pc_c <= (others => '0') after delay;
2373state_c <= '0' after delay;
2374else
2375a_c <= a_n after delay;
2376pc_c <= pc_n after delay;
2377state_c <= state_n after delay;
2378end if;
2379end if;
2380end process;
2381
2382process(op, alu, di, a_c, state_c)
2383begin
2384a_n <= a_c after delay;
2385
2386if alu = "11" and a_c(a_c'high) = '0' then a_n(a_n'high) <= '0' after delay; end if;
2387
2388if state_c = '1' then -- EXECUTE for ADD and NOR
2389assert alu(1) = '0' severity failure;
2390if alu(0) = '0' then a_n <= '0' & a_c(di'range) + unsigned('0' & di) after delay; end if;
2391if alu(0) = '1' then a_n <= a_c nor '0' & unsigned(di) after delay; end if;
2392end if;
2393end process;
2394end architecture;
2395
2396library ieee, work;
2397use ieee.std_logic_1164.all;
2398use ieee.numeric_std.all;
2399use ieee.math_real.all;
2400use work.util.all;
2401
2402entity ucpu_tb is
2403generic (g: common_generics;
2404file_name: string := "ucpu.bin");
2405end entity;
2406
2407architecture testing of ucpu_tb is
2408constant clock_period: time := 1000 ms / g.clock_frequency;
2409
2410constant data_length: positive := 8;
2411constant addr_length: positive := data_length - 2;
2412
2413signal a_addr: std_ulogic_vector(addr_length - 1 downto 0);
2414signal a_dout: std_ulogic_vector(data_length - 1 downto 0) := (others => '0');
2415
2416signal b_dwe: std_ulogic;
2417signal b_dre: std_ulogic;
2418signal b_addr: std_ulogic_vector(addr_length - 1 downto 0);
2419signal b_din: std_ulogic_vector(data_length - 1 downto 0);
2420signal b_dout: std_ulogic_vector(data_length - 1 downto 0) := (others => '0');
2421
2422signal clk, rst: std_ulogic := '0';
2423signal stop: std_ulogic := '0';
2424begin
2425cs: entity work.clock_source_tb
2426generic map (g => g, hold_rst => 2)
2427port map (stop => stop, clk => clk, rst => rst);
2428
2429bram_0: entity work.dual_port_block_ram
2430generic map (g => g,
2431addr_length => addr_length,
2432data_length => data_length,
2433file_name => file_name,
2434file_type => FILE_BINARY)
2435port map (
2436a_clk => clk,
2437a_dwe => '0',
2438a_dre => '1',
2439a_addr => a_addr,
2440a_din => (others => '0'),
2441a_dout => a_dout,
2442
2443b_clk => clk,
2444b_dwe => b_dwe,
2445b_dre => b_dre,
2446b_addr => b_addr,
2447b_din => b_din,
2448b_dout => b_dout);
2449
2450ucpu_0: entity work.ucpu
2451generic map (delay => g.delay, width => data_length)
2452port map (
2453clk => clk,
2454rst => rst,
2455pc => a_addr,
2456op => a_dout,
2457
2458re => b_dre,
2459we => b_dwe,
2460di => b_dout,
2461do => b_din,
2462adr => b_addr);
2463
2464stimulus_process: process
2465begin
2466wait for clock_period * 1000;
2467stop <= '1';
2468wait;
2469end process;
2470
2471end architecture;
2472
2473------------------------- uCPU ------------------------------------------------------
2474
2475------------------------- Restoring Division ----------------------------------------
2476--
2477-- Computes a/b in N cycles
2478--
2479-- https://en.wikipedia.org/wiki/Division_algorithm#Restoring_division
2480--
2481
2482library ieee, work;
2483use ieee.std_logic_1164.all;
2484use ieee.numeric_std.all;
2485use work.util.common_generics;
2486
2487entity restoring_divider is
2488generic (g: common_generics; N: positive);
2489port (
2490clk: in std_ulogic;
2491rst: in std_ulogic := '0';
2492
2493a: in std_ulogic_vector(N - 1 downto 0);
2494b: in std_ulogic_vector(N - 1 downto 0);
2495start: in std_ulogic;
2496done: out std_ulogic;
2497c: out std_ulogic_vector(N - 1 downto 0));
2498end entity;
2499
2500architecture rtl of restoring_divider is
2501signal a_c, a_n: unsigned(a'range) := (others => '0');
2502signal b_c, b_n: unsigned(b'range) := (others => '0');
2503signal m_c, m_n: unsigned(b'range) := (others => '0');
2504signal o_c, o_n: unsigned(c'range) := (others => '0');
2505signal e_c, e_n: std_ulogic := '0';
2506signal count_c, count_n: unsigned(work.util.n_bits(N) downto 0) := (others => '0');
2507begin
2508c <= std_ulogic_vector(o_n);
2509
2510process(clk, rst)
2511procedure reset is
2512begin
2513a_c <= (others => '0') after g.delay;
2514b_c <= (others => '0') after g.delay;
2515m_c <= (others => '0') after g.delay;
2516o_c <= (others => '0') after g.delay;
2517e_c <= '0' after g.delay;
2518count_c <= (others => '0') after g.delay;
2519end procedure;
2520begin
2521if rst = '1' and g.asynchronous_reset then
2522reset;
2523elsif rising_edge(clk) then
2524if rst = '1' and not g.asynchronous_reset then
2525reset;
2526else
2527a_c <= a_n after g.delay;
2528b_c <= b_n after g.delay;
2529m_c <= m_n after g.delay;
2530o_c <= o_n after g.delay;
2531e_c <= e_n after g.delay;
2532count_c <= count_n after g.delay;
2533end if;
2534end if;
2535end process;
2536
2537divide: process(a, b, start, a_c, b_c, m_c, e_c, o_c, count_c)
2538variable m_v: unsigned(b'range) := (others => '0');
2539begin
2540done <= '0';
2541a_n <= a_c;
2542b_n <= b_c;
2543m_v := m_c;
2544e_n <= e_c;
2545o_n <= o_c;
2546count_n <= count_c;
2547if start = '1' then
2548a_n <= unsigned(a) after g.delay;
2549b_n <= unsigned(b) after g.delay;
2550m_v := (others => '0');
2551e_n <= '1' after g.delay;
2552o_n <= (others => '0') after g.delay;
2553count_n <= (others => '0') after g.delay;
2554elsif e_c = '1' then
2555if count_c(count_c'high) = '1' then
2556done <= '1' after g.delay;
2557e_n <= '0' after g.delay;
2558o_n <= a_c after g.delay;
2559count_n <= (others => '0') after g.delay;
2560else
2561m_v(b'high downto 1) := m_v(b'high - 1 downto 0);
2562m_v(0) := a_c(a'high);
2563a_n(a'high downto 1) <= a_c(a'high - 1 downto 0) after g.delay;
2564m_v := m_v - b_c;
2565if m_v(m_v'high) = '1' then
2566m_v := m_v + b_c;
2567a_n(0) <= '0' after g.delay;
2568else
2569a_n(0) <= '1' after g.delay;
2570end if;
2571count_n <= count_c + 1 after g.delay;
2572end if;
2573else
2574count_n <= (others => '0') after g.delay;
2575end if;
2576m_n <= m_v after g.delay;
2577end process;
2578end architecture;
2579
2580library ieee, work;
2581use ieee.std_logic_1164.all;
2582use ieee.numeric_std.all;
2583use ieee.math_real.all;
2584use work.util.common_generics;
2585
2586entity restoring_divider_tb is
2587generic (g: common_generics);
2588end entity;
2589
2590architecture testing of restoring_divider_tb is
2591constant clock_period: time := 1000 ms / g.clock_frequency;
2592constant N: positive := 8;
2593
2594signal a: std_ulogic_vector(N - 1 downto 0) := (others => '0');
2595signal b: std_ulogic_vector(N - 1 downto 0) := (others => '0');
2596signal c: std_ulogic_vector(N - 1 downto 0) := (others => '0');
2597signal start, done: std_ulogic := '0';
2598
2599signal clk, rst: std_ulogic := '0';
2600signal stop: std_ulogic := '0';
2601begin
2602cs: entity work.clock_source_tb
2603generic map (g => g, hold_rst => 2)
2604port map (stop => stop, clk => clk, rst => rst);
2605
2606uut: entity work.restoring_divider
2607generic map (g => g, N => N)
2608port map (
2609clk => clk,
2610rst => rst,
2611a => a,
2612b => b,
2613start => start,
2614done => done,
2615c => c);
2616
2617stimulus_process: process
2618begin
2619wait for clock_period * 2;
2620
2621a <= x"64";
2622b <= x"0A";
2623start <= '1';
2624wait for clock_period * 1;
2625start <= '0';
2626wait until done = '1';
2627--assert c = x"0A" severity failure;
2628
2629wait for clock_period * 10;
2630b <= x"05";
2631start <= '1';
2632wait for clock_period * 1;
2633start <= '0';
2634wait until done = '1';
2635--assert c = x"14" severity failure;
2636
2637stop <= '1';
2638wait;
2639end process;
2640
2641end architecture;
2642------------------------- Restoring Divider ---------------------------------------------------
2643
2644------------------------- Debouncer -----------------------------------------------------------
2645
2646library ieee, work;
2647use ieee.std_logic_1164.all;
2648use ieee.numeric_std.all;
2649use work.util.common_generics;
2650
2651entity debounce_us is
2652generic (g: common_generics; timer_period_us: natural);
2653port (
2654clk: in std_ulogic;
2655di: in std_ulogic;
2656do: out std_ulogic := '0');
2657end entity;
2658
2659architecture rtl of debounce_us is
2660signal ff: std_ulogic_vector(1 downto 0) := (others => '0');
2661signal rst, done: std_ulogic := '0';
2662begin
2663timer: work.util.timer_us
2664generic map (g => g, timer_period_us => timer_period_us)
2665port map (
2666clk => clk,
2667rst => rst,
2668co => done);
2669
2670process(clk)
2671begin
2672if rising_edge(clk) then
2673ff(0) <= di after g.delay;
2674ff(1) <= ff(0) after g.delay;
2675if (ff(0) xor ff(1)) = '1' then
2676rst <= '1' after g.delay;
2677elsif done = '1' then
2678do <= ff(1) after g.delay;
2679else
2680rst <= '0';
2681end if;
2682end if;
2683end process;
2684end architecture;
2685
2686library ieee, work;
2687use ieee.std_logic_1164.all;
2688use ieee.numeric_std.all;
2689use work.util.common_generics;
2690
2691entity debounce_us_tb is
2692generic (g: common_generics);
2693end entity;
2694
2695architecture testing of debounce_us_tb is
2696constant clock_period: time := 1000 ms / g.clock_frequency;
2697
2698signal di, do: std_ulogic := '0';
2699signal clk, rst: std_ulogic := '0';
2700signal stop: std_ulogic := '0';
2701begin
2702cs: entity work.clock_source_tb
2703generic map (g => g, hold_rst => 2)
2704port map (stop => stop, clk => clk, rst => rst);
2705
2706uut: work.util.debounce_us
2707generic map (g => g, timer_period_us => 1)
2708port map (clk => clk, di => di, do => do);
2709
2710stimulus_process: process
2711begin
2712wait for clock_period * 2;
2713di <= '1';
2714
2715wait for 1.5 us;
2716
2717stop <= '1';
2718wait;
2719end process;
2720end architecture;
2721------------------------- Debouncer -----------------------------------------------------------
2722
2723------------------------- Debouncer Block -----------------------------------------------------
2724
2725library ieee, work;
2726use ieee.std_logic_1164.all;
2727use ieee.numeric_std.all;
2728use work.util.common_generics;
2729
2730entity debounce_block_us is
2731generic (g: common_generics; N: positive; timer_period_us: natural);
2732port (
2733clk: in std_ulogic;
2734di: in std_ulogic_vector(N - 1 downto 0);
2735do: out std_ulogic_vector(N - 1 downto 0));
2736end entity;
2737
2738architecture structural of debounce_block_us is
2739begin
2740debouncer: for i in (N - 1) downto 0 generate
2741d_instance: work.util.debounce_us
2742generic map (g => g, timer_period_us => timer_period_us)
2743port map (clk => clk, di => di(i), do => do(i));
2744end generate;
2745end architecture;
2746
2747------------------------- Debouncer Block -----------------------------------------------------
2748
2749------------------------- State Changed -------------------------------------------------------
2750library ieee, work;
2751use ieee.std_logic_1164.all;
2752use ieee.numeric_std.all;
2753use work.util.common_generics;
2754
2755entity state_changed is
2756generic (g: common_generics);
2757port (
2758clk: in std_ulogic;
2759rst: in std_ulogic;
2760di: in std_ulogic;
2761do: out std_ulogic);
2762end entity;
2763
2764architecture rtl of state_changed is
2765signal state_c, state_n: std_ulogic_vector(1 downto 0) := (others => '0');
2766begin
2767process(clk, rst)
2768begin
2769if rst = '1' and g.asynchronous_reset then
2770state_c <= (others => '0') after g.delay;
2771elsif rising_edge(clk) then
2772if rst = '1' and not g.asynchronous_reset then
2773state_c <= (others => '0') after g.delay;
2774else
2775state_c <= state_n after g.delay;
2776end if;
2777end if;
2778end process;
2779
2780do <= '1' when (state_c(0) xor state_c(1)) = '1' else '0';
2781
2782process(di, state_c)
2783begin
2784state_n(0) <= state_c(1) after g.delay;
2785state_n(1) <= di after g.delay;
2786end process;
2787end architecture;
2788
2789------------------------- Change State --------------------------------------------------------
2790
2791------------------------- Change State Block --------------------------------------------------
2792library ieee, work;
2793use ieee.std_logic_1164.all;
2794use ieee.numeric_std.all;
2795use work.util.common_generics;
2796
2797entity state_block_changed is
2798generic (g: common_generics; N: positive);
2799port (
2800clk: in std_ulogic;
2801rst: in std_ulogic;
2802di: in std_ulogic_vector(N - 1 downto 0);
2803do: out std_ulogic_vector(N - 1 downto 0));
2804end entity;
2805
2806architecture structural of state_block_changed is
2807begin
2808changes: for i in (N - 1) downto 0 generate
2809d_instance: work.util.state_changed
2810generic map (g => g)
2811port map (clk => clk, rst => rst, di => di(i), do => do(i));
2812end generate;
2813end architecture;
2814
2815------------------------- Change State Block --------------------------------------------------
2816
2817------------------------- Reset Signal Generator ----------------------------------------------
2818library ieee, work;
2819use ieee.std_logic_1164.all;
2820use ieee.numeric_std.all;
2821use work.util.all;
2822
2823entity reset_generator is
2824generic (g: common_generics; reset_period_us: natural := 0);
2825port (
2826clk: in std_logic := 'X';
2827rst: out std_logic := '0'); -- reset out!
2828end entity;
2829
2830architecture behavior of reset_generator is
2831constant cycles: natural := (g.clock_frequency / 1000000) * reset_period_us;
2832subtype counter is unsigned(max(1, n_bits(cycles) - 1) downto 0);
2833signal c_c, c_n: counter := (others => '0');
2834begin
2835process (clk)
2836begin
2837if rising_edge(clk) then
2838c_c <= c_n after g.delay;
2839end if;
2840end process;
2841
2842process (c_c)
2843begin
2844if c_c = (cycles - 1) then
2845c_n <= c_c after g.delay;
2846rst <= '0' after g.delay;
2847else
2848c_n <= c_c + 1 after g.delay;
2849rst <= '1' after g.delay;
2850end if;
2851end process;
2852end architecture;
2853
2854library ieee, work;
2855use ieee.std_logic_1164.all;
2856use work.util.common_generics;
2857
2858entity reset_generator_tb is
2859generic (g: common_generics);
2860end entity;
2861
2862architecture testing of reset_generator_tb is
2863constant clock_period: time := 1000 ms / g.clock_frequency;
2864signal stop, clk, rst: std_ulogic := '0';
2865begin
2866cs: entity work.clock_source_tb
2867generic map (g => g, hold_rst => 2)
2868port map (stop => stop, clk => clk, rst => open);
2869
2870uut: entity work.reset_generator
2871generic map (g => g, reset_period_us => 1)
2872port map (clk => clk, rst => rst);
2873
2874stimulus_process: process
2875begin
2876wait for clock_period;
2877assert rst = '1' severity failure;
2878wait for 1 us;
2879assert rst = '0' severity failure;
2880stop <= '1';
2881wait;
2882end process;
2883
2884end architecture;
2885
2886------------------------- Reset Signal Generator ----------------------------------------------
2887
2888------------------------- Bit Count -----------------------------------------------------------
2889
2890library ieee, work;
2891use ieee.std_logic_1164.all;
2892use ieee.numeric_std.all;
2893use work.util.n_bits;
2894use work.util.common_generics;
2895
2896entity bit_count is
2897generic (g: common_generics; N: positive);
2898port (
2899bits: in std_ulogic_vector(N - 1 downto 0);
2900count: out std_ulogic_vector(n_bits(N) downto 0));
2901end entity;
2902
2903architecture behavior of bit_count is
2904begin
2905process (bits)
2906constant zero: unsigned(count'high - 1 downto count'low) := (others => '0');
2907variable t: unsigned(count'range) := (others => '0');
2908begin
2909t := (others => '0');
2910for i in bits'low to bits'high loop
2911t := t + (zero & bits(i));
2912end loop;
2913count <= std_ulogic_vector(t) after g.delay;
2914end process;
2915end architecture;
2916
2917library ieee, work;
2918use ieee.std_logic_1164.all;
2919use work.util.n_bits;
2920use work.util.common_generics;
2921
2922entity bit_count_tb is
2923generic (g: common_generics);
2924end entity;
2925
2926architecture testing of bit_count_tb is
2927constant clock_period: time := 1000 ms / g.clock_frequency;
2928constant N: positive := 3;
2929signal bits: std_ulogic_vector(N - 1 downto 0) := (others => '0');
2930signal count: std_ulogic_vector(n_bits(N) downto 0) := (others => '0');
2931begin
2932uut: entity work.bit_count
2933generic map (g => g, N => N)
2934port map (bits => bits, count => count);
2935
2936stimulus_process: process
2937procedure test(b: std_ulogic_vector; c: std_ulogic_vector) is
2938begin
2939bits <= b;
2940wait for clock_period;
2941assert count = c severity failure;
2942end procedure;
2943begin
2944test("000", "000");
2945test("001", "001");
2946test("010", "001");
2947test("011", "010");
2948test("100", "001");
2949test("101", "010");
2950test("110", "010");
2951test("111", "011");
2952wait;
2953end process;
2954
2955end architecture;
2956
2957------------------------- Bit Count -----------------------------------------------------------
2958
2959------------------------- Majority Voter ------------------------------------------------------
2960--
2961-- NB. This could be constructed from a more generic 'assert output if bit
2962-- count greater than N' module.
2963--
2964
2965library ieee, work;
2966use ieee.std_logic_1164.all;
2967use ieee.numeric_std.all;
2968use work.util.all;
2969
2970entity majority is
2971generic (g: common_generics; N: positive; even_wins: boolean := false);
2972port (
2973bits: in std_ulogic_vector(N - 1 downto 0);
2974vote: out std_ulogic;
2975tie: out std_ulogic);
2976end entity;
2977
2978architecture behavior of majority is
2979signal count: std_ulogic_vector(n_bits(N) downto 0) := (others => '0');
2980-- It might be worth handling up to five or so bits in combinatorial
2981-- logic, or it might not.
2982begin
2983majority_1: if N = 1 generate
2984vote <= bits(0) after g.delay;
2985tie <= '0' after g.delay;
2986end generate;
2987
2988majority_2: if N = 2 generate
2989ew_2: if even_wins generate vote <= bits(0) or bits(1) after g.delay; end generate;
2990enw_2: if not even_wins generate vote <= bits(0) and bits(1) after g.delay; end generate;
2991tie <= bits(0) or bits(1);
2992end generate;
2993
2994majority_3: if N = 3 generate
2995vote <= (bits(0) and bits(1)) or (bits(1) and bits(2)) or (bits(0) and bits(2)) after g.delay;
2996tie <= '0' after g.delay;
2997end generate;
2998
2999majority_n: if N > 3 generate
3000bit_counter: entity work.bit_count
3001generic map (g => g, N => N)
3002port map (bits => bits, count => count);
3003
3004tie <= '1' when (unsigned(count) = N/2) and (N mod 2) = 0 else '0' after g.delay;
3005
3006process (count)
3007begin
3008if even_wins and (N mod 2) = 0 then
3009if unsigned(count) >= (N/2) then
3010vote <= '1' after g.delay;
3011else
3012vote <= '0' after g.delay;
3013end if;
3014else
3015if unsigned(count) > (N/2) then
3016vote <= '1' after g.delay;
3017else
3018vote <= '0' after g.delay;
3019end if;
3020end if;
3021end process;
3022end generate;
3023end architecture;
3024
3025library ieee, work;
3026use ieee.std_logic_1164.all;
3027use ieee.numeric_std.all;
3028use work.util.all;
3029
3030entity majority_tb is
3031generic (g: common_generics);
3032end entity;
3033
3034architecture testing of majority_tb is
3035constant clock_period: time := 1000 ms / g.clock_frequency;
3036
3037constant N_3: positive := 3;
3038constant N_4_t: positive := 4;
3039constant N_4_m: positive := 4;
3040
3041signal bits_3: std_ulogic_vector(N_3 - 1 downto 0) := (others => '0');
3042signal bits_4_t: std_ulogic_vector(N_4_t - 1 downto 0) := (others => '0');
3043signal bits_4_m: std_ulogic_vector(N_4_m - 1 downto 0) := (others => '0');
3044
3045signal vote_3, tie_3: std_ulogic := '0';
3046signal vote_4_t, tie_4_t: std_ulogic := '0';
3047signal vote_4_m, tie_4_m: std_ulogic := '0';
3048begin
3049uut_3: entity work.majority
3050generic map (g => g, N => N_3)
3051port map (bits => bits_3, vote => vote_3, tie => tie_3);
3052
3053uut_4_t: entity work.majority
3054generic map (g => g, N => N_4_t, even_wins => true)
3055port map (bits => bits_4_t, vote => vote_4_t, tie => tie_4_t);
3056
3057uut_4_m: entity work.majority
3058generic map (g => g, N => N_4_m)
3059port map (bits => bits_4_m, vote => vote_4_m, tie => tie_4_m);
3060
3061stimulus_process: process
3062procedure test_3(b: std_ulogic_vector; vote, tie: std_ulogic) is
3063begin
3064bits_3 <= b;
3065wait for clock_period;
3066assert vote_3 = vote and tie_3 = tie severity failure;
3067end procedure;
3068
3069procedure test_4_t(b: std_ulogic_vector; vote, tie: std_ulogic) is
3070begin
3071bits_4_t <= b;
3072wait for clock_period;
3073assert vote_4_t = vote and tie_4_t = tie severity failure;
3074end procedure;
3075
3076procedure test_4_m(b: std_ulogic_vector; vote, tie: std_ulogic) is
3077begin
3078bits_4_m <= b;
3079wait for clock_period;
3080assert vote_4_m = vote and tie_4_m = tie severity failure;
3081end procedure;
3082begin
3083test_3("000", '0', '0');
3084test_3("001", '0', '0');
3085test_3("010", '0', '0');
3086test_3("011", '1', '0');
3087test_3("100", '0', '0');
3088test_3("101", '1', '0');
3089test_3("110", '1', '0');
3090test_3("111", '1', '0');
3091
3092test_4_t("0000", '0', '0');
3093test_4_t("0001", '0', '0');
3094test_4_t("0010", '0', '0');
3095test_4_t("0011", '1', '1');
3096test_4_t("0100", '0', '0');
3097test_4_t("0101", '1', '1');
3098test_4_t("0110", '1', '1');
3099test_4_t("0111", '1', '0');
3100test_4_t("1000", '0', '0');
3101test_4_t("1001", '1', '1');
3102test_4_t("1010", '1', '1');
3103test_4_t("1011", '1', '0');
3104test_4_t("1100", '1', '1');
3105test_4_t("1101", '1', '0');
3106test_4_t("1110", '1', '0');
3107test_4_t("1111", '1', '0');
3108
3109test_4_m("0000", '0', '0');
3110test_4_m("0001", '0', '0');
3111test_4_m("0010", '0', '0');
3112test_4_m("0011", '0', '1');
3113test_4_m("0100", '0', '0');
3114test_4_m("0101", '0', '1');
3115test_4_m("0110", '0', '1');
3116test_4_m("0111", '1', '0');
3117test_4_m("1000", '0', '0');
3118test_4_m("1001", '0', '1');
3119test_4_m("1010", '0', '1');
3120test_4_m("1011", '1', '0');
3121test_4_m("1100", '0', '1');
3122test_4_m("1101", '1', '0');
3123test_4_m("1110", '1', '0');
3124test_4_m("1111", '1', '0');
3125
3126wait;
3127end process;
3128end architecture;
3129
3130------------------------- Majority Voter ------------------------------------------------------
3131
3132------------------------- Delay Line ----------------------------------------------------------
3133-- 'DEPTH' * clock period delay line. Minimum delay of 0.
3134--
3135-- NB. It would be possible to create a delay line that would allow you to delay samples by
3136-- varying amounts with a FIFO and a counter, which is sort of line a Run
3137-- Length Compression Decoder. A sample and a counter would be pushed to the
3138-- FIFO, the delay line mechanism would pull a sample/counter and hold the value
3139-- for that amount of time.
3140
3141library ieee, work;
3142use ieee.std_logic_1164.all;
3143use work.util.all;
3144
3145entity delay_line is
3146generic (g: common_generics; width: positive; depth: natural);
3147port (
3148clk: in std_ulogic;
3149rst: in std_ulogic;
3150ce: in std_ulogic := '1';
3151di: in std_ulogic_vector(width - 1 downto 0);
3152do: out std_ulogic_vector(width - 1 downto 0));
3153end entity;
3154
3155architecture behavior of delay_line is
3156type delay_line_t is array(integer range 0 to depth) of std_ulogic_vector(di'range);
3157signal sigs: delay_line_t := (others => (others => '0'));
3158begin
3159sigs(0) <= di;
3160delay_line_generate: for i in 0 to depth generate
3161rest: if i > 0 generate
3162ux: work.util.reg
3163generic map (g => g, N => width)
3164port map (clk => clk, rst => rst, we => ce, di => sigs(i - 1), do => sigs(i));
3165end generate;
3166end generate;
3167do <= sigs(depth);
3168end architecture;
3169
3170library ieee, work;
3171use ieee.std_logic_1164.all;
3172use work.util.all;
3173
3174entity delay_line_tb is
3175generic (g: common_generics);
3176end entity;
3177
3178architecture testing of delay_line_tb is
3179constant clock_period: time := 1000 ms / g.clock_frequency;
3180constant depth: natural := 2;
3181constant width: positive := 8;
3182signal clk, rst: std_ulogic := '0';
3183signal stop: std_ulogic := '0';
3184
3185signal di, do: std_ulogic_vector(width - 1 downto 0) := (others => '0');
3186begin
3187cs: entity work.clock_source_tb
3188generic map (g => g, hold_rst => 2)
3189port map (stop => stop, clk => clk, rst => rst);
3190
3191uut: entity work.delay_line
3192generic map (g => g, depth => depth, width => width) port map (clk => clk, rst => rst, di => di, do => do, ce => '1');
3193
3194stimulus_process: process
3195begin
3196-- put a bit into the shift register and wait
3197-- for it to come out the other size
3198wait until rst = '0';
3199di <= x"AA";
3200wait for clock_period * 1;
3201di <= x"55";
3202wait for clock_period * 1;
3203di <= x"CC";
3204wait for clock_period * 1;
3205di <= x"DD";
3206assert do = x"AA" severity failure;
3207wait for clock_period * 1;
3208di <= x"00";
3209assert do = x"55" severity failure;
3210wait for clock_period * 1;
3211assert do = x"CC" severity failure;
3212wait for clock_period * 1;
3213assert do = x"DD" severity failure;
3214wait for clock_period * 1;
3215assert do = x"00" severity failure;
3216stop <= '1';
3217wait;
3218end process;
3219end architecture;
3220
3221------------------------- Delay Line ----------------------------------------------------------
3222
3223------------------------- Gray CODEC ----------------------------------------------------------
3224
3225library ieee, work;
3226use ieee.std_logic_1164.all;
3227use work.util.all;
3228
3229entity gray_encoder is
3230generic (g: common_generics; N: positive);
3231port (di: in std_ulogic_vector(N - 1 downto 0);
3232do: out std_ulogic_vector(N - 1 downto 0));
3233end entity;
3234
3235architecture behavior of gray_encoder is
3236begin
3237gry: for i in N - 1 downto 0 generate
3238first: if i = (N - 1) generate
3239do(i) <= di(i);
3240end generate;
3241
3242rest: if i < (N - 1) generate
3243do(i) <= di(i + 1) xor di(i);
3244end generate;
3245end generate;
3246end architecture;
3247
3248library ieee, work;
3249use ieee.std_logic_1164.all;
3250use work.util.all;
3251
3252entity gray_decoder is
3253generic (g: common_generics; N: positive);
3254port (di: in std_ulogic_vector(N - 1 downto 0);
3255do: out std_ulogic_vector(N - 1 downto 0));
3256end entity;
3257
3258architecture behavior of gray_decoder is
3259begin
3260gry: for i in N - 1 downto 0 generate
3261first: if i = (N - 1) generate
3262do(i) <= di(i) after g.delay;
3263end generate;
3264
3265rest: if i < (N - 1) generate
3266do(i) <= parity(di(N - 1 downto i), true) after g.delay;
3267end generate;
3268end generate;
3269end architecture;
3270
3271library ieee, work;
3272use ieee.std_logic_1164.all;
3273use work.util.all;
3274
3275entity gray_tb is
3276generic (g: common_generics);
3277end entity;
3278
3279architecture testing of gray_tb is
3280constant clock_period: time := 1000 ms / g.clock_frequency;
3281constant n: positive := 3;
3282signal clk, rst: std_ulogic := '0';
3283signal stop: std_ulogic := '0';
3284
3285signal di, gray, do: std_ulogic_vector(n - 1 downto 0) := (others => '0');
3286begin
3287cs: entity work.clock_source_tb
3288generic map (g => g, hold_rst => 2)
3289port map (stop => stop, clk => clk, rst => rst);
3290
3291uut_encode: entity work.gray_encoder
3292generic map (g => g, n => n) port map (di => di, do => gray);
3293
3294uut_decode: entity work.gray_decoder
3295generic map (g => g, n => n) port map (di => gray, do => do);
3296
3297stimulus_process: process
3298procedure test(slv: std_ulogic_vector) is
3299begin
3300di <= slv;
3301wait for clock_period * 1;
3302assert di = do severity failure;
3303wait for clock_period * 1;
3304end procedure;
3305begin
3306di <= (others => '0');
3307wait until rst = '0';
3308test("000");
3309test("001");
3310test("010");
3311test("011");
3312test("100");
3313test("101");
3314test("110");
3315test("111");
3316stop <= '1';
3317wait;
3318end process;
3319end architecture;
3320
3321------------------------- Gray CODEC ----------------------------------------------------------
3322
3323------------------------- Parity Module -------------------------------------------------------
3324
3325library ieee, work;
3326use ieee.std_logic_1164.all;
3327use work.util.all;
3328
3329entity parity_module is
3330generic (g: common_generics; N: positive; even: boolean);
3331port (di: in std_ulogic_vector(N - 1 downto 0); do: out std_ulogic);
3332end entity;
3333
3334architecture behavior of parity_module is
3335begin
3336do <= parity(di, even) after g.delay;
3337end architecture;
3338
3339------------------------- Parity Module -------------------------------------------------------
3340
3341------------------------- Hamming CODEC ------------------------------------------------------
3342-- This is a Hamming encoder/decoder, with an extra parity bit. This can be used for error
3343-- correction and detection across a noisy line.
3344--
3345-- See <https://en.wikipedia.org/wiki/Hamming_code> for more information.
3346--
3347
3348library ieee, work;
3349use ieee.std_logic_1164.all;
3350use work.util.all;
3351
3352entity hamming_7_4_encoder is
3353generic (g: common_generics);
3354port (
3355di: in std_ulogic_vector(3 downto 0);
3356do: out std_ulogic_vector(6 downto 0);
3357parity: out std_ulogic);
3358end entity;
3359
3360architecture behavior of hamming_7_4_encoder is
3361signal p1, p2, p3: std_ulogic := '0';
3362begin
3363p1 <= di(0) xor di(1) xor di(3) after g.delay;
3364p2 <= di(0) xor di(2) xor di(3) after g.delay;
3365p3 <= di(1) xor di(2) xor di(3) after g.delay;
3366do(0) <= p1 after g.delay;
3367do(1) <= p2 after g.delay;
3368do(2) <= di(0) after g.delay;
3369do(3) <= p3 after g.delay;
3370do(4) <= di(1) after g.delay;
3371do(5) <= di(2) after g.delay;
3372do(6) <= di(3) after g.delay;
3373parity <= p1 xor p2 xor p3 xor di(0) xor di(1) xor di(2) xor di(3);
3374end architecture;
3375
3376library ieee, work;
3377use ieee.std_logic_1164.all;
3378use ieee.numeric_std.all;
3379use work.util.all;
3380
3381entity hamming_7_4_decoder is
3382generic (g: common_generics; secdec: boolean := true);
3383port (
3384di: in std_ulogic_vector(6 downto 0);
3385parity: in std_ulogic;
3386do: out std_ulogic_vector(3 downto 0);
3387single, double: out std_ulogic);
3388end entity;
3389
3390architecture behavior of hamming_7_4_decoder is
3391signal s: std_ulogic_vector(2 downto 0) := (others => '0');
3392signal co, ct, dip: std_ulogic_vector(di'high + 1 downto 0) := (others => '0');
3393signal cp: std_ulogic := '0';
3394signal unequal: std_ulogic := '0';
3395begin
3396s(2) <= di(3) xor di(4) xor di(5) xor di(6) after g.delay;
3397s(1) <= di(1) xor di(2) xor di(5) xor di(6) after g.delay;
3398s(0) <= di(0) xor di(2) xor di(4) xor di(6) after g.delay;
3399
3400do(0) <= co(2) after g.delay;
3401do(1) <= co(4) after g.delay;
3402do(2) <= co(5) after g.delay;
3403do(3) <= co(6) after g.delay;
3404
3405cp <= '0' when not secdec else di(0) xor di(1) xor di(2) xor di(3) xor di(4) xor di(5) xor di(6) after g.delay;
3406
3407dip(dip'high) <= parity when secdec else '0' after g.delay;
3408dip(di'range) <= di after g.delay;
3409
3410unequal <= '1' when ct(di'range) /= dip(di'range) else '0' after g.delay;
3411
3412process (dip, s)
3413begin
3414ct <= dip after g.delay;
3415ct(to_integer(unsigned(s) - 1)) <= not dip(to_integer(unsigned(s) - 1)) after g.delay;
3416end process;
3417
3418process (s, dip, parity, ct, cp, unequal)
3419begin
3420co <= dip;
3421single <= '0';
3422double <= '0';
3423
3424if secdec and parity /= cp then
3425if unequal = '1' then
3426single <= '1';
3427co <= ct;
3428end if;
3429else
3430if unequal = '1' then
3431if secdec then
3432double <= '1';
3433else
3434single <= '1';
3435co <= ct;
3436end if;
3437end if;
3438end if;
3439end process;
3440end architecture;
3441
3442library ieee, work;
3443use ieee.std_logic_1164.all;
3444use work.util.all;
3445use ieee.numeric_std.all;
3446use ieee.math_real.all;
3447
3448entity hamming_7_4_tb is
3449generic (g: common_generics);
3450end entity;
3451
3452architecture testing of hamming_7_4_tb is
3453constant clock_period: time := 1000 ms / g.clock_frequency;
3454constant n: positive := 3;
3455signal clk, rst: std_ulogic := '0';
3456signal stop: std_ulogic := '0';
3457signal di, do, do_s: std_ulogic_vector(3 downto 0) := (others => '0');
3458signal encoded_tx, encoded_rx, ebit: std_ulogic_vector(6 downto 0) := (others => '0');
3459signal parity, single, double: std_ulogic := '0';
3460signal parity_s, single_s, double_s: std_ulogic := '0';
3461begin
3462cs: entity work.clock_source_tb
3463generic map (g => g, hold_rst => 2)
3464port map (stop => stop, clk => clk, rst => rst);
3465
3466uut_encode: entity work.hamming_7_4_encoder
3467generic map (g => g) port map (di => di, do => encoded_tx, parity => parity);
3468
3469lossy_channel: process(encoded_tx)
3470variable seed1, seed2: positive;
3471variable r: real;
3472variable i: integer range 0 to 7;
3473begin
3474encoded_rx <= encoded_tx;
3475uniform(seed1, seed2, r);
3476if r > 0.5 then
3477uniform(seed1, seed2, r);
3478i := integer(floor(r * 6.99));
3479encoded_rx(i) <= not encoded_tx(i);
3480uniform(seed1, seed2, r);
3481end if;
3482if r > 0.5 then
3483uniform(seed1, seed2, r);
3484i := integer(floor(r * 6.99));
3485encoded_rx(i) <= not encoded_tx(i);
3486end if;
3487end process;
3488
3489ebit <= encoded_tx xor encoded_rx;
3490
3491uut_decode_secdec: entity work.hamming_7_4_decoder
3492generic map (g => g) port map (di => encoded_rx, do => do, parity => parity, single => single, double => double);
3493
3494uut_decode_single: entity work.hamming_7_4_decoder
3495generic map (g => g, secdec => false) port map (di => encoded_rx, do => do_s, parity => parity_s, single => single_s, double => double_s);
3496
3497stimulus_process: process
3498procedure test(slv: std_ulogic_vector) is
3499begin
3500di <= slv;
3501wait for clock_period * 2;
3502if bit_count_f(ebit) = 2 then
3503assert double = '1' severity failure;
3504assert single = '0' severity failure;
3505elsif bit_count_f(ebit) = 1 then
3506assert di = do severity failure;
3507assert single = '1' severity failure;
3508assert double = '0' severity failure;
3509
3510assert di = do_s severity failure;
3511assert single_s = '1' severity failure;
3512else
3513assert di = do severity failure;
3514assert double = '0' severity failure;
3515assert single = '0' severity failure;
3516
3517assert di = do_s severity failure;
3518assert single_s = '0' severity failure;
3519end if;
3520wait for clock_period * 2;
3521end procedure;
3522variable ii: unsigned(7 downto 0) := (others => '1');
3523begin
3524di <= (others => '0');
3525wait until rst = '0';
3526
3527while ii /= x"00" loop
3528ii := ii - 1;
3529test(std_ulogic_vector(ii(3 downto 0)));
3530end loop;
3531stop <= '1';
3532wait;
3533end process;
3534
3535end architecture;
3536
3537------------------------- Hamming CODEC ------------------------------------------------------
3538
3539------------------------- VGA Controller ------------------------------------------------------
3540-- VGA Controller
3541--
3542-- See:
3543-- * <https://en.wikipedia.org/wiki/Video_Graphics_Array>
3544-- * <http://www.ece.ualberta.ca/~elliott/ee552/studentAppNotes/1998_w/Altera_UP1_Board_Map/vga.html>
3545-- * <https://www.digikey.com/eewiki/pages/viewpage.action?pageId=15925278>
3546--
3547-- This purpose of this VGA controller is to provide the necessary VGA
3548-- timings for a given resolution (which has to be determined at instantiation
3549-- time and cannot be configured on the fly). The VGA controller will generate
3550-- the correct HSYNC and VSYNCH signals needed, as well as the current row and
3551-- column that is currently being drawn. This can be used to generate an image.
3552--
3553-- Example timing for 640 x 480:
3554--
3555-- |-----800 pixels / 31.778 us---------|
3556-- |-----640 Pixels--------|-160 Pixels-|
3557-- |-----25.422 us---------|--5.75 us---|
3558--
3559-- +-----------------------+------------+ VSYNC
3560-- | | ^ | |
3561-- | | | | |
3562-- | | | | |
3563-- | Display Period | 480 Rows | |
3564-- | | | | |
3565-- | | | | |
3566-- | | | | |
3567-- | | v | |
3568-- +-----------------------+ --- | |
3569-- | ^ | _| <- Front porch 0.318 ms (10 rows)
3570-- | | | |
3571-- | Blanking Period 45 Rows | | <--- VSYNC pulse 0.064 ms (2 rows)
3572-- | | | |_
3573-- | v | | <- Back porch 1.048 ms (33 rows)
3574-- +------------------------------------+ |
3575--
3576-- ___
3577-- ___________________________| |_____ HSYNC
3578-- ^ ^ ^
3579-- 0.636 us Front Porch __/ / / <-(16 pixels)
3580-- 3.813 us HSYNC Pulse ____/ / <-(96 pixels)
3581-- 1.907 us Back Porch _______/ <-(48 pixels)
3582--
3583
3584library ieee, work;
3585use ieee.std_logic_1164.all;
3586use work.util.all;
3587
3588entity vga_controller is
3589generic (
3590g: common_generics;
3591pixel_clock_frequency: positive := 25_000_000;
3592constant cfg: vga_configuration := vga_640x480);
3593port (
3594clk, rst: in std_ulogic;
3595h_sync, v_sync: out std_ulogic;
3596h_blank, v_blank: out std_ulogic;
3597column, row: out integer);
3598end entity;
3599
3600architecture behavior of vga_controller is
3601constant h_period: integer := cfg.h_pulse + cfg.h_back_porch + cfg.h_pixels + cfg.h_front_porch; -- number of pixel clocks in a row
3602constant v_period: integer := cfg.v_pulse + cfg.v_back_porch + cfg.v_pixels + cfg.v_front_porch; -- number of rows in column
3603signal h_sync_internal, v_sync_internal: std_ulogic := '0';
3604begin
3605-- The clock does not need to be exactly the correct value
3606assert pixel_clock_frequency <= (cfg.clock_frequency + 250_000)
3607and pixel_clock_frequency >= (cfg.clock_frequency - 250_000) severity warning;
3608
3609h_sync <= h_sync_internal xor cfg.h_polarity;
3610v_sync <= v_sync_internal xor cfg.v_polarity;
3611
3612process (clk, rst)
3613constant h_start: integer := cfg.h_pixels + cfg.h_front_porch;
3614constant h_end: integer := cfg.h_pixels + cfg.h_front_porch + cfg.h_pulse;
3615constant v_start: integer := cfg.v_pixels + cfg.v_front_porch;
3616constant v_end: integer := cfg.v_pixels + cfg.v_front_porch + cfg.v_pulse;
3617variable h_count: integer range 0 to h_period - 1 := 0; -- horizontal counter (counts the columns)
3618variable v_count: integer range 0 to v_period - 1 := 0; -- vertical counter (counts the rows)
3619procedure reset is
3620begin
3621h_count := 0;
3622v_count := 0;
3623h_blank <= '0' after g.delay;
3624v_blank <= '0' after g.delay;
3625column <= 0 after g.delay;
3626row <= 0 after g.delay;
3627end procedure;
3628begin
3629if rst = '1' and g.asynchronous_reset then
3630reset;
3631elsif rising_edge(clk) then
3632if rst = '1' and not g.asynchronous_reset then
3633reset;
3634else
3635if h_count < (h_period - 1) then -- pixel count
3636h_count := h_count + 1;
3637else
3638if v_count < (v_period - 1) then -- row count
3639v_count := v_count + 1;
3640else
3641v_count := 0;
3642end if;
3643h_count := 0;
3644end if;
3645
3646h_sync_internal <= not logical((h_count < h_start) or (h_count >= h_end)) after g.delay;
3647v_sync_internal <= not logical((v_count < v_start) or (v_count >= v_end)) after g.delay;
3648
3649column <= cfg.h_pixels - 1;
3650row <= cfg.v_pixels - 1;
3651
3652if h_count < cfg.h_pixels then h_blank <= '0'; column <= h_count; else h_blank <= '1'; end if;
3653if v_count < cfg.v_pixels then v_blank <= '0'; row <= v_count; else v_blank <= '1'; end if;
3654end if;
3655end if;
3656end process;
3657end architecture;
3658
3659library ieee, work;
3660use ieee.std_logic_1164.all;
3661use ieee.numeric_std.all;
3662use work.util.all;
3663
3664entity vga_tb is
3665generic (g: common_generics; pixel_clock_frequency: positive := 25_000_000; simulation_us: time := 20000 us);
3666end entity;
3667
3668architecture testing of vga_tb is
3669constant pixel_clock_period: time := 1000 ms / pixel_clock_frequency;
3670signal rst, clk: std_ulogic := '1';
3671signal stop: boolean := false;
3672signal h_sync, v_sync: std_ulogic := 'X';
3673signal h_blank, v_blank: std_ulogic := 'X';
3674signal column, row: integer := 0;
3675begin
3676duration: process begin wait for simulation_us; stop <= true; wait; end process;
3677clk_process: process
3678begin
3679rst <= '1';
3680wait for pixel_clock_period * 5;
3681rst <= '0';
3682while not stop loop
3683clk <= '1';
3684wait for pixel_clock_period / 2;
3685clk <= '0';
3686wait for pixel_clock_period / 2;
3687end loop;
3688wait;
3689end process;
3690
3691uut: work.util.vga_controller
3692generic map (g => g, pixel_clock_frequency => pixel_clock_frequency)
3693port map (
3694rst => rst,
3695clk => clk,
3696h_sync => h_sync,
3697v_sync => v_sync,
3698h_blank => h_blank,
3699v_blank => v_blank,
3700column => column,
3701row => row);
3702end architecture;
3703
3704------------------------- VGA Controller ------------------------------------------------------
3705
3706------------------------- LED Controller ------------------------------------------------------
3707--| This module implements a 7 segment display (plus decimal point) driver,
3708--| with 4 displays in total:
3709--|
3710--| _____________________ an (selects segment)
3711--| | | | |
3712--| __ __ __ __
3713--| | | | | | | | |
3714--| |__| |__| |__| |__|
3715--| | | | | | | | |
3716--| |__|. |__|. |__|. |__|.
3717--| |____|_____|_____|____ ka (value to display on segment)
3718--|
3719--| Each of the display shares a common anode for all of its LEDs, this can be
3720--| used to select an individual display
3721
3722library ieee, work;
3723use ieee.std_logic_1164.all;
3724use ieee.numeric_std.all;
3725use work.util.all;
3726
3727entity led_7_segment_display is
3728generic (
3729g: common_generics;
3730use_bcd_not_hex: boolean := true;
3731refresh_rate_us: natural := 1500;
3732number_of_led_displays: positive := 4);
3733port (
3734clk: in std_ulogic;
3735rst: in std_ulogic;
3736
3737leds_we: in std_ulogic;
3738leds: in std_ulogic_vector((number_of_led_displays * led_7_segment_character_length) - 1 downto 0);
3739
3740-- Physical outputs
3741an: out std_ulogic_vector(number_of_led_displays - 1 downto 0); -- anodes, controls on/off
3742ka: out std_ulogic_vector(7 downto 0)); -- cathodes, data on display
3743end;
3744
3745architecture rtl of led_7_segment_display is
3746
3747-- This lookup table converts a BCD character into a value
3748-- that can be displayed on an 7 segment display. The layout of which
3749-- is as follows:
3750--
3751-- A
3752-- ---
3753-- F | | B
3754-- |___|
3755-- E | G | C
3756-- |___| . DP
3757-- D
3758--
3759-- The following encoding is used to convert the input BCD character
3760-- into a value that can be put onto the display.
3761--
3762-- -----------------------------------------
3763-- | | DP| G | F | E | D | C | B | A | Hex |
3764-- |BCD| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |Hi Lo|
3765-- -----------------------------------------
3766-- | 0 | | | 1 | 1 | 1 | 1 | 1 | 1 | 3 F |
3767-- | 1 | | | | | | 1 | 1 | | 0 6 |
3768-- | 2 | | 1 | | 1 | 1 | | 1 | 1 | 5 B |
3769-- | 3 | | 1 | | | 1 | 1 | 1 | 1 | 4 F |
3770-- | 4 | | 1 | 1 | | | 1 | 1 | | 6 6 |
3771-- | 5 | | 1 | 1 | | 1 | 1 | | 1 | 6 D |
3772-- | 6 | | 1 | 1 | 1 | 1 | 1 | | 1 | 7 D |
3773-- | 7 | | | | | | 1 | 1 | 1 | 0 7 |
3774-- | 8 | | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 7 F |
3775-- | 9 | | 1 | 1 | | 1 | 1 | 1 | 1 | 6 F |
3776-- | | | | | | | | | | 0 0 |
3777-- | . | 1 | | | | | | | | 8 0 |
3778-- | - | | 1 | | | | | | | 4 0 |
3779-- -----------------------------------------
3780-- | A | | 1 | 1 | 1 | | 1 | 1 | 1 | 7 7 |
3781-- | b | | 1 | 1 | 1 | 1 | 1 | | | 7 C |
3782-- | C | | | 1 | 1 | 1 | | | 1 | 3 9 |
3783-- | d | | 1 | | 1 | 1 | 1 | 1 | | 5 E |
3784-- | E | | 1 | 1 | 1 | 1 | | | 1 | 7 9 |
3785-- | F | | 1 | 1 | 1 | | | | 1 | 7 1 |
3786-- -----------------------------------------
3787--
3788-- The table is then inverted before it goes to the output.
3789--
3790
3791function hex_to_7_segment(a: led_7_segment_character) return led_7_segment is
3792variable r: std_ulogic_vector(7 downto 0) := x"00";
3793begin
3794-- NB. You may have thought a case statement would be the best
3795-- way of doing this, and you would be right. However, Xilinx ISE
3796-- issues annoying 'INFO' statements when you do - thanks Xilinx!
3797-- The generated hardware is the same however.
3798if a = "0000" then r := x"3F"; -- 0
3799elsif a = "0001" then r := x"06"; -- 1
3800elsif a = "0010" then r := x"5B"; -- 2
3801elsif a = "0011" then r := x"4F"; -- 3
3802elsif a = "0100" then r := x"66"; -- 4
3803elsif a = "0101" then r := x"6D"; -- 5
3804elsif a = "0110" then r := x"7D"; -- 6
3805elsif a = "0111" then r := x"07"; -- 7
3806elsif a = "1000" then r := x"7F"; -- 8
3807elsif a = "1001" then r := x"6F"; -- 9
3808elsif a = "1010" then r := x"77"; -- A
3809elsif a = "1011" then r := x"7C"; -- b
3810elsif a = "1100" then r := x"39"; -- C
3811elsif a = "1101" then r := x"5E"; -- d
3812elsif a = "1110" then r := x"79"; -- E
3813elsif a = "1111" then r := x"71"; -- F
3814end if;
3815return r;
3816end function;
3817
3818function bcd_to_7_segment(a: led_7_segment_character) return led_7_segment is
3819variable r: std_ulogic_vector(7 downto 0) := x"00";
3820begin
3821case a is
3822when "0000" => r := x"3F"; -- 0
3823when "0001" => r := x"06"; -- 1
3824when "0010" => r := x"5B"; -- 2
3825when "0011" => r := x"4F"; -- 3
3826when "0100" => r := x"66"; -- 4
3827when "0101" => r := x"6D"; -- 5
3828when "0110" => r := x"7D"; -- 6
3829when "0111" => r := x"07"; -- 7
3830when "1000" => r := x"7F"; -- 8
3831when "1001" => r := x"6F"; -- 9
3832when "1010" => r := x"00"; -- Blank
3833when "1011" => r := x"80"; -- .
3834when "1100" => r := x"40"; -- -
3835when "1101" => r := x"00"; -- Unused
3836when "1110" => r := x"00"; -- Unused
3837when "1111" => r := x"00"; -- Unused
3838when others => r := x"00"; -- Unused
3839end case;
3840return r;
3841end function;
3842
3843function char_to_7_segment(a: led_7_segment_character) return led_7_segment is
3844begin
3845if use_bcd_not_hex then
3846return invert(bcd_to_7_segment(a));
3847else
3848return invert(hex_to_7_segment(a));
3849end if;
3850end function;
3851
3852signal leds_o: std_ulogic_vector(leds'range) := (others => '0');
3853
3854signal do_shift: std_ulogic := '0';
3855signal shift_reg: std_ulogic_vector(number_of_led_displays - 1 downto 0);
3856
3857signal leds_reg_o: std_ulogic_vector(leds'range) := (others => '0');
3858signal leds_reg_we_o: std_ulogic := '0';
3859begin
3860an <= invert(shift_reg) after g.delay;
3861
3862segment_reg: entity work.reg
3863generic map (g => g, N => number_of_led_displays * led_7_segment_character_length)
3864port map (
3865clk => clk,
3866rst => rst,
3867we => leds_we,
3868di => leds,
3869do => leds_reg_o);
3870
3871segment_reg_re: entity work.reg
3872generic map (g => g, N => 1)
3873port map (
3874clk => clk,
3875rst => rst,
3876we => '1',
3877di(0) => leds_we,
3878do(0) => leds_reg_we_o);
3879
3880led_gen: for i in number_of_led_displays - 1 downto 0 generate
3881led_i: entity work.reg
3882generic map (g => g, N => led_7_segment_character_length)
3883port map (
3884clk => clk,
3885rst => rst,
3886we => leds_reg_we_o,
3887di => leds_reg_o((i*led_7_segment_character_length) + led_7_segment_character_length - 1 downto (i*led_7_segment_character_length)),
3888do => leds_o((i*led_7_segment_character_length) + led_7_segment_character_length - 1 downto (i*led_7_segment_character_length)));
3889end generate;
3890
3891timer: entity work.timer_us
3892generic map (g => g, timer_period_us => refresh_rate_us)
3893port map (
3894clk => clk,
3895rst => rst,
3896co => do_shift);
3897
3898process(rst, clk, do_shift, shift_reg)
3899begin
3900if rst = '1' and g.asynchronous_reset then
3901shift_reg <= (others => '0') after g.delay;
3902shift_reg(0) <= '1' after g.delay;
3903elsif rising_edge(clk) then
3904if rst = '1' and not g.asynchronous_reset then
3905shift_reg <= (others => '0') after g.delay;
3906shift_reg(0) <= '1' after g.delay;
3907else
3908if do_shift = '1' then
3909shift_reg <= shift_reg(number_of_led_displays - 2 downto 0) & shift_reg(number_of_led_displays - 1) after g.delay;
3910else
3911shift_reg <= shift_reg after g.delay;
3912end if;
3913end if;
3914end if;
3915end process;
3916
3917process(leds_o, shift_reg)
3918begin
3919ka <= (others => '0');
3920for i in number_of_led_displays - 1 downto 0 loop
3921if '1' = shift_reg(number_of_led_displays - i - 1) then
3922ka <= char_to_7_segment(leds_o(i*led_7_segment_character_length + led_7_segment_character_length - 1 downto (i*led_7_segment_character_length))) after g.delay;
3923end if;
3924end loop;
3925end process;
3926end architecture;
3927
3928library ieee, work;
3929use ieee.std_logic_1164.all;
3930use ieee.numeric_std.all;
3931use work.util.all;
3932
3933entity led_7_segment_display_tb is
3934generic (g: common_generics);
3935end entity;
3936
3937architecture testing of led_7_segment_display_tb is
3938constant clock_period: time := 1000 ms / g.clock_frequency;
3939signal clk, rst: std_ulogic := '0';
3940signal stop: std_ulogic := '0';
3941
3942constant number_of_led_displays: positive := 4;
3943signal an: std_ulogic_vector(number_of_led_displays - 1 downto 0);
3944signal ka: std_ulogic_vector(7 downto 0);
3945signal leds_we: std_ulogic;
3946signal leds: std_ulogic_vector((number_of_led_displays * led_7_segment_character_length) - 1 downto 0);
3947begin
3948cs: entity work.clock_source_tb
3949generic map (g => g, hold_rst => 2)
3950port map (stop => stop, clk => clk, rst => rst);
3951
3952-- We have a very fast refresh rate here, just for testing purposes.
3953uut: entity work.led_7_segment_display
3954generic map (g => g, refresh_rate_us => 1)
3955port map (clk => clk, rst => rst, leds_we => leds_we, leds => leds, an => an, ka => ka);
3956
3957stimulus_process: process
3958begin
3959wait for clock_period * 2;
3960leds_we <= '1';
3961leds <= x"1234";
3962wait for clock_period * 1;
3963leds_we <= '0';
3964wait for clock_period * 1000;
3965stop <= '1';
3966wait;
3967end process;
3968
3969end architecture;
3970
3971------------------------- LED Controller ------------------------------------------------------
3972
3973------------------------- Sine / Cosine ------------------------------------------------------
3974-- Sine / Cosine calculation using multiplication
3975-- Half-inched from <https://github.com/jamesbowman/sincos>
3976-- Angles are input as signed Furmans (1 Furman = (1/pow(2, 16) of a circle))
3977-- 1 Degree is ~182 Furmans. 1 rad is ~10430 Furmans.
3978-- Result is signed scaled 16-bit integer; -1 = -32767, +1 = 32767
3979--
3980library ieee, work;
3981use ieee.std_logic_1164.all;
3982use ieee.numeric_std.all;
3983use work.util.all;
3984
3985entity sine is
3986generic (g: common_generics; pipeline: boolean := true);
3987port (
3988clk, rst, xwe: in std_ulogic;
3989x: in std_ulogic_vector(15 downto 0);
3990s: out std_ulogic_vector(15 downto 0));
3991end entity;
3992
3993architecture behavior of sine is
3994subtype val is signed(x'range);
3995subtype mul is signed((val'high * 2) + 1 downto 0);
3996function half_multiply_add(a, b, c: val) return val is
3997variable t: mul;
3998variable r: val;
3999begin
4000t := a * b;
4001r := t(t'high downto r'high + 1) + c;
4002return r;
4003end function;
4004signal n: signed(2 downto 0);
4005signal xn, z, y, sums, sumc, sum1, cc, t0, t1, t0n, t1n, sa, so: val;
4006signal cc32: mul;
4007signal xnslv, t0nslv, t1nslv: std_ulogic_vector(x'range);
4008begin
4009pipe_0: if pipeline generate
4010reg_in: work.util.reg
4011generic map (g => g, N => x'length)
4012port map (clk => clk, rst => rst, we => xwe, di => x, do => xnslv);
4013reg_out: work.util.reg
4014generic map (g => g, N => x'length)
4015port map (clk => clk, rst => rst, we => '1', di => std_ulogic_vector(so), do => s);
4016xn <= signed(xnslv);
4017t0n <= signed(t0); -- also need to delay n
4018t1n <= signed(t1); -- also need to delay n
4019end generate;
4020no_pipe_0: if not pipeline generate
4021xn <= signed(x);
4022s <= std_ulogic_vector(so) after g.delay;
4023t0n <= t0;
4024t1n <= t1;
4025end generate;
4026
4027y(1 downto 0) <= (others => '0') after g.delay;
4028y(15 downto 2) <= signed(xn(13 downto 0)) after g.delay;
4029n <= signed(xn(15 downto 13)) + "01" after g.delay;
4030z <= half_multiply_add(y, y, x"0000") after g.delay;
4031sumc <= half_multiply_add(z, x"0FBD", -x"4EE9") after g.delay;
4032sums <= half_multiply_add(z, x"04F8", -x"2953") after g.delay;
4033sum1 <= half_multiply_add(z, sums, x"6487") after g.delay;
4034t0 <= z when n(1) = '1' else y after g.delay;
4035t1 <= sumc when n(1) = '1' else sum1 after g.delay;
4036cc32 <= t0n * t1n after g.delay;
4037cc <= cc32(cc32'high - 1 downto cc'high) after g.delay;
4038sa <= cc + x"7FFF" when n(1) = '1' else cc after g.delay;
4039so <= -sa when n(2) = '1' else sa after g.delay;
4040end architecture;
4041
4042library ieee, work;
4043use ieee.std_logic_1164.all;
4044use ieee.numeric_std.all;
4045use work.util.all;
4046
4047entity cosine is
4048generic (g: common_generics; pipeline: boolean := true);
4049port (
4050clk, rst, xwe: in std_ulogic;
4051x: in std_ulogic_vector(15 downto 0);
4052c: out std_ulogic_vector(15 downto 0));
4053end entity;
4054
4055architecture behavior of cosine is
4056signal xn: std_ulogic_vector(c'range);
4057begin
4058xn <= std_ulogic_vector(signed(x) + x"4000");
4059calc: entity work.sine
4060generic map(g => g, pipeline => pipeline) port map(clk => clk, rst => rst, xwe => xwe, x => xn, s => c);
4061end architecture;
4062
4063library ieee, work;
4064use ieee.std_logic_1164.all;
4065use ieee.numeric_std.all;
4066use work.util.all;
4067
4068entity sine_tb is
4069generic (g: common_generics);
4070end entity;
4071
4072architecture testing of sine_tb is
4073constant clock_period: time := 1000 ms / g.clock_frequency;
4074signal clk, rst: std_ulogic := '0';
4075signal stop: std_ulogic := '0';
4076
4077constant number_of_led_displays: positive := 4;
4078signal x: std_ulogic_vector(15 downto 0);
4079signal s, c: std_ulogic_vector(x'range);
4080begin
4081cs: entity work.clock_source_tb
4082generic map (g => g, hold_rst => 2)
4083port map (stop => stop, clk => clk, rst => rst);
4084
4085uut_c: entity work.sine generic map (g => g) port map (clk => clk, rst => rst, xwe => '1', x => x, s => s);
4086uut_s: entity work.cosine generic map (g => g) port map (clk => clk, rst => rst, xwe => '1', x => x, c => c);
4087
4088stimulus_process: process
4089variable cnt: integer := -32768;
4090begin
4091x <= std_ulogic_vector(to_signed(cnt, x'length));
4092wait for clock_period * 2;
4093while cnt < 32768 loop
4094x <= std_ulogic_vector(to_signed(cnt, x'length));
4095wait for clock_period * 10;
4096cnt := cnt + 182;
4097end loop;
4098stop <= '1';
4099wait;
4100end process;
4101end architecture;
4102------------------------- Sine / Cosine ------------------------------------------------------
4103
4104