summaryrefslogtreecommitdiffstats
path: root/PIC/decoder.vhd
diff options
context:
space:
mode:
Diffstat (limited to 'PIC/decoder.vhd')
-rw-r--r--PIC/decoder.vhd155
1 files changed, 155 insertions, 0 deletions
diff --git a/PIC/decoder.vhd b/PIC/decoder.vhd
new file mode 100644
index 0000000..5a1eb2c
--- /dev/null
+++ b/PIC/decoder.vhd
@@ -0,0 +1,155 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use work.alu_types.all;
+
+package decoder is
+ type instruction_class_t is (
+ BIT_OP,
+ BYTE_OP,
+ LITERAL_OP,
+ CONTROL_OP,
+ UNKNOWN
+ );
+
+ type instruction_t is record
+ class : instruction_class_t;
+ op : alu_op;
+ f : std_logic_vector(6 downto 0);
+ b : std_logic_vector(2 downto 0);
+ d : std_logic;
+ k : std_logic_vector(10 downto 0);
+ end record;
+
+ pure function instruction_get_class(opc : std_logic_vector(13 downto 0)) return instruction_class_t;
+
+ pure function instruction_get_operation(
+ opc : std_logic_vector(13 downto 0);
+ instr_class : instruction_class_t)
+ return alu_op;
+
+ pure function instruction_decode(opc : std_logic_vector(13 downto 0)) return instruction_t;
+
+end package;
+
+package body decoder is
+
+ pure function instruction_decode(opc : std_logic_vector(13 downto 0))
+ return instruction_t is
+ variable instr : instruction_t;
+ begin
+ instr.class := instruction_get_class(opc);
+ instr.op := instruction_get_operation(opc, instr.class);
+
+ instr.f := (others => '0');
+ instr.b := (others => '0');
+ instr.d := '0';
+ instr.k := (others => '0');
+
+ case instr.class is
+ when BIT_OP =>
+ instr.b := opc(9 downto 7);
+ instr.f := opc(6 downto 0);
+ when BYTE_OP =>
+ instr.f := opc(6 downto 0);
+ instr.d := opc(7);
+ when LITERAL_OP | CONTROL_OP =>
+ instr.k := opc(10 downto 0);
+ when UNKNOWN =>
+ end case;
+
+ return instr;
+ end function;
+
+ pure function instruction_get_class(opc : std_logic_vector(13 downto 0))
+ return instruction_class_t is
+ begin
+ -- RETURN (0x0008) has bits[13:12]="00" but must be treated as LITERAL_OP
+ if opc = "00000000001000" then return LITERAL_OP; end if;
+ case opc(13 downto 12) is
+ -- byte-oriented file-register operations
+ when "00" =>
+ return BYTE_OP;
+ when "01" =>
+ return BIT_OP;
+ when "10" =>
+ return CONTROL_OP;
+ when "11" =>
+ return LITERAL_OP;
+ when others =>
+ return UNKNOWN;
+ end case;
+ end function;
+
+ pure function instruction_get_operation(
+ opc : std_logic_vector(13 downto 0);
+ instr_class : instruction_class_t)
+ return alu_op is
+ begin
+ case instr_class is
+
+ when BYTE_OP =>
+ case opc(11 downto 8) is
+ when "0000" =>
+ if opc(7) = '1' then return MOVWF;
+ else return NOP;
+ end if;
+ when "0001" =>
+ if opc(7) = '1' then return CLRF;
+ else return CLRW;
+ end if;
+ when "0010" => return SUBWF;
+ when "0011" => return DECF;
+ when "0100" => return IORWF;
+ when "0101" => return ANDWF;
+ when "0110" => return XORWF;
+ when "0111" => return ADDWF;
+ when "1000" => return MOVF;
+ when "1001" => return COMF;
+ when "1010" => return INCF;
+ when "1011" => return DECFSZ;
+ when "1100" => return RRF;
+ when "1101" => return RLF;
+ when "1110" => return SWAPF;
+ when "1111" => return INCFSZ;
+ when others => return NOP;
+ end case;
+
+ when BIT_OP =>
+ case opc(11 downto 10) is
+ when "00" => return BCF;
+ when "01" => return BSF;
+ when "10" => return BTFSC;
+ when "11" => return BTFSS;
+ when others => return NOP;
+ end case;
+
+ when CONTROL_OP =>
+ if opc(11) = '1' then return GOTO;
+ else return CALL;
+ end if;
+
+ when LITERAL_OP =>
+ -- fixed full-word patterns first (fall inside 00xx space)
+ -- if opc(11 downto 0) = "000000000001" then return RETFIE;
+ if opc(11 downto 0) = "000000001000" then return RETUR;
+ -- elsif opc(11 downto 0) = "000000000011" then return SLEEP;
+ -- elsif opc(11 downto 0) = "000000000100" then return CLRWDT;
+ else
+ case? opc(11 downto 8) is
+ when "00--" => return MOVLW;
+ when "01--" => return RETLW;
+ when "1000" => return IORLW;
+ when "1001" => return ANDLW;
+ when "1010" => return XORLW;
+ when "110-" => return SUBLW;
+ when "111-" => return ADDLW;
+ when others => return NOP;
+ end case?;
+ end if;
+
+ when others => return NOP;
+
+ end case;
+ end function;
+
+end decoder;