day2: add VHDL solution
This commit is contained in:
parent
e04c222407
commit
58ae72a8aa
7 changed files with 376 additions and 0 deletions
4
day2/vhdl/.gitignore
vendored
Normal file
4
day2/vhdl/.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
workdir/
|
||||||
|
*.o
|
||||||
|
*.ghw
|
||||||
|
sim
|
86
day2/vhdl/parser.vhd
Normal file
86
day2/vhdl/parser.vhd
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
library ieee;
|
||||||
|
use ieee.std_logic_1164.all;
|
||||||
|
|
||||||
|
entity parser is
|
||||||
|
port (
|
||||||
|
clk : in std_logic;
|
||||||
|
reset : in std_logic;
|
||||||
|
is_record : in std_logic;
|
||||||
|
is_data : out std_logic;
|
||||||
|
|
||||||
|
char : in character;
|
||||||
|
|
||||||
|
num1, num2 : out natural range 0 to 99;
|
||||||
|
letter : out character
|
||||||
|
);
|
||||||
|
end entity;
|
||||||
|
|
||||||
|
architecture behaviour of parser is
|
||||||
|
type state_t is (S_NUM1, S_NUM2, S_LETTER, S_COLON, S_END_SPACE, S_DATA);
|
||||||
|
signal state : state_t := S_NUM1;
|
||||||
|
|
||||||
|
subtype digit is natural range 0 to 9;
|
||||||
|
type multiples_lookup_t is array(digit) of natural range 0 to 90;
|
||||||
|
constant TEN_MULTIPLES : multiples_lookup_t := (0, 10, 20, 30, 40, 50, 60, 70, 80, 90);
|
||||||
|
|
||||||
|
-- most significant digit of number
|
||||||
|
signal prev_digit : digit := 0;
|
||||||
|
signal current_digit : digit;
|
||||||
|
signal complete_num : natural range 0 to 99;
|
||||||
|
|
||||||
|
function char_to_digit(input : in character) return digit is
|
||||||
|
begin
|
||||||
|
if input >= '0' and input <= '9' then
|
||||||
|
return character'pos(input) - character'pos('0');
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
end if;
|
||||||
|
end function;
|
||||||
|
begin
|
||||||
|
current_digit <= char_to_digit(char);
|
||||||
|
complete_num <= TEN_MULTIPLES(prev_digit) + current_digit;
|
||||||
|
|
||||||
|
process(clk)
|
||||||
|
begin
|
||||||
|
if rising_edge(clk) then
|
||||||
|
if reset then
|
||||||
|
prev_digit <= 0;
|
||||||
|
state <= S_NUM1;
|
||||||
|
else
|
||||||
|
prev_digit <= 0;
|
||||||
|
|
||||||
|
case state is
|
||||||
|
when S_NUM1 =>
|
||||||
|
if is_record then
|
||||||
|
if char = '-' then
|
||||||
|
state <= S_NUM2;
|
||||||
|
else
|
||||||
|
num1 <= complete_num;
|
||||||
|
prev_digit <= current_digit;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
when S_NUM2 =>
|
||||||
|
if char = ' ' then
|
||||||
|
state <= S_LETTER;
|
||||||
|
else
|
||||||
|
num2 <= complete_num;
|
||||||
|
prev_digit <= current_digit;
|
||||||
|
end if;
|
||||||
|
when S_LETTER =>
|
||||||
|
letter <= char;
|
||||||
|
state <= S_COLON;
|
||||||
|
when S_COLON =>
|
||||||
|
state <= S_END_SPACE;
|
||||||
|
when S_END_SPACE =>
|
||||||
|
state <= S_DATA;
|
||||||
|
when S_DATA =>
|
||||||
|
if not is_record then
|
||||||
|
state <= S_NUM1;
|
||||||
|
end if;
|
||||||
|
end case;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
end process;
|
||||||
|
|
||||||
|
is_data <= '1' when state = S_DATA else '0';
|
||||||
|
end architecture;
|
9
day2/vhdl/run.sh
Executable file
9
day2/vhdl/run.sh
Executable file
|
@ -0,0 +1,9 @@
|
||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
mkdir -p workdir
|
||||||
|
|
||||||
|
ghdl analyze --std=08 --workdir=workdir parser.vhd verifier.vhd top.vhd sim.vhd
|
||||||
|
ghdl elab-run --std=08 --workdir=workdir sim -gSTEP=1 -gFILENAME="../input.txt"
|
||||||
|
ghdl elab-run --std=08 --workdir=workdir sim -gSTEP=2 -gFILENAME="../input.txt"
|
47
day2/vhdl/sim.gtkw
Normal file
47
day2/vhdl/sim.gtkw
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
[*]
|
||||||
|
[*] GTKWave Analyzer v3.3.104 (w)1999-2020 BSI
|
||||||
|
[*] Wed Dec 2 10:02:23 2020
|
||||||
|
[*]
|
||||||
|
[dumpfile] "/home/xiretza/dev/aoc2020/day2/sim.ghw"
|
||||||
|
[dumpfile_mtime] "Wed Dec 2 10:01:08 2020"
|
||||||
|
[dumpfile_size] 410436
|
||||||
|
[savefile] "/home/xiretza/dev/aoc2020/day2/sim.gtkw"
|
||||||
|
[timestart] 410945000000
|
||||||
|
[size] 1600 853
|
||||||
|
[pos] -1 -1
|
||||||
|
*-27.864407 226600000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
|
||||||
|
[treeopen] top.
|
||||||
|
[treeopen] top.sim.
|
||||||
|
[treeopen] top.sim.top.
|
||||||
|
[sst_width] 221
|
||||||
|
[signals_width] 260
|
||||||
|
[sst_expanded] 1
|
||||||
|
[sst_vpaned_height] 233
|
||||||
|
@28
|
||||||
|
top.sim.clk
|
||||||
|
top.sim.reset
|
||||||
|
top.sim.top.parser_inst.is_record
|
||||||
|
@420
|
||||||
|
top.sim.top.char
|
||||||
|
@200
|
||||||
|
-
|
||||||
|
@28
|
||||||
|
top.sim.top.parser_inst.is_data
|
||||||
|
@420
|
||||||
|
top.sim.top.num1
|
||||||
|
top.sim.top.num2
|
||||||
|
top.sim.top.letter
|
||||||
|
@200
|
||||||
|
-
|
||||||
|
@420
|
||||||
|
top.sim.top.verifier_inst.count
|
||||||
|
@28
|
||||||
|
top.sim.top.verifier_inst.verified
|
||||||
|
@200
|
||||||
|
-
|
||||||
|
@24
|
||||||
|
#{top.sim.num_verified[11:0]} top.sim.num_verified[11] top.sim.num_verified[10] top.sim.num_verified[9] top.sim.num_verified[8] top.sim.num_verified[7] top.sim.num_verified[6] top.sim.num_verified[5] top.sim.num_verified[4] top.sim.num_verified[3] top.sim.num_verified[2] top.sim.num_verified[1] top.sim.num_verified[0]
|
||||||
|
@29
|
||||||
|
top.sim.top.record_ended
|
||||||
|
[pattern_trace] 1
|
||||||
|
[pattern_trace] 0
|
88
day2/vhdl/sim.vhd
Normal file
88
day2/vhdl/sim.vhd
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
library ieee;
|
||||||
|
use ieee.std_logic_1164.all,
|
||||||
|
ieee.numeric_std.all;
|
||||||
|
|
||||||
|
use std.textio.all;
|
||||||
|
|
||||||
|
entity sim is
|
||||||
|
generic (
|
||||||
|
FILENAME : string := "input.txt";
|
||||||
|
COUNTER_WIDTH : positive := 12;
|
||||||
|
STEP : natural range 1 to 2
|
||||||
|
);
|
||||||
|
end entity;
|
||||||
|
|
||||||
|
architecture a of sim is
|
||||||
|
file file_handle : text open read_mode is FILENAME;
|
||||||
|
signal char_in : character;
|
||||||
|
signal clk, reset, is_record : std_logic;
|
||||||
|
signal num_verified : unsigned(COUNTER_WIDTH-1 downto 0);
|
||||||
|
|
||||||
|
procedure print(s: string) is
|
||||||
|
variable l : line;
|
||||||
|
begin
|
||||||
|
write(l, s);
|
||||||
|
writeline(output, l);
|
||||||
|
end procedure;
|
||||||
|
begin
|
||||||
|
process
|
||||||
|
variable current_line : line;
|
||||||
|
variable current_char : character;
|
||||||
|
variable good : boolean;
|
||||||
|
|
||||||
|
procedure cycle_clock is
|
||||||
|
begin
|
||||||
|
wait for 10 ns;
|
||||||
|
clk <= '0';
|
||||||
|
wait for 10 ns;
|
||||||
|
clk <= '1';
|
||||||
|
wait for 0 ns;
|
||||||
|
end procedure;
|
||||||
|
begin
|
||||||
|
clk <= '0';
|
||||||
|
is_record <= '0';
|
||||||
|
char_in <= NUL;
|
||||||
|
|
||||||
|
reset <= '1';
|
||||||
|
cycle_clock;
|
||||||
|
reset <= '0';
|
||||||
|
cycle_clock;
|
||||||
|
|
||||||
|
lines_loop: loop
|
||||||
|
exit lines_loop when endfile(file_handle);
|
||||||
|
readline(file_handle, current_line);
|
||||||
|
|
||||||
|
is_record <= '1';
|
||||||
|
|
||||||
|
chars_loop: loop
|
||||||
|
read(current_line, current_char, good);
|
||||||
|
exit chars_loop when not good;
|
||||||
|
|
||||||
|
char_in <= current_char;
|
||||||
|
cycle_clock;
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
is_record <= '0';
|
||||||
|
cycle_clock;
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
cycle_clock;
|
||||||
|
|
||||||
|
print(to_string(to_integer(num_verified)));
|
||||||
|
|
||||||
|
wait;
|
||||||
|
end process;
|
||||||
|
|
||||||
|
top: entity work.top
|
||||||
|
generic map (
|
||||||
|
COUNTER_WIDTH => COUNTER_WIDTH,
|
||||||
|
STEP => STEP
|
||||||
|
)
|
||||||
|
port map (
|
||||||
|
clk => clk,
|
||||||
|
reset => reset,
|
||||||
|
char => char_in,
|
||||||
|
is_record => is_record,
|
||||||
|
num_verified => num_verified
|
||||||
|
);
|
||||||
|
end architecture;
|
84
day2/vhdl/top.vhd
Normal file
84
day2/vhdl/top.vhd
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
library ieee;
|
||||||
|
use ieee.std_logic_1164.all,
|
||||||
|
ieee.numeric_std.all;
|
||||||
|
|
||||||
|
entity top is
|
||||||
|
generic (
|
||||||
|
COUNTER_WIDTH : positive;
|
||||||
|
STEP : natural range 1 to 2
|
||||||
|
);
|
||||||
|
port (
|
||||||
|
clk : in std_logic;
|
||||||
|
reset : in std_logic;
|
||||||
|
char : in character;
|
||||||
|
is_record : in std_logic;
|
||||||
|
num_verified : out unsigned(COUNTER_WIDTH-1 downto 0)
|
||||||
|
);
|
||||||
|
end entity;
|
||||||
|
|
||||||
|
architecture behaviour of top is
|
||||||
|
signal is_data : std_logic;
|
||||||
|
signal num1, num2 : natural range 0 to 99;
|
||||||
|
signal letter : character;
|
||||||
|
|
||||||
|
signal prev_is_record : std_logic;
|
||||||
|
signal record_ended : std_logic;
|
||||||
|
|
||||||
|
signal verified : std_logic;
|
||||||
|
begin
|
||||||
|
record_ended <= prev_is_record and not is_record;
|
||||||
|
|
||||||
|
parser_inst: entity work.parser
|
||||||
|
port map (
|
||||||
|
clk => clk,
|
||||||
|
reset => reset,
|
||||||
|
is_record => is_record,
|
||||||
|
is_data => is_data,
|
||||||
|
char => char,
|
||||||
|
|
||||||
|
num1 => num1,
|
||||||
|
num2 => num2,
|
||||||
|
letter => letter
|
||||||
|
);
|
||||||
|
|
||||||
|
generate_verifier: if step = 1 generate
|
||||||
|
verifier_inst: entity work.verifier(step1)
|
||||||
|
port map (
|
||||||
|
clk => clk,
|
||||||
|
reset => reset or record_ended,
|
||||||
|
is_data => is_data,
|
||||||
|
num1 => num1,
|
||||||
|
num2 => num2,
|
||||||
|
letter => letter,
|
||||||
|
char => char,
|
||||||
|
verified => verified
|
||||||
|
);
|
||||||
|
elsif step = 2 generate
|
||||||
|
verifier_inst: entity work.verifier(step2)
|
||||||
|
port map (
|
||||||
|
clk => clk,
|
||||||
|
reset => reset or record_ended,
|
||||||
|
is_data => is_data,
|
||||||
|
num1 => num1,
|
||||||
|
num2 => num2,
|
||||||
|
letter => letter,
|
||||||
|
char => char,
|
||||||
|
verified => verified
|
||||||
|
);
|
||||||
|
else generate
|
||||||
|
assert false report "Bad value for ""step""" severity failure;
|
||||||
|
end generate;
|
||||||
|
|
||||||
|
process(clk)
|
||||||
|
begin
|
||||||
|
if rising_edge(clk) then
|
||||||
|
prev_is_record <= is_record;
|
||||||
|
if reset then
|
||||||
|
prev_is_record <= '0';
|
||||||
|
num_verified <= (others => '0');
|
||||||
|
elsif record_ended and verified then
|
||||||
|
num_verified <= num_verified + 1;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
end process;
|
||||||
|
end architecture;
|
58
day2/vhdl/verifier.vhd
Normal file
58
day2/vhdl/verifier.vhd
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
library ieee;
|
||||||
|
use ieee.std_logic_1164.all;
|
||||||
|
|
||||||
|
entity verifier is
|
||||||
|
port (
|
||||||
|
clk : in std_logic;
|
||||||
|
reset : in std_logic;
|
||||||
|
is_data : in std_logic;
|
||||||
|
|
||||||
|
num1, num2 : in natural range 0 to 99;
|
||||||
|
letter : in character;
|
||||||
|
|
||||||
|
char : in character;
|
||||||
|
|
||||||
|
verified : out std_logic
|
||||||
|
);
|
||||||
|
end entity;
|
||||||
|
|
||||||
|
architecture step1 of verifier is
|
||||||
|
signal count : natural range 0 to 99;
|
||||||
|
begin
|
||||||
|
process(clk)
|
||||||
|
begin
|
||||||
|
if rising_edge(clk) then
|
||||||
|
if reset then
|
||||||
|
count <= 0;
|
||||||
|
elsif is_data then
|
||||||
|
if char = letter then
|
||||||
|
count <= count + 1;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
end process;
|
||||||
|
|
||||||
|
verified <= '1' when num1 <= count and count <= num2 else '0';
|
||||||
|
end architecture;
|
||||||
|
|
||||||
|
architecture step2 of verifier is
|
||||||
|
signal count : natural range 1 to 99;
|
||||||
|
signal parity : std_logic;
|
||||||
|
begin
|
||||||
|
process(clk)
|
||||||
|
begin
|
||||||
|
if rising_edge(clk) then
|
||||||
|
if reset then
|
||||||
|
count <= 1;
|
||||||
|
parity <= '0';
|
||||||
|
elsif is_data then
|
||||||
|
count <= count + 1;
|
||||||
|
if (count = num1 or count = num2) and char = letter then
|
||||||
|
parity <= not parity;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
end process;
|
||||||
|
|
||||||
|
verified <= parity;
|
||||||
|
end architecture;
|
Loading…
Reference in a new issue