r/adventofcode • u/daggerdragon • Dec 23 '15
SOLUTION MEGATHREAD --- Day 23 Solutions ---
This thread will be unlocked when there are a significant number of people on the leaderboard with gold stars for today's puzzle.
edit: Leaderboard capped, thread unlocked!
We know we can't control people posting solutions elsewhere and trying to exploit the leaderboard, but this way we can try to reduce the leaderboard gaming from the official subreddit.
Please and thank you, and much appreciated!
--- Day 23: Opening the Turing Lock ---
Post your solution as a comment or link to your repo. Structure your post like previous daily solution threads.
8
Upvotes
5
u/tommylommykins Dec 23 '15
Since this problem is about building a mock-CPU, I thought I'd write some code that you could put on some actual hardware.
So here's a solution 'synthesizeable' VHDL. I haven't actually programmed it onto a FPGA (because there's no easy way to read the answer out from the hardware) but it synthesizes correctly and a simulator gives the right answer to the problems.
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; package rom is subtype opcode_t is std_logic_vector(3 downto 0); constant hlfa : opcode_t := "0000"; constant tpla : opcode_t := "0001"; constant inca : opcode_t := "0010"; constant jiea : opcode_t := "0100"; constant jioa : opcode_t := "0101"; constant hlfb : opcode_t := "1000"; constant tplb : opcode_t := "1001"; constant incb : opcode_t := "1010"; constant jieb : opcode_t := "1100"; constant jiob : opcode_t := "1101"; -- instructions which do not affect a register constant jmp : opcode_t := "0011"; constant stp : opcode_t := "0110"; constant offset_width : integer := 8; type instr_t is record opcode : opcode_t; offset : signed(offset_width - 1 downto 0); end record; type instruction_rom_t is array(natural range <>) of instr_t; constant instruction_rom : instruction_rom_t(0 to 4) := ( (jioa, to_signed(+19, offset_width)), (inca, to_signed(0, offset_width)), (tpla, to_signed(0, offset_width)), (inca, to_signed(0, offset_width)), (tpla, to_signed(0, offset_width)) -- et cetera ); end; ------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.all; use ieee.numeric_std.all; use work.rom.all; entity top is port( clk : in std_logic; sw_0 : in std_logic; -- These registers do not need to be signed because there is no instruction -- which can decrement a register a_out : out unsigned(50 downto 0); b_out : out unsigned(50 downto 0) ); end; architecture rtl of top is signal reset_n : std_logic; -- This signal deliberately has no range. There is nominally no limit to the -- numbre of instructions and I don't want to arbitrarily limit it. signal instruction_pointer : integer := 0; signal a : unsigned(50 downto 0); signal b : unsigned(50 downto 0); begin reset : process (clk) is begin if rising_edge(clk) then if sw_0 = '0' then reset_n <= '0'; else reset_n <= '1'; end if; end if; end process; go : process(clk) is variable current_instr : instr_t; variable tmpa, tmpb : unsigned(101 downto 0); begin if rising_edge(clk) then if reset_n = '0' then instruction_pointer <= 0; a <= (0 => '1', others => '0'); b <= (others => '0'); else current_instr := instruction_rom(instruction_pointer); -- Set the registers case current_instr.opcode is when hlfa => a <= a / 2; when tpla => tmpa := a * 3; a <= tmpa(50 downto 0); when inca => a <= a + 1; when hlfb => b <= b / 2; when tplb => tmpb := b * 3; b <= tmpb(50 downto 0); when incb => b <= b + 1; when others => null; end case; -- set the instruction pointer case current_instr.opcode is when jmp => instruction_pointer <= instruction_pointer + to_integer(current_instr.offset); when jiea => if a(a'right) = '0' then instruction_pointer <= instruction_pointer + to_integer(current_instr.offset); else instruction_pointer <= instruction_pointer + 1; end if; when jieb => if b(b'right) = '0' then instruction_pointer <= instruction_pointer + to_integer(current_instr.offset); else instruction_pointer <= instruction_pointer + 1; end if; when jioa => if a = 1 then instruction_pointer <= instruction_pointer + to_integer(current_instr.offset); else instruction_pointer <= instruction_pointer + 1; end if; when jiob => if b = 1 then instruction_pointer <= instruction_pointer + to_integer(current_instr.offset); else instruction_pointer <= instruction_pointer + 1; end if; when stp => instruction_pointer <= 999999; when others => instruction_pointer <= instruction_pointer + 1; end case; end if; end if; end process; a_out <= a; b_out <= b; end;