day2: add VHDL solution

This commit is contained in:
Xiretza 2020-12-02 11:09:36 +01:00
parent e04c222407
commit 58ae72a8aa
Signed by: xiretza
GPG Key ID: 17B78226F7139993
7 changed files with 376 additions and 0 deletions

4
day2/vhdl/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
workdir/
*.o
*.ghw
sim

86
day2/vhdl/parser.vhd Normal file
View 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
View 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
View 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
View 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
View 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
View 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;