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

Subversion Repositories forth-cpu

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

Go to most recent revision | 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
--| components, unless marked with a "_tb" suffix (or is the function n_bits).
6
--| @author         Richard James Howe
7
--| @copyright      Copyright 2017 Richard James Howe
8
--| @license        MIT
9
--| @email          howe.r.j.89@gmail.com
10
-------------------------------------------------------------------------------
11
library ieee;
12
use ieee.std_logic_1164.all;
13
use ieee.numeric_std.all;
14
use std.textio.all;
15
 
16
package util is
17
        component util_tb is
18
                generic(clock_frequency: positive);
19
        end component;
20
 
21
        component clock_source_tb is
22
                generic(clock_frequency: positive; hold_rst: positive := 1);
23
                port(
24
                        stop:            in     std_ulogic := '0';
25
                        clk:             buffer std_ulogic;
26
                        clk_with_jitter: out    std_ulogic := '0';
27
                        rst:             out    std_ulogic := '0');
28
        end component;
29
 
30
        component reg
31
                generic(N: positive);
32
                port(
33
                        clk: in  std_ulogic;
34
                        rst: in  std_ulogic;
35
                        we:  in  std_ulogic;
36
                        di:  in  std_ulogic_vector(N - 1 downto 0);
37
                        do:  out std_ulogic_vector(N - 1 downto 0));
38
        end component;
39
 
40
        component shift_register
41
                generic(N: positive);
42
                port(
43
                        clk:     in  std_ulogic;
44
                        rst:     in  std_ulogic;
45
                        we:      in  std_ulogic;
46
                        di:      in  std_ulogic;
47
                        do:      out std_ulogic;
48
 
49
                        -- optional
50
                        load_we: in  std_ulogic := '0';
51
                        load_i:  in  std_ulogic_vector(N - 1 downto 0) := (others => '0');
52
                        load_o:  out std_ulogic_vector(N - 1 downto 0));
53
        end component;
54
 
55
        component shift_register_tb
56
                generic(clock_frequency: positive);
57
        end component;
58
 
59
        component timer_us
60
                generic(clock_frequency: positive; timer_period_us: natural);
61
                port(
62
                        clk: in  std_ulogic;
63
                        rst: in  std_ulogic;
64
                        co:  out std_ulogic);
65
        end component;
66
 
67
        component timer_us_tb
68
                generic(clock_frequency: positive);
69
        end component;
70
 
71
        component rising_edge_detector is
72
        port(
73
                clk:    in  std_ulogic;
74
                rst:    in  std_ulogic;
75
                di:     in  std_ulogic;
76
                do:     out std_ulogic);
77
        end component;
78
 
79
        component rising_edge_detector_tb is
80
                generic(clock_frequency: positive);
81
        end component;
82
 
83
        component rising_edge_detectors is
84
        generic(N: positive);
85
        port(
86
                clk:    in  std_ulogic;
87
                rst:    in  std_ulogic;
88
                di:     in  std_ulogic_vector(N - 1 downto 0);
89
                do:     out std_ulogic_vector(N - 1 downto 0));
90
        end component;
91
 
92
 
93
        -- @note half_adder test bench is folded in to full_adder_tb
94
        component half_adder is
95
                port(
96
                        a:     in  std_ulogic;
97
                        b:     in  std_ulogic;
98
                        sum:   out std_ulogic;
99
                        carry: out std_ulogic);
100
        end component;
101
 
102
        component full_adder is
103
                port(
104
                        x:     in    std_ulogic;
105
                        y:     in    std_ulogic;
106
                        z:     in    std_ulogic;
107
                        sum:   out   std_ulogic;
108
                        carry: out   std_ulogic);
109
        end component;
110
 
111
        component full_adder_tb is
112
                generic(clock_frequency: positive);
113
        end component;
114
 
115
        component fifo is
116
                generic (data_width: positive;
117
                        fifo_depth: positive);
118
                port (
119
                        clk:   in  std_ulogic;
120
                        rst:   in  std_ulogic;
121
                        di:    in  std_ulogic_vector(data_width - 1 downto 0);
122
                        we:    in  std_ulogic;
123
                        re:    in  std_ulogic;
124
                        do:    out std_ulogic_vector(data_width - 1 downto 0);
125
 
126
                        -- optional
127
                        full:  out std_ulogic := '0';
128
                        empty: out std_ulogic := '1');
129
        end component;
130
 
131
        component fifo_tb is
132
                generic(clock_frequency: positive);
133
        end component;
134
 
135
        component counter is
136
                generic(
137
                        N: positive);
138
                port(
139
                        clk:     in  std_ulogic;
140
                        rst:     in  std_ulogic;
141
                        ce:      in  std_ulogic;
142
                        cr:      in  std_ulogic;
143
                        dout:    out std_ulogic_vector(N - 1 downto 0);
144
 
145
                        -- optional
146
                        load_we: in  std_ulogic := '0';
147
                        load_i:  in  std_ulogic_vector(N - 1 downto 0) := (others => '0'));
148
        end component;
149
 
150
        component counter_tb is
151
                generic(clock_frequency: positive);
152
        end component;
153
 
154
        component lfsr is
155
                generic(constant tap: std_ulogic_vector);
156
                port
157
                (
158
                        clk: in  std_ulogic;
159
                        rst: in  std_ulogic;
160
                        ce:  in  std_ulogic := '1';
161
                        we:  in  std_ulogic;
162
                        di:  in  std_ulogic_vector(tap'high + 1 to tap'low);
163
                        do:  out std_ulogic_vector(tap'high + 1 to tap'low));
164
        end component;
165
 
166
        component lfsr_tb is
167
                generic(clock_frequency: positive);
168
        end component;
169
 
170
        component io_pins is
171
                generic(
172
                        N: positive);
173
                port
174
                (
175
                        clk:         in    std_ulogic;
176
                        rst:         in    std_ulogic;
177
                        control:     in    std_ulogic_vector(N - 1 downto 0);
178
                        control_we:  in    std_ulogic;
179
                        din:         in    std_ulogic_vector(N - 1 downto 0);
180
                        din_we:      in    std_ulogic;
181
                        dout:        out   std_ulogic_vector(N - 1 downto 0);
182
                        pins:        inout std_logic_vector(N - 1 downto 0));
183
        end component;
184
 
185
        component io_pins_tb is
186
                generic(clock_frequency: positive);
187
        end component;
188
 
189
        type file_format is (FILE_HEX, FILE_BINARY, FILE_NONE);
190
 
191
        component dual_port_block_ram is
192
        generic(addr_length: positive    := 12;
193
                data_length: positive    := 16;
194
                file_name:   string      := "memory.bin";
195
                file_type:   file_format := FILE_BINARY);
196
        port(
197
                -- port A of dual port RAM
198
                a_clk:  in  std_ulogic;
199
                a_dwe:  in  std_ulogic;
200
                a_dre:  in  std_ulogic;
201
                a_addr: in  std_ulogic_vector(addr_length - 1 downto 0);
202
                a_din:  in  std_ulogic_vector(data_length - 1 downto 0);
203
                a_dout: out std_ulogic_vector(data_length - 1 downto 0) := (others => '0');
204
                -- port B of dual port RAM
205
                b_clk:  in  std_ulogic;
206
                b_dwe:  in  std_ulogic;
207
                b_dre:  in  std_ulogic;
208
                b_addr: in  std_ulogic_vector(addr_length - 1 downto 0);
209
                b_din:  in  std_ulogic_vector(data_length - 1 downto 0);
210
                b_dout: out std_ulogic_vector(data_length - 1 downto 0) := (others => '0'));
211
        end component;
212
 
213
        component single_port_block_ram is
214
        generic(addr_length: positive    := 12;
215
                data_length: positive    := 16;
216
                file_name:   string      := "memory.bin";
217
                file_type:   file_format := FILE_BINARY);
218
        port(
219
                clk:  in  std_ulogic;
220
                dwe:  in  std_ulogic;
221
                dre:  in  std_ulogic;
222
                addr: in  std_ulogic_vector(addr_length - 1 downto 0);
223
                din:  in  std_ulogic_vector(data_length - 1 downto 0);
224
                dout: out std_ulogic_vector(data_length - 1 downto 0) := (others => '0'));
225
        end component;
226
 
227
        component data_source is
228
                generic(addr_length: positive    := 12;
229
                        data_length: positive    := 16;
230
                        file_name:   string      := "memory.bin";
231
                        file_type:   file_format := FILE_BINARY);
232
                port(
233
                        clk:     in  std_ulogic;
234
                        rst:     in  std_ulogic;
235
 
236
                        ce:      in  std_ulogic := '1';
237
                        cr:      in  std_ulogic;
238
 
239
                        load:    in  std_ulogic_vector(addr_length - 1 downto 0) := (others => '0');
240
                        load_we: in  std_ulogic := '0';
241
 
242
                        dout:    out std_ulogic_vector(data_length - 1 downto 0));
243
        end component;
244
 
245
        component ucpu is
246
                generic(width: positive range 8 to 32 := 8);
247
                port(
248
                        clk, rst: in  std_ulogic;
249
 
250
                        pc:       out std_ulogic_vector(width - 3 downto 0);
251
                        op:       in  std_ulogic_vector(width - 1 downto 0);
252
 
253
                        adr:      out std_ulogic_vector(width - 3 downto 0);
254
                        di:       in  std_ulogic_vector(width - 1 downto 0);
255
                        re, we:   out std_ulogic;
256
                        do:       out std_ulogic_vector(width - 1 downto 0));
257
        end component;
258
 
259
        component ucpu_tb is
260
                generic(
261
                        clock_frequency: positive;
262
                        file_name: string := "ucpu.bin");
263
        end component;
264
 
265
        component restoring_divider is
266
                generic(N: positive);
267
                port(
268
                        clk:   in  std_ulogic;
269
                        rst:   in  std_ulogic := '0';
270
 
271
                        a:     in  std_ulogic_vector(N - 1 downto 0);
272
                        b:     in  std_ulogic_vector(N - 1 downto 0);
273
                        start: in  std_ulogic;
274
                        done:  out std_ulogic;
275
                        c:     out std_ulogic_vector(N - 1 downto 0));
276
        end component;
277
 
278
        component restoring_divider_tb is
279
                generic(clock_frequency: positive);
280
        end component;
281
 
282
        component debounce_us is
283
                generic(clock_frequency: positive; timer_period_us: natural);
284
                port(
285
                        clk:   in  std_ulogic;
286
                        di:    in  std_ulogic;
287
                        do:    out std_ulogic);
288
        end component;
289
 
290
        component debounce_block_us is
291
                generic(N: positive; clock_frequency: positive; timer_period_us: natural);
292
                port(
293
                        clk:   in  std_ulogic;
294
                        di:    in  std_ulogic_vector(N - 1 downto 0);
295
                        do:    out std_ulogic_vector(N - 1 downto 0));
296
        end component;
297
 
298
        component debounce_us_tb is
299
                generic(clock_frequency: positive);
300
        end component;
301
 
302
        component state_changed is
303
                port(
304
                        clk: in  std_ulogic;
305
                        rst: in  std_ulogic;
306
                        di:  in  std_ulogic;
307
                        do:  out std_ulogic);
308
        end component;
309
 
310
        component state_block_changed is
311
                generic(N: positive);
312
                port(
313
                        clk: in  std_ulogic;
314
                        rst: in  std_ulogic;
315
                        di:  in  std_ulogic_vector(N - 1 downto 0);
316
                        do:  out std_ulogic_vector(N - 1 downto 0));
317
        end component;
318
 
319
        function max(a: natural; b: natural) return natural;
320
        function min(a: natural; b: natural) return natural;
