| 1 |
2 |
howe.r.j.8 |
-- File: util.vhd
|
| 2 |
|
|
-- Author: Richard James Howe
|
| 3 |
|
|
-- Repository: https://github.com/howerj/bit-serial
|
| 4 |
|
|
-- License: MIT
|
| 5 |
|
|
-- Description: Utility module, mostly taken from another project
|
| 6 |
|
|
-- of mine, <https://github.com/howerj/forth-cpu>.
|
| 7 |
|
|
|
| 8 |
|
|
library ieee, work;
|
| 9 |
|
|
use ieee.std_logic_1164.all;
|
| 10 |
|
|
use ieee.numeric_std.all;
|
| 11 |
|
|
use std.textio.all;
|
| 12 |
|
|
|
| 13 |
|
|
package util is
|
| 14 |
|
|
-- Not all modules will need every generic specified here, even so it
|
| 15 |
|
|
-- is easier to group the common generics in one structure.
|
| 16 |
|
|
type common_generics is record
|
| 17 |
|
|
clock_frequency: positive; -- clock frequency of module clock
|
| 18 |
|
|
delay: time; -- gate delay for simulation purposes
|
| 19 |
|
|
asynchronous_reset: boolean; -- use asynchronous reset if true
|
| 20 |
|
|
end record;
|
| 21 |
|
|
|
| 22 |
|
|
constant default_settings: common_generics := (
|
| 23 |
|
|
clock_frequency => 100_000_000,
|
| 24 |
|
|
delay => 0 ns,
|
| 25 |
|
|
asynchronous_reset => true
|
| 26 |
|
|
);
|
| 27 |
|
|
|
| 28 |
|
|
type file_format is (FILE_HEX, FILE_BINARY, FILE_NONE);
|
| 29 |
|
|
|
| 30 |
|
|
component single_port_block_ram is
|
| 31 |
|
|
generic (g: common_generics;
|
| 32 |
|
|
addr_length: positive := 12;
|
| 33 |
|
|
data_length: positive := 16;
|
| 34 |
|
|
file_name: string := "memory.bin";
|
| 35 |
|
|
file_type: file_format := FILE_BINARY);
|
| 36 |
|
|
port (
|
| 37 |
|
|
clk: in std_ulogic;
|
| 38 |
|
|
dwe: in std_ulogic;
|
| 39 |
|
|
dre: in std_ulogic;
|
| 40 |
|
|
addr: in std_ulogic_vector(addr_length - 1 downto 0);
|
| 41 |
|
|
din: in std_ulogic_vector(data_length - 1 downto 0);
|
| 42 |
|
|
dout: out std_ulogic_vector(data_length - 1 downto 0) := (others => '0'));
|
| 43 |
|
|
end component;
|
| 44 |
|
|
|
| 45 |
|
|
function hex_char_to_std_ulogic_vector_tb(hc: character) return std_ulogic_vector;
|
| 46 |
|
|
end;
|
| 47 |
|
|
|
| 48 |
|
|
package body util is
|
| 49 |
|
|
function hex_char_to_std_ulogic_vector_tb(hc: character) return std_ulogic_vector is
|
| 50 |
|
|
variable slv: std_ulogic_vector(3 downto 0);
|
| 51 |
|
|
begin
|
| 52 |
|
|
case hc is
|
| 53 |
|
|
when '0' => slv := "0000";
|
| 54 |
|
|
when '1' => slv := "0001";
|
| 55 |
|
|
when '2' => slv := "0010";
|
| 56 |
|
|
when '3' => slv := "0011";
|
| 57 |
|
|
when '4' => slv := "0100";
|
| 58 |
|
|
when '5' => slv := "0101";
|
| 59 |
|
|
when '6' => slv := "0110";
|
| 60 |
|
|
when '7' => slv := "0111";
|
| 61 |
|
|
when '8' => slv := "1000";
|
| 62 |
|
|
when '9' => slv := "1001";
|
| 63 |
|
|
when 'A' => slv := "1010";
|
| 64 |
|
|
when 'a' => slv := "1010";
|
| 65 |
|
|
when 'B' => slv := "1011";
|
| 66 |
|
|
when 'b' => slv := "1011";
|
| 67 |
|
|
when 'C' => slv := "1100";
|
| 68 |
|
|
when 'c' => slv := "1100";
|
| 69 |
|
|
when 'D' => slv := "1101";
|
| 70 |
|
|
when 'd' => slv := "1101";
|
| 71 |
|
|
when 'E' => slv := "1110";
|
| 72 |
|
|
when 'e' => slv := "1110";
|
| 73 |
|
|
when 'F' => slv := "1111";
|
| 74 |
|
|
when 'f' => slv := "1111";
|
| 75 |
|
|
when others => slv := "XXXX";
|
| 76 |
|
|
end case;
|
| 77 |
|
|
assert (slv /= "XXXX") report " not a valid hex character: " & hc severity failure;
|
| 78 |
|
|
return slv;
|
| 79 |
|
|
end;
|
| 80 |
|
|
end;
|
| 81 |
|
|
|
| 82 |
|
|
library ieee, work;
|
| 83 |
|
|
use ieee.std_logic_1164.all;
|
| 84 |
|
|
use ieee.numeric_std.all;
|
| 85 |
|
|
use std.textio.all;
|
| 86 |
|
|
use work.util.all;
|
| 87 |
|
|
|
| 88 |
|
|
entity single_port_block_ram is
|
| 89 |
|
|
generic (g: common_generics;
|
| 90 |
|
|
addr_length: positive := 12;
|
| 91 |
|
|
data_length: positive := 16;
|
| 92 |
|
|
file_name: string := "memory.bin";
|
| 93 |
|
|
file_type: file_format := FILE_BINARY);
|
| 94 |
|
|
port (
|
| 95 |
|
|
clk: in std_ulogic;
|
| 96 |
|
|
dwe: in std_ulogic;
|
| 97 |
|
|
dre: in std_ulogic;
|
| 98 |
|
|
addr: in std_ulogic_vector(addr_length - 1 downto 0);
|
| 99 |
|
|
din: in std_ulogic_vector(data_length - 1 downto 0);
|
| 100 |
|
|
dout: out std_ulogic_vector(data_length - 1 downto 0) := (others => '0'));
|
| 101 |
|
|
end entity;
|
| 102 |
|
|
|
| 103 |
|
|
architecture behav of single_port_block_ram is
|
| 104 |
|
|
constant ram_size: positive := 2 ** addr_length;
|
| 105 |
|
|
|
| 106 |
|
|
type ram_type is array ((ram_size - 1 ) downto 0) of std_ulogic_vector(data_length - 1 downto 0);
|
| 107 |
|
|
|
| 108 |
|
|
impure function initialize_ram(the_file_name: in string; the_file_type: in file_format) return ram_type is
|
| 109 |
|
|
variable ram_data: ram_type;
|
| 110 |
|
|
file in_file: text is in the_file_name;
|
| 111 |
|
|
variable input_line: line;
|
| 112 |
|
|
variable tmp: bit_vector(data_length - 1 downto 0);
|
| 113 |
|
|
variable c: character;
|
| 114 |
|
|
variable slv: std_ulogic_vector(data_length - 1 downto 0);
|
| 115 |
|
|
begin
|
| 116 |
|
|
for i in 0 to ram_size - 1 loop
|
| 117 |
|
|
if the_file_type = FILE_NONE then
|
| 118 |
|
|
ram_data(i):=(others => '0');
|
| 119 |
|
|
elsif not endfile(in_file) then
|
| 120 |
|
|
readline(in_file,input_line);
|
| 121 |
|
|
if the_file_type = FILE_BINARY then
|
| 122 |
|
|
read(input_line, tmp);
|
| 123 |
|
|
ram_data(i) := std_ulogic_vector(to_stdlogicvector(tmp));
|
| 124 |
|
|
elsif the_file_type = FILE_HEX then -- hexadecimal
|
| 125 |
|
|
assert (data_length mod 4) = 0 report "(data_length%4)!=0" severity failure;
|
| 126 |
|
|
for j in 1 to (data_length/4) loop
|
| 127 |
|
|
c:= input_line((data_length/4) - j + 1);
|
| 128 |
|
|
slv((j*4)-1 downto (j*4)-4) := hex_char_to_std_ulogic_vector_tb(c);
|
| 129 |
|
|
end loop;
|
| 130 |
|
|
ram_data(i) := slv;
|
| 131 |
|
|
else
|
| 132 |
|
|
report "Incorrect file type given: " & file_format'image(the_file_type) severity failure;
|
| 133 |
|
|
end if;
|
| 134 |
|
|
else
|
| 135 |
|
|
ram_data(i) := (others => '0');
|
| 136 |
|
|
end if;
|
| 137 |
|
|
end loop;
|
| 138 |
|
|
file_close(in_file);
|
| 139 |
|
|
return ram_data;
|
| 140 |
|
|
end function;
|
| 141 |
|
|
|
| 142 |
|
|
shared variable ram: ram_type := initialize_ram(file_name, file_type);
|
| 143 |
|
|
|
| 144 |
|
|
begin
|
| 145 |
|
|
block_ram: process(clk)
|
| 146 |
|
|
begin
|
| 147 |
|
|
if rising_edge(clk) then
|
| 148 |
|
|
if dwe = '1' then
|
| 149 |
|
|
ram(to_integer(unsigned(addr))) := din;
|
| 150 |
|
|
end if;
|
| 151 |
|
|
|
| 152 |
|
|
if dre = '1' then
|
| 153 |
|
|
dout <= ram(to_integer(unsigned(addr))) after g.delay;
|
| 154 |
|
|
else
|
| 155 |
|
|
dout <= (others => '0') after g.delay;
|
| 156 |
|
|
end if;
|
| 157 |
|
|
end if;
|
| 158 |
|
|
end process;
|
| 159 |
|
|
end architecture;
|
| 160 |
|
|
|
| 161 |
|
|
|