diff options
| author | Väinö Kauppila <vaino@vke.fi> | 2026-04-19 00:33:08 +0300 |
|---|---|---|
| committer | Väinö Kauppila <vaino@vke.fi> | 2026-04-19 00:33:08 +0300 |
| commit | 8bd8dd6ce07fb8e247f651b3c61c94bb1f00895a (patch) | |
| tree | 87bd95bd073d68efd0ad31a34f0d8926c32ff6db /PIC | |
| download | vhdl_pic-8bd8dd6ce07fb8e247f651b3c61c94bb1f00895a.tar.gz vhdl_pic-8bd8dd6ce07fb8e247f651b3c61c94bb1f00895a.zip | |
starting files and example programs
Diffstat (limited to 'PIC')
| -rw-r--r-- | PIC/ALU.vhd | 211 | ||||
| -rw-r--r-- | PIC/PIC.vhd | 181 | ||||
| -rw-r--r-- | PIC/blink.c | 35 | ||||
| -rw-r--r-- | PIC/common.vhd | 10 | ||||
| -rw-r--r-- | PIC/decoder.vhd | 155 | ||||
| -rw-r--r-- | PIC/dpram.vhd | 110 | ||||
| -rw-r--r-- | PIC/fifo.vhd | 75 | ||||
| -rw-r--r-- | PIC/hdl-prj.json | 24 | ||||
| -rw-r--r-- | PIC/hexfile_reader.vhd | 342 | ||||
| -rw-r--r-- | PIC/pic_top.vhd | 81 | ||||
| -rw-r--r-- | PIC/prog_rom.vhd | 1045 | ||||
| -rw-r--r-- | PIC/stack.vhd | 51 | ||||
| -rw-r--r-- | PIC/state_machine.vhd | 224 | ||||
| -rw-r--r-- | PIC/tb_pic.vhd | 83 | ||||
| -rw-r--r-- | PIC/tb_stack.vhd | 121 | ||||
| -rw-r--r-- | PIC/test_uart.c | 36 | ||||
| -rw-r--r-- | PIC/uart.vhd | 195 |
17 files changed, 2979 insertions, 0 deletions
diff --git a/PIC/ALU.vhd b/PIC/ALU.vhd new file mode 100644 index 0000000..ac770a6 --- /dev/null +++ b/PIC/ALU.vhd @@ -0,0 +1,211 @@ +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 + do_skip_out <= '1' when unsigned(t) = 0 else '0'; + 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 => + 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)))); + + 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; diff --git a/PIC/PIC.vhd b/PIC/PIC.vhd new file mode 100644 index 0000000..a31bec7 --- /dev/null +++ b/PIC/PIC.vhd @@ -0,0 +1,181 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.alu_types.all; + +entity PIC is + generic ( + CLK_FREQ : positive := 50_000_000; -- 50M, GW5A clock + BAUD_RATE : positive := 115_200 + ); + port ( + clk : in std_logic; + reset : in std_logic; + opcode : in std_logic_vector(13 downto 0); + + program_counter : out std_logic_vector(12 downto 0) := (others => '0'); + instruction_return : out std_logic := '0'; + work_reg : out std_logic_vector(7 downto 0) := (others => '0'); + status : out std_logic_vector(2 downto 0) := (others => '0'); + port_a : out std_logic_vector(7 downto 0) := (others => '0'); + port_b : out std_logic_vector(7 downto 0) := (others => '0'); + + -- UART physical pins + uart_tx : out std_logic; + uart_rx : in std_logic + ); +end entity PIC; + +architecture rtl of PIC is + signal W : std_logic_vector(7 downto 0) := (others => '0'); + + signal alu_operation : alu_op; + signal alu_result : std_logic_vector(7 downto 0); + signal alu_skip : std_logic; + + signal mem_q : std_logic_vector(7 downto 0); + signal mem_qstatus : std_logic_vector(2 downto 0); + signal mem_we : std_logic; + signal mem_re : std_logic; + + signal bit_select : std_logic_vector(2 downto 0); + signal addr : std_logic_vector(6 downto 0); + signal sm_data : std_logic_vector(7 downto 0); + signal sm_pc : std_logic_vector(12 downto 0); + signal we_w : std_logic; + signal instr_ret : std_logic; + signal alu_status : std_logic_vector(2 downto 0); + + signal use_literal : std_logic; + signal we_status : std_logic; + signal b_operand : std_logic_vector(7 downto 0); + + signal stack_push : std_logic; + signal stack_pop : std_logic; + signal stack_din : std_logic_vector(12 downto 0); + signal stack_dout : std_logic_vector(12 downto 0); + + -- UART <-> dpram bridge signals + signal uart_tx_byte : std_logic_vector(7 downto 0); + signal uart_tx_send : std_logic; + signal uart_tx_done : std_logic; + signal uart_rx_byte : std_logic_vector(7 downto 0); + signal uart_rx_rd_en : std_logic; + signal uart_rx_empty : std_logic; + signal uart_rx_full : std_logic; + +begin + + work_reg <= W; + program_counter <= sm_pc; + instruction_return <= instr_ret; + status <= alu_status; + + b_operand_select : process(use_literal, sm_data, mem_q) + begin + if use_literal = '1' then + b_operand <= sm_data; + else + b_operand <= mem_q; + end if; + end process; + + w_reg : process(clk) + begin + if rising_edge(clk) then + if we_w = '1' then + W <= alu_result; + end if; + end if; + end process w_reg; + + sm : entity work.state_machine(rtl) + port map ( + clk => clk, + opcode => opcode, + reset => reset, + op => alu_operation, + we_mem => mem_we, + re_mem => mem_re, + we_w => we_w, + instr_ret => instr_ret, + bit_select => bit_select, + data => sm_data, + pc => sm_pc, + addr => addr, + use_literal => use_literal, + we_status => we_status, + stack_push => stack_push, + stack_pop => stack_pop, + stack_din => stack_din, + stack_dout => stack_dout, + alu_skip => alu_skip, + alu_result => alu_result + ); + + alu : entity work.alu(rtl) + port map ( + a => W, + b => b_operand, + op => alu_operation, + bit_select => bit_select, + status_in => mem_qstatus, + result => alu_result, + status => alu_status, + skip => alu_skip + ); + + stk : entity work.stack(rtl) + port map ( + clk => clk, + reset => reset, + push => stack_push, + pop => stack_pop, + din => stack_din, + dout => stack_dout + ); + + mem : entity work.dpram(rtl) + generic map (DEPTH => 128) + port map ( + clk => clk, + we => mem_we, + re => mem_re, + d => alu_result, + d_status => "00000" & alu_status, + addr => addr, + q => mem_q, + q_status => mem_qstatus, + port_a => port_a, + port_b => port_b, + we_status => we_status, + uart_tx_byte => uart_tx_byte, + uart_tx_send => uart_tx_send, + uart_tx_done => uart_tx_done, + uart_rx_byte => uart_rx_byte, + uart_rx_rd_en => uart_rx_rd_en, + uart_rx_empty => uart_rx_empty, + uart_rx_full => uart_rx_full + ); + + uart_inst : entity work.uart + generic map ( + CLK_FREQ => CLK_FREQ, + BAUD_RATE => BAUD_RATE, + CLKS_PER_BIT => CLK_FREQ / BAUD_RATE + ) + port map ( + clk => clk, + tx_should_send => uart_tx_send, + byte_in => uart_tx_byte, + tx_done => uart_tx_done, + baud_tick => open, + uart_tx => uart_tx, + uart_rx => uart_rx, + rd_en => uart_rx_rd_en, + rx_data => uart_rx_byte, + rx_empty => uart_rx_empty, + rx_full => uart_rx_full + ); + +end architecture rtl; diff --git a/PIC/blink.c b/PIC/blink.c new file mode 100644 index 0000000..6789b0a --- /dev/null +++ b/PIC/blink.c @@ -0,0 +1,35 @@ +#include <pic16f84a.h> + +typedef unsigned char uint8_t; + +// Global volatile so sdcc cannot optimise the delay loops away. +static volatile uint8_t _d0, _d1, _d2; + +// Busy-wait ~500 ms at 50 MHz. +// 200 × 256 × 256 = 13 107 200 inner iterations. +// Each iteration ≈ 3 uint8_t instructions × 20 ns = 60 ns. +// Total ≈ 786 ms (tune outer count _d0 < N to taste). +static void delay(void) { + _d0 = 0; + do { + _d1 = 0; + do { + _d2 = 0; + do { _d2++; } while (_d2 != 0); + } while (++_d1 != 30); + _d0++; + } while (_d0 != 116); +} + +void main(void) { + // port_b(0) drives activity_led at E8 on the Tang Primer 25K. + // port_a(0) drives led at L6. Both ports are always outputs in this CPU. + while (1) { + PORTB = 0x01; // activity_led (E8) on + PORTA = 0x01; // led (L6) on + delay(); + PORTB = 0x00; // activity_led (E8) off + PORTA = 0x00; // led (L6) off + delay(); + } +} diff --git a/PIC/common.vhd b/PIC/common.vhd new file mode 100644 index 0000000..c986ec5 --- /dev/null +++ b/PIC/common.vhd @@ -0,0 +1,10 @@ +package alu_types is + type alu_op is (ADDWF, ANDWF, ADDLW, ANDLW, BCF, BTFSC, + BSF, BTFSS, CLRF, CLRW, COMF, DECF, + DECFSZ, INCF, INCFSZ, IORLW, MOVF, MOVWF, CALL, + GOTO, MOVLW, RETLW, RETUR, IORWF, NOP, + RLF, RRF, SUBLW, SUBWF, SWAPF, XORLW, XORWF); + + -- Status register bits: Z=2, DC=1, C=0 + type alu_flag is (FLAG_Z, FLAG_DC, FLAG_C); +end package; 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; diff --git a/PIC/dpram.vhd b/PIC/dpram.vhd new file mode 100644 index 0000000..44d7adf --- /dev/null +++ b/PIC/dpram.vhd @@ -0,0 +1,110 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +-- Data memory with UART memory-mapped registers. +-- Addresses 0x70-0x72 are used (unimplemented in real PIC16F84A, no header conflict): +-- 0x70 UART_TX write: send byte (held until tx_done) +-- 0x71 UART_RX read: current FIFO head (FWFT), pulses rd_en to pop +-- 0x72 UART_STATUS read: "00000" & rx_full & rx_empty & tx_busy + +entity dpram is + generic (DEPTH : positive := 128); + port ( + clk : in std_logic; + we : in std_logic; + re : in std_logic; + d : in std_logic_vector(7 downto 0); + d_status : in std_logic_vector(7 downto 0); + addr : in std_logic_vector(6 downto 0); + q : out std_logic_vector(7 downto 0); + q_status : out std_logic_vector(2 downto 0); + + port_a : out std_logic_vector(7 downto 0); + port_b : out std_logic_vector(7 downto 0); + we_status : in std_logic; + + -- UART interface + uart_tx_byte : out std_logic_vector(7 downto 0) := (others => '0'); + uart_tx_send : out std_logic := '0'; + uart_tx_done : in std_logic; + uart_rx_byte : in std_logic_vector(7 downto 0); + uart_rx_rd_en : out std_logic := '0'; + uart_rx_empty : in std_logic; + uart_rx_full : in std_logic + ); +end entity dpram; + +architecture rtl of dpram is + type mem_t is + array (0 to DEPTH - 1) + of std_logic_vector(7 downto 0); + + signal mem : mem_t := (others => (others => '0')); + signal uart_tx_pending : std_logic := '0'; + +begin + -- STATUS output is combinatorial + q_status <= mem(16#03#)(2 downto 0); + + port_a <= mem(16#05#); + port_b <= mem(16#06#); + + -- tx_send is high while a transmission is in progress + uart_tx_send <= uart_tx_pending; + + -- SR: set when CPU writes to 0x08, clear when UART asserts tx_done + tx_ctrl : process(clk) + begin + if rising_edge(clk) then + if we = '1' and addr = "1110000" then -- 0x70 UART_TX + uart_tx_byte <= d; + uart_tx_pending <= '1'; + elsif uart_tx_done = '1' then + uart_tx_pending <= '0'; + end if; + end if; + end process tx_ctrl; + + read : process(clk) + begin + if rising_edge(clk) then + uart_rx_rd_en <= '0'; -- default: no pop + if re = '1' then + if addr = "1110001" then -- 0x71 UART_RX + q <= uart_rx_byte; -- FWFT head, valid combinatorially + if uart_rx_empty = '0' then + uart_rx_rd_en <= '1'; -- advance FIFO pointer + end if; + elsif addr = "1110010" then -- 0x72 UART_STATUS + q <= "00000" & uart_rx_full & uart_rx_empty & uart_tx_pending; + else + q <= mem(to_integer(unsigned(addr))); + end if; + end if; + end if; + end process read; + + write : process(clk) + begin + if rising_edge(clk) then + if we_status = '1' then + mem(16#03#) <= d_status; + end if; + if we = '1' then + if addr = "0000011" then -- 0x03 STATUS: direct write + mem(16#03#) <= d; + elsif addr = "1110000" or -- 0x70 UART_TX + addr = "1110001" or -- 0x71 UART_RX (read-only but handled gracefully) + addr = "1110010" then -- 0x72 UART_STATUS (read-only) + -- UART-mapped addresses: don't write to RAM; still update STATUS + mem(16#03#) <= d_status; + else + mem(16#03#) <= d_status; + mem(to_integer(unsigned(addr))) <= d; + end if; + end if; + end if; + end process write; + +end architecture rtl; diff --git a/PIC/fifo.vhd b/PIC/fifo.vhd new file mode 100644 index 0000000..9dd8523 --- /dev/null +++ b/PIC/fifo.vhd @@ -0,0 +1,75 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +-- First-word fall-through (FWFT) FIFO. +-- dout always presents the current head combinatorially (no read latency). +-- rd_en advances the read pointer; the next head is visible on the same cycle. +-- DEPTH must be a power of 2; ADDR_BITS = log2(DEPTH). + +entity fifo is + generic ( + DEPTH : positive := 16; + ADDR_BITS : positive := 4; + WIDTH : positive := 8 + ); + port ( + clk : in std_logic; + wr_en : in std_logic; + rd_en : in std_logic; + din : in std_logic_vector(WIDTH - 1 downto 0); + dout : out std_logic_vector(WIDTH - 1 downto 0); + full : out std_logic; + empty : out std_logic + ); +end entity fifo; + +architecture rtl of fifo is + + -- MSB pointer trick: pointers are ADDR_BITS+1 wide. + -- Empty: read_ptr = write_ptr + -- Full: (read_ptr XOR write_ptr) = DEPTH (MSBs differ, lower bits equal) + signal read_ptr : unsigned(ADDR_BITS downto 0) := (others => '0'); + signal write_ptr : unsigned(ADDR_BITS downto 0) := (others => '0'); + + type mem_t is + array (0 to DEPTH - 1) + of std_logic_vector(WIDTH - 1 downto 0); + + signal mem : mem_t := (others => (others => '0')); + + signal empty_i : std_logic; + signal full_i : std_logic; + +begin + + empty_i <= '1' when read_ptr = write_ptr else '0'; + full_i <= '1' when (read_ptr xor write_ptr) = to_unsigned(DEPTH, ADDR_BITS + 1) + else '0'; + + empty <= empty_i; + full <= full_i; + + -- FWFT: head is always visible without asserting rd_en + dout <= mem(to_integer(read_ptr(ADDR_BITS - 1 downto 0))); + + enqueue : process(clk) + begin + if rising_edge(clk) then + if wr_en = '1' and full_i = '0' then + mem(to_integer(write_ptr(ADDR_BITS - 1 downto 0))) <= din; + write_ptr <= write_ptr + 1; + end if; + end if; + end process enqueue; + + dequeue : process(clk) + begin + if rising_edge(clk) then + if rd_en = '1' and empty_i = '0' then + read_ptr <= read_ptr + 1; + end if; + end if; + end process dequeue; + +end architecture rtl; diff --git a/PIC/hdl-prj.json b/PIC/hdl-prj.json new file mode 100644 index 0000000..b557c2b --- /dev/null +++ b/PIC/hdl-prj.json @@ -0,0 +1,24 @@ +{ + "options": { + "ghdl_analysis": [ + "-fexplicit", + "--std=08" + ] + }, + "files": [ + { "file": "common.vhd", "language": "vhdl" }, + { "file": "decoder.vhd", "language": "vhdl" }, + { "file": "hexfile_reader.vhd", "language": "vhdl" }, + { "file": "fifo.vhd", "language": "vhdl" }, + { "file": "uart.vhd", "language": "vhdl" }, + { "file": "ALU.vhd", "language": "vhdl" }, + { "file": "stack.vhd", "language": "vhdl" }, + { "file": "dpram.vhd", "language": "vhdl" }, + { "file": "state_machine.vhd", "language": "vhdl" }, + { "file": "PIC.vhd", "language": "vhdl" }, + { "file": "prog_rom.vhd", "language": "vhdl" }, + { "file": "pic_top.vhd", "language": "vhdl" }, + { "file": "tb_stack.vhd", "language": "vhdl" }, + { "file": "tb_pic.vhd", "language": "vhdl" } + ] +} diff --git a/PIC/hexfile_reader.vhd b/PIC/hexfile_reader.vhd new file mode 100644 index 0000000..143a264 --- /dev/null +++ b/PIC/hexfile_reader.vhd @@ -0,0 +1,342 @@ +------------------------------------------------------------------------------- +--Usage of the reader: +-- +--CONSTANT ihex_data : STRING := +--"/home/pro/autosub/erkka/digital/matlab/esim.HEX; +--VARIABLE memory : program_array := (OTHERS => (OTHERS => '0')); +-- +--read_ihex_file(ihex_data, memory); +-- +-- If some constant definitions are missing, try to figure them out. +-- If you can't contact Erkka Laulainen, elaulain@ecdl.tkk.fi, room I313A +------------------------------------------------------------------------------- + +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +--USE ieee.std_logic_arith.ALL; +USE ieee.numeric_std.ALL; +USE std.textio.ALL; +USE ieee.std_logic_textio.ALL; +USE ieee.std_logic_misc.ALL; + + +PACKAGE read_intel_hex_pack IS + CONSTANT debug : BOOLEAN := true; + + ------------------------------------------------------------------------------ + ----- Design Parameters ----------------------------------------------------- + ------------------------------------------------------------------------------ + + CONSTANT Inst_bits : INTEGER := 14; + CONSTANT data_bits : INTEGER := 8; + CONSTANT inst_mem_size : INTEGER := 1024; + TYPE program_array IS ARRAY (0 TO inst_mem_size-1) OF STD_LOGIC_VECTOR(Inst_bits-1 DOWNTO 0); + + ------------------------------------------------------------------------------ + ----- Reset Values ----------------------------------------------------------- + ------------------------------------------------------------------------------ + +-- CONSTANT W_RESET : STD_ULOGIC_VECTOR(data_bits-1 DOWNTO 0) := "XXXXXXXX"; +-- CONSTANT INDF_RESET : STD_ULOGIC_VECTOR(data_bits-1 DOWNTO 0) := "--------"; +-- CONSTANT TMR0_RESET : STD_ULOGIC_VECTOR(data_bits-1 DOWNTO 0) := "XXXXXXXX"; +-- CONSTANT PCL_RESET : STD_ULOGIC_VECTOR(data_bits-1 DOWNTO 0) := "00000000"; +-- CONSTANT STATUS_RESET : STD_ULOGIC_VECTOR(data_bits-1 DOWNTO 0) := "00011XXX"; +-- CONSTANT FSR_RESET : STD_ULOGIC_VECTOR(data_bits-1 DOWNTO 0) := "XXXXXXXX"; +-- CONSTANT PORTA_RESET : STD_ULOGIC_VECTOR(4 DOWNTO 0) := "XXXXX"; +-- CONSTANT PORTB_RESET : STD_ULOGIC_VECTOR(data_bits-1 DOWNTO 0) := "XXXXXXXX"; +-- CONSTANT EEDATA_RESET : STD_ULOGIC_VECTOR(data_bits-1 DOWNTO 0) := "XXXXXXXX"; +-- CONSTANT EEADR_RESET : STD_ULOGIC_VECTOR(data_bits-1 DOWNTO 0) := "XXXXXXXX"; +-- CONSTANT PCLATH_RESET : STD_ULOGIC_VECTOR(4 DOWNTO 0) := "00000"; +-- CONSTANT INTCON_RESET : STD_ULOGIC_VECTOR(data_bits-1 DOWNTO 0) := "0000000X"; +-- CONSTANT OPTION_REG_RESET : STD_ULOGIC_VECTOR(data_bits-1 DOWNTO 0) := "11111111"; +-- CONSTANT TRISA_RESET : STD_ULOGIC_VECTOR(4 DOWNTO 0) := "11111"; +-- CONSTANT TRISB_RESET : STD_ULOGIC_VECTOR(data_bits-1 DOWNTO 0) := "11111111"; +-- CONSTANT EECON1_RESET : STD_ULOGIC_VECTOR(4 DOWNTO 0) := "0X000"; +-- CONSTANT EECON2_RESET : STD_ULOGIC_VECTOR(data_bits-1 DOWNTO 0) := "--------"; + + ------------------------------------------------------------------------------ + ----- Operations Codes ------------------------------------------------------- + ------------------------------------------------------------------------------ + + ----- BYTE-ORIENTED FILE REGISTER OPERATIONS --------------------------------- + +-- CONSTANT ADDWF : STD_ULOGIC_VECTOR := "000111--------"; +-- CONSTANT ANDWF : STD_ULOGIC_VECTOR := "000101--------"; +-- CONSTANT CLRF : STD_ULOGIC_VECTOR := "0000011-------"; +-- CONSTANT CLRW : STD_ULOGIC_VECTOR := "0000010-------"; +-- CONSTANT COMF : STD_ULOGIC_VECTOR := "001001--------"; +-- CONSTANT DECF : STD_ULOGIC_VECTOR := "000011--------"; +-- CONSTANT DECFSZ : STD_ULOGIC_VECTOR := "001011--------"; +-- CONSTANT INCF : STD_ULOGIC_VECTOR := "001010--------"; +-- CONSTANT INCFSZ : STD_ULOGIC_VECTOR := "001111--------"; +-- CONSTANT IORWF : STD_ULOGIC_VECTOR := "000100--------"; +-- CONSTANT MOVF : STD_ULOGIC_VECTOR := "001000--------"; +-- CONSTANT MOVWF : STD_ULOGIC_VECTOR := "0000001-------"; +-- CONSTANT NOP : STD_ULOGIC_VECTOR := "0000000--00000"; +-- CONSTANT RLF : STD_ULOGIC_VECTOR := "001101--------"; +-- CONSTANT RRF : STD_ULOGIC_VECTOR := "001100--------"; +-- CONSTANT SUBWF : STD_ULOGIC_VECTOR := "000010--------"; +-- CONSTANT SWAPF : STD_ULOGIC_VECTOR := "001110--------"; +-- CONSTANT XORWF : STD_ULOGIC_VECTOR := "000110--------"; + + ----- BIT-ORIENTED FILE REGISTER OPERATIONS ---------------------------------- + +-- CONSTANT BCF : STD_ULOGIC_VECTOR := "0100----------"; +-- CONSTANT BSF : STD_ULOGIC_VECTOR := "0101----------"; +-- CONSTANT BTFSC : STD_ULOGIC_VECTOR := "0110----------"; +-- CONSTANT BTFSS : STD_ULOGIC_VECTOR := "0111----------"; + + ----- LITERAL AND CONTROL OPERATIONS ----------------------------------------- + +-- CONSTANT ADDLW : STD_ULOGIC_VECTOR := "11111---------"; +-- CONSTANT ANDLW : STD_ULOGIC_VECTOR := "111001--------"; +-- CONSTANT CALL : STD_ULOGIC_VECTOR := "100-----------"; +-- CONSTANT CLRWDT : STD_ULOGIC_VECTOR := "00000001100100"; +-- CONSTANT GOTO : STD_ULOGIC_VECTOR := "101-----------"; +-- CONSTANT IORLW : STD_ULOGIC_VECTOR := "111000--------"; +-- CONSTANT MOVLW : STD_ULOGIC_VECTOR := "1100----------"; +-- CONSTANT RETFIE : STD_ULOGIC_VECTOR := "00000000001001"; +-- CONSTANT RETLW : STD_ULOGIC_VECTOR := "1101----------"; +-- CONSTANT RET : STD_ULOGIC_VECTOR := "00000000001000"; +-- CONSTANT SLEEP : STD_ULOGIC_VECTOR := "00000001100011"; +-- CONSTANT SUBLW : STD_ULOGIC_VECTOR := "11110---------"; +-- CONSTANT XORLW : STD_ULOGIC_VECTOR := "111010--------"; + + ------------------------------------------------------------------------------ + ----- Special Function Register Address -------------------------------------- + ------------------------------------------------------------------------------ + +-- CONSTANT INDF_ADR : STD_ULOGIC_VECTOR := "-0000000"; +-- CONSTANT TMR0_ADR : STD_ULOGIC_VECTOR := "00000001"; +-- CONSTANT PCL_ADR : STD_ULOGIC_VECTOR := "-0000010"; +-- CONSTANT STATUS_ADR : STD_ULOGIC_VECTOR := "-0000011"; +-- CONSTANT FSR_ADR : STD_ULOGIC_VECTOR := "-0000100"; +-- CONSTANT PORTA_ADR : STD_ULOGIC_VECTOR := "00000101"; +-- CONSTANT PORTB_ADR : STD_ULOGIC_VECTOR := "00000110"; +-- CONSTANT EEDATA_ADR : STD_ULOGIC_VECTOR := "00001000"; +-- CONSTANT EEARD_ADR : STD_ULOGIC_VECTOR := "00001001"; +-- CONSTANT PCLATH_ADR : STD_ULOGIC_VECTOR := "-0001010"; +-- CONSTANT INTCON_ADR : STD_ULOGIC_VECTOR := "-0001011"; +-- CONSTANT OPTION_ADR : STD_ULOGIC_VECTOR := "10000001"; +-- CONSTANT TRISA_ADR : STD_ULOGIC_VECTOR := "10000101"; +-- CONSTANT TRISB_ADR : STD_ULOGIC_VECTOR := "10000110"; +-- CONSTANT EECON1_ADR : STD_ULOGIC_VECTOR := "10001000"; +-- CONSTANT EECON2_ADR : STD_ULOGIC_VECTOR := "10001001"; + + ------------------------------------------------------------------------------ + ----- STATUS Register Constants ---------------------------------------------- + ------------------------------------------------------------------------------ + +-- CONSTANT RP0_BIT : INTEGER := 5; +-- CONSTANT TO_BIT : INTEGER := 4; +-- CONSTANT PD_BIT : INTEGER := 3; +-- CONSTANT Z_BIT : INTEGER := 2; +-- CONSTANT DC_BIT : INTEGER := 1; +-- CONSTANT CARRY_BIT : INTEGER := 0; + + ------------------------------------------------------------------------------ + ----- INTCON Register Constants ---------------------------------------------- + ------------------------------------------------------------------------------ + +-- CONSTANT GIE_BIT : INTEGER := 7; +-- CONSTANT EEIE_BIT : INTEGER := 6; +-- CONSTANT T0IE_BIT : INTEGER := 5; +-- CONSTANT INTE_BIT : INTEGER := 4; +-- CONSTANT RBIE_BIT : INTEGER := 3; +-- CONSTANT T0IF_BIT : INTEGER := 2; +-- CONSTANT INTF_BIT : INTEGER := 1; +-- CONSTANT RBIF_BIT : INTEGER := 0; + + ------------------------------------------------------------------------------ + ----- OPTION Register Constants ---------------------------------------------- + ------------------------------------------------------------------------------ + +-- CONSTANT RBPU_BIT : INTEGER := 7; +-- CONSTANT INTEDG_BIT : INTEGER := 6; +-- CONSTANT T0CS_BIT : INTEGER := 5; +-- CONSTANT T0SE_BIT : INTEGER := 4; +-- CONSTANT PSA_BIT : INTEGER := 3; +-- CONSTANT PS2_BIT : INTEGER := 2; +-- CONSTANT PS1_BIT : INTEGER := 1; +-- CONSTANT PS0_BIT : INTEGER := 0; + + PROCEDURE read_ihex_file (program_name : IN STRING; memory : OUT program_array); + +END PACKAGE read_intel_hex_pack; + +PACKAGE BODY read_intel_hex_pack IS + + PROCEDURE str_to_hex (str : IN STRING; result : INOUT NATURAL) IS + VARIABLE ch : CHARACTER; + BEGIN + result := 0; + FOR i IN 1 TO str'LENGTH LOOP + ch := str(i); + IF '0' <= ch and ch <= '9' THEN + result := result*16 + character'pos(ch) - character'pos('0'); + ELSIF 'A' <= ch and ch <= 'F' THEN + result := result*16 + character'pos(ch) - character'pos('A') + 10; + ELSIF 'a' <= ch and ch <= 'f' THEN + result := result*16 + character'pos(ch) - character'pos('a') + 10; + ELSE + -- ASSERT 1; REPORT "FAILURE: str_to_hex: Non-hex character encountered!"; SEVERITY FAILURE; + END IF; + END LOOP; + END str_to_hex; + + PROCEDURE read_line_header (L : INOUT LINE; byte_count : INOUT INTEGER; address : INOUT INTEGER; record_type : INOUT INTEGER) IS + VARIABLE byte_count_str : STRING(1 to 2); + VARIABLE address_str : STRING(1 to 4); + VARIABLE record_type_str : STRING(1 to 2); + BEGIN + -- Read byte count + FOR i IN 1 TO 2 LOOP + READ(L, byte_count_str(i)); + END LOOP; + str_to_hex(byte_count_str, byte_count); + -- ASSERT debug; REPORT "DEBUG read_line_header: byte count is" & byte_count; SEVERITY NOTE; + -- Read address + FOR i IN 1 TO 4 LOOP + READ(L, address_str(i)); + END LOOP; + str_to_hex(address_str, address); + -- ASSERT debug; REPORT "DEBUG read_line_header: address is" & address; SEVERITY NOTE; + -- Read record type + FOR i IN 1 TO 2 LOOP + READ(L, record_type_str(i)); + END LOOP; + str_to_hex(record_type_str, record_type); + -- ASSERT debug; REPORT "DEBUG read_line_header: record type is" & recod_type; SEVERITY NOTE; + END read_line_header; + + + PROCEDURE read_instruction (L : INOUT LINE; instruction_hex : INOUT INTEGER) IS + VARIABLE instruction_str : STRING(1 TO 4); + VARIABLE instruction_str_tmp : STRING(1 TO 4); + VARIABLE ch : CHARACTER; + BEGIN + -- L pointer is pointing to the instruction we want to read + -- Thus, no need to update pointer + + -- Read instruction + FOR i IN 1 TO 4 LOOP + READ(L, instruction_str(i)); + END LOOP; + + -- Swap 2 lower and 2 higher byte: 1234 -> 3412 + instruction_str_tmp(1 TO 2) := instruction_str(1 to 2); + instruction_str(1 TO 2) := instruction_str(3 to 4); + instruction_str(3 TO 4) := instruction_str_tmp(1 TO 2); + str_to_hex(instruction_str, instruction_hex); + -- ASSERT debug; REPORT "DEBUG read_instruction: instruction " & instruction_no & "is " & instruction_hex; SEVERITY NOTE; + END read_instruction; + + + PROCEDURE read_ihex_file (program_name : IN STRING; memory : OUT program_array) IS + FILE program : TEXT open READ_MODE is program_name; + VARIABLE L : LINE; + VARIABLE byte_count : INTEGER := 0; + VARIABLE address : NATURAL := 0; + VARIABLE record_type : INTEGER := 0; + -- VARIABLE base_address : INTEGER := 0; + -- VARIABLE current_address : INTEGER := 0; + VARIABLE instruction : INTEGER := 0; + VARIABLE ch : CHARACTER; + BEGIN + WHILE NOT ENDFILE(program) LOOP + byte_count := 0; + address := 0; + record_type := 0; + + READLINE(program, L); + + -- Move line pointer over semicolon + READ(L, ch); + -- Read first byte count, address and record type on the line + read_line_header(L, byte_count, address, record_type); + + CASE record_type IS + + WHEN 0 => -- Data record + FOR i IN 1 TO byte_count/2 LOOP -- toimiiko jos byte count == 1? + read_instruction(L, instruction); + memory(address/2+i-1) := STD_LOGIC_VECTOR(to_unsigned(instruction, Inst_bits)); -- XXX + END LOOP; + + WHEN 1 => -- EOF record + NULL; + + WHEN 2 => -- Extended Segment Address Record + -- ASSERT 1; REPORT "Extended Segment Address record type 0x02 not implemented"; SEVERITY FAILURE; + + WHEN 3 => -- Start Segment Address Record + -- ASSERT 1; REPORT "Start Segment Address record type 0x03 not implemented"; SEVERITY FAILURE; + + WHEN 4 => -- + -- FOR i IN 0 TO 1 LOOP + read_instruction(L, instruction); + -- ASSERT (instruction /= 0); REPORT "Extended Linear Address Record not zero";SEVERITY FAILURE; + -- END LOOP; + + WHEN 5 => -- Start Linear Address Record + -- ASSERT 1; REPORT "Start Linear Address record type 0x05 not implemented"; SEVERITY FAILURE; + + WHEN OTHERS => + -- ASSERT 1; REPORT "Invalid Intel HEX format record type"; SEVERITY FAILURE; + + END CASE; + + END LOOP; -- Read file + END PROCEDURE read_ihex_file; + +END PACKAGE BODY read_intel_hex_pack; + +--PROCEDURE read_ihex_file (program_name : IN STRING; memory : OUT program_array) IS -- pitaako maaritella tyyppi muualla?? +-- FILE program : TEXT IS IN "/home/pro/autosub/erkka/digital/modelsim/" & program_name; -- saako program namen? +-- TYPE program_array IS ARRAY (0 TO inst_mem_size-1) OF STD_LOGIC_VECTOR(Inst_bits-1 DOWNTO 0); +-- VARIABLE L : LINE; +-- VARIABLE byte_count : INTEGER := 0; +-- VARIABLE address : INTEGER := 0; +-- VARIABLE record_type : INTEGER := 0; +-- VARIABLE base_address : INTEGER := 0; +-- -- VARIABLE current_address : INTEGER := 0; +-- VARIABLE instruction : INTEGER := 0; +--BEGIN +-- WHILE NOT ENDFILE(program) LOOP +-- READLINE(program, L); +-- read_line_header(L, byte_count, address, record_type); +-- +-- CASE record_type IS +-- +-- WHEN X"00" => -- Data record +-- FOR i IN 0 TO byte_count-1 LOOP -- toimiiko jos byte count == 1? +-- read_instruction(L, i, instruction); +-- program_array(address/2 + i) := instruction; -- tsekkaa +-- END LOOP; +-- +-- WHEN X"01" => -- EOF record +-- NULL; +-- +-- WHEN X"02" => -- Extended Segment Address Record +-- ASSERT 1; REPORT "Extended Segment Address record type 0x02 not implemented"; SEVERITY FAILURE; +-- +-- WHEN X"03" => -- Start Segment Address Record +-- ASSERT 1; REPORT "Start Segment Address record type 0x03 not implemented"; SEVERITY FAILURE; +-- +-- WHEN X"04" => -- +-- FOR i IN 0 TO 1 LOOP +-- read_instruction(L, i, instruction); +-- ASSERT (instruction /= 0); REPORT "Extended Linear Address Record not zero";SEVERITY FAILURE; +-- END LOOP; +-- +-- WHEN X"05" => -- Start Linear Address Record +-- ASSERT 1; REPORT "Start Linear Address record type 0x05 not implemented"; SEVERITY FAILURE; +-- +-- WHEN OTHERS => +-- ASSERT 1; REPORT "Invalid Intel HEX format record type"; SEVERITY FAILURE; +-- +-- END CASE; +-- +-- END LOOP; -- Read file +--END PROCESS read_ihex_file; +-- diff --git a/PIC/pic_top.vhd b/PIC/pic_top.vhd new file mode 100644 index 0000000..f0cb4bd --- /dev/null +++ b/PIC/pic_top.vhd @@ -0,0 +1,81 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +-- FPGA top-level for the Tang Primer 25K (GW5A-LV25MG121). +-- Pin assignments live in primer25k.cst. +-- The prog_rom entity holds the compiled program; swap its 'rom' constant +-- to deploy a new program without changing anything else. + +entity pic_top is + port ( + clk : in std_logic; -- 50 MHz board clock (E2) + reset_btn : in std_logic; -- H11 user button, active high, pulled down + uart_rx : in std_logic; -- B3 + uart_tx : out std_logic; -- C3 + activity_led : out std_logic; -- E8 — driven by port_b(0) + led : out std_logic -- L6 — driven by port_a(0), blink from C + ); +end entity pic_top; + +architecture rtl of pic_top is + + constant CLK_FREQ : positive := 50_000_000; + + -- Power-on reset: hold reset for 64 cycles then release + signal rst_cnt : unsigned(5 downto 0) := (others => '0'); + signal reset : std_logic := '1'; + + signal pc : std_logic_vector(12 downto 0); + signal opcode : std_logic_vector(13 downto 0); + signal port_a : std_logic_vector(7 downto 0); + signal port_b : std_logic_vector(7 downto 0); + signal work_reg : std_logic_vector(7 downto 0); + signal status : std_logic_vector(2 downto 0); + signal instr_ret : std_logic; + +begin + + por : process(clk) + begin + if rising_edge(clk) then + if reset_btn = '1' then + rst_cnt <= (others => '0'); -- re-arm counter while button held + reset <= '1'; + elsif rst_cnt(5) = '0' then + rst_cnt <= rst_cnt + 1; + reset <= '1'; + else + reset <= '0'; + end if; + end if; + end process por; + + activity_led <= port_b(0); + led <= port_a(0); + + rom : entity work.prog_rom + port map ( + addr => pc, + data => opcode + ); + + cpu : entity work.PIC + generic map ( + CLK_FREQ => CLK_FREQ + ) + port map ( + clk => clk, + reset => reset, + opcode => opcode, + program_counter => pc, + instruction_return => instr_ret, + work_reg => work_reg, + status => status, + port_a => port_a, + port_b => port_b, + uart_tx => uart_tx, + uart_rx => uart_rx + ); + +end architecture rtl; diff --git a/PIC/prog_rom.vhd b/PIC/prog_rom.vhd new file mode 100644 index 0000000..6ef8001 --- /dev/null +++ b/PIC/prog_rom.vhd @@ -0,0 +1,1045 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity prog_rom is + generic ( + DEPTH : positive := 1024 + ); + port ( + addr : in std_logic_vector(12 downto 0); + data : out std_logic_vector(13 downto 0) + ); +end entity prog_rom; + +architecture rtl of prog_rom is + type rom_t is array (0 to 1024 - 1) of std_logic_vector(13 downto 0); + constant rom : rom_t := ( + 0 => "00000000000000", + 1 => "10100000000010", + 2 => "11000000011000", + 3 => "00000010011010", + 4 => "11000000000001", + 5 => "00000010011011", + 6 => "11000010000000", + 7 => "00000000000000", + 8 => "00000000000000", + 9 => "10000010011110", + 10 => "00000000000000", + 11 => "00000000000000", + 12 => "01001010000011", + 13 => "00000000000000", + 14 => "00000010011101", + 15 => "00100000011011", + 16 => "00000010011100", + 17 => "11000000011010", + 18 => "00000010011110", + 19 => "11000000000001", + 20 => "00000010011111", + 21 => "01001010000011", + 22 => "00000000000000", + 23 => "00100000011100", + 24 => "00000010100000", + 25 => "00100000011101", + 26 => "00000010100001", + 27 => "11000011111111", + 28 => "00011110011100", + 29 => "01110000000011", + 30 => "00001110011101", + 31 => "00100000100001", + 32 => "00010000100000", + 33 => "01100100000011", + 34 => "10100010011010", + 35 => "11000000000100", + 36 => "00011100011110", + 37 => "00000010100000", + 38 => "00000110100001", + 39 => "00110110100001", + 40 => "00100000011111", + 41 => "00011110100001", + 42 => "00100000100000", + 43 => "00000010011010", + 44 => "00100000100001", + 45 => "00000010011011", + 46 => "11000010000000", + 47 => "00000000000000", + 48 => "00000000000000", + 49 => "10000010011110", + 50 => "00000000000000", + 51 => "00000000000000", + 52 => "01001010000011", + 53 => "00000000000000", + 54 => "00000010100011", + 55 => "00100000011011", + 56 => "00000010100010", + 57 => "00100000011110", + 58 => "00000010011010", + 59 => "00100000011111", + 60 => "00000010011011", + 61 => "11000010000000", + 62 => "00000000000000", + 63 => "00000000000000", + 64 => "10000010011110", + 65 => "00000000000000", + 66 => "00000000000000", + 67 => "01001010000011", + 68 => "00000000000000", + 69 => "00000010100101", + 70 => "00000010100001", + 71 => "00100000011011", + 72 => "00000010100000", + 73 => "00000010100100", + 74 => "11000000000010", + 75 => "00011100011110", + 76 => "00000010100000", + 77 => "00000110100001", + 78 => "00110110100001", + 79 => "00100000011111", + 80 => "00011110100001", + 81 => "00100000100000", + 82 => "00000010011010", + 83 => "00100000100001", + 84 => "00000010011011", + 85 => "11000010000000", + 86 => "00000000000000", + 87 => "00000000000000", + 88 => "10000010011110", + 89 => "00000000000000", + 90 => "00000000000000", + 91 => "01001010000011", + 92 => "00000000000000", + 93 => "00000010100001", + 94 => "00000010100111", + 95 => "00100000011011", + 96 => "00000010100110", + 97 => "00000010100000", + 98 => "01001010000011", + 99 => "00000000000000", + 100 => "00100000100010", + 101 => "00000010100110", + 102 => "00100000100011", + 103 => "00000010100111", + 104 => "11000011111111", + 105 => "00011110100010", + 106 => "01110000000011", + 107 => "00001110100011", + 108 => "00100000100111", + 109 => "00010000100110", + 110 => "01100100000011", + 111 => "10100010010011", + 112 => "00100000100100", + 113 => "00000010011010", + 114 => "00100000100101", + 115 => "00000010011011", + 116 => "11000010000000", + 117 => "00000000000000", + 118 => "00000000000000", + 119 => "10000010111111", + 120 => "00000000000000", + 121 => "00000000000000", + 122 => "01001010000011", + 123 => "00000000000000", + 124 => "00000010100110", + 125 => "00100000100000", + 126 => "01001010000011", + 127 => "01001100000011", + 128 => "00000010000100", + 129 => "01001110000011", + 130 => "01001010000011", + 131 => "00000000000000", + 132 => "01100000100001", + 133 => "01011110000011", + 134 => "00100000100110", + 135 => "01001010000011", + 136 => "01001100000011", + 137 => "00000010000000", + 138 => "01001010000011", + 139 => "00000000000000", + 140 => "00101010100100", + 141 => "01100100000011", + 142 => "00101010100101", + 143 => "00101010100000", + 144 => "01100100000011", + 145 => "00101010100001", + 146 => "10100001100010", + 147 => "11000000000110", + 148 => "01001010000011", + 149 => "00000000000000", + 150 => "00011110011110", + 151 => "01100000000011", + 152 => "00101010011111", + 153 => "10100000010101", + 154 => "00000000000000", + 155 => "00000000000000", + 156 => "10100011010010", + 157 => "00000000001000", + 158 => "11101000000000", + 159 => "01100100000011", + 160 => "10100010100110", + 161 => "11101010000000", + 162 => "01100100000011", + 163 => "10100010110000", + 164 => "00000110011011", + 165 => "11010000000000", + 166 => "00100000011010", + 167 => "00000010000100", + 168 => "01001110000011", + 169 => "01100000011011", + 170 => "01011110000011", + 171 => "00100000000000", + 172 => "00000010011011", + 173 => "00101010000100", + 174 => "00100000000000", + 175 => "00000000001000", + 176 => "00000000000000", + 177 => "00000000000000", + 178 => "10000011001101", + 179 => "00000010011001", + 180 => "00111110011010", + 181 => "00001110011011", + 182 => "00101010011011", + 183 => "00000000000000", + 184 => "00000000000000", + 185 => "10000011001101", + 186 => "00000010011000", + 187 => "00100000011001", + 188 => "00000010011011", + 189 => "00100000011000", + 190 => "00000000001000", + 191 => "11101000000000", + 192 => "01100100000011", + 193 => "10100011000110", + 194 => "11101010000000", + 195 => "01100100000011", + 196 => "10100011001101", + 197 => "11010000000000", + 198 => "00100000011010", + 199 => "00000010000100", + 200 => "01001110000011", + 201 => "01100000011011", + 202 => "01011110000011", + 203 => "00100000000000", + 204 => "00000000001000", + 205 => "00100000011011", + 206 => "00000010001010", + 207 => "00100000011010", + 208 => "00000010000010", + 209 => "00000000001000", + 210 => "11000000000000", + 211 => "00000010101111", + 212 => "11000011111101", + 213 => "00000010101110", + 214 => "11000010000000", + 215 => "00000010110000", + 216 => "00100000101110", + 217 => "00000010011010", + 218 => "00100000101111", + 219 => "00000010011011", + 220 => "00100000110000", + 221 => "00000010101100", + 222 => "00100000011011", + 223 => "00000010101011", + 224 => "00100000011010", + 225 => "00000010101010", + 226 => "00100000101010", + 227 => "00000010011010", + 228 => "00100000101011", + 229 => "00000010011011", + 230 => "00100000101100", + 231 => "10000010111111", + 232 => "00000010101101", + 233 => "00100000101101", + 234 => "01100100000011", + 235 => "10100011110100", + 236 => "00100000101101", + 237 => "10000100001111", + 238 => "00101010101010", + 239 => "01100100000011", + 240 => "00101010101011", + 241 => "01100100000011", + 242 => "00101010101100", + 243 => "10100011100010", + 244 => "01001010000011", + 245 => "00100001110010", + 246 => "00000010101110", + 247 => "01100010101110", + 248 => "10100011110100", + 249 => "00100001110001", + 250 => "10000100001111", + 251 => "10100011110100", + 252 => "00000000001000", + 253 => "11010001001000", + 254 => "11010001100101", + 255 => "11010001101100", + 256 => "11010001101100", + 257 => "11010001101111", + 258 => "11010000100000", + 259 => "11010001100110", + 260 => "11010001110010", + 261 => "11010001101111", + 262 => "11010001101101", + 263 => "11010000100000", + 264 => "11010001010000", + 265 => "11010001001001", + 266 => "11010001000011", + 267 => "11010000100001", + 268 => "11010000001101", + 269 => "11010000001010", + 270 => "11010000000000", + 271 => "00000010101000", + 272 => "01001010000011", + 273 => "00100001110010", + 274 => "00000010101001", + 275 => "01100000101001", + 276 => "10100100010000", + 277 => "00100000101000", + 278 => "00000011110000", + 279 => "00000000001000", + 280 => "11010000000001", + 281 => "11010000000000", + 282 => "11010000100000", + 283 => "11010000000001", + 284 => "11010000110001", + 285 => "11010000000000", + 286 => "11010000000001", + 287 => "11010000000000", + 288 => "11010000000000", + 289 => "00000000000000", + 290 => "00000000000000", + 291 => "00000000000000", + 292 => "00000000000000", + 293 => "00000000000000", + 294 => "00000000000000", + 295 => "00000000000000", + 296 => "00000000000000", + 297 => "00000000000000", + 298 => "00000000000000", + 299 => "00000000000000", + 300 => "00000000000000", + 301 => "00000000000000", + 302 => "00000000000000", + 303 => "00000000000000", + 304 => "00000000000000", + 305 => "00000000000000", + 306 => "00000000000000", + 307 => "00000000000000", + 308 => "00000000000000", + 309 => "00000000000000", + 310 => "00000000000000", + 311 => "00000000000000", + 312 => "00000000000000", + 313 => "00000000000000", + 314 => "00000000000000", + 315 => "00000000000000", + 316 => "00000000000000", + 317 => "00000000000000", + 318 => "00000000000000", + 319 => "00000000000000", + 320 => "00000000000000", + 321 => "00000000000000", + 322 => "00000000000000", + 323 => "00000000000000", + 324 => "00000000000000", + 325 => "00000000000000", + 326 => "00000000000000", + 327 => "00000000000000", + 328 => "00000000000000", + 329 => "00000000000000", + 330 => "00000000000000", + 331 => "00000000000000", + 332 => "00000000000000", + 333 => "00000000000000", + 334 => "00000000000000", + 335 => "00000000000000", + 336 => "00000000000000", + 337 => "00000000000000", + 338 => "00000000000000", + 339 => "00000000000000", + 340 => "00000000000000", + 341 => "00000000000000", + 342 => "00000000000000", + 343 => "00000000000000", + 344 => "00000000000000", + 345 => "00000000000000", + 346 => "00000000000000", + 347 => "00000000000000", + 348 => "00000000000000", + 349 => "00000000000000", + 350 => "00000000000000", + 351 => "00000000000000", + 352 => "00000000000000", + 353 => "00000000000000", + 354 => "00000000000000", + 355 => "00000000000000", + 356 => "00000000000000", + 357 => "00000000000000", + 358 => "00000000000000", + 359 => "00000000000000", + 360 => "00000000000000", + 361 => "00000000000000", + 362 => "00000000000000", + 363 => "00000000000000", + 364 => "00000000000000", + 365 => "00000000000000", + 366 => "00000000000000", + 367 => "00000000000000", + 368 => "00000000000000", + 369 => "00000000000000", + 370 => "00000000000000", + 371 => "00000000000000", + 372 => "00000000000000", + 373 => "00000000000000", + 374 => "00000000000000", + 375 => "00000000000000", + 376 => "00000000000000", + 377 => "00000000000000", + 378 => "00000000000000", + 379 => "00000000000000", + 380 => "00000000000000", + 381 => "00000000000000", + 382 => "00000000000000", + 383 => "00000000000000", + 384 => "00000000000000", + 385 => "00000000000000", + 386 => "00000000000000", + 387 => "00000000000000", + 388 => "00000000000000", + 389 => "00000000000000", + 390 => "00000000000000", + 391 => "00000000000000", + 392 => "00000000000000", + 393 => "00000000000000", + 394 => "00000000000000", + 395 => "00000000000000", + 396 => "00000000000000", + 397 => "00000000000000", + 398 => "00000000000000", + 399 => "00000000000000", + 400 => "00000000000000", + 401 => "00000000000000", + 402 => "00000000000000", + 403 => "00000000000000", + 404 => "00000000000000", + 405 => "00000000000000", + 406 => "00000000000000", + 407 => "00000000000000", + 408 => "00000000000000", + 409 => "00000000000000", + 410 => "00000000000000", + 411 => "00000000000000", + 412 => "00000000000000", + 413 => "00000000000000", + 414 => "00000000000000", + 415 => "00000000000000", + 416 => "00000000000000", + 417 => "00000000000000", + 418 => "00000000000000", + 419 => "00000000000000", + 420 => "00000000000000", + 421 => "00000000000000", + 422 => "00000000000000", + 423 => "00000000000000", + 424 => "00000000000000", + 425 => "00000000000000", + 426 => "00000000000000", + 427 => "00000000000000", + 428 => "00000000000000", + 429 => "00000000000000", + 430 => "00000000000000", + 431 => "00000000000000", + 432 => "00000000000000", + 433 => "00000000000000", + 434 => "00000000000000", + 435 => "00000000000000", + 436 => "00000000000000", + 437 => "00000000000000", + 438 => "00000000000000", + 439 => "00000000000000", + 440 => "00000000000000", + 441 => "00000000000000", + 442 => "00000000000000", + 443 => "00000000000000", + 444 => "00000000000000", + 445 => "00000000000000", + 446 => "00000000000000", + 447 => "00000000000000", + 448 => "00000000000000", + 449 => "00000000000000", + 450 => "00000000000000", + 451 => "00000000000000", + 452 => "00000000000000", + 453 => "00000000000000", + 454 => "00000000000000", + 455 => "00000000000000", + 456 => "00000000000000", + 457 => "00000000000000", + 458 => "00000000000000", + 459 => "00000000000000", + 460 => "00000000000000", + 461 => "00000000000000", + 462 => "00000000000000", + 463 => "00000000000000", + 464 => "00000000000000", + 465 => "00000000000000", + 466 => "00000000000000", + 467 => "00000000000000", + 468 => "00000000000000", + 469 => "00000000000000", + 470 => "00000000000000", + 471 => "00000000000000", + 472 => "00000000000000", + 473 => "00000000000000", + 474 => "00000000000000", + 475 => "00000000000000", + 476 => "00000000000000", + 477 => "00000000000000", + 478 => "00000000000000", + 479 => "00000000000000", + 480 => "00000000000000", + 481 => "00000000000000", + 482 => "00000000000000", + 483 => "00000000000000", + 484 => "00000000000000", + 485 => "00000000000000", + 486 => "00000000000000", + 487 => "00000000000000", + 488 => "00000000000000", + 489 => "00000000000000", + 490 => "00000000000000", + 491 => "00000000000000", + 492 => "00000000000000", + 493 => "00000000000000", + 494 => "00000000000000", + 495 => "00000000000000", + 496 => "00000000000000", + 497 => "00000000000000", + 498 => "00000000000000", + 499 => "00000000000000", + 500 => "00000000000000", + 501 => "00000000000000", + 502 => "00000000000000", + 503 => "00000000000000", + 504 => "00000000000000", + 505 => "00000000000000", + 506 => "00000000000000", + 507 => "00000000000000", + 508 => "00000000000000", + 509 => "00000000000000", + 510 => "00000000000000", + 511 => "00000000000000", + 512 => "00000000000000", + 513 => "00000000000000", + 514 => "00000000000000", + 515 => "00000000000000", + 516 => "00000000000000", + 517 => "00000000000000", + 518 => "00000000000000", + 519 => "00000000000000", + 520 => "00000000000000", + 521 => "00000000000000", + 522 => "00000000000000", + 523 => "00000000000000", + 524 => "00000000000000", + 525 => "00000000000000", + 526 => "00000000000000", + 527 => "00000000000000", + 528 => "00000000000000", + 529 => "00000000000000", + 530 => "00000000000000", + 531 => "00000000000000", + 532 => "00000000000000", + 533 => "00000000000000", + 534 => "00000000000000", + 535 => "00000000000000", + 536 => "00000000000000", + 537 => "00000000000000", + 538 => "00000000000000", + 539 => "00000000000000", + 540 => "00000000000000", + 541 => "00000000000000", + 542 => "00000000000000", + 543 => "00000000000000", + 544 => "00000000000000", + 545 => "00000000000000", + 546 => "00000000000000", + 547 => "00000000000000", + 548 => "00000000000000", + 549 => "00000000000000", + 550 => "00000000000000", + 551 => "00000000000000", + 552 => "00000000000000", + 553 => "00000000000000", + 554 => "00000000000000", + 555 => "00000000000000", + 556 => "00000000000000", + 557 => "00000000000000", + 558 => "00000000000000", + 559 => "00000000000000", + 560 => "00000000000000", + 561 => "00000000000000", + 562 => "00000000000000", + 563 => "00000000000000", + 564 => "00000000000000", + 565 => "00000000000000", + 566 => "00000000000000", + 567 => "00000000000000", + 568 => "00000000000000", + 569 => "00000000000000", + 570 => "00000000000000", + 571 => "00000000000000", + 572 => "00000000000000", + 573 => "00000000000000", + 574 => "00000000000000", + 575 => "00000000000000", + 576 => "00000000000000", + 577 => "00000000000000", + 578 => "00000000000000", + 579 => "00000000000000", + 580 => "00000000000000", + 581 => "00000000000000", + 582 => "00000000000000", + 583 => "00000000000000", + 584 => "00000000000000", + 585 => "00000000000000", + 586 => "00000000000000", + 587 => "00000000000000", + 588 => "00000000000000", + 589 => "00000000000000", + 590 => "00000000000000", + 591 => "00000000000000", + 592 => "00000000000000", + 593 => "00000000000000", + 594 => "00000000000000", + 595 => "00000000000000", + 596 => "00000000000000", + 597 => "00000000000000", + 598 => "00000000000000", + 599 => "00000000000000", + 600 => "00000000000000", + 601 => "00000000000000", + 602 => "00000000000000", + 603 => "00000000000000", + 604 => "00000000000000", + 605 => "00000000000000", + 606 => "00000000000000", + 607 => "00000000000000", + 608 => "00000000000000", + 609 => "00000000000000", + 610 => "00000000000000", + 611 => "00000000000000", + 612 => "00000000000000", + 613 => "00000000000000", + 614 => "00000000000000", + 615 => "00000000000000", + 616 => "00000000000000", + 617 => "00000000000000", + 618 => "00000000000000", + 619 => "00000000000000", + 620 => "00000000000000", + 621 => "00000000000000", + 622 => "00000000000000", + 623 => "00000000000000", + 624 => "00000000000000", + 625 => "00000000000000", + 626 => "00000000000000", + 627 => "00000000000000", + 628 => "00000000000000", + 629 => "00000000000000", + 630 => "00000000000000", + 631 => "00000000000000", + 632 => "00000000000000", + 633 => "00000000000000", + 634 => "00000000000000", + 635 => "00000000000000", + 636 => "00000000000000", + 637 => "00000000000000", + 638 => "00000000000000", + 639 => "00000000000000", + 640 => "00000000000000", + 641 => "00000000000000", + 642 => "00000000000000", + 643 => "00000000000000", + 644 => "00000000000000", + 645 => "00000000000000", + 646 => "00000000000000", + 647 => "00000000000000", + 648 => "00000000000000", + 649 => "00000000000000", + 650 => "00000000000000", + 651 => "00000000000000", + 652 => "00000000000000", + 653 => "00000000000000", + 654 => "00000000000000", + 655 => "00000000000000", + 656 => "00000000000000", + 657 => "00000000000000", + 658 => "00000000000000", + 659 => "00000000000000", + 660 => "00000000000000", + 661 => "00000000000000", + 662 => "00000000000000", + 663 => "00000000000000", + 664 => "00000000000000", + 665 => "00000000000000", + 666 => "00000000000000", + 667 => "00000000000000", + 668 => "00000000000000", + 669 => "00000000000000", + 670 => "00000000000000", + 671 => "00000000000000", + 672 => "00000000000000", + 673 => "00000000000000", + 674 => "00000000000000", + 675 => "00000000000000", + 676 => "00000000000000", + 677 => "00000000000000", + 678 => "00000000000000", + 679 => "00000000000000", + 680 => "00000000000000", + 681 => "00000000000000", + 682 => "00000000000000", + 683 => "00000000000000", + 684 => "00000000000000", + 685 => "00000000000000", + 686 => "00000000000000", + 687 => "00000000000000", + 688 => "00000000000000", + 689 => "00000000000000", + 690 => "00000000000000", + 691 => "00000000000000", + 692 => "00000000000000", + 693 => "00000000000000", + 694 => "00000000000000", + 695 => "00000000000000", + 696 => "00000000000000", + 697 => "00000000000000", + 698 => "00000000000000", + 699 => "00000000000000", + 700 => "00000000000000", + 701 => "00000000000000", + 702 => "00000000000000", + 703 => "00000000000000", + 704 => "00000000000000", + 705 => "00000000000000", + 706 => "00000000000000", + 707 => "00000000000000", + 708 => "00000000000000", + 709 => "00000000000000", + 710 => "00000000000000", + 711 => "00000000000000", + 712 => "00000000000000", + 713 => "00000000000000", + 714 => "00000000000000", + 715 => "00000000000000", + 716 => "00000000000000", + 717 => "00000000000000", + 718 => "00000000000000", + 719 => "00000000000000", + 720 => "00000000000000", + 721 => "00000000000000", + 722 => "00000000000000", + 723 => "00000000000000", + 724 => "00000000000000", + 725 => "00000000000000", + 726 => "00000000000000", + 727 => "00000000000000", + 728 => "00000000000000", + 729 => "00000000000000", + 730 => "00000000000000", + 731 => "00000000000000", + 732 => "00000000000000", + 733 => "00000000000000", + 734 => "00000000000000", + 735 => "00000000000000", + 736 => "00000000000000", + 737 => "00000000000000", + 738 => "00000000000000", + 739 => "00000000000000", + 740 => "00000000000000", + 741 => "00000000000000", + 742 => "00000000000000", + 743 => "00000000000000", + 744 => "00000000000000", + 745 => "00000000000000", + 746 => "00000000000000", + 747 => "00000000000000", + 748 => "00000000000000", + 749 => "00000000000000", + 750 => "00000000000000", + 751 => "00000000000000", + 752 => "00000000000000", + 753 => "00000000000000", + 754 => "00000000000000", + 755 => "00000000000000", + 756 => "00000000000000", + 757 => "00000000000000", + 758 => "00000000000000", + 759 => "00000000000000", + 760 => "00000000000000", + 761 => "00000000000000", + 762 => "00000000000000", + 763 => "00000000000000", + 764 => "00000000000000", + 765 => "00000000000000", + 766 => "00000000000000", + 767 => "00000000000000", + 768 => "00000000000000", + 769 => "00000000000000", + 770 => "00000000000000", + 771 => "00000000000000", + 772 => "00000000000000", + 773 => "00000000000000", + 774 => "00000000000000", + 775 => "00000000000000", + 776 => "00000000000000", + 777 => "00000000000000", + 778 => "00000000000000", + 779 => "00000000000000", + 780 => "00000000000000", + 781 => "00000000000000", + 782 => "00000000000000", + 783 => "00000000000000", + 784 => "00000000000000", + 785 => "00000000000000", + 786 => "00000000000000", + 787 => "00000000000000", + 788 => "00000000000000", + 789 => "00000000000000", + 790 => "00000000000000", + 791 => "00000000000000", + 792 => "00000000000000", + 793 => "00000000000000", + 794 => "00000000000000", + 795 => "00000000000000", + 796 => "00000000000000", + 797 => "00000000000000", + 798 => "00000000000000", + 799 => "00000000000000", + 800 => "00000000000000", + 801 => "00000000000000", + 802 => "00000000000000", + 803 => "00000000000000", + 804 => "00000000000000", + 805 => "00000000000000", + 806 => "00000000000000", + 807 => "00000000000000", + 808 => "00000000000000", + 809 => "00000000000000", + 810 => "00000000000000", + 811 => "00000000000000", + 812 => "00000000000000", + 813 => "00000000000000", + 814 => "00000000000000", + 815 => "00000000000000", + 816 => "00000000000000", + 817 => "00000000000000", + 818 => "00000000000000", + 819 => "00000000000000", + 820 => "00000000000000", + 821 => "00000000000000", + 822 => "00000000000000", + 823 => "00000000000000", + 824 => "00000000000000", + 825 => "00000000000000", + 826 => "00000000000000", + 827 => "00000000000000", + 828 => "00000000000000", + 829 => "00000000000000", + 830 => "00000000000000", + 831 => "00000000000000", + 832 => "00000000000000", + 833 => "00000000000000", + 834 => "00000000000000", + 835 => "00000000000000", + 836 => "00000000000000", + 837 => "00000000000000", + 838 => "00000000000000", + 839 => "00000000000000", + 840 => "00000000000000", + 841 => "00000000000000", + 842 => "00000000000000", + 843 => "00000000000000", + 844 => "00000000000000", + 845 => "00000000000000", + 846 => "00000000000000", + 847 => "00000000000000", + 848 => "00000000000000", + 849 => "00000000000000", + 850 => "00000000000000", + 851 => "00000000000000", + 852 => "00000000000000", + 853 => "00000000000000", + 854 => "00000000000000", + 855 => "00000000000000", + 856 => "00000000000000", + 857 => "00000000000000", + 858 => "00000000000000", + 859 => "00000000000000", + 860 => "00000000000000", + 861 => "00000000000000", + 862 => "00000000000000", + 863 => "00000000000000", + 864 => "00000000000000", + 865 => "00000000000000", + 866 => "00000000000000", + 867 => "00000000000000", + 868 => "00000000000000", + 869 => "00000000000000", + 870 => "00000000000000", + 871 => "00000000000000", + 872 => "00000000000000", + 873 => "00000000000000", + 874 => "00000000000000", + 875 => "00000000000000", + 876 => "00000000000000", + 877 => "00000000000000", + 878 => "00000000000000", + 879 => "00000000000000", + 880 => "00000000000000", + 881 => "00000000000000", + 882 => "00000000000000", + 883 => "00000000000000", + 884 => "00000000000000", + 885 => "00000000000000", + 886 => "00000000000000", + 887 => "00000000000000", + 888 => "00000000000000", + 889 => "00000000000000", + 890 => "00000000000000", + 891 => "00000000000000", + 892 => "00000000000000", + 893 => "00000000000000", + 894 => "00000000000000", + 895 => "00000000000000", + 896 => "00000000000000", + 897 => "00000000000000", + 898 => "00000000000000", + 899 => "00000000000000", + 900 => "00000000000000", + 901 => "00000000000000", + 902 => "00000000000000", + 903 => "00000000000000", + 904 => "00000000000000", + 905 => "00000000000000", + 906 => "00000000000000", + 907 => "00000000000000", + 908 => "00000000000000", + 909 => "00000000000000", + 910 => "00000000000000", + 911 => "00000000000000", + 912 => "00000000000000", + 913 => "00000000000000", + 914 => "00000000000000", + 915 => "00000000000000", + 916 => "00000000000000", + 917 => "00000000000000", + 918 => "00000000000000", + 919 => "00000000000000", + 920 => "00000000000000", + 921 => "00000000000000", + 922 => "00000000000000", + 923 => "00000000000000", + 924 => "00000000000000", + 925 => "00000000000000", + 926 => "00000000000000", + 927 => "00000000000000", + 928 => "00000000000000", + 929 => "00000000000000", + 930 => "00000000000000", + 931 => "00000000000000", + 932 => "00000000000000", + 933 => "00000000000000", + 934 => "00000000000000", + 935 => "00000000000000", + 936 => "00000000000000", + 937 => "00000000000000", + 938 => "00000000000000", + 939 => "00000000000000", + 940 => "00000000000000", + 941 => "00000000000000", + 942 => "00000000000000", + 943 => "00000000000000", + 944 => "00000000000000", + 945 => "00000000000000", + 946 => "00000000000000", + 947 => "00000000000000", + 948 => "00000000000000", + 949 => "00000000000000", + 950 => "00000000000000", + 951 => "00000000000000", + 952 => "00000000000000", + 953 => "00000000000000", + 954 => "00000000000000", + 955 => "00000000000000", + 956 => "00000000000000", + 957 => "00000000000000", + 958 => "00000000000000", + 959 => "00000000000000", + 960 => "00000000000000", + 961 => "00000000000000", + 962 => "00000000000000", + 963 => "00000000000000", + 964 => "00000000000000", + 965 => "00000000000000", + 966 => "00000000000000", + 967 => "00000000000000", + 968 => "00000000000000", + 969 => "00000000000000", + 970 => "00000000000000", + 971 => "00000000000000", + 972 => "00000000000000", + 973 => "00000000000000", + 974 => "00000000000000", + 975 => "00000000000000", + 976 => "00000000000000", + 977 => "00000000000000", + 978 => "00000000000000", + 979 => "00000000000000", + 980 => "00000000000000", + 981 => "00000000000000", + 982 => "00000000000000", + 983 => "00000000000000", + 984 => "00000000000000", + 985 => "00000000000000", + 986 => "00000000000000", + 987 => "00000000000000", + 988 => "00000000000000", + 989 => "00000000000000", + 990 => "00000000000000", + 991 => "00000000000000", + 992 => "00000000000000", + 993 => "00000000000000", + 994 => "00000000000000", + 995 => "00000000000000", + 996 => "00000000000000", + 997 => "00000000000000", + 998 => "00000000000000", + 999 => "00000000000000", + 1000 => "00000000000000", + 1001 => "00000000000000", + 1002 => "00000000000000", + 1003 => "00000000000000", + 1004 => "00000000000000", + 1005 => "00000000000000", + 1006 => "00000000000000", + 1007 => "00000000000000", + 1008 => "00000000000000", + 1009 => "00000000000000", + 1010 => "00000000000000", + 1011 => "00000000000000", + 1012 => "00000000000000", + 1013 => "00000000000000", + 1014 => "00000000000000", + 1015 => "00000000000000", + 1016 => "00000000000000", + 1017 => "00000000000000", + 1018 => "00000000000000", + 1019 => "00000000000000", + 1020 => "00000000000000", + 1021 => "00000000000000", + 1022 => "00000000000000", + 1023 => "00000000000000" + ); +begin + data <= rom(to_integer(unsigned(addr(9 downto 0)))); +end architecture rtl; diff --git a/PIC/stack.vhd b/PIC/stack.vhd new file mode 100644 index 0000000..fd376c0 --- /dev/null +++ b/PIC/stack.vhd @@ -0,0 +1,51 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity stack is + generic ( + DEPTH : positive := 8; + WIDTH : positive := 13 + ); + port ( + clk : in std_logic; + reset : in std_logic; + push : in std_logic; + pop : in std_logic; + din : in std_logic_vector(WIDTH - 1 downto 0); + dout : out std_logic_vector(WIDTH - 1 downto 0) + ); +end entity stack; + +architecture rtl of stack is + + type stack_t is + array (0 to DEPTH - 1) + of std_logic_vector(WIDTH - 1 downto 0); + + signal mem : stack_t + := (others => (others => '0')); + + -- write pointer + signal top : unsigned(2 downto 0) + := (others => '0'); +begin + + dout <= + mem(to_integer(top - 1)) when top /= 0 else (others => '0'); + + stck : process(clk, reset) + begin + if reset = '1' then + top <= (others => '0'); + elsif rising_edge(clk) then + if push = '1' then + mem(to_integer(top)) <= din; + top <= top + 1; + elsif pop = '1' then + top <= top - 1; + end if; + end if; + end process; + +end architecture rtl; diff --git a/PIC/state_machine.vhd b/PIC/state_machine.vhd new file mode 100644 index 0000000..464e0bc --- /dev/null +++ b/PIC/state_machine.vhd @@ -0,0 +1,224 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.alu_types.all; + +use work.decoder.all; + +entity state_machine is + port( + clk : in std_logic; + opcode : in std_logic_vector(13 downto 0); + + reset : in std_logic; + + op : out alu_op; + we_mem : out std_logic := '0'; + re_mem : out std_logic := '0'; + we_w : out std_logic := '0'; + instr_ret : out std_logic := '0'; + bit_select : out std_logic_vector(2 downto 0) := (others => '0'); + data : out std_logic_vector(7 downto 0) := (others => '0'); + pc : out std_logic_vector(12 downto 0); + addr : out std_logic_vector(6 downto 0) := (others => '0'); + + use_literal : out std_logic; + we_status : out std_logic := '0'; + + stack_push : out std_logic := '0'; + stack_pop : out std_logic := '0'; + stack_din : out std_logic_vector(12 downto 0) := (others => '0'); + stack_dout : in std_logic_vector(12 downto 0); + + alu_skip : in std_logic; + alu_result : in std_logic_vector(7 downto 0) + ); + + +end entity state_machine; + +architecture rtl of state_machine is + type state_t is (IFetch, MRead, Execute, MWrite); + + signal pc_internal : std_logic_vector(12 downto 0) := (others => '0'); + signal state : state_t := IFetch; + signal pclath : std_logic_vector(4 downto 0) := (others => '0'); + +begin + pc <= pc_internal; + + fsm : process(clk) + variable instr : instruction_t; + + -- do we do a phantom nop after this instruction? + variable do_phantom_nop : boolean := false; + variable is_phantom : boolean := false; + -- true when phantom came from DECFSZ/INCFSZ skip (must still increment PC) + -- false when phantom came from GOTO/CALL/RETURN (PC already at target) + variable is_skip_phantom : boolean := false; + begin + + if rising_edge(clk) then + + re_mem <= '0'; + we_mem <= '0'; + we_w <= '0'; + we_status <= '0'; + instr_ret <= '0'; + stack_push <= '0'; + stack_pop <= '0'; + + if reset = '1' then + pc_internal <= (others => '0'); + pclath <= (others => '0'); + state <= IFetch; + do_phantom_nop := false; + else + + case state is + when IFetch => + + -- if we had a branch before, this cycle is a NOP. + if do_phantom_nop then + instr := instruction_decode((others => '0')); + do_phantom_nop := false; + is_phantom := true; + -- is_skip_phantom carries over from whoever set do_phantom_nop + else + instr := instruction_decode(opcode); + is_phantom := false; + is_skip_phantom := false; + end if; + + -- set use_literal based on decoded instruction, holds through MWrite + if instr.class = LITERAL_OP then + use_literal <= '1'; + else + use_literal <= '0'; + end if; + + -- for literal operations + data <= instr.k(7 downto 0); + + -- for memory-read/write operations + addr <= instr.f; + + -- for bit-select operations + bit_select <= instr.b; + + state <= Mread; + + when MRead => + + -- read memory addressed by the opcode + -- MOVWF, CLRF, CLRW, NOP are write-only. + if instr.class = BIT_OP or + (instr.class = BYTE_OP and + instr.op /= MOVWF and instr.op /= CLRF and + instr.op /= CLRW and instr.op /= NOP) then + re_mem <= '1'; + end if; + + + + state <= Execute; + + when Execute => + + op <= instr.op; -- move the decoded instruction to the ALU + + if not is_phantom then + + -- increment PC or change address, different for different instructions. + if instr.op = GOTO then + + pc_internal <= "00" & instr.k; + do_phantom_nop := true; + is_skip_phantom := false; + + elsif instr.op = CALL then + + -- push PC+1 to the stack + stack_din <= std_logic_vector(unsigned(pc_internal) + 1); + stack_push <= '1'; + + -- go to the function we called + pc_internal <= "00" & instr.k; + do_phantom_nop := true; + is_skip_phantom := false; + + elsif instr.op = RETUR or instr.op = RETLW then + + -- pop the PC from stack. + pc_internal <= stack_dout; + stack_pop <= '1'; -- pop deferred to next cycle. + do_phantom_nop := true; + is_skip_phantom := false; + + else + pc_internal <= std_logic_vector(unsigned(pc_internal) + 1); + end if; + + elsif is_skip_phantom then + -- skip phantom: PC was at the skipped instruction, step past it + pc_internal <= std_logic_vector(unsigned(pc_internal) + 1); + end if; + -- branch phantom: PC already at target, no change needed + + state <= MWrite; + + when MWrite => + + -- write to correct memory based on class (skip for phantom NOP) + if not is_phantom then + case instr.class is + when BYTE_OP => + if instr.op /= NOP then + if instr.d = '1' then + we_mem <= '1'; + -- Write to PCLATH (addr 0x0A): latch upper PC bits + if instr.f = "0001010" then + pclath <= alu_result(4 downto 0); + end if; + -- Write to PCL (addr 0x02): redirect PC, like a GOTO + if instr.f = "0000010" then + pc_internal <= pclath & alu_result; + do_phantom_nop := true; + is_skip_phantom := false; + end if; + else + we_w <= '1'; + end if; + end if; + when BIT_OP => + -- NOT for the BTFSS or BTFSC instructions. + if instr.op = BCF or instr.op = BSF then + we_mem <= '1'; + end if; + when LITERAL_OP => + if instr.op /= NOP and instr.op /= RETUR then + we_w <= '1'; + end if; + when others => null; + end case; + end if; + + -- DECFSZ/INCFSZ/BTFSS/BTFSC: skip next instruction if ALU signals skip + if not is_phantom and + (instr.op = DECFSZ or instr.op = INCFSZ or instr.op = BTFSS or instr.op = BTFSC) and alu_skip = '1' then + do_phantom_nop := true; + is_skip_phantom := true; + end if; + + if not is_phantom then + we_status <= '1'; + instr_ret <= '1'; + end if; + state <= IFetch; + + end case; + end if; -- reset + end if; + end process fsm; + +end architecture rtl; diff --git a/PIC/tb_pic.vhd b/PIC/tb_pic.vhd new file mode 100644 index 0000000..067e154 --- /dev/null +++ b/PIC/tb_pic.vhd @@ -0,0 +1,83 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use work.read_intel_hex_pack.all; + +entity tb_pic is +end entity tb_pic; + +architecture behavioural of tb_pic is + constant T_clk : time := 20 ns; -- 50M + constant HEX_FILE : string := "program.hex"; + constant SIM_CYCLES : integer := 800_000; + + signal clk : std_logic := '0'; + signal reset : std_logic := '1'; + signal opcode : std_logic_vector(13 downto 0); + + signal program_counter : std_logic_vector(12 downto 0); + signal instruction_return : std_logic; + signal work_reg : std_logic_vector(7 downto 0); + signal status : std_logic_vector(2 downto 0); + signal port_a : std_logic_vector(7 downto 0); + signal port_b : std_logic_vector(7 downto 0); + + signal done : boolean := false; + + signal uart_tx : std_logic; + signal uart_rx : std_logic := '1'; -- idle high (no incoming bytes) + + -- program memory: 1024 x 14-bit + signal prog_mem : program_array := (others => (others => '0')); + +begin + + clk <= not clk after T_clk / 2 when not done else unaffected; + + -- drive opcode from program memory using PC + opcode <= prog_mem(to_integer(unsigned(program_counter))); + + dut : entity work.PIC(rtl) + generic map ( + CLK_FREQ => 50_000_000 -- 10 MHz, matches T_clk = 100 ns + ) + port map ( + clk => clk, + reset => reset, + opcode => opcode, + program_counter => program_counter, + instruction_return => instruction_return, + work_reg => work_reg, + status => status, + port_a => port_a, + port_b => port_b, + uart_tx => uart_tx, + uart_rx => uart_rx + ); + + stimulus : process is + variable mem : program_array; + begin + -- load hex file into program memory + read_ihex_file(HEX_FILE, mem); + prog_mem <= mem; + + -- reset pulse + reset <= '1'; + wait for T_clk * 2; + reset <= '0'; + + -- run for SIM_CYCLES instruction cycles + for i in 0 to SIM_CYCLES - 1 loop + wait until rising_edge(clk); + end loop; + + report "simulation done. port_a=" & integer'image(to_integer(unsigned(port_a))) + & " port_b=" & integer'image(to_integer(unsigned(port_b))) + severity note; + + done <= true; + wait; + end process stimulus; + +end architecture behavioural; diff --git a/PIC/tb_stack.vhd b/PIC/tb_stack.vhd new file mode 100644 index 0000000..5b386e9 --- /dev/null +++ b/PIC/tb_stack.vhd @@ -0,0 +1,121 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity tb_stack is +end entity tb_stack; + +architecture behavioural of tb_stack is + constant T_clk : time := 10 ns; + constant W : positive := 13; + + signal clk : std_logic := '0'; + signal reset : std_logic := '0'; + signal push : std_logic := '0'; + signal pop : std_logic := '0'; + signal din : std_logic_vector(W - 1 downto 0) := (others => '0'); + signal dout : std_logic_vector(W - 1 downto 0); + + signal done : boolean := false; + + procedure tick(signal clk_in : in std_logic) is + begin + wait until rising_edge(clk_in); + wait for 1 ns; + end procedure; + +begin + + clk <= not clk after T_clk / 2 when not done else unaffected; + + dut : entity work.stack(rtl) + generic map (DEPTH => 8, WIDTH => W) + port map ( + clk => clk, + reset => reset, + push => push, + pop => pop, + din => din, + dout => dout + ); + + stimulus : process is + begin + + -- test 1: reset clears stack + report "test 1: reset"; + reset <= '1'; + wait for T_clk; + reset <= '0'; + wait for 1 ns; + assert dout = std_logic_vector(to_unsigned(0, W)) + report "reset: dout should be 0" severity error; + + -- test 2: push one value and read it back + report "test 2: push/pop single value"; + din <= std_logic_vector(to_unsigned(16#42#, W)); + push <= '1'; + tick(clk); + push <= '0'; + assert dout = std_logic_vector(to_unsigned(16#42#, W)) + report "push: dout should be 0x42" severity error; + pop <= '1'; + tick(clk); + pop <= '0'; + assert dout = std_logic_vector(to_unsigned(0, W)) + report "pop: dout should be 0 (empty)" severity error; + + -- test 3: push multiple values, pop in LIFO order + report "test 3: LIFO order"; + din <= std_logic_vector(to_unsigned(16#100#, W)); + push <= '1'; + tick(clk); + din <= std_logic_vector(to_unsigned(16#200#, W)); + tick(clk); + din <= std_logic_vector(to_unsigned(16#300#, W)); + tick(clk); + push <= '0'; + assert dout = std_logic_vector(to_unsigned(16#300#, W)) + report "LIFO: top should be 0x300" severity error; + pop <= '1'; + tick(clk); + assert dout = std_logic_vector(to_unsigned(16#200#, W)) + report "LIFO: after 1 pop should be 0x200" severity error; + tick(clk); + assert dout = std_logic_vector(to_unsigned(16#100#, W)) + report "LIFO: after 2 pops should be 0x100" severity error; + tick(clk); + pop <= '0'; + assert dout = std_logic_vector(to_unsigned(0, W)) + report "LIFO: stack empty, dout should be 0" severity error; + + report "test 4: overflow wraparound"; + push <= '1'; + for i in 1 to 8 loop + din <= std_logic_vector(to_unsigned(i, W)); + tick(clk); + end loop; + push <= '0'; + -- after 8 pushes top wraps to 0, so stack looks empty + assert dout = std_logic_vector(to_unsigned(0, W)) + report "overflow: top wrapped to 0, dout should be 0" severity error; + + -- test 5: reset mid-operation clears pointer + report "test 5: reset mid-operation"; + din <= std_logic_vector(to_unsigned(16#1FF#, W)); + push <= '1'; + tick(clk); + push <= '0'; + reset <= '1'; + wait for T_clk; + reset <= '0'; + wait for 1 ns; + assert dout = std_logic_vector(to_unsigned(0, W)) + report "reset mid-op: dout should be 0" severity error; + + report "All stack tests done" severity note; + done <= true; + wait; + end process stimulus; + +end architecture behavioural; diff --git a/PIC/test_uart.c b/PIC/test_uart.c new file mode 100644 index 0000000..f453e21 --- /dev/null +++ b/PIC/test_uart.c @@ -0,0 +1,36 @@ +#include <pic16f84a.h> + +typedef unsigned char uint8_t; + +// UART memory-mapped registers (hooked up in dpram.vhd). +// Placed at 0x70-0x72: unimplemented in the real PIC16F84A so no +// conflict with the SFR definitions in pic16f84a.h. +// 0x70 UART_TX write: transmit a byte +// 0x71 UART_RX read: receive a byte (pops the RX FIFO) +// 0x72 UART_STATUS read: bit0=tx_busy, bit1=rx_empty, bit2=rx_full +__sfr __at(0x70) UART_TX; +__sfr __at(0x71) UART_RX; +__sfr __at(0x72) UART_STATUS; + +static void uart_send(uint8_t byte) { + while (UART_STATUS & 0x01); // wait until tx_busy = 0 + UART_TX = byte; +} + +static void uart_puts(const char *s) { + while (*s) { + uart_send((uint8_t)*s); + s++; + } +} + +void main(void) { + uart_puts("Hello from PIC!\r\n"); + + // Echo loop: read every incoming byte and send it back + while (1) { + if (!(UART_STATUS & 0x02)) { // rx_empty = 0 → data available + uart_send(UART_RX); + } + } +} diff --git a/PIC/uart.vhd b/PIC/uart.vhd new file mode 100644 index 0000000..a0fad93 --- /dev/null +++ b/PIC/uart.vhd @@ -0,0 +1,195 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +-- TX: fire and forget (8E1) +-- RX: FIFO-backed (8E1), consumer reads via rd_en/rx_data/rx_empty + +entity uart is + generic ( + CLK_FREQ : positive := 50_000_000; + BAUD_RATE : positive := 115_200; + CLKS_PER_BIT : positive := CLK_FREQ / BAUD_RATE + ); + port ( + clk : in std_logic; + -- TX + tx_should_send : in std_logic; + byte_in : in std_logic_vector(7 downto 0); + tx_done : out std_logic; + baud_tick : out std_logic; + uart_tx : out std_logic; + -- RX + uart_rx : in std_logic; + rd_en : in std_logic; + rx_data : out std_logic_vector(7 downto 0); + rx_empty : out std_logic; + rx_full : out std_logic + ); +end entity uart; + +architecture rtl of uart is + + signal baud_counter : std_logic_vector(15 downto 0) + := (others => '0'); + signal baud_tick_i : std_logic := '0'; + + signal tx_out : std_logic := '1'; + signal current_byte : std_logic_vector(7 downto 0) := (others => '0'); + signal tx_byte_latch : std_logic_vector(7 downto 0) := (others => '0'); + + -- RX input synchronizer (2FF, idle state is '1') + signal uart_rx_meta : std_logic := '1'; + signal uart_rx_sync : std_logic := '1'; + + -- RX FIFO wiring + signal fifo_wr_en : std_logic := '0'; + signal fifo_din : std_logic_vector(7 downto 0) + := (others => '0'); + signal fifo_full : std_logic := '0'; + +begin + + uart_tx <= tx_out; + baud_tick <= baud_tick_i; + + rx_fifo : entity work.fifo + generic map (DEPTH => 64, ADDR_BITS => 6, WIDTH => 8) + port map ( + clk => clk, + wr_en => fifo_wr_en, + rd_en => rd_en, + din => fifo_din, + dout => rx_data, + full => fifo_full, + empty => rx_empty + ); + + rx_full <= fifo_full; + + uart_rx_synchronizer : process(clk) + begin + if rising_edge(clk) then + uart_rx_meta <= uart_rx; + uart_rx_sync <= uart_rx_meta; + end if; + end process uart_rx_synchronizer; + + uart_baud_timer : process(clk) + begin + if rising_edge(clk) then + if unsigned(baud_counter) = CLKS_PER_BIT - 1 then + baud_counter <= (others => '0'); + baud_tick_i <= '1'; + else + baud_counter <= std_logic_vector(unsigned(baud_counter) + 1); + baud_tick_i <= '0'; + end if; + end if; + end process uart_baud_timer; + + uart_transmit_byte : process(clk) + type t_state is (idle, start, data, parity, stop); + variable state : t_state := idle; + variable bit_index : unsigned(2 downto 0); + variable parity_value : std_logic; + begin + if rising_edge(clk) then + tx_done <= '0'; + if baud_tick_i = '1' then + case state is + when idle => + if tx_should_send = '1' then + tx_out <= '0'; -- start bit immediately + tx_byte_latch <= byte_in; -- latch byte now + parity_value := '0'; + bit_index := (others => '0'); + state := data; + end if; + when start => + null; -- unused, kept for completeness + when data => + tx_out <= tx_byte_latch(to_integer(bit_index)); + parity_value := parity_value xor tx_byte_latch(to_integer(bit_index)); + if bit_index = 7 then + state := parity; + else + state := data; + end if; + bit_index := bit_index + 1; + when parity => + tx_out <= parity_value; + state := stop; + when stop => + tx_out <= '1'; + tx_done <= '1'; + state := idle; + end case; + end if; + end if; + end process uart_transmit_byte; + + uart_receive_byte : process(clk) + type rx_state_t is (idle, start, data, parity, stop); + variable state : rx_state_t := idle; + variable bit_index : unsigned(2 downto 0); + variable rx_byte : std_logic_vector(7 downto 0); + variable parity_val : std_logic; + variable rx_counter : unsigned(15 downto 0); + begin + if rising_edge(clk) then + fifo_wr_en <= '0'; + case state is + when idle => + if uart_rx_sync = '0' then + rx_counter := to_unsigned(CLKS_PER_BIT / 2, 16); + state := start; + end if; + when start => + if rx_counter = 0 then + if uart_rx_sync = '0' then + rx_counter := to_unsigned(CLKS_PER_BIT - 1, 16); + bit_index := (others => '0'); + parity_val := '0'; + state := data; + else + state := idle; + end if; + else + rx_counter := rx_counter - 1; + end if; + when data => + if rx_counter = 0 then + rx_byte(to_integer(bit_index)) := uart_rx_sync; + parity_val := parity_val xor uart_rx_sync; + rx_counter := to_unsigned(CLKS_PER_BIT - 1, 16); + if bit_index = 7 then + state := parity; + else + bit_index := bit_index + 1; + end if; + else + rx_counter := rx_counter - 1; + end if; + when parity => + if rx_counter = 0 then + rx_counter := to_unsigned(CLKS_PER_BIT - 1, 16); + state := stop; + else + rx_counter := rx_counter - 1; + end if; + when stop => + if rx_counter = 0 then + if uart_rx_sync = '1' and fifo_full = '0' then + fifo_din <= rx_byte; + fifo_wr_en <= '1'; + end if; + state := idle; + else + rx_counter := rx_counter - 1; + end if; + end case; + end if; + end process uart_receive_byte; + +end architecture rtl; |
