📄 piccore.vhd
字号:
-- PICCORE.vhd-- CPU core of CQPIC (PIC16F84/16F84A)-- (1) Version 1.00a Nov 1 1999-- (2) Version 1.00b Dec 10 2000 made a patch for BUG in MAX+plus2 VHDL compiler-- (3) Version 1.00c Aug 07 2002 made a patch for carry flag operations at substraction operations-- (4) Version 1.00d Aug 26 2004 debugged Z flag behavior (in case such that distinations are same as them)---- Copyright(c)1999-2004 Sumio Morioka-- e-mail:morioka@fb3.so-net.ne.jp, URL:http://www02.so-net.ne.jp/~morioka/cqpic.htmlibrary ieee;use ieee.std_logic_1164.all;use ieee.std_logic_unsigned.all;entity piccore is generic ( -- You can change the following parameters as you would like STACK_SIZE : integer := 8; -- Size of PC stack WDT_SIZE : integer := 255 -- Size of watch dog timer (WDT) ); port ( -- program ROM data bus/address bus progdata : in std_logic_vector(13 downto 0); -- ROM read data progadr : out std_logic_vector(12 downto 0); -- ROM address -- data RAM data bus/address bus/control signals ramdtin : in std_logic_vector(7 downto 0); -- RAM read data ramdtout : out std_logic_vector(7 downto 0); -- RAM write data ramadr : out std_logic_vector(8 downto 0); -- RAM address; ramadr(8..7) indicates RAM-BANK readram : out std_logic; -- RAM read strobe (H active) writeram : out std_logic; -- RAM write strobe (H active) -- EEPROM data bus/address bus existeeprom : in std_logic; -- Set to '1' if EEPROM is implemented. eepdtin : in std_logic_vector(7 downto 0); -- EEPROM read data eepdtout : out std_logic_vector(7 downto 0); -- EEPROM write data eepadr : out std_logic_vector(7 downto 0); -- EEPROM address readeepreq : out std_logic; -- EEPROM read request (H active) readeepack : in std_logic; -- EEPROM read acknowledge (H active) writeeepreq : out std_logic; -- EEPROM write request (H active) writeeepack : in std_logic; -- EEPROM write acknowledge (H active) -- I/O ports porta_in : in std_logic_vector(4 downto 0); -- PORT-A input data porta_out : out std_logic_vector(4 downto 0); -- PORT-A output data porta_dir : out std_logic_vector(4 downto 0); -- TRISA: PORT-A signal direction (H:input, L:output) portb_in : in std_logic_vector(7 downto 0); -- PORT-B input data portb_out : out std_logic_vector(7 downto 0); -- PORT-B output data portb_dir : out std_logic_vector(7 downto 0); -- TRISB: PORT-B signal direction (H:input, L:output) rbpu : out std_logic; -- PORT_B pull-up enable (usually not used) -- PORT-B interrupt input int0 : in std_logic; -- PORT-B(0) INT int4 : in std_logic; -- PORT-B(4) INT int5 : in std_logic; -- PORT-B(5) INT int6 : in std_logic; -- PORT-B(6) INT int7 : in std_logic; -- PORT-B(7) INT -- TMR0 Control t0cki : in std_logic; -- T0CKI (PORT-A(4)) -- Watch Dog Timer Control wdtena : in std_logic; -- WDT enable (H active) wdtclk : in std_logic; -- WDT clock wdtfull : out std_logic; -- WDT-full indicator (H active) -- CPU clock stop/start indicators powerdown : out std_logic; -- SLEEP-mode; if H, you can stop system clock clkin startclkin : out std_logic; -- WAKEUP; if H, you should turn on clock for waking up from sleep-mode -- CPU reset ponrst_n : in std_logic; -- Power-on reset (L active) mclr_n : in std_logic; -- Normal reset (L active) -- CPU clock clkin : in std_logic; -- Clock input clkout : out std_logic -- Clock output (clkin/4) );end piccore;architecture RTL of piccore is -- User registers signal w_reg : std_logic_vector(7 downto 0); -- W signal tmr0_reg : std_logic_vector(7 downto 0); -- TMR0 signal pc_reg : std_logic_vector(12 downto 0); -- PCH/PCL signal status_reg : std_logic_vector(7 downto 0); -- STATUS signal fsr_reg : std_logic_vector(7 downto 0); -- FSR signal portain_sync_reg : std_logic_vector(4 downto 0); -- PORTA IN (synchronizer) signal portaout_reg : std_logic_vector(4 downto 0); -- PORTA OUT signal portbin_sync_reg : std_logic_vector(7 downto 0); -- PORTB IN (synchronizer) signal portbout_reg : std_logic_vector(7 downto 0); -- PORTB OUT signal eedata_reg : std_logic_vector(7 downto 0); -- EEDATA signal eeadr_reg : std_logic_vector(7 downto 0); -- EEADR signal pclath_reg : std_logic_vector(4 downto 0); -- PCLATH signal intcon_reg : std_logic_vector(7 downto 0); -- INTCON signal option_reg : std_logic_vector(7 downto 0); -- OPTION signal trisa_reg : std_logic_vector(4 downto 0); -- TRISA signal trisb_reg : std_logic_vector(7 downto 0); -- TRISB signal eecon1_reg : std_logic_vector(4 downto 0); -- EECON1 -- Internal registers for controlling instruction execution signal inst_reg : std_logic_vector(13 downto 0); -- Hold fetched op-code/operand signal aluinp1_reg : std_logic_vector(7 downto 0); -- data source (1 of 2)--> changed ver1.00c, 2002/08/07-- signal aluinp2_reg : std_logic_vector(7 downto 0); -- data source (2 of 2) signal aluinp2_reg : std_logic_vector(8 downto 0); -- data source (2 of 2)--< signal aluout_reg : std_logic_vector(7 downto 0); -- result of calculation signal exec_op_reg : std_logic; -- if L (i.e. GOTO instruction etc), stall exec of instruction signal intstart_reg : std_logic; -- if H (i.e. interrupt), stall exec of instruction signal sleepflag_reg : std_logic; -- if H, sleeping -- Stack type STACK_TYPE is array (STACK_SIZE - 1 downto 0) of std_logic_vector(12 downto 0); signal stack_reg : STACK_TYPE; -- stack body (array of data-registers) signal stack_pnt_reg : integer range 0 to STACK_SIZE - 1; -- stack pointer (binary encoded) signal stack_pos_node : std_logic_vector(STACK_SIZE - 1 downto 0); -- same with stack pointer, but one-hot encoded signal stacktop_node : std_logic_vector(12 downto 0); -- data value of stack-top -- WDT register and its control signal wdt_reg : integer range 0 to WDT_SIZE; -- WDT counter signal wdt_full_reg : std_logic; -- WDT->CPU; hold WDT-full signal until CPU is reset signal wdt_full_sync_reg : std_logic_vector(2 downto 0); -- CPU; synchronizer for wdt_full_reg signal wdt_clr_reg : std_logic; -- CPU->WDT; request to zero-clear wdt_reg signal wdt_clr_reqhold_reg : std_logic; -- CPU; hold a clear-request if previous request is still processing signal wdtclr_req_reg : std_logic_vector(1 downto 0); -- WDT; synchronizer for wdt_clr_reg signal wdtclr_ack : std_logic; -- WDT->CPU; ack to wdt_clr_reg (same with wdtclr_req_reg(1)) signal wdtclr_ack_sync_reg : std_logic; -- CPU; synchronizer for wdtclr_ack signal wdtfull_clr_reg : std_logic; -- CPU->WDT; requst to clear wdt_full_reg signal wdtfullclr_req_reg : std_logic_vector(1 downto 0); -- WDT; synchronizer for wdtfull_clr_reg -- TMR0 prescaler signal psck : std_logic; -- clock for prescaler signal pscale_reg : integer range 0 to 255; -- prescaler signal ps_full_reg : std_logic; -- clock for TMR0, from prescaler signal inctmrck : std_logic; -- clock for TMR0 signal inctmrhold_reg : std_logic; -- hold TMR0 increment request -- Interrupt registers/nodes signal intrise_reg : std_logic_vector(4 downto 0); -- detect positive edge of PORT-B inputs signal intdown_reg : std_logic_vector(4 downto 0); -- detect negative edge of PORT-B inputs signal rb0_int, rb4_int, rb5_int, rb6_int, rb7_int : std_logic;-- interrupt trigger signal rbint : std_logic; -- RB4-7 interrupt trigger signal inte : std_logic; -- RB0 interrupt trigger signal intclr_reg : std_logic_vector(4 downto 0); -- CPU; clear intrise_reg and intdown_reg -- State register constant STATEBIT_SIZE : integer := 3; signal state_reg : std_logic_vector(STATEBIT_SIZE - 1 downto 0); constant Qreset : std_logic_vector(STATEBIT_SIZE - 1 downto 0) := "100"; -- reset state constant Q1 : std_logic_vector(STATEBIT_SIZE - 1 downto 0) := "000"; -- state Q1 constant Q2 : std_logic_vector(STATEBIT_SIZE - 1 downto 0) := "001"; -- state Q2 constant Q3 : std_logic_vector(STATEBIT_SIZE - 1 downto 0) := "011"; -- state Q3 constant Q4 : std_logic_vector(STATEBIT_SIZE - 1 downto 0) := "010"; -- state Q4 -- Result of decoding instruction signal INST_ADDLW, INST_ADDWF, INST_ANDLW, INST_ANDWF, INST_BCF, INST_BSF, INST_BTFSC, INST_BTFSS : std_logic; signal INST_CALL, INST_CLRF, INST_CLRW, INST_CLRWDT, INST_COMF, INST_DECF, INST_DECFSZ : std_logic; signal INST_GOTO, INST_INCF, INST_INCFSZ, INST_IORLW, INST_IORWF, INST_MOVLW, INST_MOVF, INST_MOVWF : std_logic; signal INST_RETFIE, INST_RETLW, INST_RET, INST_RLF, INST_RRF : std_logic; signal INST_SLEEP, INST_SUBLW, INST_SUBWF, INST_SWAPF, INST_XORLW, INST_XORWF : std_logic; -- Result of calculating RAM access address signal ramadr_node : std_logic_vector(8 downto 0); -- RAM access address signal ADDR_TMR0, ADDR_PCL, ADDR_STAT, ADDR_FSR, ADDR_PORTA, ADDR_PORTB : std_logic; signal ADDR_EEDATA, ADDR_EEADR, ADDR_PCLATH, ADDR_INTCON, ADDR_OPTION, ADDR_TRISA, ADDR_TRISB : std_logic;-- signal ADDR_EECON1, ADDR_EECON2, ADDR_SRAM : std_logic; signal ADDR_EECON1, ADDR_SRAM : std_logic; -- Other output registers (for removing hazards) signal writeram_reg : std_logic; -- data-sram write strobe--> deleted ver1.00c, 2002/08/07-- signal ramadr_reg : std_logic_vector(8 downto 0); -- data-sram address--< signal clkout_reg : std_logic; -- clkout output -- Synchronizers signal inte_sync_reg : std_logic; signal rbint_sync_reg : std_logic; signal inctmr_sync_reg : std_logic_vector(1 downto 0); signal rdeep_sync_reg : std_logic; signal wreep_sync_reg : std_logic; signal mclr_sync_reg : std_logic; signal poweron_sync_reg : std_logic;begin-- CPU synchronizers u0:process (clkin) begin if (clkin'event and clkin = '1') then inte_sync_reg <= inte; rbint_sync_reg <= rbint; wdtclr_ack_sync_reg <= wdtclr_ack; mclr_sync_reg <= mclr_n; poweron_sync_reg <= ponrst_n; rdeep_sync_reg <= readeepack; wreep_sync_reg <= writeeepack; inctmr_sync_reg(0) <= inctmrck; inctmr_sync_reg(1) <= inctmr_sync_reg(0); if (poweron_sync_reg = '0' or mclr_sync_reg = '0') then wdt_full_sync_reg <= "000"; else wdt_full_sync_reg(0) <= wdt_full_reg; wdt_full_sync_reg(1) <= wdt_full_sync_reg(0); -- (remove meta-stable) wdt_full_sync_reg(2) <= wdt_full_sync_reg(1); -- (detect positive edge) end if; end if; end process;-- Decode OPcode (see pp.54 of PIC16F84 data sheet) -- only 1 signal of the following signals will be '1' INST_CALL <= '1' when inst_reg(13 downto 11) = "100" else '0'; INST_GOTO <= '1' when inst_reg(13 downto 11) = "101" else '0'; INST_BCF <= '1' when inst_reg(13 downto 10) = "0100" else '0'; INST_BSF <= '1' when inst_reg(13 downto 10) = "0101" else '0'; INST_BTFSC <= '1' when inst_reg(13 downto 10) = "0110" else '0'; INST_BTFSS <= '1' when inst_reg(13 downto 10) = "0111" else '0'; INST_MOVLW <= '1' when inst_reg(13 downto 10) = "1100" else '0'; INST_RETLW <= '1' when inst_reg(13 downto 10) = "1101" else '0'; INST_SUBLW <= '1' when inst_reg(13 downto 9) = "11110" else '0'; INST_ADDLW <= '1' when inst_reg(13 downto 9) = "11111" else '0'; INST_IORLW <= '1' when inst_reg(13 downto 8) = "111000" else '0'; INST_ANDLW <= '1' when inst_reg(13 downto 8) = "111001" else '0'; INST_XORLW <= '1' when inst_reg(13 downto 8) = "111010" else '0'; INST_SUBWF <= '1' when inst_reg(13 downto 8) = "000010" else '0'; INST_DECF <= '1' when inst_reg(13 downto 8) = "000011" else '0'; INST_IORWF <= '1' when inst_reg(13 downto 8) = "000100" else '0'; INST_ANDWF <= '1' when inst_reg(13 downto 8) = "000101" else '0'; INST_XORWF <= '1' when inst_reg(13 downto 8) = "000110" else '0'; INST_ADDWF <= '1' when inst_reg(13 downto 8) = "000111" else '0'; INST_MOVF <= '1' when inst_reg(13 downto 8) = "001000" else '0'; INST_COMF <= '1' when inst_reg(13 downto 8) = "001001" else '0'; INST_INCF <= '1' when inst_reg(13 downto 8) = "001010" else '0'; INST_DECFSZ <= '1' when inst_reg(13 downto 8) = "001011" else '0'; INST_RRF <= '1' when inst_reg(13 downto 8) = "001100" else '0'; INST_RLF <= '1' when inst_reg(13 downto 8) = "001101" else '0'; INST_SWAPF <= '1' when inst_reg(13 downto 8) = "001110" else '0'; INST_INCFSZ <= '1' when inst_reg(13 downto 8) = "001111" else '0'; INST_MOVWF <= '1' when inst_reg(13 downto 7) = "0000001" else '0'; INST_CLRW <= '1' when inst_reg(13 downto 7) = "0000010" else '0'; INST_CLRF <= '1' when inst_reg(13 downto 7) = "0000011" else '0'; INST_RET <= '1' when inst_reg(13 downto 0) = "00000000001000" else '0'; INST_RETFIE <= '1' when inst_reg(13 downto 0) = "00000000001001" else '0'; INST_SLEEP <= '1' when inst_reg(13 downto 0) = "00000001100011" else '0'; INST_CLRWDT <= '1' when inst_reg(13 downto 0) = "00000001100100" else '0';-- Calculate RAM access address (see pp.19 of PIC16F84 data sheet) -- if "d"=0, indirect addressing is used, so RAM address is BANK+FSR -- otherwise, RAM address is BANK+"d" -- (see pp.19 of PIC16F84 data sheet) ramadr_node <= status_reg(7) & fsr_reg(7 downto 0) when inst_reg(6 downto 0) = "0000000" else status_reg(6 downto 5) & inst_reg(6 downto 0); -- check if this is an access to external RAM or not ADDR_SRAM <= '1' when ramadr_node(6 downto 0) > "0001011" else '0'; -- 0CH-7FH, 8CH-FFH -- check if this is an access to special register or not -- only 1 signal of the following signals will be '1' ADDR_TMR0 <= '1' when ramadr_node(7 downto 0) = "00000001" else '0'; -- 01H ADDR_PCL <= '1' when ramadr_node(6 downto 0) = "0000010" else '0'; -- 02H, 82H ADDR_STAT <= '1' when ramadr_node(6 downto 0) = "0000011" else '0'; -- 03H, 83H ADDR_FSR <= '1' when ramadr_node(6 downto 0) = "0000100" else '0'; -- 04H, 84H ADDR_PORTA <= '1' when ramadr_node(7 downto 0) = "00000101" else '0'; -- 05H ADDR_PORTB <= '1' when ramadr_node(7 downto 0) = "00000110" else '0'; -- 06H ADDR_EEDATA <= '1' when ramadr_node(7 downto 0) = "00001000" else '0'; -- 08H ADDR_EEADR <= '1' when ramadr_node(7 downto 0) = "00001001" else '0'; -- 09H ADDR_PCLATH <= '1' when ramadr_node(6 downto 0) = "0001010" else '0'; -- 0AH, 8AH ADDR_INTCON <= '1' when ramadr_node(6 downto 0) = "0001011" else '0'; -- 0BH, 8BH ADDR_OPTION <= '1' when ramadr_node(7 downto 0) = "10000001" else '0'; -- 81H ADDR_TRISA <= '1' when ramadr_node(7 downto 0) = "10000101" else '0'; -- 85H ADDR_TRISB <= '1' when ramadr_node(7 downto 0) = "10000110" else '0'; -- 86H ADDR_EECON1 <= '1' when ramadr_node(7 downto 0) = "10001000" else '0'; -- 88H-- ADDR_EECON2 <= '1' when ramadr_node(7 downto 0) = "10001001" else '0'; -- 89H-- Read value of PC-STACK top -- convert binary value of stack pointer into onehot value (for reducing circuit) ND1: for I in 0 to STACK_SIZE - 1 generate stack_pos_node(I) <= '1' when stack_pnt_reg = I else '0'; end generate ND1; -- pick up value of stack-top from stack cells u1:process (stack_reg, stack_pos_node) variable stack_cell : STACK_TYPE; -- value of each stack cell variable top : std_logic_vector(12 downto 0); -- value of stack top begin for I in 0 to STACK_SIZE - 1 loop if (stack_pos_node(I) = '1') then -- (if the position is stack top) stack_cell(I) := stack_reg(I); else stack_cell(I) := "0000000000000"; end if; end loop;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -