library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use work.alu_types.all; entity alu is port ( a, b : in std_logic_vector(7 downto 0); -- inputs to ALU. In -- general here 'a' is -- a value from working -- register W and 'b' -- is from a file -- register. op : in alu_op; -- ALU operation which -- one to use bit_select : in std_logic_vector(2 downto 0); -- this is the 'b' signal in -- the datasheet. status_in : in std_logic_vector(2 downto 0); -- status before ALU operation. status : out std_logic_vector(2 downto 0); -- status after ALU operation. result : out std_logic_vector(7 downto 0); -- result of the ALU -- operation. This is -- then either stored -- in file register f -- or work register W. skip : out std_logic -- SKIP signal. -- the status register is of form: -- IRP RP1 RP0 ~TO ~PD Z DC C -- 7 6 5 4 3 2 1 0 -- ALU only operates on 3 least significant bits. ); end entity alu; architecture rtl of alu is -- ternary op; returns x1 if cond is true, x2 otherwise. pure function sel(cond : boolean; x1, x2 : std_logic) return std_logic is begin if cond then return x1; else return x2; end if; end function; -- return status with the given flag set to val, all other bits same pure function set_flag(flag : alu_flag; val : std_logic; stat : std_logic_vector(2 downto 0)) return std_logic_vector is variable s_out : std_logic_vector(2 downto 0) := stat; begin case flag is when FLAG_Z => s_out(2) := val; when FLAG_DC => s_out(1) := val; when FLAG_C => s_out(0) := val; end case; return s_out; end function; -- Computes val +/- 1, drives result and either sets Z flag or skip signal. procedure inc_dec( val : in std_logic_vector(7 downto 0); inc : in boolean; -- true = increment, false = decrement do_skip : in boolean; -- true for *FSZ variants signal res : out std_logic_vector(7 downto 0); signal stat : out std_logic_vector(2 downto 0); signal do_skip_out : out std_logic; stat_in : in std_logic_vector(2 downto 0) ) is variable t : std_logic_vector(7 downto 0); begin if inc then t := std_logic_vector(unsigned(val) + 1); else t := std_logic_vector(unsigned(val) - 1); end if; res <= t; if do_skip then if unsigned(t) = 0 then do_skip_out <= '1'; else do_skip_out <= '0'; end if; else stat <= set_flag(FLAG_Z, sel(unsigned(t) = 0, '1', '0'), stat_in); end if; end procedure; begin process(a, b, op, bit_select, status_in) variable tmp : std_logic_vector(7 downto 0); variable tmp_extended : std_logic_vector(8 downto 0); variable tmp_status : std_logic_vector(2 downto 0); begin -- DEFAULT case (NOP) result <= (others => '0'); -- default: zero result skip <= '0'; -- default: no skip status <= status_in; -- default: pass status thru case op is when NOP => -- nothing when ADDWF | ADDLW => -- addition tmp_extended := std_logic_vector(unsigned('0' & a) + unsigned('0' & b)); -- DC tmp(4 downto 0) := std_logic_vector(('0' & unsigned(a(3 downto 0))) + ('0' & unsigned(b(3 downto 0)))); -- flags tmp_status := set_flag(FLAG_Z, sel(unsigned(tmp_extended(7 downto 0)) = 0, '1', '0'), status_in); tmp_status := set_flag(FLAG_C, tmp_extended(8), tmp_status); tmp_status := set_flag(FLAG_DC, tmp(4), tmp_status); status <= tmp_status; result <= tmp_extended(7 downto 0); when SUBLW | SUBWF => -- PIC16F84A: SUBWF = f - W, SUBLW = k - W → dest = b - a tmp_extended := std_logic_vector(unsigned('0' & b) - unsigned('0' & a)); -- DC: borrow out of lower nibble tmp(4 downto 0) := std_logic_vector(('0' & unsigned(b(3 downto 0))) - ('0' & unsigned(a(3 downto 0)))); tmp_status := set_flag(FLAG_Z, sel(unsigned(tmp_extended(7 downto 0)) = 0, '1', '0'), status_in); tmp_status := set_flag(FLAG_C, not tmp_extended(8), tmp_status); tmp_status := set_flag(FLAG_DC, not tmp(4), tmp_status); status <= tmp_status; result <= tmp_extended(7 downto 0); when IORLW | IORWF => tmp := a or b; result <= tmp; status <= set_flag(FLAG_Z, sel(unsigned(tmp) = 0, '1', '0'), status_in); when ANDWF | ANDLW => tmp := a and b; result <= tmp; status <= set_flag(FLAG_Z, sel(unsigned(tmp) = 0, '1', '0'), status_in); when XORLW | XORWF => tmp := a xor b; result <= tmp; status <= set_flag(FLAG_Z, sel(unsigned(tmp) = 0, '1', '0'), status_in); when COMF => tmp := not b; result <= tmp; status <= set_flag(FLAG_Z, sel(unsigned(tmp) = 0, '1', '0'), status_in); when DECF => inc_dec(b, false, false, result, status, skip, status_in); when DECFSZ => inc_dec(b, false, true, result, status, skip, status_in); when INCF => inc_dec(b, true, false, result, status, skip, status_in); when INCFSZ => inc_dec(b, true, true, result, status, skip, status_in); when RLF => tmp := std_logic_vector(shift_left(unsigned(b), 1)); tmp(0) := status_in(0); status(0) <= b(7); result <= tmp; when RRF => tmp := std_logic_vector(shift_right(unsigned(b), 1)); tmp(7) := status_in(0); status(0) <= b(0); result <= tmp; when BCF => result <= b; result(to_integer(unsigned(bit_select))) <= '0'; when BTFSC => skip <= not b(to_integer(unsigned(bit_select))); when BSF => result <= b; result(to_integer(unsigned(bit_select))) <= '1'; when BTFSS => skip <= b(to_integer(unsigned(bit_select))); when SWAPF => tmp(7 downto 4) := b(3 downto 0); tmp(3 downto 0) := b(7 downto 4); result <= tmp; when CLRF | CLRW => result <= (others => '0'); status <= set_flag(FLAG_Z, '1', status_in); when MOVF => result <= b; status <= set_flag(FLAG_Z, sel(unsigned(b) = 0, '1', '0'), status_in); when MOVWF => result <= a; when MOVLW => result <= b; when CALL => null; when GOTO => null; when RETLW => result <= b; when RETUR => null; end case; end process; end architecture rtl;