⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 piccpu.vhd

📁 The Synthetic PIC Verion 1.1 This a VHDL synthesizable model of a simple PIC 16C5x microcontro
💻 VHD
📖 第 1 页 / 共 2 页
字号:
	OPCODE_XORWF   <= '1' when INST(11 downto 6) = XORWF     else '0';
	OPCODE_ADDWF   <= '1' when INST(11 downto 6) = ADDWF     else '0';
	OPCODE_IORWF   <= '1' when INST(11 downto 6) = IORWF     else '0';
	OPCODE_MOVF    <= '1' when INST(11 downto 6) = MOVF      else '0';
	OPCODE_COMF    <= '1' when INST(11 downto 6) = COMF      else '0';
	OPCODE_INCF    <= '1' when INST(11 downto 6) = INCF      else '0';
	OPCODE_DECFSZ  <= '1' when INST(11 downto 6) = DECFSZ    else '0';
	OPCODE_RRF     <= '1' when INST(11 downto 6) = RRF       else '0';
	OPCODE_RLF     <= '1' when INST(11 downto 6) = RLF       else '0';
	OPCODE_SWAPF   <= '1' when INST(11 downto 6) = SWAPF     else '0';
	OPCODE_INCFSZ  <= '1' when INST(11 downto 6) = INCFSZ    else '0';

	-- Bit-Oriented File Register Operations
	OPCODE_BCF     <= '1' when INST(11 downto 8) = BCF      else '0';
	OPCODE_BSF     <= '1' when INST(11 downto 8) = BSF      else '0';
	OPCODE_BTFSC   <= '1' when INST(11 downto 8) = BTFSC    else '0';
	OPCODE_BTFSS   <= '1' when INST(11 downto 8) = BTFSS    else '0';

	 -- Literal and Control Operations
	OPCODE_OPTION  <= '1' when INST(11 downto 0) = OPTION   else '0';
	OPCODE_SLEEP   <= '1' when INST(11 downto 0) = SLEEP    else '0';
	OPCODE_CLRWDT  <= '1' when INST(11 downto 0) = CLRWDT   else '0';
	--*** CHECK OUT THE TRIS INSTRUCTION
	OPCODE_TRIS    <= '1' when INST(11 downto 0) = TRIS     else '0';
	OPCODE_RETLW   <= '1' when INST(11 downto 8) = RETLW    else '0';
	OPCODE_CALL    <= '1' when INST(11 downto 8) = CALL     else '0';
	OPCODE_GOTO    <= '1' when INST(11 downto 9) = GOTO     else '0';
	OPCODE_MOVLW   <= '1' when INST(11 downto 8) = MOVLW    else '0';
	OPCODE_IORLW   <= '1' when INST(11 downto 8) = IORLW    else '0';
	OPCODE_ANDLW   <= '1' when INST(11 downto 8) = ANDLW    else '0';
	OPCODE_XORLW   <= '1' when INST(11 downto 8) = XORLW    else '0';

	-- So, look at the instruction chart.  Which instructions affect the Z flag
	--
	STATUS_Z_WRITE <= '1' when ((OPCODE_CLRW  = '1') OR
										(OPCODE_CLRF  = '1')  OR
										(OPCODE_SUBWF = '1') OR
										(OPCODE_DECF  = '1')  OR
										(OPCODE_IORWF = '1') OR
										(OPCODE_ANDWF = '1') OR
										(OPCODE_XORWF = '1') OR
										(OPCODE_ADDWF = '1') OR
										(OPCODE_MOVF  = '1')  OR
										(OPCODE_COMF  = '1')  OR
										(OPCODE_INCF  = '1')  OR
										(OPCODE_IORLW = '1') OR
										(OPCODE_ANDLW = '1') OR
										(OPCODE_XORLW = '1')) Else '0';

	-- So, look at the instruction chart.  Which instructions affect the C flag
	--
	STATUS_C_WRITE <= '1' when ((OPCODE_SUBWF = '1') OR
										(OPCODE_ADDWF = '1') OR
										(OPCODE_RRF   = '1') OR
										(OPCODE_RLF   = '1')) Else '0';

	-- The input to the W register is WIN and is fed by a mux.
	-- There are only two busses that can affect a new W value; the W
	-- register itself, or the ALU output.  Now, even though there is
	-- a MOVLW instruction, the literal travels through the ALU!
	--
	WIN <= ALUOUT when ( (OPCODE_CLRW    = '1') OR
								(OPCODE_SUBWF   = '1' AND D = '0') OR
								(OPCODE_DECF    = '1' AND D = '0') OR
								(OPCODE_IORWF   = '1' AND D = '0') OR
								(OPCODE_ANDWF   = '1' AND D = '0') OR
								(OPCODE_XORWF   = '1' AND D = '0') OR
								(OPCODE_ADDWF   = '1' AND D = '0') OR
								(OPCODE_MOVF    = '1' AND D = '0') OR
								(OPCODE_COMF    = '1' AND D = '0') OR
								(OPCODE_INCF    = '1' AND D = '0') OR
								(OPCODE_DECFSZ  = '1' AND D = '0') OR
								(OPCODE_RRF     = '1' AND D = '0') OR
								(OPCODE_RLF     = '1' AND D = '0') OR
								(OPCODE_SWAPF   = '1' AND D = '0') OR
								(OPCODE_INCFSZ  = '1' AND D = '0') OR
								(OPCODE_RETLW   = '1') OR
								(OPCODE_MOVLW   = '1') OR
								(OPCODE_IORLW   = '1') OR
								(OPCODE_ANDLW   = '1') OR
								(OPCODE_XORLW   = '1'))
	  else W;

	-- The input to the Register File is FIN and is fed by a mux.
	-- The only two sources for new Register File values is either
	-- the register file itself (in other words, no change) or the
	-- output of the ALU.  Remember!  Most data gets routed through
	-- the ALU even if the ALU is not really doing anything to it.
	-- Look at the ALUOP operations per instruction to really understand
	-- this.
	--
	FIN <= ALUOUT when ( (OPCODE_CLRF    = '1')  OR
								(OPCODE_MOVWF   = '1')  OR
								(OPCODE_SUBWF   = '1' AND D = '1') OR
								(OPCODE_DECF    = '1' AND D = '1') OR
								(OPCODE_IORWF   = '1' AND D = '1') OR
								(OPCODE_ANDWF   = '1' AND D = '1') OR
								(OPCODE_XORWF   = '1' AND D = '1') OR
								(OPCODE_ADDWF   = '1' AND D = '1') OR
								(OPCODE_MOVF    = '1' AND D = '1') OR
								(OPCODE_COMF    = '1' AND D = '1') OR
								(OPCODE_INCF    = '1' AND D = '1') OR
								(OPCODE_DECFSZ  = '1' AND D = '1') OR
								(OPCODE_RRF     = '1' AND D = '1') OR
								(OPCODE_RLF     = '1' AND D = '1') OR
								(OPCODE_SWAPF   = '1' AND D = '1') OR
								(OPCODE_BCF     = '1') OR
								(OPCODE_BSF     = '1') OR
								(OPCODE_INCFSZ  = '1' AND D = '1'))
	  else FOUT;

	-- Register File write enable depends on the instruction..
	FWE <= '1' when (    (OPCODE_CLRF    = '1')  OR
								(OPCODE_MOVWF   = '1')  OR
								(OPCODE_BCF     = '1')  OR
								(OPCODE_BSF     = '1')  OR
								(OPCODE_SUBWF   = '1' AND D = '1') OR
								(OPCODE_DECF    = '1' AND D = '1') OR
								(OPCODE_IORWF   = '1' AND D = '1') OR
								(OPCODE_ANDWF   = '1' AND D = '1') OR
								(OPCODE_XORWF   = '1' AND D = '1') OR
								(OPCODE_ADDWF   = '1' AND D = '1') OR
								(OPCODE_MOVF    = '1' AND D = '1') OR
								(OPCODE_COMF    = '1' AND D = '1') OR
								(OPCODE_INCF    = '1' AND D = '1') OR
								(OPCODE_DECFSZ  = '1' AND D = '1') OR
								(OPCODE_RRF     = '1' AND D = '1') OR
								(OPCODE_RLF     = '1' AND D = '1') OR
								(OPCODE_SWAPF   = '1' AND D = '1') OR
								(OPCODE_INCFSZ  = '1' AND D = '1'))
	  else '0';



	-- The exact operation the ALU will perform is a function
	-- of the instruction.  Note that the ALU is used to do
	-- things like copying and clearing registers.  For example,
	-- clearing a register can be accomplished by XORing any
	-- two identical input into ALU and feeding the resulting
	-- zero into the destination, therefore, the CLRW instruction
	-- will force the ALU to do an XOR.
	--
	-- One way to see this, is to take the PIC instruction set table from
	-- the data book, and add 3 new columns.  First, the ALUA mux input
	-- (which can be F, K, or W), second column is the ALUB mux input
	-- (which can be F, K,, W or "00000001") and finally the third column
	-- which is the ALUOP.  For many instructions, the ALUOP is obvious.
	-- For example, for the ADDWF instruction, the ALUOP value is ALU_ADD.
	-- But for instruction like CLRW or MOVWF the ALUOP will be XOR, or OR.
	-- A little bit of Boolean Algebra will help you through this.
	--
	-- I believe that the above mechanisms are likely what is actually going
	-- on in the PIC, but since I'm not privy to their design, this is speculation.
	--
	ALUOP  <= ALUOP_SUB  when (OPCODE_SUBWF  = '1') OR
									  (OPCODE_DECF   = '1') OR
									  (OPCODE_DECFSZ = '1') else
				 ALUOP_ADD  when (OPCODE_ADDWF  = '1') OR
									  (OPCODE_INCF   = '1') OR
									  (OPCODE_INCFSZ = '1') else
				 ALUOP_OR   when (OPCODE_MOVWF  = '1') OR
									  (OPCODE_IORWF  = '1') OR
									  (OPCODE_MOVF   = '1') OR
									  (OPCODE_RETLW  = '1') OR
									  (OPCODE_MOVLW  = '1') OR
									  (OPCODE_IORLW  = '1') else
				 ALUOP_AND  when (OPCODE_ANDWF  = '1') OR
									  (OPCODE_ANDLW  = '1') else
				 ALUOP_XOR  when (OPCODE_CLRW   = '1') OR
									  (OPCODE_CLRF   = '1') OR
									  (OPCODE_XORWF  = '1') OR
									  (OPCODE_XORLW  = '1') else
				 ALUOP_COM  when (OPCODE_COMF   = '1') else
				 ALUOP_ROR  when (OPCODE_RRF    = '1') else
				 ALUOP_ROL  when (OPCODE_RLF    = '1') else
				 ALUOP_BITCLR when (OPCODE_BCF  = '1') else
				 ALUOP_BITSET when (OPCODE_BSF  = '1') else
				 ALUOP_BITTESTCLR when (OPCODE_BTFSC  = '1') else
				 ALUOP_BITTESTSET when (OPCODE_BTFSS  = '1') else
				 ALUOP_SWAP when (OPCODE_SWAPF  = '1') else
		 "1111";

	-- ALU Input port A should normally simply get the current W register.
	--
	ALUA  <= FOUT when (OPCODE_SUBWF  = '1') OR
							 (OPCODE_DECF   = '1') OR
							 (OPCODE_MOVF   = '1') OR
							 (OPCODE_COMF   = '1') OR
							 (OPCODE_INCF   = '1') OR
							 (OPCODE_DECFSZ = '1') OR
							 (OPCODE_RRF    = '1') OR
							 (OPCODE_RLF    = '1') OR
							 (OPCODE_SWAPF  = '1') OR
							 (OPCODE_INCFSZ = '1') OR
							 (OPCODE_BCF    = '1') OR
							 (OPCODE_BSF    = '1') OR
							 (OPCODE_BTFSC  = '1') OR
							 (OPCODE_BTFSS  = '1') else
				K    when (OPCODE_USE_K_OPERAND = '1')
		 else W;

	-- ALU Input port B should normally simply get the current F register file.
	--
	ALUB  <= W    when (OPCODE_MOVWF    = '1') OR
							 (OPCODE_CLRW     = '1') OR
							 (OPCODE_CLRF     = '1') OR
							 (OPCODE_SUBWF    = '1') OR
							 (OPCODE_IORLW    = '1') OR
							 (OPCODE_ANDLW    = '1') OR
							 (OPCODE_XORLW    = '1')  else
		 K         when (OPCODE_BCF      = '1') OR
							 (OPCODE_BSF      = '1') OR
							 (OPCODE_BTFSC    = '1') OR
							 (OPCODE_BTFSS    = '1') OR
							 (OPCODE_RETLW    = '1') OR
							 (OPCODE_MOVLW    = '1')  else
		"00000001" when (OPCODE_DECF     = '1') OR
							 (OPCODE_INCF     = '1') OR
							 (OPCODE_DECFSZ   = '1') OR
							 (OPCODE_INCFSZ   = '1')
		else FOUT;

	-- Process for deriving our 4 phase clock from the main clock.
	-- This is how the real PIC does it..
	--
	ClockDivider: process (Clk)
	begin
		-- *** Generate internal 4 phase clock
		if Clk'EVENT AND Clk = '1' then
			if MRST = '0' then
				Q1 <= '1';
				Q2 <= '0';
				Q3 <= '0';
				Q4 <= '0';
			else
				Q1 <= Q4;
				Q2 <= Q1;
				Q3 <= Q2;
				Q4 <= Q3;
			end if;
		end if;
	end process ClockDivider;

	-- Main Process is based on rising edge of Q1.
	--
	MainProcess: process (Q1)

	begin
		if Q1'EVENT AND Q1 = '1' then

			-- RESET!
			if MRST = '0' then
				-- Perhaps, more things need to be reset, but this is the minimum.
				PC     <= RESET_VECTOR;
				INST   <= NOP;
				STATUS <= "00000000";
			else

				-- For 2 cycle instructions, latch a NOP into INST so as not to
				-- distrurb ongoing instruction.
				if (OPCODE_GOTO   = '1') OR
					(OPCODE_RETLW  = '1') OR
					(OPCODE_CALL   = '1') OR
					(OPCODE_DECFSZ = '1' AND ALUZ = '1') OR
					(OPCODE_INCFSZ = '1' AND ALUZ = '1') OR
					(OPCODE_BTFSC  = '1' AND ALUZ = '1') OR
					(OPCODE_BTFSS  = '1' AND ALUZ = '1') OR
					(FWE = '1' AND v1d2int(FSEL) = 2)  then
					-- NOP
					INST <= NOP;
				else
					INST <= RomData;
				end if;

				-- Latch new values of registers based on MUX select lines
				W <= WIN;

				-- Handle writes to registers not actually in the REGFILE.
				-- Special functions could be added here!
				--
				if FWE = '1' then
					case v1d2int(FSEL) is
						when 0 => NULL;
						when 1 => RTCC   <= FIN;
						-- when 2 => PC(7 downto 0)     <= FIN; *** handle this below ***
						when 3 => STATUS <= FIN;
						when 4 => FSR    <= FIN;
						-- when 5 => PortA  <= FIN;  -- Let's make PortA an input !
						when 6 => PortBRegister <= FIN;
						when 7 => PortCRegister <= FIN;
						when OTHERS => NULL;
					end case;
				end if;

				-- Handle Status Flags
				if STATUS_C_WRITE = '1' then
					STATUS(0) <= ALUCOUT;
				end if;

				if STATUS_Z_WRITE = '1' then
					STATUS(2) <= ALUZ;
				end if;

				-- Handle the PC
				--
				-- GOTO instruction
				if OPCODE_GOTO = '1' then
					PC(8 downto 0) <= LONGK;

				-- CALL instruction
				elsif OPCODE_CALL = '1' then
					PC(7 downto 0) <= K;
					case v1d2int(STACKLEVEL) is
						when 0 => STACK1 <= PC;
									 STACKLEVEL <= "01";
						when 1 => STACK2 <= PC;
									 STACKLEVEL <= "10";
						when OTHERS => NULL;
					end case;

				-- RETLW instruction
				elsif OPCODE_RETLW = '1' then
					-- You can add more stack levels here!
					case v1d2int(STACKLEVEL) is
						when 1 => PC <= STACK1;
									 STACKLEVEL <= "00";
						when 2 => PC <= STACK2;
									 STACKLEVEL <= "01";
						when OTHERS => NULL;

					end case;

				-- Handle direct write to PC
				--
				elsif FWE = '1' AND v1d2int(FSEL) = 2 then
					PC(7 downto 0) <= FIN;

				-- Otherwise, just increment the PC
				else
					PC <= PCPLUS1(10 downto 0);
				end if;
			end if;
		end if;
	end process;

	-- *** NOT YET IMPLEMENTED ***
	-- *** In general, modeling of Ports is minimal. ***
	--
	-- Process for sampling input ports based on rising edge of Q2
	--SampleInputs: process (Q2)
	--
	--begin
	--	if PRising(Q2) then
	--
	--	end if;
	--end process SampleInputs;

end first;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -