summaryrefslogtreecommitdiffstats
path: root/hdl/ALU.vhd
diff options
context:
space:
mode:
authorVaino Kauppila <vaino@vke.fi>2026-04-19 12:32:58 +0300
committerVaino Kauppila <vaino@vke.fi>2026-04-19 12:32:58 +0300
commiteb8643ddbef43547eb7bfe58789a3908926c7258 (patch)
treefadfba88a1c71b266b8c67df166a3a6ead6b30d1 /hdl/ALU.vhd
parent129a1c975dbd0c042576010b1f6eb40d19fc5733 (diff)
downloadvhdl_pic-eb8643ddbef43547eb7bfe58789a3908926c7258.tar.gz
vhdl_pic-eb8643ddbef43547eb7bfe58789a3908926c7258.zip
refactor dir structure, add fib.c
Diffstat (limited to 'hdl/ALU.vhd')
-rw-r--r--hdl/ALU.vhd216
1 files changed, 216 insertions, 0 deletions
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;