321
        function n_bits(x: natural) return natural;
322
        function n_bits(x: std_ulogic_vector) return natural;
323
        function reverse (a: in std_ulogic_vector) return std_ulogic_vector;
324
        function invert(slv:std_ulogic_vector) return std_ulogic_vector;
325
        function parity(slv:std_ulogic_vector; even: boolean) return std_ulogic;
326
        function select_bit(indexed, selector: std_ulogic_vector) return std_ulogic;
327
        function priority(order: std_ulogic_vector; high: boolean) return natural;
328
        function priority(order: std_ulogic_vector; high: boolean) return std_ulogic_vector;
329
        function mux(a: std_ulogic_vector; b: std_ulogic_vector; sel: std_ulogic) return std_ulogic_vector;
330
        function mux(a: std_ulogic; b: std_ulogic; sel: std_ulogic) return std_ulogic;
331
        function mux(a, b : std_ulogic_vector) return std_ulogic;
332
        function decode(encoded: std_ulogic_vector) return std_ulogic_vector;
333
        function hex_char_to_std_ulogic_vector(hc: character) return std_ulogic_vector;
334
        function to_std_ulogic_vector(s: string) return std_ulogic_vector;
335
 
336
        type ulogic_string is array(integer range <>) of std_ulogic_vector(7 downto 0);
337
        function to_std_ulogic_vector(s: string) return ulogic_string;
338
 
339
        --- Not synthesizable ---
340
 
341
        subtype configuration_name is string(1 to 8);
342
 
343
        type configuration_item is record
344
                name:  configuration_name;
345
                value: integer;
346
        end record;
347
 
348
        type configuration_items is array(integer range <>) of configuration_item;
349
 
350
        function search_configuration_tb(find_me: configuration_name; ci: configuration_items) return integer;
351
        procedure read_configuration_tb(file_name:  string; ci: inout configuration_items);
352
        procedure write_configuration_tb(file_name: string; ci: configuration_items);
353
 
354
end;
355
 
356
package body util is
357
 
358
        function max(a: natural; b: natural) return natural is
359
        begin
360
                if (a > b) then return a; else return b; end if;
361
        end function;
362
 
363
        function min(a: natural; b: natural) return natural is
364
        begin
365
                if (a < b) then return a; else return b; end if;
366
        end function;
367
 
368
        function n_bits(x: natural) return natural is
369
                variable x1: natural := max(x, 1) - 1;
370
                variable n:  natural := 1;
371
        begin
372
                while x1 > 1 loop
373
                        x1 := x1 / 2;
374
                        n  := n + 1;
375
                end loop;
376
                return n;
377
        end function;
378
 
379
        function n_bits(x: std_ulogic_vector) return natural is
380
        begin
