OpenCores
URL https://opencores.org/ocsvn/forth-cpu/forth-cpu/trunk

Subversion Repositories forth-cpu

[/] [forth-cpu/] [trunk/] [util.vhd] - Blame information for rev 5

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.