From eb8643ddbef43547eb7bfe58789a3908926c7258 Mon Sep 17 00:00:00 2001 From: Vaino Kauppila Date: Sun, 19 Apr 2026 12:32:58 +0300 Subject: refactor dir structure, add fib.c --- .gitignore | 25 +- Makefile | 41 +- Makefile.inner | 96 ++--- PIC/ALU.vhd | 216 ---------- PIC/PIC.vhd | 181 --------- PIC/blink.c | 35 -- PIC/common.vhd | 10 - PIC/decoder.vhd | 155 ------- PIC/dpram.vhd | 110 ----- PIC/fifo.vhd | 75 ---- PIC/hdl-prj.json | 24 -- PIC/hexfile_reader.vhd | 342 ---------------- PIC/pic_top.vhd | 81 ---- PIC/prog_rom.vhd | 1045 ------------------------------------------------ PIC/stack.vhd | 51 --- PIC/state_machine.vhd | 222 ---------- PIC/tb_pic.vhd | 83 ---- PIC/tb_stack.vhd | 121 ------ PIC/test_uart.c | 67 ---- PIC/uart.vhd | 195 --------- fw/blink.c | 35 ++ fw/fib.c | 84 ++++ fw/test_uart.c | 69 ++++ hdl/ALU.vhd | 216 ++++++++++ hdl/PIC.vhd | 181 +++++++++ hdl/common.vhd | 10 + hdl/decoder.vhd | 155 +++++++ hdl/dpram.vhd | 110 +++++ hdl/fifo.vhd | 75 ++++ hdl/hdl-prj.json | 24 ++ hdl/hexfile_reader.vhd | 342 ++++++++++++++++ hdl/pic_top.vhd | 81 ++++ hdl/stack.vhd | 51 +++ hdl/state_machine.vhd | 230 +++++++++++ hdl/tb_pic.vhd | 83 ++++ hdl/tb_stack.vhd | 121 ++++++ hdl/uart.vhd | 195 +++++++++ test_uart.c | 0 test_uart.hex | 50 --- 39 files changed, 2136 insertions(+), 3151 deletions(-) delete mode 100644 PIC/ALU.vhd delete mode 100644 PIC/PIC.vhd delete mode 100644 PIC/blink.c delete mode 100644 PIC/common.vhd delete mode 100644 PIC/decoder.vhd delete mode 100644 PIC/dpram.vhd delete mode 100644 PIC/fifo.vhd delete mode 100644 PIC/hdl-prj.json delete mode 100644 PIC/hexfile_reader.vhd delete mode 100644 PIC/pic_top.vhd delete mode 100644 PIC/prog_rom.vhd delete mode 100644 PIC/stack.vhd delete mode 100644 PIC/state_machine.vhd delete mode 100644 PIC/tb_pic.vhd delete mode 100644 PIC/tb_stack.vhd delete mode 100644 PIC/test_uart.c delete mode 100644 PIC/uart.vhd create mode 100644 fw/blink.c create mode 100644 fw/fib.c create mode 100644 fw/test_uart.c create mode 100644 hdl/ALU.vhd create mode 100644 hdl/PIC.vhd create mode 100644 hdl/common.vhd create mode 100644 hdl/decoder.vhd create mode 100644 hdl/dpram.vhd create mode 100644 hdl/fifo.vhd create mode 100644 hdl/hdl-prj.json create mode 100644 hdl/hexfile_reader.vhd create mode 100644 hdl/pic_top.vhd create mode 100644 hdl/stack.vhd create mode 100644 hdl/state_machine.vhd create mode 100644 hdl/tb_pic.vhd create mode 100644 hdl/tb_stack.vhd create mode 100644 hdl/uart.vhd delete mode 100644 test_uart.c delete mode 100644 test_uart.hex diff --git a/.gitignore b/.gitignore index bb8c473..757e427 100644 --- a/.gitignore +++ b/.gitignore @@ -1,28 +1,13 @@ -# GHDL build artifacts -*.o -e~*.o -work-obj*.cf -tb_pic -tb_stack +# All build artifacts land in build/ +build/ -# Simulation output -*.vcd - -# Synthesis / P&R outputs -*.json -!PIC/hdl-prj.json -*.fs -*_pnr.json -*_timing.json - -# SDCC compiler outputs +# SDCC compiler outputs that may land alongside source *.asm *.cod *.lst *.ihx -program.hex -# Keep test_uart.hex — it's the assembled firmware -# (remove this comment and add test_uart.hex here if you regenerate it from source) +*.hex +hdl/prog_rom.vhd # Python cache __pycache__/ diff --git a/Makefile b/Makefile index dbc5712..ca56c27 100644 --- a/Makefile +++ b/Makefile @@ -1,54 +1,55 @@ IMAGE = fpga-tools PODMAN = podman run --rm -v $(CURDIR):/workspace $(IMAGE) +BUILD = build + # Which C program to build. Override: make PROG=test_uart PROG ?= blink -# ── Host-side C compilation (sdcc on host) ────────────────────────────────── +$(BUILD): + mkdir -p $@ -blink.hex: PIC/blink.c - sdcc --use-non-free -mpic14 -p16f84a $< +# -- Host-side C compilation (sdcc on host) -------------------------------------------- -test_uart.hex: PIC/test_uart.c - sdcc --use-non-free -mpic14 -p16f84a $< +$(BUILD)/%.hex: fw/%.c | $(BUILD) + cd $(BUILD) && sdcc --use-non-free -mpic14 -p16f84a $(CURDIR)/fw/$*.c # program.hex is what the testbench loads at runtime -program.hex: $(PROG).hex +$(BUILD)/program.hex: $(BUILD)/$(PROG).hex cp $< $@ # prog_rom.vhd embeds the program for synthesis -PIC/prog_rom.vhd: program.hex +hdl/prog_rom.vhd: $(BUILD)/program.hex python3 hex2rom.py $< > $@ # Regenerate ROM from an arbitrary hex file: make rom HEX=foo.hex rom: - python3 hex2rom.py $(HEX) > PIC/prog_rom.vhd + python3 hex2rom.py $(HEX) > hdl/prog_rom.vhd -# ── Container targets ──────────────────────────────────────────────────────── +# -- Container targets ---------------------------------------------------------------------------- -all: PIC/prog_rom.vhd +all: hdl/prog_rom.vhd $(PODMAN) make -f Makefile.inner -sim: program.hex +sim: $(BUILD)/program.hex $(PODMAN) make -f Makefile.inner sim -flash: pic_top.fs +flash: $(BUILD)/pic_top.fs openFPGALoader -b tangprimer25k $< show-top: - $(PODMAN) make -f Makefile.inner pic_top.dot - xdot pic_top.dot + $(PODMAN) make -f Makefile.inner $(BUILD)/pic_top.dot + xdot $(BUILD)/pic_top.dot show-uart: - $(PODMAN) make -f Makefile.inner uart.dot - xdot uart.dot + $(PODMAN) make -f Makefile.inner $(BUILD)/uart.dot + xdot $(BUILD)/uart.dot -# ── Clean ──────────────────────────────────────────────────────────────────── +# -- Clean ---------------------------------------------------------------------------- clean: $(PODMAN) make -f Makefile.inner clean - rm -f program.hex PIC/prog_rom.vhd - rm -f blink.hex blink.asm blink.cod blink.lst - rm -f test_uart.hex test_uart.asm test_uart.cod test_uart.lst + rm -rf $(BUILD) + rm -f hdl/prog_rom.vhd .PHONY: all sim clean flash show-top show-uart rom diff --git a/Makefile.inner b/Makefile.inner index 3184cc3..957843c 100644 --- a/Makefile.inner +++ b/Makefile.inner @@ -1,4 +1,5 @@ -PIC_DIR = PIC +HDL_DIR = hdl +BUILD = build DEVICE = GW5A-LV25MG121NES FAMILY = GW5A-25A @@ -10,72 +11,71 @@ STD = --std=08 # Synthesizable sources (no testbenches, no VHDL file-I/O packages) SYN_FILES = \ - $(PIC_DIR)/common.vhd \ - $(PIC_DIR)/decoder.vhd \ - $(PIC_DIR)/fifo.vhd \ - $(PIC_DIR)/uart.vhd \ - $(PIC_DIR)/ALU.vhd \ - $(PIC_DIR)/stack.vhd \ - $(PIC_DIR)/dpram.vhd \ - $(PIC_DIR)/state_machine.vhd \ - $(PIC_DIR)/PIC.vhd \ - $(PIC_DIR)/prog_rom.vhd \ - $(PIC_DIR)/pic_top.vhd + $(HDL_DIR)/common.vhd \ + $(HDL_DIR)/decoder.vhd \ + $(HDL_DIR)/fifo.vhd \ + $(HDL_DIR)/uart.vhd \ + $(HDL_DIR)/ALU.vhd \ + $(HDL_DIR)/stack.vhd \ + $(HDL_DIR)/dpram.vhd \ + $(HDL_DIR)/state_machine.vhd \ + $(HDL_DIR)/PIC.vhd \ + $(HDL_DIR)/prog_rom.vhd \ + $(HDL_DIR)/pic_top.vhd # Simulation adds the hex-reader package and testbenches SIM_FILES = \ - $(PIC_DIR)/common.vhd \ - $(PIC_DIR)/decoder.vhd \ - $(PIC_DIR)/hexfile_reader.vhd \ - $(PIC_DIR)/fifo.vhd \ - $(PIC_DIR)/uart.vhd \ - $(PIC_DIR)/ALU.vhd \ - $(PIC_DIR)/stack.vhd \ - $(PIC_DIR)/dpram.vhd \ - $(PIC_DIR)/state_machine.vhd \ - $(PIC_DIR)/PIC.vhd + $(HDL_DIR)/common.vhd \ + $(HDL_DIR)/decoder.vhd \ + $(HDL_DIR)/hexfile_reader.vhd \ + $(HDL_DIR)/fifo.vhd \ + $(HDL_DIR)/uart.vhd \ + $(HDL_DIR)/ALU.vhd \ + $(HDL_DIR)/stack.vhd \ + $(HDL_DIR)/dpram.vhd \ + $(HDL_DIR)/state_machine.vhd \ + $(HDL_DIR)/PIC.vhd TB_FILES = \ - $(PIC_DIR)/tb_stack.vhd \ - $(PIC_DIR)/tb_pic.vhd + $(HDL_DIR)/tb_stack.vhd \ + $(HDL_DIR)/tb_pic.vhd -all: $(TOP).fs +all: $(BUILD)/$(TOP).fs + +$(BUILD): + mkdir -p $@ # Synthesize -$(TOP).json: $(SYN_FILES) - ghdl -a $(STD) $(SYN_FILES) - yosys $(MODULE) -p "ghdl $(STD) $(TOP); memory_map; synth_gowin -json $@ -family gw5a" +$(BUILD)/$(TOP).json: $(SYN_FILES) | $(BUILD) + ghdl -a $(STD) --workdir=$(BUILD) $(SYN_FILES) + yosys $(MODULE) -p "ghdl $(STD) --workdir=$(BUILD) $(TOP); memory_map; synth_gowin -json $@ -family gw5a" # Place and route -$(TOP)_pnr.json: $(TOP).json $(CST) +$(BUILD)/$(TOP)_pnr.json: $(BUILD)/$(TOP).json $(CST) nextpnr-himbaechel --json $< --write $@ \ --device $(DEVICE) --vopt family=GW5A-25A --vopt cst=$(CST) \ - --vopt sspi_as_gpio --freq 50 --report $(TOP)_timing.json + --vopt sspi_as_gpio --freq 50 --report $(BUILD)/$(TOP)_timing.json # Pack bitstream -$(TOP).fs: $(TOP)_pnr.json +$(BUILD)/$(TOP).fs: $(BUILD)/$(TOP)_pnr.json gowin_pack --sspi_as_gpio --cpu_as_gpio -d $(FAMILY) -o $@ $< -sim: $(SIM_FILES) $(TB_FILES) - ghdl -a $(STD) $(SIM_FILES) $(TB_FILES) - ghdl -e $(STD) tb_stack - ghdl -r $(STD) tb_stack - ghdl -e $(STD) tb_pic - ghdl -r $(STD) tb_pic --vcd=tb_pic.vcd +sim: $(SIM_FILES) $(TB_FILES) | $(BUILD) + ghdl -a $(STD) --workdir=$(BUILD) $(SIM_FILES) $(TB_FILES) + ghdl -e $(STD) --workdir=$(BUILD) -o $(BUILD)/tb_stack tb_stack + ghdl -r $(STD) --workdir=$(BUILD) tb_stack + ghdl -e $(STD) --workdir=$(BUILD) -o $(BUILD)/tb_pic tb_pic + ghdl -r $(STD) --workdir=$(BUILD) tb_pic --vcd=$(BUILD)/tb_pic.vcd -pic_top.dot: $(SYN_FILES) - ghdl -a $(STD) $(SYN_FILES) - yosys $(MODULE) -p "ghdl $(STD) $(TOP); show -format dot -prefix pic_top" +$(BUILD)/pic_top.dot: $(SYN_FILES) | $(BUILD) + ghdl -a $(STD) --workdir=$(BUILD) $(SYN_FILES) + yosys $(MODULE) -p "ghdl $(STD) --workdir=$(BUILD) $(TOP); show -format dot -prefix $(BUILD)/pic_top" -uart.dot: $(PIC_DIR)/fifo.vhd $(PIC_DIR)/uart.vhd - ghdl -a $(STD) $(PIC_DIR)/fifo.vhd $(PIC_DIR)/uart.vhd - yosys $(MODULE) -p "ghdl $(STD) uart; show -format dot -prefix uart" +$(BUILD)/uart.dot: $(HDL_DIR)/fifo.vhd $(HDL_DIR)/uart.vhd | $(BUILD) + ghdl -a $(STD) --workdir=$(BUILD) $(HDL_DIR)/fifo.vhd $(HDL_DIR)/uart.vhd + yosys $(MODULE) -p "ghdl $(STD) --workdir=$(BUILD) uart; show -format dot -prefix $(BUILD)/uart" clean: - rm -f $(TOP).json $(TOP)_pnr.json $(TOP).fs $(TOP)_timing.json - rm -f pic_top.dot uart.dot - rm -f *.o work-obj08.cf e~*.lst - rm -f *.vcd - rm -f tb_pic tb_stack + rm -rf $(BUILD) .PHONY: all sim clean diff --git a/PIC/ALU.vhd b/PIC/ALU.vhd deleted file mode 100644 index b7c0344..0000000 --- a/PIC/ALU.vhd +++ /dev/null @@ -1,216 +0,0 @@ -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; diff --git a/PIC/PIC.vhd b/PIC/PIC.vhd deleted file mode 100644 index a31bec7..0000000 --- a/PIC/PIC.vhd +++ /dev/null @@ -1,181 +0,0 @@ -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 deleted file mode 100644 index 6789b0a..0000000 --- a/PIC/blink.c +++ /dev/null @@ -1,35 +0,0 @@ -#include - -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 deleted file mode 100644 index c986ec5..0000000 --- a/PIC/common.vhd +++ /dev/null @@ -1,10 +0,0 @@ -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 deleted file mode 100644 index 5a1eb2c..0000000 --- a/PIC/decoder.vhd +++ /dev/null @@ -1,155 +0,0 @@ -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 deleted file mode 100644 index 44d7adf..0000000 --- a/PIC/dpram.vhd +++ /dev/null @@ -1,110 +0,0 @@ -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 deleted file mode 100644 index 9dd8523..0000000 --- a/PIC/fifo.vhd +++ /dev/null @@ -1,75 +0,0 @@ -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 deleted file mode 100644 index b557c2b..0000000 --- a/PIC/hdl-prj.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "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 deleted file mode 100644 index 143a264..0000000 --- a/PIC/hexfile_reader.vhd +++ /dev/null @@ -1,342 +0,0 @@ -------------------------------------------------------------------------------- ---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 deleted file mode 100644 index f0cb4bd..0000000 --- a/PIC/pic_top.vhd +++ /dev/null @@ -1,81 +0,0 @@ -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 deleted file mode 100644 index f3dcf64..0000000 --- a/PIC/prog_rom.vhd +++ /dev/null @@ -1,1045 +0,0 @@ -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 => "11000001101111", - 3 => "00000010011010", - 4 => "11000000000001", - 5 => "00000010011011", - 6 => "11000010000000", - 7 => "00000000000000", - 8 => "00000000000000", - 9 => "10000100010010", - 10 => "00000000000000", - 11 => "00000000000000", - 12 => "01001010000011", - 13 => "00000000000000", - 14 => "00000010011101", - 15 => "00100000011011", - 16 => "00000010011100", - 17 => "11000001110001", - 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 => "10000100010010", - 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 => "10000100010010", - 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 => "10000100010010", - 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 => "10000100110011", - 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 => "10100010011110", - 157 => "00000000001000", - 158 => "00000110110101", - 159 => "11000000000001", - 160 => "00000010101111", - 161 => "11000001100111", - 162 => "00000010101110", - 163 => "11000010000000", - 164 => "00000010110000", - 165 => "00100000101110", - 166 => "00000010011010", - 167 => "00100000101111", - 168 => "00000010011011", - 169 => "00100000110000", - 170 => "10000101000110", - 171 => "11000001000011", - 172 => "10000101011110", - 173 => "11000000111010", - 174 => "10000101011110", - 175 => "00100000110101", - 176 => "00000010101110", - 177 => "00000110101111", - 178 => "11000011001000", - 179 => "00001000101110", - 180 => "01110000000011", - 181 => "10100011000000", - 182 => "11000000110010", - 183 => "10000101011110", - 184 => "00100000101110", - 185 => "00000010110000", - 186 => "11000000111000", - 187 => "00011100110000", - 188 => "00000010101110", - 189 => "11000000000001", - 190 => "00000010101111", - 191 => "10100011001101", - 192 => "11000001100100", - 193 => "00001000101110", - 194 => "01110000000011", - 195 => "10100011001101", - 196 => "11000000110001", - 197 => "10000101011110", - 198 => "00100000101110", - 199 => "00000010110000", - 200 => "11000010011100", - 201 => "00011100110000", - 202 => "00000010101110", - 203 => "11000000000001", - 204 => "00000010101111", - 205 => "11000000110000", - 206 => "00000010110000", - 207 => "11000000001010", - 208 => "00001000101110", - 209 => "01110000000011", - 210 => "10100011011010", - 211 => "00100000101110", - 212 => "00000010110001", - 213 => "11000011110110", - 214 => "00011100110001", - 215 => "00000010101110", - 216 => "00101010110000", - 217 => "10100011001111", - 218 => "00100000110000", - 219 => "00000010110001", - 220 => "00100000101111", - 221 => "01110100000011", - 222 => "10100011100011", - 223 => "00100000110000", - 224 => "11101000110000", - 225 => "01100100000011", - 226 => "10100011100101", - 227 => "00100000110001", - 228 => "10000101011110", - 229 => "00100000101110", - 230 => "00000010101111", - 231 => "11000000110000", - 232 => "00011100101111", - 233 => "00000010101110", - 234 => "10000101011110", - 235 => "11000000000001", - 236 => "00000010101111", - 237 => "11000001110111", - 238 => "00000010101110", - 239 => "11000010000000", - 240 => "00000010110000", - 241 => "00100000101110", - 242 => "00000010011010", - 243 => "00100000101111", - 244 => "00000010011011", - 245 => "00100000110000", - 246 => "10000101000110", - 247 => "00101010110101", - 248 => "00000110110010", - 249 => "00000110110011", - 250 => "00000110110100", - 251 => "00100000110100", - 252 => "00000010101000", - 253 => "00101000101000", - 254 => "00000010110100", - 255 => "00100000110100", - 256 => "01110100000011", - 257 => "10100011111011", - 258 => "00101000110011", - 259 => "00000010101000", - 260 => "00000010110011", - 261 => "00100000101000", - 262 => "11101000011110", - 263 => "01110100000011", - 264 => "10100011111010", - 265 => "00100000110010", - 266 => "00000010101000", - 267 => "00101000101000", - 268 => "00000010110010", - 269 => "11101001110100", - 270 => "01110100000011", - 271 => "10100011111001", - 272 => "10100010101011", - 273 => "00000000001000", - 274 => "11101000000000", - 275 => "01100100000011", - 276 => "10100100011010", - 277 => "11101010000000", - 278 => "01100100000011", - 279 => "10100100100100", - 280 => "00000110011011", - 281 => "11010000000000", - 282 => "00100000011010", - 283 => "00000010000100", - 284 => "01001110000011", - 285 => "01100000011011", - 286 => "01011110000011", - 287 => "00100000000000", - 288 => "00000010011011", - 289 => "00101010000100", - 290 => "00100000000000", - 291 => "00000000001000", - 292 => "00000000000000", - 293 => "00000000000000", - 294 => "10000101000001", - 295 => "00000010011001", - 296 => "00111110011010", - 297 => "00001110011011", - 298 => "00101010011011", - 299 => "00000000000000", - 300 => "00000000000000", - 301 => "10000101000001", - 302 => "00000010011000", - 303 => "00100000011001", - 304 => "00000010011011", - 305 => "00100000011000", - 306 => "00000000001000", - 307 => "11101000000000", - 308 => "01100100000011", - 309 => "10100100111010", - 310 => "11101010000000", - 311 => "01100100000011", - 312 => "10100101000001", - 313 => "11010000000000", - 314 => "00100000011010", - 315 => "00000010000100", - 316 => "01001110000011", - 317 => "01100000011011", - 318 => "01011110000011", - 319 => "00100000000000", - 320 => "00000000001000", - 321 => "00100000011011", - 322 => "00000010001010", - 323 => "00100000011010", - 324 => "00000010000010", - 325 => "00000000001000", - 326 => "00000010101100", - 327 => "00100000011011", - 328 => "00000010101011", - 329 => "00100000011010", - 330 => "00000010101010", - 331 => "00100000101010", - 332 => "00000010011010", - 333 => "00100000101011", - 334 => "00000010011011", - 335 => "00100000101100", - 336 => "10000100110011", - 337 => "00000010101101", - 338 => "00100000101101", - 339 => "01100100000011", - 340 => "10100101011101", - 341 => "00100000101101", - 342 => "10000101011110", - 343 => "00101010101010", - 344 => "01100100000011", - 345 => "00101010101011", - 346 => "01100100000011", - 347 => "00101010101100", - 348 => "10100101001011", - 349 => "00000000001000", - 350 => "00000010101000", - 351 => "01001010000011", - 352 => "00100001110010", - 353 => "00000010101001", - 354 => "01100000101001", - 355 => "10100101011111", - 356 => "00100000101000", - 357 => "00000011110000", - 358 => "00000000001000", - 359 => "11010001001000", - 360 => "11010001100101", - 361 => "11010001101100", - 362 => "11010001101100", - 363 => "11010001101111", - 364 => "11010000001101", - 365 => "11010000001010", - 366 => "11010000000000", - 367 => "11010000000001", - 368 => "11010000000000", - 369 => "11010001111010", - 370 => "11010000000001", - 371 => "11010000110110", - 372 => "11010000000000", - 373 => "11010000000001", - 374 => "11010000000000", - 375 => "11010000001101", - 376 => "11010000001010", - 377 => "11010000000000", - 378 => "11010000000000", - 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 deleted file mode 100644 index fd376c0..0000000 --- a/PIC/stack.vhd +++ /dev/null @@ -1,51 +0,0 @@ -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 deleted file mode 100644 index 24da581..0000000 --- a/PIC/state_machine.vhd +++ /dev/null @@ -1,222 +0,0 @@ -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 deleted file mode 100644 index 067e154..0000000 --- a/PIC/tb_pic.vhd +++ /dev/null @@ -1,83 +0,0 @@ -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 deleted file mode 100644 index 5b386e9..0000000 --- a/PIC/tb_stack.vhd +++ /dev/null @@ -1,121 +0,0 @@ -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 deleted file mode 100644 index 2656371..0000000 --- a/PIC/test_uart.c +++ /dev/null @@ -1,67 +0,0 @@ -#include - -typedef unsigned char uint8_t; - -__sfr __at(0x70) UART_TX; -__sfr __at(0x71) UART_RX; -__sfr __at(0x72) UART_STATUS; - -static volatile uint8_t _d0, _d1, _d2; -static uint8_t counter; - -static void delay(void) { - _d0 = 0; - do { - _d1 = 0; - do { - _d2 = 0; - do { _d2++; } while (_d2 != 0); - } while (++_d1 != 30); - _d0++; - } while (_d0 != 116); -} - -static void uart_send(uint8_t byte) { - while (UART_STATUS & 0x01); - UART_TX = byte; -} - -// Keep this ONLY for literal strings (ROM) -static void uart_puts_rom(const char *s) { - while (*s) { - uart_send((uint8_t)*s); - s++; - } -} - -void main(void) { - counter = 0; - uart_puts_rom("Hello\r\n"); - - while (1) { - uint8_t v = counter; - uint8_t started = 0; - - uart_send('C'); - uart_send(':'); - - // Hundreds - if (v >= 200) { uart_send('2'); v -= 200; started = 1; } - else if (v >= 100) { uart_send('1'); v -= 100; started = 1; } - - // Tens - { - uint8_t tens = '0'; - while (v >= 10) { v -= 10; tens++; } - if (started || tens != '0') { uart_send(tens); } - } - - // Units (always) - uart_send(v + '0'); - - uart_puts_rom("\r\n"); - - counter++; - delay(); - } -} diff --git a/PIC/uart.vhd b/PIC/uart.vhd deleted file mode 100644 index a0fad93..0000000 --- a/PIC/uart.vhd +++ /dev/null @@ -1,195 +0,0 @@ -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; diff --git a/fw/blink.c b/fw/blink.c new file mode 100644 index 0000000..6789b0a --- /dev/null +++ b/fw/blink.c @@ -0,0 +1,35 @@ +#include + +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/fw/fib.c b/fw/fib.c new file mode 100644 index 0000000..2ba9535 --- /dev/null +++ b/fw/fib.c @@ -0,0 +1,84 @@ +#include + +typedef unsigned char uint8_t; + +__sfr __at(0x70) UART_TX; +__sfr __at(0x71) UART_RX; +__sfr __at(0x72) UART_STATUS; + +static volatile uint8_t _d0, _d1, _d2; + +// Custom delay to make the output readable at 50MHz +static void delay(void) { + _d0 = 0; + do { + _d1 = 0; + do { + _d2 = 0; + do { _d2++; } while (_d2 != 0); + } while (++_d1 != 50); // Increased for 50MHz visibility + _d0++; + } while (_d0 != 20); +} + +static void uart_send(uint8_t byte) { + while (UART_STATUS & 0x01); + UART_TX = byte; +} + +static void uart_puts_rom(const char *s) { + while (*s) { + uart_send((uint8_t)*s); + s++; + } +} + +// Simple BCD printer for 8-bit numbers +void print_uint8(uint8_t v) { + uint8_t started = 0; + + // Hundreds + if (v >= 200) { uart_send('2'); v -= 200; started = 1; } + else if (v >= 100) { uart_send('1'); v -= 100; started = 1; } + + // Tens + uint8_t tens = '0'; + while (v >= 10) { v -= 10; tens++; } + if (started || tens != '0') { uart_send(tens); } + + // Units + uart_send(v + '0'); +} + +void main(void) { + uint8_t a, b, next; + + uart_puts_rom("\x1B[2J\x1B[H"); // Clear screen, Home cursor + uart_puts_rom("PIC16F84A @ 50MHz Fibonacci\r\n"); + uart_puts_rom("---------------------------\r\n"); + + while (1) { + a = 0; + b = 1; + + while (a <= 233) { // Max 8-bit Fib is 233 + print_uint8(a); + uart_puts_rom(", "); + + next = a + b; + a = b; + b = next; + + delay(); + + // Break before overflow + if (a == 233) { + print_uint8(a); + break; + } + } + + uart_puts_rom("\r\nRestarting...\r\n"); + delay(); + } +} diff --git a/fw/test_uart.c b/fw/test_uart.c new file mode 100644 index 0000000..4e18dc5 --- /dev/null +++ b/fw/test_uart.c @@ -0,0 +1,69 @@ +#include + +typedef unsigned char uint8_t; + +__sfr __at(0x70) UART_TX; +__sfr __at(0x71) UART_RX; +__sfr __at(0x72) UART_STATUS; + +static volatile uint8_t _d0, _d1, _d2; +static uint8_t counter; + +static void delay(void) { + _d0 = 0; + do { + _d1 = 0; + do { + _d2 = 0; + do { _d2++; } while (_d2 != 0); + } while (++_d1 != 30); + _d0++; + } while (_d0 != 10); +} + +static void uart_send(uint8_t byte) { + while (UART_STATUS & 0x01); + UART_TX = byte; +} + +// Keep this ONLY for literal strings (ROM) +static void uart_puts_rom(const char *s) { + while (*s) { + uart_send((uint8_t)*s); + s++; + } +} + +void main(void) { + counter = 0; + uart_puts_rom("counter\r\n"); + + while (1) { + uint8_t v = counter; + uint8_t started = 0; + + + uart_puts_rom("\r"); + uart_puts_rom("\x1B[K"); + + uart_send('C'); + uart_send(':'); + + // Hundreds + if (v >= 200) { uart_send('2'); v -= 200; started = 1; } + else if (v >= 100) { uart_send('1'); v -= 100; started = 1; } + + // Tens + { + uint8_t tens = '0'; + while (v >= 10) { v -= 10; tens++; } + if (started || tens != '0') { uart_send(tens); } + } + + // Units (always) + uart_send(v + '0'); + + counter++; + delay(); + } +} 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; diff --git a/hdl/PIC.vhd b/hdl/PIC.vhd new file mode 100644 index 0000000..a31bec7 --- /dev/null +++ b/hdl/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/hdl/common.vhd b/hdl/common.vhd new file mode 100644 index 0000000..c986ec5 --- /dev/null +++ b/hdl/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/hdl/decoder.vhd b/hdl/decoder.vhd new file mode 100644 index 0000000..5a1eb2c --- /dev/null +++ b/hdl/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/hdl/dpram.vhd b/hdl/dpram.vhd new file mode 100644 index 0000000..44d7adf --- /dev/null +++ b/hdl/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/hdl/fifo.vhd b/hdl/fifo.vhd new file mode 100644 index 0000000..9dd8523 --- /dev/null +++ b/hdl/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/hdl/hdl-prj.json b/hdl/hdl-prj.json new file mode 100644 index 0000000..b557c2b --- /dev/null +++ b/hdl/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/hdl/hexfile_reader.vhd b/hdl/hexfile_reader.vhd new file mode 100644 index 0000000..143a264 --- /dev/null +++ b/hdl/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/hdl/pic_top.vhd b/hdl/pic_top.vhd new file mode 100644 index 0000000..f0cb4bd --- /dev/null +++ b/hdl/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/hdl/stack.vhd b/hdl/stack.vhd new file mode 100644 index 0000000..fd376c0 --- /dev/null +++ b/hdl/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/hdl/state_machine.vhd b/hdl/state_machine.vhd new file mode 100644 index 0000000..5b1c623 --- /dev/null +++ b/hdl/state_machine.vhd @@ -0,0 +1,230 @@ +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'; + -- branch instructions complete over 2 cycles; pulse instr_ret only + -- on the phantom NOP cycle (below), not here + if instr.op /= GOTO and instr.op /= CALL and + instr.op /= RETUR and instr.op /= RETLW then + instr_ret <= '1'; + end if; + elsif not is_skip_phantom then + -- branch phantom NOP: this is the true end of the 2-cycle instruction + instr_ret <= '1'; + end if; + state <= IFetch; + + end case; + end if; -- reset + end if; + end process fsm; + +end architecture rtl; diff --git a/hdl/tb_pic.vhd b/hdl/tb_pic.vhd new file mode 100644 index 0000000..6e82ae2 --- /dev/null +++ b/hdl/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 := "build/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/hdl/tb_stack.vhd b/hdl/tb_stack.vhd new file mode 100644 index 0000000..5b386e9 --- /dev/null +++ b/hdl/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/hdl/uart.vhd b/hdl/uart.vhd new file mode 100644 index 0000000..a0fad93 --- /dev/null +++ b/hdl/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; diff --git a/test_uart.c b/test_uart.c deleted file mode 100644 index e69de29..0000000 diff --git a/test_uart.hex b/test_uart.hex deleted file mode 100644 index 70d8c2f..0000000 --- a/test_uart.hex +++ /dev/null @@ -1,50 +0,0 @@ -:020000040000FA -:10000000000002286F309A0001309B008030000011 -:100010000000122100000000831200009D001B0858 -:100020009C0071309E0001309F00831200001C086C -:10003000A0001D08A100FF309C07031C9D032108A0 -:10004000200403199A2804301E07A000A101A10D65 -:100050001F08A10720089A0021089B00803000009B -:10006000000012210000000083120000A3001B0802 -:10007000A2001E089A001F089B00803000000000AC -:1000800012210000000083120000A500A1001B083F -:10009000A000A40002301E07A000A101A10D1F08AE -:1000A000A10720089A0021089B0080300000000072 -:1000B00012210000000083120000A100A7001B080D -:1000C000A600A000831200002208A6002308A700B3 -:1000D000FF30A207031CA303270826040319932853 -:1000E00024089A0025089B0080300000000033217E -:1000F0000000000083120000A600200883120313F2 -:1001000084008313831200002118831726088312AA -:100110000313800083120000A40A0319A50AA00A91 -:100120000319A10A62280630831200009E070318F3 -:100130009F0A1528000000009E280800B501013024 -:10014000AF006730AE008030B0002E089A002F0854 -:100150009B00300846213508AE00AF0143305E21D8 -:100160003A305E21C8302E02031CC02832305E2196 -:100170002E08B00038303007AE000130AF00CD2877 -:1001800064302E02031CCD2831305E212E08B000D1 -:100190009C303007AE000130AF003030B0000A3084 -:1001A0002E02031CDA282E08B100F6303107AE000B -:1001B000B00ACF283008B1002F08031DE32830080B -:1001C000303A0319E52831085E212E08AF0030309F -:1001D0002F07AE005E210130AF007730AE008030D7 -:1001E000B0002E089A002F089B0030084621B50A5F -:1001F000B201B301B4013408A800280AB4003408DD -:10020000031DFB28330AA800B30028081E3A031D6B -:10021000FA283208A800280AB200743A031DF92807 -:10022000AB280800003A03191A29803A0319242937 -:100230009B0100341A08840083131B1883170008DD -:100240009B00840A0008080000000000412199007A -:100250009A0F9B039B0A0000000041219800190897 -:100260009B0018080800003A03193A29803A03193C -:10027000412900341A08840083131B1883170008CF -:1002800008001B088A001A0882000800AC001B083E -:10029000AB001A08AA002A089A002B089B002C0819 -:1002A0003321AD002D0803195D292D085E21AA0A0E -:1002B0000319AB0A0319AC0A4B290800A8008312E2 -:1002C0007208A90029185F292808F000080048349E -:1002D00065346C346C346F340D340A3400340134BA -:1002E00000347A34013436340034013400340D34AF -:0602F0000A340034003462 -:00000001FF -- cgit v1.3