381
                return n_bits(x'high);
382
        end function;
383
 
384
        -- https://stackoverflow.com/questions/13584307
385
        function reverse (a: in std_ulogic_vector) return std_ulogic_vector is
386
                variable result: std_ulogic_vector(a'range);
387
                alias aa: std_ulogic_vector(a'reverse_range) is a;
388
        begin
389
                for i in aa'range loop
390
                        result(i) := aa(i);
391
                end loop;
392
                return result;
393
        end;
394
 
395
        function invert(slv: std_ulogic_vector) return std_ulogic_vector is
396
                variable z: std_ulogic_vector(slv'range);
397
        begin
398
                for i in slv'range loop
399
                        z(i) := not(slv(i));
400
                end loop;
401
                return z;
402
        end;
403
 
404
        function parity(slv: std_ulogic_vector; even: boolean) return std_ulogic is
405
                variable z: std_ulogic := '0';
406
        begin
407
                if not even then
408
                        z := '1';
409
                end if;
410
                for i in slv'range loop
411
                        z := z xor slv(i);
412
                end loop;
413
                return z;
414
        end;
415
 
416
        function select_bit(indexed, selector: std_ulogic_vector) return std_ulogic is
417
                variable z: std_ulogic := 'X';
418
        begin
419
                assert n_bits(indexed) = selector'high + 1 severity failure;
420
                for i in indexed'range loop
421
                        if i = to_integer(unsigned(selector)) then
422
                                z := indexed(i);
423
                        end if;
424
                end loop;
425
                return z;
426
        end;
427
 
428
        function priority(order: std_ulogic_vector; high: boolean) return natural is
429
                variable p: natural := 0;
430
        begin
431
                if not high then
432
                        for i in order'high + 1 downto 1 loop
433
                                if order(i-1) = '1' then
434
                                        p := i - 1;
435
                                end if;
436
                        end loop;
437
                else
438
                        for i in 1 to order'high + 1 loop
439
                                if order(i-1) = '1' then
440
                                        p := i - 1;
441
                                end if;
442
                        end loop;
443
                end if;
444
                return p;
445
        end;
446
 
447
        function priority(order: std_ulogic_vector; high: boolean) return std_ulogic_vector is
448
                variable length: natural := n_bits(order'length);
449
        begin
450
                return std_ulogic_vector(to_unsigned(priority(order, high), length));
451
        end;
452
 
453
        function mux(a: std_ulogic_vector; b: std_ulogic_vector; sel: std_ulogic) return std_ulogic_vector is
454
                variable m: std_ulogic_vector(a'range) := (others => 'X');
455
        begin
456
                if sel = '0' then m := a; else m := b; end if;
457
                return m;
458
        end;
459
 
460
        function mux(a: std_ulogic; b: std_ulogic; sel: std_ulogic) return std_ulogic is
461
                variable m: std_ulogic := 'X';
462
        begin
463
                if sel = '0' then m := a; else m := b; end if;
464
                return m;
465
        end;
466
 
467
        function mux(a, b : std_ulogic_vector) return std_ulogic is
468
                variable r: std_ulogic_vector(b'length - 1 downto 0) := (others => 'X');
469
                variable i: integer;
470
        begin
471
                r := b;
472
                i := to_integer(unsigned(a));
473
                return r(i);
474
        end;
475
 
476
        function decode(encoded : std_ulogic_vector) return std_ulogic_vector is
477
                variable r: std_ulogic_vector((2 ** encoded'length) - 1 downto 0) := (others => '0');
478
                variable i: natural;
479
        begin
480
                i    := to_integer(unsigned(encoded));
481
                r(i) := '1';
482
                return r;
483
        end;
484
 
485
        function hex_char_to_std_ulogic_vector(hc: character) return std_ulogic_vector is
486
                variable slv: std_ulogic_vector(3 downto 0);
487
        begin
488
                case hc is
489
                when '0' => slv := "0000";
490
                when '1' => slv := "0001";
491
                when '2' => slv := "0010";
492
                when '3' => slv := "0011";
493
                when '4' => slv := "0100";
494
                when '5' => slv := "0101";
495
                when '6' => slv := "0110";
496
                when '7' => slv := "0111";
497
                when '8' => slv := "1000";
498
                when '9' => slv := "1001";
499
                when 'A' => slv := "1010";
500
                when 'a' => slv := "1010";
501
                when 'B' => slv := "1011";
502
                when 'b' => slv := "1011";
503
                when 'C' => slv := "1100";
504
                when 'c' => slv := "1100";
505
                when 'D' => slv := "1101";
506
                when 'd' => slv := "1101";
507
                when 'E' => slv := "1110";
508
                when 'e' => slv := "1110";
509
                when 'F' => slv := "1111";
510
                when 'f' => slv := "1111";
511
                when others => slv := "XXXX";
512
                end case;
513
                assert (slv /= "XXXX") report " not a valid hex character: " & hc  severity failure;
514
                return slv;
515
        end;
516
 
517
        -- <https://stackoverflow.com/questions/30519849/vhdl-convert-string-to-std-logic-vector>
518
        function to_std_ulogic_vector(s: string) return std_ulogic_vector is
519
            variable ret: std_ulogic_vector(s'length*8-1 downto 0);
520
        begin
521
            for i in s'range loop
522
                ret(i*8+7 downto i*8) := std_ulogic_vector(to_unsigned(character'pos(s(i)), 8));
523
            end loop;
524
            return ret;
525
        end;
526
 
527
        function to_std_ulogic_vector(s: string) return ulogic_string is
528
            variable ret: ulogic_string(s'range);
529
        begin
530
                for i in s'range loop
531
                        ret(i) := std_ulogic_vector(to_unsigned(character'pos(s(i)), 8));
532
                end loop;
533
                return ret;
534
        end;
535
 
536
        --- Not synthesizable ---
537
 
538
        -- Find a string in a configuration items array, or returns -1 on
539
        -- failure to find the string.
540
        function search_configuration_tb(find_me: configuration_name; ci: configuration_items) return integer is
541
        begin
542
                for i in ci'range loop
543
                        if ci(i).name = find_me then
544
                                return i;
545
                        end if;
546
                end loop;
547
                return -1;
548
        end;
549
 
550
        -- VHDL provides quite a limited set of options for dealing with
551
        -- operations that are not synthesizeable but would be useful for
552
        -- in test benches. This method provides a crude way of reading
553
        -- in configurable options. It has a very strict format.
554
        --
555
        -- The format is line oriented, it expects a string on a line
556
        -- with a length equal to the "configuration_name" type, which
557
        -- is a subtype of "string". It finds the corresponding record
558
        -- in configuration_items if it exists. It then reads in an
559
        -- integer from the next line and sets the record for it.
560
        --
561
        -- Any deviation from this format causes an error and the simulation
562
        -- to halt, whilst not a good practice to do error checking with asserts
563
        -- there is no better way in VHDL in this case. The only sensible
564
        -- action on an error would for the configuration file to be fixed
565
        -- anyway.
566
        --
567
        -- Comment lines and variable length strings would be nice, but
568
        -- are too much of a hassle.
569
        --
570
        -- The configuration function only deal with part of the configuration
571
        -- process, it does not deal with deserialization into structures
572
        -- more useful to the user - like into individual signals.
573
        --
574
        procedure read_configuration_tb(file_name: string; ci: inout configuration_items) is
575
                file     in_file: text is in file_name;
576
                variable in_line: line;
577
                variable d:       integer;
578
                variable s:       configuration_name;
579
                variable index:   integer;
580
        begin
581
                while not endfile(in_file) loop
582
 
583
                        readline(in_file, in_line);
584
                        read(in_line, s);
585
                        index := search_configuration_tb(s, ci);
586
 
587
                        assert index >= 0 report "Unknown configuration item: " & s severity failure;
588
 
589
                        readline(in_file, in_line);
590
                        read(in_line, d);
591
 
592
                        ci(index).value := d;
593
 
594
                        report "Config Item: '" & ci(index).name & "' = " & integer'image(ci(index).value);
595
                end loop;
596
                file_close(in_file);
597
        end procedure;
598
 
599
        procedure write_configuration_tb(file_name: string; ci: configuration_items) is
600
                file     out_file: text is out file_name;
601
                variable out_line: line;
602
        begin
603
                for i in ci'range loop
604
                        write(out_line, ci(i).name);
605
                        writeline(out_file, out_line);
606
                        write(out_line, ci(i).value);
607
                        writeline(out_file, out_line);
608
                end loop;
609
        end procedure;
610
 
611
end;
612
 
613
------------------------- Utility Test Bench ----------------------------------------
614
library ieee;
615
use ieee.std_logic_1164.all;
616
use work.util.all;
617
 
618
entity util_tb is
619
        generic(clock_frequency: positive);
620
end entity;
621
 
622
architecture behav of util_tb is
623
begin
624
        uut_shiftReg: work.util.shift_register_tb    generic map(clock_frequency => clock_frequency);
625
        uut_timer_us: work.util.timer_us_tb          generic map(clock_frequency => clock_frequency);
626
        uut_full_add: work.util.full_adder_tb        generic map(clock_frequency => clock_frequency);
627
        uut_fifo:     work.util.fifo_tb              generic map(clock_frequency => clock_frequency);
628
        uut_counter:  work.util.counter_tb           generic map(clock_frequency => clock_frequency);
629
        uut_lfsr:     work.util.lfsr_tb              generic map(clock_frequency => clock_frequency);
630
        uut_ucpu:     work.util.ucpu_tb              generic map(clock_frequency => clock_frequency);
631
        uut_rdivider: work.util.restoring_divider_tb generic map(clock_frequency => clock_frequency);
632
        uut_debounce: work.util.debounce_us_tb       generic map(clock_frequency => clock_frequency);
633
        uut_rising_edge_detector: work.util.rising_edge_detector_tb generic map(clock_frequency => clock_frequency);
634
 
635
        stimulus_process: process
636
        begin
637
                assert max(5, 4)                 =  5      severity failure;
638
                assert work.util.min(5, 4)       =  4      severity failure;
639
                assert n_bits(1)                 =  1      severity failure;
640
                assert n_bits(2)                 =  1      severity failure;
641
                assert n_bits(7)                 =  3      severity failure;
642
                assert n_bits(8)                 =  3      severity failure;
643
                assert n_bits(9)                 =  4      severity failure;
644
                assert reverse("1")              =  "1"    severity failure;
645
                assert reverse("0")              =  "0"    severity failure;
646
                assert reverse("10")             =  "01"   severity failure;
647
                assert reverse("11")             =  "11"   severity failure;
648
                assert reverse("0101")           =  "1010" severity failure;
649
                assert invert("1")               =  "0"    severity failure;
650
                assert invert("0")               =  "1"    severity failure;
651
                assert invert("0101")            =  "1010" severity failure;
652
                assert select_bit("01000", "01") =  '1'    severity failure;
653
                assert parity("0", true)         =  '0'    severity failure;
654
                assert parity("1", true)         =  '1'    severity failure;
655
                assert parity("11", true)        =  '0'    severity failure;
656
                assert parity("1010001", true)   =  '1'    severity failure;
657
                assert parity("0", false)        =  '1'    severity failure;
658
                assert parity("1", false)        =  '0'    severity failure;
659
                assert parity("11", false)       =  '1'    severity failure;
660
                assert parity("1010001", false)  =  '0'    severity failure;
661
                assert priority("01001", false)  =  1      severity failure;
662
                assert mux("1010", "0101", '0')  =  "1010" severity failure;
663
                assert mux("1010", "0101", '1')  =  "0101" severity failure;
664
                assert decode("00")              =  "0001" severity failure;
665
                assert decode("01")              =  "0010" severity failure;
666
                assert decode("10")              =  "0100" severity failure;
667
                assert decode("11")              =  "1000" severity failure;
668
                -- n_bits(x: std_ulogic_vector) return natural;
669
                -- mux(a, b : std_ulogic_vector) return std_ulogic;
670
                wait;
671
        end process;
672
end architecture;
673
 
674
------------------------- Function Test Bench ---------------------------------------
675
 
676
------------------------- Test bench clock source -----------------------------------
677
 
678
library ieee;
679
use ieee.std_logic_1164.all;
680
use ieee.numeric_std.all;
681
use ieee.math_real.all;
682
 
683
entity clock_source_tb is
684
        generic(clock_frequency: positive; hold_rst: positive := 1);
685
        port(
686
                stop:            in     std_ulogic := '0';
687
                clk:             buffer std_ulogic;
688
                clk_with_jitter: out    std_ulogic := '0';
689
                rst:             out    std_ulogic := '0');
690
end entity;
691
 
692
architecture rtl of clock_source_tb is
693
        constant clock_period: time      :=  1000 ms / clock_frequency;
694
        signal jitter_delay:   time      := 0 ns;
695
        signal jitter_clk:     std_ulogic := '0';
696
begin
697
        clk_process: process
698
                variable seed1, seed2 : positive;
699
                variable r : real;
700
        begin
701
                while stop = '0' loop
702
                        uniform(seed1, seed2, r);
703
                        jitter_delay <= r * 1 ns;
704
 
705
                        clk <= '1';
706
                        wait for clock_period / 2;
707
                        clk <= '0';
708
                        wait for clock_period / 2;
709
                end loop;
710
                wait;
711
        end process;
712
 
713
        clk_with_jitter <= transport clk after jitter_delay;
714
 
715
        rst_process: process
716
        begin
717
                rst <= '1';
718
                wait for clock_period * hold_rst;
719
                rst <= '0';
720
                wait;
721
        end process;
722
 
723
end architecture;
724
 
725
------------------------- Generic Register of std_ulogic_vector ----------------------
726
 
727
library ieee;
728
use ieee.std_logic_1164.all;
729
use ieee.numeric_std.all;
730
 
731
entity reg is
732
        generic(
733
                N: positive);
734
        port
735
        (
736
                clk: in  std_ulogic;
737
                rst: in  std_ulogic;
738
                we:  in  std_ulogic;
739
                di:  in  std_ulogic_vector(N - 1 downto 0);
740
                do:  out std_ulogic_vector(N - 1 downto 0));
741
end entity;
742
 
743
architecture rtl of reg is
744
        signal r_c, r_n: std_ulogic_vector(N - 1 downto 0) := (others => '0');
745
begin
746
        do <= r_c;
747
 
748
        process(rst, clk)
749
        begin
750
                if rst = '1' then
751
                        r_c <= (others => '0');
752
                elsif rising_edge(clk) then
753
                        r_c <= r_n;
754
                end if;
755
        end process;
756
 
757
        process(r_c, di, we)
758
        begin
759
                r_n <= r_c;
760
                if we = '1' then
761
                        r_n <= di;
762
                end if;
763
        end process;
764
end;
765
 
766
------------------------- Generic Register of std_ulogic_vector ----------------------
767
 
768
------------------------- Shift register --------------------------------------------
769
library ieee;
770
use ieee.std_logic_1164.all;
771
use ieee.numeric_std.all;
772
 
773
-- https://stackoverflow.com/questions/36342960/optional-ports-in-vhdl
774
entity shift_register is
775
        generic(N: positive);
776
        port
777
        (
778
                clk:     in  std_ulogic;
779
                rst:     in  std_ulogic;
780
                we:      in  std_ulogic;
781
                di:      in  std_ulogic;
782
                do:      out std_ulogic;
783
 
784
                load_we: in  std_ulogic := '0';
785
                load_i:  in  std_ulogic_vector(N - 1 downto 0) := (others => '0');
786
                load_o:  out std_ulogic_vector(N - 1 downto 0));
787
end entity;
788
 
789
architecture rtl of shift_register is
790
        signal r_c, r_n : std_ulogic_vector(N - 1 downto 0) := (others => '0');
791
begin
792
        do     <= r_c(0);
793
        load_o <= r_c;
794
 
795
        process(rst, clk)
796
        begin
797
                if rst = '1' then
798
                        r_c <= (others => '0');
799
                elsif rising_edge(clk) then
800
                        r_c <= r_n;
801
                end if;
802
        end process;
803
 
804
        process(r_c, di, we, load_i, load_we)
805
        begin
806
                if load_we = '1' then
807
                        r_n <= load_i;
808
                else
809
                        r_n <= "0" & r_c(N - 1 downto 1);
810
                        if we = '1' then
811
                                r_n(N-1) <= di;
812
                        end if;
813
                end if;
814
        end process;
815
end;
816
 
817
library ieee;
818
use ieee.std_logic_1164.all;
819
use ieee.numeric_std.all;
820
 
821
entity shift_register_tb is
822
        generic(clock_frequency: positive);
823
end entity;
824
 
825
architecture behav of shift_register_tb is
826
        constant N: positive := 8;
827
        constant clock_period: time :=  1000 ms / clock_frequency;
828
        signal we: std_ulogic := '0';
829
        signal di: std_ulogic := '0';
830
        signal do: std_ulogic := '0';
831
 
832
        signal clk, rst: std_ulogic := '0';
833
        signal stop: std_ulogic := '0';
834
begin
835
        cs: entity work.clock_source_tb
836
                generic map(clock_frequency => clock_frequency, hold_rst => 2)
837
                port map(stop => stop, clk => clk, rst => rst);
838
 
839
        uut: entity work.shift_register
840
        generic map(N => N) port map(clk => clk, rst => rst, we => we, di => di, do => do);
841
 
842
        stimulus_process: process
843
        begin
844
                -- put a bit into the shift register and wait
845
                -- for it to come out the other size
846
                wait until rst = '0';
847
                di <= '1';
848
                we <= '1';
849
                wait for clock_period;
850
                di <= '0';
851
                we <= '0';
852
                for I in 0 to 7 loop
853
                        assert do = '0' report "bit appeared to quickly";
854
                        wait for clock_period;
855
                end loop;
856
                assert do = '1' report "bit disappeared in shift register";
857
                wait for clock_period * 1;
858
                assert do = '0' report "extra bit set in shift register";
859
                stop <= '1';
860
                wait;
861
        end process;
862
end;
863
------------------------- Shift register --------------------------------------------
864
 
865
------------------------- Microsecond Timer -----------------------------------------
866
library ieee;
867
use ieee.std_logic_1164.all;
868
use ieee.numeric_std.all;
869
use work.util.max;
870
use work.util.n_bits;
871
 
872
entity timer_us is
873
        generic(
874
                clock_frequency: positive;
875
                timer_period_us: positive := 1);
876
        port(
877
                clk:  in std_ulogic := 'X';
878
                rst:  in std_ulogic := 'X';
879
                co:  out std_ulogic := '0');
880
end timer_us;
881
 
882
architecture rtl of timer_us is
883
        constant cycles:   natural := (clock_frequency / 1000000) * timer_period_us;
884
        subtype  counter is unsigned(max(1, n_bits(cycles) - 1) downto 0);
885
        signal   c_c, c_n: counter := (others => '0');
886
begin
887
        process (clk, rst)
888
        begin
889
                if rst = '1' then
890
                        c_c <= (others => '0');
891
                elsif rising_edge(clk) then
892
                        c_c <= c_n;
893
                end if;
894
        end process;
895
 
896
        process (c_c)
897
        begin
898
                if c_c = (cycles - 1) then
899
                        c_n <= (others => '0');
900
                        co  <= '1';
901
                else
902
                        c_n <= c_c + 1;
903
                        co  <= '0';
904
                end if;
905
        end process;
906
end;
907
 
908
library ieee;
909
use ieee.std_logic_1164.all;
910
use ieee.numeric_std.all;
911
 
912
entity timer_us_tb is
913
        generic(clock_frequency: positive);
914
end;
915
 
916
architecture behav of timer_us_tb is
917
        constant clock_period: time := 1000 ms / clock_frequency;
918
        signal co: std_ulogic        := 'X';
919
        signal clk, rst: std_ulogic  := '0';
920
        signal stop: std_ulogic      := '0';
921
begin
922
        cs: entity work.clock_source_tb
923
                generic map(clock_frequency => clock_frequency, hold_rst => 2)
924
                port map(stop => stop, clk => clk, rst => rst);
925
 
926
        uut: entity work.timer_us
927
                generic map(clock_frequency => clock_frequency, timer_period_us => 1)
928
                port map(clk => clk, rst => rst, co => co);
929
 
930
        stimulus_process: process
931
        begin
932
                wait for 1 us;
933
                assert co = '0' severity failure;
934
                wait for clock_period;
935
                assert co = '1' severity failure;
936
                stop <= '1';
937
                wait;
938
        end process;
939
end;
940
 
941
------------------------- Microsecond Timer -----------------------------------------
942
 
943
------------------------- Rising Edge Detector --------------------------------------
944
library ieee;
945
use ieee.std_logic_1164.all;
946
 
947
entity rising_edge_detector is
948
port(
949
        clk:    in  std_ulogic;
950
        rst:    in  std_ulogic;
951
        di:     in  std_ulogic;
952
        do:     out std_ulogic);
953
end;
954
 
955
architecture rtl of rising_edge_detector is
956
        signal sin_0: std_ulogic := '0';
957
        signal sin_1: std_ulogic := '0';
958
begin
959
        red: process(clk, rst)
960
        begin
961
                if rst = '1' then
962
                        sin_0 <= '0';
963
                        sin_1 <= '0';
964
                elsif rising_edge(clk) then
965
                        sin_0 <= di;
966
                        sin_1 <= sin_0;
967
                end if;
968
        end process;
969
        do <= not sin_1 and sin_0;
970
end architecture;
971
 
972
library ieee;
973
use ieee.std_logic_1164.all;
974
use ieee.numeric_std.all;
975
 
976
entity rising_edge_detector_tb is
977
        generic(clock_frequency: positive);
978
end;
979
 
980
architecture behav of rising_edge_detector_tb is
981
        constant clock_period: time := 1000 ms / clock_frequency;
982
        signal di:  std_ulogic := '0';
983
        signal do: std_ulogic := 'X';
984
 
985
        signal clk, rst: std_ulogic := '0';
986
        signal stop: std_ulogic := '0';
987
begin
988
        cs: entity work.clock_source_tb
989
                generic map(clock_frequency => clock_frequency, hold_rst => 2)
990
                port map(stop => stop, clk => clk, rst => rst);
991
 
992
        uut: entity work.rising_edge_detector
993
                port map(clk => clk, rst => rst, di => di, do => do);
994
 
995
        stimulus_process: process
996
        begin
997
                wait for clock_period * 5;
998
                assert do = '0' severity failure;
999
                wait for clock_period;
1000
                di <= '1';
1001
                wait for clock_period * 0.5;
1002
                assert do = '1' severity failure;
1003
                wait for clock_period * 1.5;
1004
                di <= '0';
1005
                assert do = '0' severity failure;
1006
                wait for clock_period;
1007
                assert do = '0' severity failure;
1008
 
1009
                assert stop = '0' report "Test bench not run to completion";
1010
                stop <= '1';
1011
                wait;
1012
        end process;
1013
end architecture;
1014
 
1015
library ieee;
1016
use ieee.std_logic_1164.all;
1017
 
1018
entity rising_edge_detectors is
1019
generic(N: positive);
1020
port(
1021
        clk:    in  std_ulogic;
1022
        rst:    in  std_ulogic;
1023
        di:     in  std_ulogic_vector(N - 1 downto 0);
1024
        do:     out std_ulogic_vector(N - 1 downto 0));
1025
end entity;
1026
 
1027
architecture structural of rising_edge_detectors is
1028
begin
1029
        changes: for i in N - 1 downto 0 generate
1030
                d_instance: work.util.rising_edge_detector
1031
                        port map(clk => clk, rst => rst, di => di(i), do => do(i));
1032
        end generate;
1033
end architecture;
1034
 
1035
------------------------- Rising Edge Detector --------------------------------------
1036
 
1037
------------------------- Half Adder ------------------------------------------------
1038
library ieee;
1039
use ieee.std_logic_1164.all;
1040
 
1041
entity half_adder is
1042
        port(
1043
                a:     in  std_ulogic;
1044
                b:     in  std_ulogic;
1045
                sum:   out std_ulogic;
1046
                carry: out std_ulogic);
1047
end entity;
1048
 
1049
architecture rtl of half_adder is
1050
begin
1051
        sum   <= a xor b;
1052
        carry <= a and b;
1053
end architecture;
1054
 
1055
------------------------- Half Adder ------------------------------------------------
1056
 
1057
------------------------- Full Adder ------------------------------------------------
1058
 
1059
library ieee;
1060
use ieee.std_logic_1164.all;
1061
 
1062
entity full_adder is
1063
        port(
1064
                x:     in    std_ulogic;
1065
                y:     in    std_ulogic;
1066
                z:     in    std_ulogic;
1067
                sum:   out   std_ulogic;
1068
                carry: out   std_ulogic);
1069
end entity;
1070
 
1071
architecture rtl of full_adder is
1072
        signal carry1, carry2, sum1: std_ulogic;
1073
begin
1074
        ha1: entity work.half_adder port map(a => x,    b => y, sum => sum1, carry => carry1);
1075
        ha2: entity work.half_adder port map(a => sum1, b => z, sum => sum,  carry => carry2);
1076
        carry <= carry1 or carry2;
1077
end architecture;
1078
 
1079
library ieee;
1080
use ieee.std_logic_1164.all;
1081
 
1082
entity full_adder_tb is
1083
        generic(clock_frequency: positive);
1084
end entity;
1085
 
1086
architecture behav of full_adder_tb is
1087
        constant clock_period: time  := 1000 ms / clock_frequency;
1088
        signal x, y, z:    std_ulogic := '0';
1089
        signal sum, carry: std_ulogic := '0';
1090
 
1091
        type stimulus_data   is array (0 to 7)              of std_ulogic_vector(2 downto 0);
1092
        type stimulus_result is array (stimulus_data'range) of std_ulogic_vector(0 to     1);
1093
 
1094
        constant data: stimulus_data := (
1095
 
1096
                2 => "010", 3 => "011",
1097
                4 => "100", 5 => "101",
1098
                6 => "110", 7 => "111");
1099
 
1100
        constant result: stimulus_result := (
1101
 
1102
                2 => "10",  3 => "01",
1103
                4 => "10",  5 => "01",
1104
                6 => "01",  7 => "11");
1105
 
1106
        signal clk, rst: std_ulogic := '0';
1107
        signal stop: std_ulogic     := '0';
1108
begin
1109
        cs: entity work.clock_source_tb
1110
                generic map(clock_frequency => clock_frequency, hold_rst => 2)
1111
                port map(stop => stop, clk => clk, rst => rst);
1112
 
1113
        uut: entity work.full_adder port map(x => x, y => y, z => z, sum => sum, carry => carry);
1114
 
1115
        stimulus_process: process
1116
        begin
1117
                wait for clock_period;
1118
                for i in data'range loop
1119
                        x <= data(i)(0);
1120
                        y <= data(i)(1);
1121
                        z <= data(i)(2);
1122
                        wait for clock_period;
1123
                        assert sum = result(i)(0) and carry = result(i)(1)
1124
                                report
1125
                                        "For: "       & std_ulogic'image(x) & std_ulogic'image(y) & std_ulogic'image(z) &
1126
                                        " Got: "      & std_ulogic'image(sum)          & std_ulogic'image(carry) &
1127
                                        " Expected: " & std_ulogic'image(result(i)(0)) & std_ulogic'image(result(i)(1))
1128
                                severity failure;
1129
                        wait for clock_period;
1130
                end loop;
1131
 
1132
                stop <= '1';
1133
                wait;
1134
        end process;
1135
end architecture;
1136
 
1137
------------------------- Full Adder ------------------------------------------------
1138
 
1139
------------------------- FIFO ------------------------------------------------------
1140
 
1141
-- Originally from http://www.deathbylogic.com/2013/07/vhdl-standard-fifo/
1142
-- @copyright Public Domain
1143
-- @todo Add more comments about the FIFOs origin, add assertions test
1144
-- synthesis, make this more generic (with empty FIFO and FIFO count signals)
1145
--
1146
-- The code can be used freely and appears to be public domain, comment
1147
-- from author is: "You can use any code posted here freely, there is no copyright."
1148
--
1149
-- @note The FIFO has been modified from the original to bring it in line with
1150
-- this projects coding standards.
1151
 
1152
library ieee;
1153
use ieee.std_logic_1164.all;
1154
use ieee.numeric_std.all;
1155
 
1156
entity fifo is
1157
        generic(
1158
                data_width: positive;
1159
                fifo_depth: positive);
1160
        port(
1161
                clk:   in  std_ulogic;
1162
                rst:   in  std_ulogic;
1163
                we:    in  std_ulogic;
1164
                di:    in  std_ulogic_vector (data_width - 1 downto 0);
1165
                re:    in  std_ulogic;
1166
                do:    out std_ulogic_vector (data_width - 1 downto 0);
1167
                empty: out std_ulogic := '1';
1168
                full:  out std_ulogic := '0');
1169
end fifo;
1170
 
1171
architecture behavioral of fifo is
1172
begin
1173
 
1174
        -- memory pointer process
1175
        fifo_proc: process (clk, rst)
1176
                type fifo_memory is array (0 to fifo_depth - 1) of std_ulogic_vector (data_width - 1 downto 0);
1177
                variable memory: fifo_memory;
1178
 
1179
                variable head: natural range 0 to fifo_depth - 1;
1180
                variable tail: natural range 0 to fifo_depth - 1;
1181
 
1182
                variable looped: boolean;
1183
        begin
1184
                if rst = '1' then
1185
                        head := 0;
1186
                        tail := 0;
1187
 
1188
                        looped := false;
1189
 
1190
                        full  <= '0';
1191
                        empty <= '1';
1192
                        do    <= (others => '0');
1193
                elsif rising_edge(clk) then
1194
                        do    <= (others => '0');
1195
                        if re = '1' then
1196
                                if looped = true or head /= tail then
1197
                                        -- update data output
1198
                                        do <= memory(tail);
1199
 
1200
                                        -- update tail pointer as needed
1201
                                        if tail = fifo_depth - 1 then
1202
                                                tail   := 0;
1203
                                                looped := false;
1204
                                        else
1205
                                                tail := tail + 1;
1206
                                        end if;
1207
                                end if;
1208
                        end if;
1209
 
1210
                        if we = '1' then
1211
                                if looped = false or head /= tail then
1212
                                        -- write data to memory
1213
                                        memory(head) := di;
1214
 
1215
                                        -- increment head pointer as needed
1216
                                        if head = fifo_depth - 1 then
1217
                                                head := 0;
1218
 
1219
                                                looped := true;
1220
                                        else
1221
                                                head := head + 1;
1222
                                        end if;
1223
                                end if;
1224
                        end if;
1225
 
1226
                        -- update empty and full flags
1227
                        if head = tail then
1228
                                if looped then
1229
                                        full  <= '1';
1230
                                else
1231
                                        empty <= '1';
1232
                                end if;
1233
                        else
1234
                                empty   <= '0';
1235
                                full    <= '0';
1236
                        end if;
1237
                end if;
1238
        end process;
1239
end architecture;
1240
 
1241
library ieee;
1242
use ieee.std_logic_1164.all;
1243
use ieee.numeric_std.all;
1244
 
1245
entity fifo_tb is
1246
        generic(clock_frequency: positive);
1247
end entity;
1248
 
1249
architecture behavior of fifo_tb is
1250
        constant clock_period: time  := 1000 ms / clock_frequency;
1251
        constant data_width: positive := 8;
1252
        constant fifo_depth: positive := 16;
1253
 
1254
        signal di:      std_ulogic_vector(data_width - 1 downto 0) := (others => '0');
1255
        signal re:       std_ulogic := '0';
1256
        signal we:       std_ulogic := '0';
1257
 
1258
        signal do:       std_ulogic_vector(data_width - 1 downto 0) := (others => '0');
1259
        signal empty:    std_ulogic := '0';
1260
        signal full:     std_ulogic := '0';
1261
 
1262
        signal clk, rst: std_ulogic := '0';
1263
        signal stop_w:   std_ulogic := '0';
1264
        signal stop_r:   std_ulogic := '0';
1265
        signal stop:     std_ulogic := '0';
1266
begin
1267
        cs: entity work.clock_source_tb
1268
                generic map(clock_frequency => clock_frequency, hold_rst => 2)
1269
                port map(stop => stop, clk => clk, rst => rst);
1270
 
1271
        stop <= '1' when stop_w = '1' and stop_r = '1' else '0';
1272
 
1273
        uut: entity work.fifo
1274
                generic map(data_width => data_width, fifo_depth => fifo_depth)
1275
                port map (
1276
                        clk   => clk,
1277
                        rst   => rst,
1278
                        di    => di,
1279
                        we    => we,
1280
                        re    => re,
1281
                        do    => do,
1282
                        full  => full,
1283
                        empty => empty);
1284
 
1285
        write_process: process
1286
                variable counter: unsigned (data_width - 1 downto 0) := (others => '0');
1287
        begin
1288
                wait for clock_period * 20;
1289
 
1290
                for i in 1 to 32 loop
1291
                        counter := counter + 1;
1292
                        di <= std_ulogic_vector(counter);
1293
                        wait for clock_period * 1;
1294
                        we <= '1';
1295
                        wait for clock_period * 1;
1296
                        we <= '0';
1297
                end loop;
1298
 
1299
                wait for clock_period * 20;
1300
 
1301
                for i in 1 to 32 loop
1302
                        counter := counter + 1;
1303
                        di <= std_ulogic_vector(counter);
1304
                        wait for clock_period * 1;
1305
                        we <= '1';
1306
                        wait for clock_period * 1;
1307
                        we <= '0';
1308
                end loop;
1309
 
1310
                stop_w <= '1';
1311
                wait;
1312
        end process;
1313
 
1314
        read_process: process
1315
        begin
1316
                wait for clock_period * 60;
1317
                re <= '1';
1318
                wait for clock_period * 60;
1319
                re <= '0';
1320
                wait for clock_period * 256 * 2;
1321
                re <= '1';
1322
 
1323
                stop_r <= '1';
1324
                wait;
1325
        end process;
1326
end architecture;
1327
 
1328
------------------------- FIFO ------------------------------------------------------
1329
 
1330
------------------------- Free running counter --------------------------------------
1331
 
1332
library ieee;
1333
use ieee.std_logic_1164.all;
1334
use ieee.numeric_std.all;
1335
 
1336
entity counter is
1337
        generic(
1338
                N: positive);
1339
        port(
1340
                clk:     in  std_ulogic;
1341
                rst:     in  std_ulogic;
1342
                ce:      in  std_ulogic;
1343
                cr:      in  std_ulogic;
1344
                dout:    out std_ulogic_vector(N - 1 downto 0);
1345
 
1346
                load_we: in  std_ulogic := '0';
1347
                load_i:  in  std_ulogic_vector(N - 1 downto 0) := (others => '0'));
1348
end entity;
1349
 
1350
architecture rtl of counter is
1351
        signal c_c, c_n: unsigned(N - 1 downto 0) := (others => '0');
1352
begin
1353
        dout <= std_ulogic_vector(c_c);
1354
 
1355
        process(clk, rst)
1356
        begin
1357
                if rst = '1' then
1358
                        c_c <= (others => '0');
1359
                elsif rising_edge(clk) then
1360
                        c_c <= c_n;
1361
                end if;
1362
        end process;
1363
 
1364
        process(c_c, cr, ce, load_we, load_i)
1365
        begin
1366
                c_n <= c_c;
1367
                if load_we = '1' then
1368
                        c_n <= unsigned(load_i);
1369
                else
1370
                        if cr = '1' then
1371
                                c_n <= (others => '0');
1372
                        elsif ce = '1' then
1373
                                c_n <= c_c + 1;
1374
                        end if;
1375
                end if;
1376
        end process;
1377
 
1378
end architecture;
1379
 
1380
library ieee;
1381
use ieee.std_logic_1164.all;
1382
use ieee.numeric_std.all;
1383
 
1384
entity counter_tb is
1385
        generic(clock_frequency: positive);
1386
end entity;
1387
 
1388
architecture behavior of counter_tb is
1389
        constant clock_period: time     := 1000 ms / clock_frequency;
1390
        constant length:       positive := 2;
1391
 
1392
        -- inputs
1393
        signal ce: std_ulogic := '0';
1394
        signal cr: std_ulogic := '0';
1395
 
1396
        -- outputs
1397
        signal dout: std_ulogic_vector(length - 1 downto 0);
1398
 
1399
        -- test data
1400
        type stimulus_data   is array (0 to 16)             of std_ulogic_vector(1 downto 0);
1401
        type stimulus_result is array (stimulus_data'range) of std_ulogic_vector(0 to     1);
1402
 
1403
        constant data: stimulus_data := (
1404
 
1405
                 2 => "01",  3 => "01",
1406
                 4 => "00",  5 => "00",
1407
                 6 => "10",  7 => "00",
1408
                 8 => "01",  9 => "01",
1409
                10 => "11", 11 => "00",
1410
                12 => "01", 13 => "01",
1411
                14 => "01", 15 => "01",
1412
                16 => "01");
1413
 
1414
        constant result: stimulus_result := (
1415
 
1416
                 2 => "00",  3 => "01",
1417
                 4 => "10",  5 => "10",
1418
                 6 => "10",  7 => "00",
1419
                 8 => "00",  9 => "01",
1420
                10 => "10", 11 => "00",
1421
                12 => "00", 13 => "01",
1422
                14 => "10", 15 => "11",
1423
                16 => "00");
1424
 
1425
        signal clk, rst: std_ulogic := '0';
1426
        signal stop:     std_ulogic := '0';
1427
begin
1428
        cs: entity work.clock_source_tb
1429
                generic map(clock_frequency => clock_frequency, hold_rst => 2)
1430
                port map(stop => stop, clk => clk, rst => rst);
1431
 
1432
        uut: entity work.counter
1433
                generic map(
1434
                        N => length)
1435
                port map(
1436
                        clk   => clk,
1437
                        rst   => rst,
1438
                        ce    => ce,
1439
                        cr    => cr,
1440
                        dout  => dout);
1441
 
1442
        stimulus_process: process
1443
        begin
1444
                wait for clock_period;
1445
                for i in data'range loop
1446
                        ce <= data(i)(0);
1447
                        cr <= data(i)(1);
1448
                        wait for clock_period;
1449
                        assert dout = result(i)
1450
                                report
1451
                                        "For: ce("    & std_ulogic'image(ce) & ") cr(" & std_ulogic'image(cr) & ") " &
1452
                                        " Got: "      & integer'image(to_integer(unsigned(dout))) &
1453
                                        " Expected: " & integer'image(to_integer(unsigned(result(i))))
1454
                                severity failure;
1455
                end loop;
1456
                stop <= '1';
1457
                wait;
1458
        end process;
1459
 
1460
end architecture;
1461
 
1462
------------------------- Free running counter --------------------------------------
1463
 
1464
------------------------- Linear Feedback Shift Register ----------------------------
1465
-- For good sources on LFSR see
1466
-- * https://sites.ualberta.ca/~delliott/ee552/studentAppNotes/1999f/Drivers_Ed/lfsr.html
1467
-- * https://en.wikipedia.org/wiki/Linear-feedback_shift_register
1468
--
1469
-- Some optimal taps
1470
--
1471
-- Taps start at the left most std_ulogic element of tap at '0' and proceed to
1472
-- the highest bit. To instantiate an instance of the LFSR set tap to a
1473
-- standard logic vector one less the size of LFSR that you want. An 8-bit
1474
-- LFSR can be made by setting it 'tap' to "0111001". The LFSR will need to
1475
-- be loaded with a seed value, set 'do' to that value and assert 'we'. The
1476
-- LFSR will only run when 'ce' is asserted, otherwise it will preserve the
1477
-- current value.
1478
--
1479
-- Number of bits   Taps      Cycle Time
1480
--      8           1,2,3,7    255
1481
--      16          1,2,4,15   65535
1482
--      32          1,5,6,31   4294967295
1483
--
1484
-- This component could be improved a lot, and it could also be used to
1485
-- calculate CRCs, which are basically the same computation. Its interface
1486
-- is not the best either, being a free running counter.
1487
--
1488
 
1489
library ieee;
1490
use ieee.std_logic_1164.all;
1491
use ieee.numeric_std.all;
1492
 
1493
entity lfsr is
1494
        generic(constant tap: std_ulogic_vector);
1495
        port
1496
        (
1497
                clk: in  std_ulogic;
1498
                rst: in  std_ulogic;
1499
                we:  in  std_ulogic;
1500
                ce:  in  std_ulogic := '1';
1501
                di:  in  std_ulogic_vector(tap'high + 1 downto tap'low);
1502
                do:  out std_ulogic_vector(tap'high + 1 downto tap'low));
1503
end entity;
1504
 
1505
architecture rtl of lfsr is
1506
        signal r_c, r_n : std_ulogic_vector(di'range) := (others => '0');
1507
begin
1508
        do <= r_c;
1509
 
1510
        process(rst, clk)
1511
        begin
1512
                if rst = '1' then
1513
                        r_c <= (others => '0');
1514
                elsif rising_edge(clk) then
1515
                        r_c <= r_n;
1516
                end if;
1517
        end process;
1518
 
1519
        process(r_c, di, we, ce)
1520
        begin
1521
                if we = '1' then
1522
                        r_n <= di;
1523
                elsif ce = '1' then
1524
 
1525
                        r_n(r_n'high) <= r_c(r_c'low);
1526
 
1527
                        for i in tap'high downto tap'low loop
1528
                                if tap(i) = '1' then
1529
                                        r_n(i) <= r_c(r_c'low) xor r_c(i+1);
1530
                                else
1531
                                        r_n(i) <= r_c(i+1);
1532
                                end if;
1533
                        end loop;
1534
                else
1535
                        r_n <= r_c;
1536
                end if;
1537
        end process;
1538
end architecture;
1539
 
1540
library ieee;
1541
use ieee.std_logic_1164.all;
1542
use ieee.numeric_std.all;
1543
 
1544
entity lfsr_tb is
1545
        generic(clock_frequency: positive);
1546
end entity;
1547
 
1548
architecture behavior of lfsr_tb is
1549
        constant clock_period: time     := 1000 ms / clock_frequency;
1550
        signal we: std_ulogic := '0';
1551
        signal do, di: std_ulogic_vector(7 downto 0) := (others => '0');
1552
 
1553
        signal clk, rst: std_ulogic := '0';
1554
        signal stop:     std_ulogic := '0';
1555
begin
1556
        cs: entity work.clock_source_tb
1557
                generic map(clock_frequency => clock_frequency, hold_rst => 2)
1558
                port map(stop => stop, clk => clk, rst => rst);
1559
 
1560
        uut: entity work.lfsr
1561
                generic map(tap => "0111001")
1562
                port map(clk => clk,
1563
                         rst => rst,
1564
                         we => we,
1565
                         di => di,
1566
                         do => do);
1567
 
1568
        stimulus_process: process
1569
        begin
1570
                wait for clock_period * 2;
1571
                we   <= '1';
1572
                di   <= "00000001";
1573
                wait for clock_period;
1574
                we   <= '0';
1575
                stop <= '1';
1576
                wait;
1577
        end process;
1578
 
1579
end architecture;
1580
 
1581
------------------------- Linear Feedback Shift Register ----------------------------
1582
 
1583
------------------------- I/O Pin Controller ----------------------------------------
1584
-- @todo Test this in hardware
1585
--
1586
-- This is a simple I/O pin control module, there is a control register which
1587
-- sets whether the pins are to be read in (control = '0') or set to the value written to
1588
-- "din" (control = '1').
1589
 
1590
library ieee;
1591
use ieee.std_logic_1164.all;
1592
use ieee.numeric_std.all;
1593
 
1594
entity io_pins is
1595
        generic(
1596
                N: positive);
1597
        port
1598
        (
1599
                clk:         in    std_ulogic;
1600
                rst:         in    std_ulogic;
1601
                control:     in    std_ulogic_vector(N - 1 downto 0);
1602
                control_we:  in    std_ulogic;
1603
                din:         in    std_ulogic_vector(N - 1 downto 0);
1604
                din_we:      in    std_ulogic;
1605
                dout:        out   std_ulogic_vector(N - 1 downto 0);
1606
                pins:        inout std_logic_vector(N - 1 downto 0));
1607
end entity;
1608
 
1609
architecture rtl of io_pins is
1610
        signal control_o: std_ulogic_vector(control'range) := (others => '0');
1611
        signal din_o:     std_ulogic_vector(din'range)     := (others => '0');
1612
begin
1613
 
1614
        control_r: entity work.reg generic map(N => N) port map(clk => clk, rst => rst, di => control, we => control_we, do => control_o);
1615
        din_r:     entity work.reg generic map(N => N) port map(clk => clk, rst => rst, di => din,     we => din_we,     do => din_o);
1616
 
1617
        pins_i: for i in control_o'range generate
1618
                dout(i) <= pins(i)  when control_o(i) = '0' else '0';
1619
                pins(i) <= din_o(i) when control_o(i) = '1' else 'Z';
1620
        end generate;
1621
 
1622
end architecture;
1623
 
1624
library ieee;
1625
use ieee.std_logic_1164.all;
1626
use ieee.numeric_std.all;
1627
 
1628
entity io_pins_tb is
1629
        generic(clock_frequency: positive);
1630
end entity;
1631
 
1632
architecture behavior of io_pins_tb is
1633
        constant clock_period: time := 1000 ms / clock_frequency;
1634
        constant N: positive := 8;
1635
 
1636
        signal control: std_ulogic_vector(N - 1 downto 0) := (others => '0');
1637
        signal din:     std_ulogic_vector(N - 1 downto 0) := (others => '0');
1638
        signal dout:    std_ulogic_vector(N - 1 downto 0) := (others => '0');
1639
        signal pins:    std_logic_vector(N - 1 downto 0)  := (others => 'L'); -- !
1640
 
1641
        signal control_we: std_ulogic := '0';
1642
        signal din_we: std_ulogic     := '0';
1643
 
1644
 
1645
        signal clk, rst: std_ulogic := '0';
1646
        signal stop:     std_ulogic := '0';
1647
begin
1648
        cs: entity work.clock_source_tb
1649
                generic map(clock_frequency => clock_frequency, hold_rst => 2)
1650
                port map(stop => stop, clk => clk, rst => rst);
1651
 
1652
        uut: entity work.io_pins
1653
                generic map(N => N)
1654
                port map(
1655
                        clk         =>  clk,
1656
                        rst         =>  rst,
1657
                        control     =>  control,
1658
                        control_we  =>  control_we,
1659
                        din         =>  din,
1660
                        din_we      =>  din_we,
1661
                        dout        =>  dout,
1662
                        pins        =>  pins);
1663
 
1664
        stimulus_process: process
1665
        begin
1666
                wait for clock_period * 2;
1667
                control    <= x"0f"; -- write lower pins
1668
                control_we <= '1';
1669
 
1670
                wait for clock_period;
1671
                din        <= x"AA";
1672
                din_we     <= '1';
1673
 
1674
                wait for clock_period * 2;
1675
                pins <= (others => 'H'); -- !
1676
                wait for clock_period * 2;
1677
                stop <= '1';
1678
                wait;
1679
        end process;
1680
 
1681
end architecture;
1682
 
1683
------------------------- I/O Pin Controller ----------------------------------------
1684
 
1685
------------------------- Single and Dual Port Block RAM ----------------------------
1686
--|
1687
--| @warning The function initialize_ram has to be present in each architecture
1688
--| block ram that uses it (as far as I am aware) which means they could fall
1689
--| out of sync. This could be remedied with VHDL-2008.
1690
---------------------------------------------------------------------------------
1691
 
1692
--- Dual Port Model ---
1693
 
1694
library ieee;
1695
use ieee.std_logic_1164.all;
1696
use ieee.numeric_std.all;
1697
use std.textio.all;
1698
use work.util.all;
1699
 
1700
entity dual_port_block_ram is
1701
 
1702
        -- The dual port Block RAM module can be initialized from a file,
1703
        -- or initialized to all zeros. The model can be synthesized (with
1704
        -- Xilinx's ISE) into BRAM.
1705
        --
1706
        -- Valid file_type options include:
1707
        --
1708
        -- FILE_BINARY - A binary file (ASCII '0' and '1', one number per line)
1709
        -- FILE_HEX    - A Hex file (ASCII '0-9' 'a-f', 'A-F', one number per line)
1710
        -- FILE_NONE   - RAM contents will be defaulted to all zeros, no file will
1711
        --               be read from
1712
        --
1713
        -- @todo Read in actual binary data files, see: https://stackoverflow.com/questions/14173652
1714
        --
1715
        -- The data length must be divisible by 4 if the "hex" option is
1716
        -- given.
1717
        --
1718
        -- These default values for addr_length and data_length have been
1719
        -- chosen so as to fill the block RAM available on a Spartan 6.
1720
        --
1721
        generic(addr_length: positive    := 12;
1722
                data_length: positive    := 16;
1723
                file_name:   string      := "memory.bin";
1724
                file_type:   file_format := FILE_BINARY);
1725
        port(
1726
                --| Port A of dual port RAM
1727
                a_clk:  in  std_ulogic;
1728
                a_dwe:  in  std_ulogic;
1729
                a_dre:  in  std_ulogic;
1730
                a_addr: in  std_ulogic_vector(addr_length - 1 downto 0);
1731
                a_din:  in  std_ulogic_vector(data_length - 1 downto 0);
1732
                a_dout: out std_ulogic_vector(data_length - 1 downto 0) := (others => '0');
1733
                --| Port B of dual port RAM
1734
                b_clk:  in  std_ulogic;
1735
                b_dwe:  in  std_ulogic;
1736
                b_dre:  in  std_ulogic;
1737
                b_addr: in  std_ulogic_vector(addr_length - 1 downto 0);
1738
                b_din:  in  std_ulogic_vector(data_length - 1 downto 0);
1739
                b_dout: out std_ulogic_vector(data_length - 1 downto 0) := (others => '0'));
1740
end entity;
1741
 
1742
architecture behav of dual_port_block_ram is
1743
        constant ram_size: positive := 2 ** addr_length;
1744
 
1745
        type ram_type is array ((ram_size - 1 ) downto 0) of std_ulogic_vector(data_length - 1 downto 0);
1746
 
1747
        impure function initialize_ram(file_name: in string; file_type: in file_format) return ram_type is
1748
                variable ram_data:   ram_type;
1749
                file     in_file:    text is in file_name;
1750
                variable input_line: line;
1751
                variable tmp:        bit_vector(data_length - 1 downto 0);
1752
                variable c:          character;
1753
                variable slv:        std_ulogic_vector(data_length - 1 downto 0);
1754
        begin
1755
                for i in 0 to ram_size - 1 loop
1756
                        if file_type = FILE_NONE then
1757
                                ram_data(i):=(others => '0');
1758
                        elsif not endfile(in_file) then
1759
                                readline(in_file,input_line);
1760
                                if file_type = FILE_BINARY then
1761
                                        read(input_line, tmp);
1762
                                        ram_data(i) := std_ulogic_vector(to_stdlogicvector(tmp));
1763
                                elsif file_type = FILE_HEX then
1764
                                        assert (data_length mod 4) = 0 report "(data_length%4)!=0" severity failure;
1765
                                        for j in 1 to (data_length/4) loop
1766
                                                c:= input_line((data_length/4) - j + 1);
1767
                                                slv((j*4)-1 downto (j*4)-4) := hex_char_to_std_ulogic_vector(c);
1768
                                        end loop;
1769
                                        ram_data(i) := slv;
1770
                                else
1771
                                        report "Incorrect file type given: " & file_format'image(file_type) severity failure;
1772
                                end if;
1773
                        else
1774
                                ram_data(i) := (others => '0');
1775
                        end if;
1776
                end loop;
1777
                file_close(in_file);
1778
                return ram_data;
1779
        end function;
1780
 
1781
        shared variable ram: ram_type := initialize_ram(file_name, file_type);
1782
 
1783
begin
1784
        a_ram: process(a_clk)
1785
        begin
1786
                if rising_edge(a_clk) then
1787
                        if a_dwe = '1' then
1788
                                ram(to_integer(unsigned(a_addr))) := a_din;
1789
                        end if;
1790
                        if a_dre = '1' then
1791
                                a_dout <= ram(to_integer(unsigned(a_addr)));
1792
                        else
1793
                                a_dout <= (others => '0');
1794
                        end if;
1795
                end if;
1796
        end process;
1797
 
1798
        b_ram: process(b_clk)
1799
        begin
1800
                if rising_edge(b_clk) then
1801
                        if b_dwe = '1' then
1802
                                ram(to_integer(unsigned(b_addr))) := b_din;
1803
                        end if;
1804
                        if b_dre = '1' then
1805
                                b_dout <= ram(to_integer(unsigned(b_addr)));
1806
                        else
1807
                                b_dout <= (others => '0');
1808
                        end if;
1809
                end if;
1810
        end process;
1811
end architecture;
1812
 
1813
--- Single Port Model ---
1814
 
1815
library ieee;
1816
use ieee.std_logic_1164.all;
1817
use ieee.numeric_std.all;
1818
use std.textio.all;
1819
use work.util.all;
1820
 
1821
entity single_port_block_ram is
1822
        generic(addr_length: positive    := 12;
1823
                data_length: positive    := 16;
1824
                file_name:   string      := "memory.bin";
1825
                file_type:   file_format := FILE_BINARY);
1826
        port(
1827
                clk:  in  std_ulogic;
1828
                dwe:  in  std_ulogic;
1829
                dre:  in  std_ulogic;
1830
                addr: in  std_ulogic_vector(addr_length - 1 downto 0);
1831
                din:  in  std_ulogic_vector(data_length - 1 downto 0);
1832
                dout: out std_ulogic_vector(data_length - 1 downto 0) := (others => '0'));
1833
end entity;
1834
 
1835
architecture behav of single_port_block_ram is
1836
        constant ram_size: positive := 2 ** addr_length;
1837
 
1838
        type ram_type is array ((ram_size - 1 ) downto 0) of std_ulogic_vector(data_length - 1 downto 0);
1839
 
1840
        impure function initialize_ram(file_name: in string; file_type: in file_format) return ram_type is
1841
                variable ram_data:   ram_type;
1842
                file     in_file:    text is in file_name;
1843
                variable input_line: line;
1844
                variable tmp:        bit_vector(data_length - 1 downto 0);
1845
                variable c:          character;
1846
                variable slv:        std_ulogic_vector(data_length - 1 downto 0);
1847
        begin
1848
                for i in 0 to ram_size - 1 loop
1849
                        if file_type = FILE_NONE then
1850
                                ram_data(i):=(others => '0');
1851
                        elsif not endfile(in_file) then
1852
                                readline(in_file,input_line);
1853
                                if file_type = FILE_BINARY then
1854
                                        read(input_line, tmp);
1855
                                        ram_data(i) := std_ulogic_vector(to_stdlogicvector(tmp));
1856
                                elsif file_type = FILE_HEX then -- hexadecimal
1857
                                        assert (data_length mod 4) = 0 report "(data_length%4)!=0" severity failure;
1858
                                        for j in 1 to (data_length/4) loop
1859
                                                c:= input_line((data_length/4) - j + 1);
1860
                                                slv((j*4)-1 downto (j*4)-4) := hex_char_to_std_ulogic_vector(c);
1861
                                        end loop;
1862
                                        ram_data(i) := slv;
1863
                                else
1864
                                        report "Incorrect file type given: " & file_format'image(file_type) severity failure;
1865
                                end if;
1866
                        else
1867
                                ram_data(i) := (others => '0');
1868
                        end if;
1869
                end loop;
1870
                file_close(in_file);
1871
                return ram_data;
1872
        end function;
1873
 
1874
        shared variable ram: ram_type := initialize_ram(file_name, file_type);
1875
begin
1876
        block_ram: process(clk)
1877
        begin
1878
                if rising_edge(clk) then
1879
                        if dwe = '1' then
1880
                                ram(to_integer(unsigned(addr))) := din;
1881
                        end if;
1882
 
1883
                        if dre = '1' then
1884
                                dout <= ram(to_integer(unsigned(addr)));
1885
                        else
1886
                                dout <= (others => '0');
1887
                        end if;
1888
                end if;
1889
        end process;
1890
end architecture;
1891
 
1892
------------------------- Single and Dual Port Block RAM ----------------------------
1893
 
1894
------------------------- Data Source -----------------------------------------------
1895
--|
1896
--| This module spits out a bunch of data
1897
--|
1898
--| @todo Create a single module that can be used to capture and replay data at
1899
--| a configurable rate. This could be used as a logger or as a waveform
1900
--| generator. Depending on the generics used this should synthesize to either
1901
--| logger, or a data source, or both. A pre-divider could also be supplied as
1902
--| generic options, to lower the clock rate.
1903
--|
1904
 
1905
library ieee,work;
1906
use ieee.std_logic_1164.all;
1907
use ieee.numeric_std.all;
1908
use work.util.single_port_block_ram;
1909
use work.util.counter;
1910
use work.util.all;
1911
 
1912
entity data_source is
1913
        generic(addr_length: positive    := 12;
1914
                data_length: positive    := 16;
1915
                file_name:   string      := "memory.bin";
1916
                file_type:   file_format := FILE_BINARY);
1917
        port(
1918
                clk:     in  std_ulogic;
1919
                rst:     in  std_ulogic;
1920
 
1921
                ce:      in  std_ulogic := '1';
1922
                cr:      in  std_ulogic;
1923
 
1924
                load:    in  std_ulogic_vector(addr_length - 1 downto 0) := (others => '0');
1925
                load_we: in  std_ulogic := '0';
1926
 
1927
                dout:    out std_ulogic_vector(data_length - 1 downto 0));
1928
end entity;
1929
 
1930
architecture structural of data_source is
1931
        signal addr: std_ulogic_vector(addr_length - 1 downto 0);
1932
begin
1933
        count: work.util.counter
1934
                generic map(
1935
                        N => addr_length)
1936
                port map(
1937
                        clk      =>  clk,
1938
                        rst      =>  rst,
1939
                        ce       =>  ce,
1940
                        cr       =>  cr,
1941
                        dout     =>  addr,
1942
                        load_i   =>  load,
1943
                        load_we  =>  load_we);
1944
 
1945
        ram: work.util.single_port_block_ram
1946
                generic map(
1947
                        addr_length => addr_length,
1948
                        data_length => data_length,
1949
                        file_name   => file_name,
1950
                        file_type   => file_type)
1951
                port map(
1952
                        clk  => clk,
1953
                        addr => addr,
1954
                        dwe  => '0',
1955
                        dre  => '1',
1956
                        din  => (others => '0'),
1957
                        dout => dout);
1958
 
1959
end architecture;
1960
 
1961
------------------------- Data Source -----------------------------------------------
1962
 
1963
------------------------- uCPU ------------------------------------------------------
1964
-- @brief An incredible simple microcontroller
1965
-- @license MIT
1966
-- @author Richard James Howe
1967
-- @copyright Richard James Howe (2017)
1968
--
1969
-- Based on:
1970
-- https://stackoverflow.com/questions/20955863/vhdl-microprocessor-microcontroller
1971
--
1972
--  INSTRUCTION    CYCLES 87 6543210 OPERATION
1973
--  ADD WITH CARRY   2    00 ADDRESS A = A   + MEM[ADDRESS]
1974
--  NOR              2    01 ADDRESS A = A NOR MEM[ADDRESS]
1975
--  STORE            1    10 ADDRESS MEM[ADDRESS] = A
1976
--  JCC              1    11 ADDRESS IF(CARRY) { PC = ADDRESS, CLEAR CARRY }
1977
--
1978
-- It would be interesting to make a customizable CPU in which the
1979
-- instructions could be customized based upon what. Another interesting
1980
-- possibility is making a simple assembler purely in VHDL, which should
1981
-- be possible, but difficult. A single port version would require another
1982
-- state to fetch the operand and another register, or more states.
1983
--
1984
-- @todo Test in hardware, document, make assembler, and a project that
1985
-- just contains an instantiation of this core.
1986
--
1987
 
1988
library ieee,work;
1989
use ieee.std_logic_1164.all;
1990
use ieee.numeric_std.all;
1991
 
1992
entity ucpu is
1993
        generic(width: positive range 8 to 32 := 8);
1994
        port(
1995
                clk, rst: in  std_ulogic;
1996
 
1997
                pc:       out std_ulogic_vector(width - 3 downto 0);
1998
                op:       in  std_ulogic_vector(width - 1 downto 0);
1999
 
2000
                adr:      out std_ulogic_vector(width - 3 downto 0);
2001
                di:       in  std_ulogic_vector(width - 1 downto 0);
2002
                re, we:   out std_ulogic;
2003
                do:       out std_ulogic_vector(width - 1 downto 0));
2004
end entity;
2005
 
2006
architecture rtl of ucpu is
2007
        signal a_c,   a_n:       unsigned(di'high + 1 downto di'low) := (others => '0'); -- accumulator
2008
        signal pc_c,  pc_n:      unsigned(pc'range)                  := (others => '0');
2009
        signal alu:              std_ulogic_vector(1 downto 0)        := (others => '0');
2010
        signal state_c, state_n: std_ulogic                           := '0'; -- FETCH/Single cycle instruction or EXECUTE
2011
begin
2012
        pc          <= std_ulogic_vector(pc_n);
2013
        do          <= std_ulogic_vector(a_c(do'range));
2014
        alu         <= op(op'high downto op'high - 1);
2015
        adr         <= op(adr'range);
2016
        we          <= '1' when alu = "10" else '0'; -- STORE
2017
        re          <= alu(1) nor state_c;           -- FETCH for ADD and NOR
2018
        state_n     <= alu(1) nor state_c;           -- FETCH not taken or FETCH done
2019
        pc_n        <= unsigned(op(pc_n'range)) when (alu = "11"    and a_c(a_c'high) = '0') else -- Jump when carry set
2020
                        pc_c                    when (state_c = '0' and alu(1) = '0')        else -- FETCH
2021
                        pc_c + 1; -- EXECUTE
2022
 
2023
        process(clk, rst)
2024
        begin
2025
                if rst = '1' then
2026
                        a_c     <= (others => '0');
2027
                        pc_c    <= (others => '0');
2028
                        state_c <= '0';
2029
                elsif rising_edge(clk) then
2030
                        a_c     <= a_n;
2031
                        pc_c    <= pc_n;
2032
                        state_c <= state_n;
2033
                end if;
2034
        end process;
2035
 
2036
        process(op, alu, di, a_c, state_c)
2037
        begin
2038
                a_n     <= a_c;
2039
 
2040
                if alu = "11" and a_c(a_c'high) = '0' then a_n(a_n'high) <= '0'; end if;
2041
 
2042
                if state_c = '1' then -- EXECUTE for ADD and NOR
2043
                        assert alu(1) = '0' severity failure;
2044
                        if alu(0) = '0' then a_n <= '0' & a_c(di'range) + unsigned('0' & di); end if;
2045
                        if alu(0) = '1' then a_n <= a_c nor '0' & unsigned(di); end if;
2046
                end if;
2047
        end process;
2048
end architecture;
2049
 
2050
library ieee,work;
2051
use ieee.std_logic_1164.all;
2052
use ieee.numeric_std.all;
2053
use ieee.math_real.all;
2054
use work.util.all;
2055
 
2056
entity ucpu_tb is
2057
        generic(
2058
                clock_frequency: positive;
2059
                file_name: string := "ucpu.bin");
2060
end entity;
2061
 
2062
architecture testing of ucpu_tb is
2063
        constant clk_period:      time     := 1000 ms / clock_frequency;
2064
 
2065
        constant data_length: positive := 8;
2066
        constant addr_length: positive := data_length - 2;
2067
 
2068
        signal a_addr: std_ulogic_vector(addr_length - 1 downto 0);
2069
        signal a_dout: std_ulogic_vector(data_length - 1 downto 0) := (others => '0');
2070
 
2071
        signal b_dwe:  std_ulogic;
2072
        signal b_dre:  std_ulogic;
2073
        signal b_addr: std_ulogic_vector(addr_length - 1 downto 0);
2074
        signal b_din:  std_ulogic_vector(data_length - 1 downto 0);
2075
        signal b_dout: std_ulogic_vector(data_length - 1 downto 0) := (others => '0');
2076
 
2077
        signal clk, rst: std_ulogic := '0';
2078
        signal stop:     std_ulogic := '0';
2079
begin
2080
        cs: entity work.clock_source_tb
2081
                generic map(clock_frequency => clock_frequency, hold_rst => 2)
2082
                port map(stop => stop, clk => clk, rst => rst);
2083
 
2084
        bram_0: entity work.dual_port_block_ram
2085
        generic map(
2086
                addr_length => addr_length,
2087
                data_length => data_length,
2088
                file_name   => file_name,
2089
                file_type   => FILE_BINARY)
2090
        port map(
2091
                a_clk   =>  clk,
2092
                a_dwe   =>  '0',
2093
                a_dre   =>  '1',
2094
                a_addr  =>  a_addr,
2095
                a_din   =>  (others => '0'),
2096
                a_dout  =>  a_dout,
2097
 
2098
                b_clk   =>  clk,
2099
                b_dwe   =>  b_dwe,
2100
                b_dre   =>  b_dre,
2101
                b_addr  =>  b_addr,
2102
                b_din   =>  b_din,
2103
                b_dout  =>  b_dout);
2104
 
2105
        ucpu_0: entity work.ucpu
2106
        generic map(width => data_length)
2107
        port map(
2108
                clk => clk,
2109
                rst => rst,
2110
                pc  => a_addr,
2111
                op  => a_dout,
2112
 
2113
                re  => b_dre,
2114
                we  => b_dwe,
2115
                di  => b_dout,
2116
                do  => b_din,
2117
                adr => b_addr);
2118
 
2119
        stimulus_process: process
2120
        begin
2121
                wait for clk_period * 1000;
2122
                stop <= '1';
2123
                wait;
2124
        end process;
2125
 
2126
end architecture;
2127
 
2128
------------------------- uCPU ------------------------------------------------------
2129
 
2130
------------------------- Restoring Division ----------------------------------------
2131
-- @todo Add remainder to output, rename signals, make a
2132
-- better test bench, add non-restoring division, and describe module
2133
--
2134
-- Computes a/b in N cycles
2135
--
2136
-- https://en.wikipedia.org/wiki/Division_algorithm#Restoring_division
2137
--
2138
--
2139
library ieee,work;
2140
use ieee.std_logic_1164.all;
2141
use ieee.numeric_std.all;
2142
 
2143
entity restoring_divider is
2144
        generic(N: positive);
2145
        port(
2146
                clk:   in  std_ulogic;
2147
                rst:   in  std_ulogic := '0';
2148
 
2149
                a:     in  unsigned(N - 1 downto 0);
2150
                b:     in  unsigned(N - 1 downto 0);
2151
                start: in  std_ulogic;
2152
                done:  out std_ulogic;
2153
                c:     out unsigned(N - 1 downto 0));
2154
end entity;
2155
 
2156
architecture rtl of restoring_divider is
2157
        signal a_c, a_n: unsigned(a'range) := (others => '0');
2158
        signal b_c, b_n: unsigned(b'range) := (others => '0');
2159
        signal m_c, m_n: unsigned(b'range) := (others => '0');
2160
        signal o_c, o_n: unsigned(c'range) := (others => '0');
2161
        signal e_c, e_n: std_ulogic         := '0';
2162
        signal count_c, count_n: unsigned(work.util.n_bits(N) downto 0) := (others => '0');
2163
begin
2164
        c <= o_n;
2165
 
2166
        process(clk, rst)
2167
        begin
2168
                if rst = '1' then
2169
                        a_c      <=  (others  =>  '0');
2170
                        b_c      <=  (others  =>  '0');
2171
                        m_c      <=  (others  =>  '0');
2172
                        o_c      <=  (others  =>  '0');
2173
                        e_c      <=  '0';
2174
                        count_c  <=  (others  =>  '0');
2175
                elsif rising_edge(clk) then
2176
                        a_c      <=  a_n;
2177
                        b_c      <=  b_n;
2178
                        m_c      <=  m_n;
2179
                        o_c      <=  o_n;
2180
                        e_c      <=  e_n;
2181
                        count_c  <=  count_n;
2182
                end if;
2183
        end process;
2184
 
2185
        divide: process(a, b, start, a_c, b_c, m_c, e_c, o_c, count_c)
2186
                variable m_v: unsigned(b'range) := (others => '0');
2187
        begin
2188
                done     <=  '0';
2189
                a_n      <=  a_c;
2190
                b_n      <=  b_c;
2191
                m_v      :=  m_c;
2192
                e_n      <=  e_c;
2193
                o_n      <=  o_c;
2194
                count_n  <=  count_c;
2195
                if start = '1' then
2196
                        a_n   <= a;
2197
                        b_n   <= b;
2198
                        m_v   := (others => '0');
2199
                        e_n   <= '1';
2200
                        o_n   <= (others => '0');
2201
                        count_n <= (others => '0');
2202
                elsif e_c = '1' then
2203
                        if count_c(count_c'high) = '1' then
2204
                                done  <= '1';
2205
                                e_n   <= '0';
2206
                                o_n   <= a_c;
2207
                                count_n <= (others => '0');
2208
                        else
2209
                                m_v(b'high downto 1) := m_v(b'high - 1 downto 0);
2210
                                m_v(0) := a_c(a'high);
2211
                                a_n(a'high downto 1) <= a_c(a'high - 1 downto 0);
2212
                                m_v := m_v - b_c;
2213
                                if m_v(m_v'high) = '1' then
2214
                                        m_v := m_v + b_c;
2215
                                        a_n(0) <= '0';
2216
                                else
2217
                                        a_n(0) <= '1';
2218
                                end if;
2219
                                count_n <= count_c + 1;
2220
                        end if;
2221
                else
2222
                        count_n <= (others => '0');
2223
                end if;
2224
                m_n <= m_v;
2225
        end process;
2226
end architecture;
2227
 
2228
library ieee,work;
2229
use ieee.std_logic_1164.all;
2230
use ieee.numeric_std.all;
2231
use ieee.math_real.all;
2232
 
2233
entity restoring_divider_tb is
2234
        generic(clock_frequency: positive);
2235
end entity;
2236
 
2237
architecture testing of restoring_divider_tb is
2238
        constant clk_period: time     := 1000 ms / clock_frequency;
2239
        constant N:          positive := 8;
2240
 
2241
        signal a: unsigned(N - 1 downto 0) := (others => '0');
2242
        signal b: unsigned(N - 1 downto 0) := (others => '0');
2243
        signal c: unsigned(N - 1 downto 0) := (others => '0');
2244
        signal start, done: std_ulogic := '0';
2245
 
2246
        signal clk, rst: std_ulogic := '0';
2247
        signal stop:     std_ulogic := '0';
2248
begin
2249
        cs: entity work.clock_source_tb
2250
                generic map(clock_frequency => clock_frequency, hold_rst => 2)
2251
                port map(stop => stop, clk => clk, rst => rst);
2252
 
2253
        uut: entity work.restoring_divider
2254
                generic map(N => N)
2255
                port map(
2256
                        clk   => clk,
2257
                        rst   => rst,
2258
                        a     => a,
2259
                        b     => b,
2260
                        start => start,
2261
                        done  => done,
2262
                        c     => c);
2263
 
2264
        stimulus_process: process
2265
        begin
2266
                wait for clk_period * 2;
2267
 
2268
                a <= x"64";
2269
                b <= x"0A";
2270
                start <= '1';
2271
                wait for clk_period * 1;
2272
                start <= '0';
2273
                wait until done = '1';
2274
                --assert c = x"0A" severity failure;
2275
 
2276
                wait for clk_period * 10;
2277
                b     <= x"05";
2278
                start <= '1';
2279
                wait for clk_period * 1;
2280
                start <= '0';
2281
                wait until done = '1';
2282
                --assert c = x"14" severity failure;
2283
 
2284
                stop <= '1';
2285
                wait;
2286
        end process;
2287
 
2288
end architecture;
2289
------------------------- Restoring Divider ---------------------------------------------------
2290
 
2291
------------------------- Debouncer -----------------------------------------------------------
2292
 
2293
library ieee,work;
2294
use ieee.std_logic_1164.all;
2295
use ieee.numeric_std.all;
2296
 
2297
entity debounce_us is
2298
        generic(clock_frequency: positive; timer_period_us: natural);
2299
        port(
2300
                clk:   in  std_ulogic;
2301
                di:    in  std_ulogic;
2302
                do:    out std_ulogic := '0');
2303
end entity;
2304
 
2305
architecture rtl of debounce_us is
2306
        signal ff: std_ulogic_vector(1 downto 0) := (others => '0');
2307
        signal rst, done: std_ulogic             := '0';
2308
begin
2309
        timer: work.util.timer_us
2310
                generic map(
2311
                        clock_frequency => clock_frequency,
2312
                        timer_period_us => timer_period_us)
2313
                port map(
2314
                        clk => clk,
2315
                        rst => rst,
2316
                        co  => done);
2317
 
2318
        process(clk)
2319
        begin
2320
                if rising_edge(clk) then
2321
                        ff(0) <= di;
2322
                        ff(1) <= ff(0);
2323
                        rst   <= '0';
2324
                        if (ff(0) xor ff(1)) = '1' then
2325
                                rst <= '1';
2326
                        elsif done = '1' then
2327
                                do  <= ff(1);
2328
                        end if;
2329
                end if;
2330
        end process;
2331
end architecture;
2332
 
2333
library ieee,work;
2334
use ieee.std_logic_1164.all;
2335
use ieee.numeric_std.all;
2336
 
2337
entity debounce_us_tb is
2338
        generic(clock_frequency: positive);
2339
end entity;
2340
 
2341
architecture testing of debounce_us_tb is
2342
        constant clk_period: time     := 1000 ms / clock_frequency;
2343
 
2344
        signal di,  do:  std_ulogic := '0';
2345
        signal clk, rst: std_ulogic := '0';
2346
        signal stop:     std_ulogic := '0';
2347
begin
2348
        cs: entity work.clock_source_tb
2349
                generic map(clock_frequency => clock_frequency, hold_rst => 2)
2350
                port map(stop => stop, clk => clk, rst => rst);
2351
 
2352
        uut: work.util.debounce_us
2353
                generic map(clock_frequency => clock_frequency, timer_period_us => 1)
2354
                port map(clk => clk, di => di, do => do);
2355
 
2356
        stimulus_process: process
2357
        begin
2358
                wait for clk_period * 2;
2359
                di <= '1';
2360
 
2361
                wait for 1.5 us;
2362
 
2363
                stop <= '1';
2364
                wait;
2365
        end process;
2366
end architecture;
2367
------------------------- Debouncer -----------------------------------------------------------
2368
 
2369
------------------------- Debouncer Block -----------------------------------------------------
2370
 
2371
library ieee,work;
2372
use ieee.std_logic_1164.all;
2373
use ieee.numeric_std.all;
2374
 
2375
entity debounce_block_us is
2376
        generic(N: positive; clock_frequency: positive; timer_period_us: natural);
2377
        port(
2378
                clk:   in  std_ulogic;
2379
                di:    in  std_ulogic_vector(N - 1 downto 0);
2380
                do:    out std_ulogic_vector(N - 1 downto 0));
2381
end entity;
2382
 
2383
architecture structural of debounce_block_us is
2384
begin
2385
        debouncer: for i in N - 1 downto 0 generate
2386
                d_instance: work.util.debounce_us
2387
                        generic map(
2388
                                clock_frequency => clock_frequency,
2389
                                timer_period_us => timer_period_us)
2390
                        port map(clk => clk, di => di(i), do => do(i));
2391
        end generate;
2392
end architecture;
2393
 
2394
------------------------- Debouncer Block -----------------------------------------------------
2395
 
2396
------------------------- State Changed -------------------------------------------------------
2397
library ieee,work;
2398
use ieee.std_logic_1164.all;
2399
use ieee.numeric_std.all;
2400
 
2401
entity state_changed is
2402
        port(
2403
                clk: in  std_ulogic;
2404
                rst: in  std_ulogic;
2405
                di:  in  std_ulogic;
2406
                do:  out std_ulogic);
2407
end entity;
2408
 
2409
architecture rtl of state_changed is
2410
        signal state_c, state_n: std_ulogic_vector(1 downto 0) := (others => '0');
2411
begin
2412
        process(clk, rst)
2413
        begin
2414
                if rst = '1' then
2415
                        state_c <= (others => '0');
2416
                elsif rising_edge(clk) then
2417
                        state_c <= state_n;
2418
                end if;
2419
        end process;
2420
 
2421
        do <= '1' when (state_c(0) xor state_c(1)) = '1' else '0';
2422
 
2423
        process(di, state_c)
2424
        begin
2425
                state_n(0) <= state_c(1);
2426
                state_n(1) <= di;
2427
        end process;
2428
end architecture;
2429
 
2430
------------------------- Change State --------------------------------------------------------
2431
 
2432
------------------------- Change State Block --------------------------------------------------
2433
library ieee,work;
2434
use ieee.std_logic_1164.all;
2435
use ieee.numeric_std.all;
2436
 
2437
entity state_block_changed is
2438
        generic(N: positive);
2439
        port(
2440
                clk: in  std_ulogic;
2441
                rst: in  std_ulogic;
2442
                di:  in  std_ulogic_vector(N - 1 downto 0);
2443
                do:  out std_ulogic_vector(N - 1 downto 0));
2444
end entity;
2445
 
2446
architecture structural of state_block_changed is
2447
begin
2448
        changes: for i in N - 1 downto 0 generate
2449
                d_instance: work.util.state_changed
2450
                        port map(clk => clk, rst => rst, di => di(i), do => do(i));
2451
        end generate;
2452
end architecture;
2453
 
2454
------------------------- Change State Block --------------------------------------------------

powered by: WebSVN 2.1.0

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