From eb8643ddbef43547eb7bfe58789a3908926c7258 Mon Sep 17 00:00:00 2001 From: Vaino Kauppila Date: Sun, 19 Apr 2026 12:32:58 +0300 Subject: refactor dir structure, add fib.c --- hdl/ALU.vhd | 216 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 216 insertions(+) create mode 100644 hdl/ALU.vhd (limited to 'hdl/ALU.vhd') diff --git a/hdl/ALU.vhd b/hdl/ALU.vhd new file mode 100644 index 0000000..b7c0344 --- /dev/null +++ b/hdl/ALU.vhd @@ -0,0 +1,216 @@ +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; -- cgit v1.3