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

📄 cpu65xx_fast.vhd

📁 FPGA64的VHDL源代码
💻 VHD
📖 第 1 页 / 共 4 页
字号:
			end if;
		when others =>
			null;
		end case;

		if (opcInfo(aluMode1From to aluMode1To) = aluModeBit)
		or (opcInfo(aluMode1From to aluMode1To) = aluModeFlg) then
			varN := rmwBits(7);
		else
			varN := nineBits(7);
		end if;
		varC := ninebits(8);
		if opcInfo(aluMode2From to aluMode2To) = aluModeArr then
			varC := aluInput(7);
			varV := aluInput(7) xor aluInput(6);
		end if;

		case opcInfo(aluMode2From to aluMode2To) is
		when aluModeAdc =>
			-- decimal mode high bits correction, is done after setting Z and N flags
			varV := (A(7) xor ninebits(7)) and (rmwBits(7) xor ninebits(7));
			if D = '1' then
				if ninebits(8 downto 4) > 9 then
					ninebits(8 downto 4) := ninebits(8 downto 4) + 6;
					varC := '1';
				end if;
			end if;
		when aluModeSbc =>
			varV := (A(7) xor ninebits(7)) and ((not rmwBits(7)) xor ninebits(7));
			if D = '1' then
				-- Check for borrow (lower 4 bits)
				if lowBits(5) = '0' then
					ninebits(3 downto 0) := ninebits(3 downto 0) - 6;
				end if;
				-- Check for borrow (upper 4 bits)
				if ninebits(8) = '0' then
					ninebits(8 downto 4) := ninebits(8 downto 4) - 6;
				end if;
			end if;
		when aluModeArr =>
			if D = '1' then
				if (("0" & aluInput(3 downto 0)) + ("0000" & aluInput(0))) > 5 then
					ninebits(3 downto 0) := ninebits(3 downto 0) + 6;
				end if;
				if (("0" & aluInput(7 downto 4)) + ("0000" & aluInput(4))) > 5 then
					ninebits(8 downto 4) := ninebits(8 downto 4) + 6;
					varC := '1';
				else
					varC := '0';
				end if;
			end if;
		when others =>
			null;
		end case;

		if rising_edge(clk) then
			aluRmwReg <= rmwBits(7 downto 0);
			aluNineReg <= ninebits(7 downto 0);
			aluCReg <= varC;
			aluZReg <= varZ;
			aluVReg <= varV;
			aluNReg <= varN;
		end if;

		aluRmwOut <= rmwBits(7 downto 0);
		aluRegisterOut <= ninebits(7 downto 0);
		aluC <= varC;
		aluZ <= varZ;
		aluV <= varV;
		aluN <= varN;
		if pipelineAluOut then
			aluRmwOut <= aluRmwReg;
			aluRegisterOut <= aluNineReg;
			aluC <= aluCReg;
			aluZ <= aluZReg;
			aluV <= aluVReg;
			aluN <= aluNReg;
		end if;
	end process;

calcInterrupt: process(clk)
	begin
		if rising_edge(clk) then
			if enable = '1' then
				if theCpuCycle = cycleStack4
				or reset = '1' then
					nmiReg <= '1';
				end if;

				if nextCpuCycle /= cycleBranchTaken
				and nextCpuCycle /= opcodeFetch then
					irqReg <= irq_n;
					nmiEdge <= nmi_n;
					if (nmiEdge = '1') and (nmi_n = '0') then
						nmiReg <= '0';
					end if;
				end if;
				-- The 'or opcInfo(opcSetI)' prevents NMI immediately after BRK or IRQ.
				-- Presumably this is done in the real 6502/6510 to prevent a double IRQ.
				processIrq <= not ((nmiReg and (irqReg or I)) or opcInfo(opcIRQ));
			end if;
		end if;
	end process;

calcNextOpcode: process(clk, di, reset, processIrq)
		variable myNextOpcode : unsigned(7 downto 0);
	begin
		-- Next opcode is read from input unless a reset or IRQ is pending.
		myNextOpcode := di;
		if reset = '1' then
			myNextOpcode := X"4C";
		elsif processIrq = '1' then
			myNextOpcode := X"00";
		end if;
		
		nextOpcode <= myNextOpcode;
	end process;

	nextOpcInfo <= opcodeInfoTable(to_integer(nextOpcode));
	process(clk)
	begin
		if rising_edge(clk) then
			nextOpcInfoReg <= nextOpcInfo;
		end if;
	end process;

	-- Read bits and flags from opcodeInfoTable and store in opcInfo.
	-- This info is used to control the execution of the opcode.
calcOpcInfo: process(clk)
	begin
		if rising_edge(clk) then
			if enable = '1' then
				if (reset = '1') or (theCpuCycle = opcodeFetch) then
					opcInfo <= nextOpcInfo;
					if pipelineOpcode then
						opcInfo <= nextOpcInfoReg;
					end if;
				end if;
			end if;
		end if;
	end process;

calcTheOpcode:	process(clk)
	begin	
		if rising_edge(clk) then
			if enable = '1' then
				if theCpuCycle = opcodeFetch then
					irqActive <= '0';
					if processIrq = '1' then
						irqActive <= '1';
					end if;
					-- Fetch opcode
					theOpcode <= nextOpcode;
				end if;
			end if;
		end if;
	end process;
	
-- -----------------------------------------------------------------------
-- State machine
-- -----------------------------------------------------------------------
	process(enable, theCpuCycle, opcInfo)
	begin
		updateRegisters <= false;
		if enable = '1' then
			if opcInfo(opcRti) = '1' then
				if theCpuCycle = cycleRead then
					updateRegisters <= true;
				end if;
			elsif theCpuCycle = opcodeFetch then
				updateRegisters <= true;
			end if;
		end if;
	end process;

	debugOpcode <= theOpcode;
	process(clk)
	begin
		if rising_edge(clk) then
			if enable = '1' then
				theCpuCycle <= nextCpuCycle;
			end if;
			if reset = '1' then
				theCpuCycle <= cycle2;
			end if;				
		end if;			
	end process;

	-- Determine the next cpu cycle. After the last cycle we always
	-- go to opcodeFetch to get the next opcode.
calcNextCpuCycle: process(theCpuCycle, opcInfo, theOpcode, indexOut, T, N, V, C, Z)
	begin
		nextCpuCycle <= opcodeFetch;

		case theCpuCycle is
		when opcodeFetch =>
			nextCpuCycle <= cycle2;
		when cycle2 =>
			if opcInfo(opcBranch) = '1' then
				if (N = theOpcode(5) and theOpcode(7 downto 6) = "00")
				or (V = theOpcode(5) and theOpcode(7 downto 6) = "01")
				or (C = theOpcode(5) and theOpcode(7 downto 6) = "10")
				or (Z = theOpcode(5) and theOpcode(7 downto 6) = "11") then
					-- Branch condition is true
					nextCpuCycle <= cycleBranchTaken;
				end if;
			elsif (opcInfo(opcStackUp) = '1') then
				nextCpuCycle <= cycleStack1;
			elsif opcInfo(opcStackAddr) = '1'
			and opcInfo(opcStackData) = '1' then
				nextCpuCycle <= cycleStack2;
			elsif opcInfo(opcStackAddr) = '1' then
				nextCpuCycle <= cycleStack1;
			elsif opcInfo(opcStackData) = '1' then
				nextCpuCycle <= cycleWrite;
			elsif opcInfo(opcAbsolute) = '1' then
				nextCpuCycle <= cycle3;
			elsif opcInfo(opcIndirect) = '1' then
				if opcInfo(indexX) = '1' then
					nextCpuCycle <= cyclePreIndirect;			
				else
					nextCpuCycle <= cycleIndirect;
				end if;					
			elsif opcInfo(opcZeroPage) = '1' then
				if opcInfo(opcWrite) = '1' then
					if (opcInfo(indexX) = '1')
					or (opcInfo(indexY) = '1') then
						nextCpuCycle <= cyclePreWrite;
					else						
						nextCpuCycle <= cycleWrite;
					end if;						
				else
					if (opcInfo(indexX) = '1')
					or (opcInfo(indexY) = '1') then
						nextCpuCycle <= cyclePreRead;
					else						
						nextCpuCycle <= cycleRead2;
					end if;						
				end if;					
			elsif opcInfo(opcJump) = '1' then
				nextCpuCycle <= cycleJump;
			end if;
		when cycle3 =>
			nextCpuCycle <= cycleRead;
			if opcInfo(opcWrite) = '1' then
				if (opcInfo(indexX) = '1')
				or (opcInfo(indexY) = '1') then
					nextCpuCycle <= cyclePreWrite;
				else						
					nextCpuCycle <= cycleWrite;
				end if;					
			end if;
			if (opcInfo(opcIndirect) = '1')
			and (opcInfo(indexX) = '1') then
				if opcInfo(opcWrite) = '1' then
					nextCpuCycle <= cycleWrite;
				else					
					nextCpuCycle <= cycleRead2;
				end if;
			end if;									
		when cyclePreIndirect =>			
			nextCpuCycle <= cycleIndirect;
		when cycleIndirect =>
			nextCpuCycle <= cycle3;
		when cycleBranchTaken =>
			if indexOut(8) /= T(7) then
				-- Page boundary crossing during branch.
				nextCpuCycle <= cycleBranchPage;
			end if;
		when cyclePreRead =>
			if opcInfo(opcZeroPage) = '1' then
				nextCpuCycle <= cycleRead2;
			end if;
		when cycleRead =>
			if opcInfo(opcJump) = '1' then
				nextCpuCycle <= cycleJump;
			elsif indexOut(8) = '1' then
				-- Page boundary crossing while indexed addressing.
				nextCpuCycle <= cycleRead2;
			elsif opcInfo(opcRmw) = '1' then
				nextCpuCycle <= cycleRmw;
				if opcInfo(indexX) = '1'
				or opcInfo(indexY) = '1' then
					-- 6510 needs extra cycle for indexed addressing
					-- combined with RMW indexing
					nextCpuCycle <= cycleRead2;
				end if;
			end if;											
		when cycleRead2 =>
			if opcInfo(opcRmw) = '1' then
				nextCpuCycle <= cycleRmw;
			end if;											
		when cycleRmw =>
			nextCpuCycle <= cycleWrite;
		when cyclePreWrite =>
			nextCpuCycle <= cycleWrite;
		when cycleStack1 =>
			nextCpuCycle <= cycleRead;
			if opcInfo(opcStackAddr) = '1' then
				nextCpuCycle <= cycleStack2;
			end if;				
		when cycleStack2 =>
			nextCpuCycle <= cycleStack3;
			if opcInfo(opcRti) = '1' then
				nextCpuCycle <= cycleRead;
			end if;
			if opcInfo(opcStackData) = '0'
			and opcInfo(opcStackUp) = '1' then
				nextCpuCycle <= cycleJump;
			end if;
		when cycleStack3 =>
			nextCpuCycle <= cycleRead;
			if opcInfo(opcStackData) = '0'
			or opcInfo(opcStackUp) = '1' then
				nextCpuCycle <= cycleJump;
			elsif opcInfo(opcStackAddr) = '1' then
				nextCpuCycle <= cycleStack4;				
			end if;
		when cycleStack4 =>
			nextCpuCycle <= cycleRead;
		when cycleJump =>
			if opcInfo(opcIncrAfter) = '1' then
				-- Insert extra cycle
				nextCpuCycle <= cycleEnd;
			end if;				
		when others =>
			null;
		end case;
	end process;		

-- -----------------------------------------------------------------------
-- T register
-- -----------------------------------------------------------------------
calcT: process(clk)
	begin
		if rising_edge(clk) then
			if enable = '1' then
				case theCpuCycle is
				when cycle2 =>
					T <= di;
				when cycleStack1 | cycleStack2 =>
					if opcInfo(opcStackUp) = '1' then
						-- Read from stack
						T <= di;
					end if;											
				when cycleIndirect | cycleRead | cycleRead2 =>
					T <= di;
				when others =>
					null;					
				end case;
			end if;
		end if;		
	end process;

-- -----------------------------------------------------------------------
-- A register
-- -----------------------------------------------------------------------
	process(clk)
	begin
		if rising_edge(clk) then
			if updateRegisters then
				if opcInfo(opcUpdateA) = '1' then
					A <= aluRegisterOut;
				end if;					
			end if;
		end if;
	end process;

-- -----------------------------------------------------------------------
-- X register
-- -----------------------------------------------------------------------
	process(clk)
	begin
		if rising_edge(clk) then
			if updateRegisters then
				if opcInfo(opcUpdateX) = '1' then
					X <= aluRegisterOut;
				end if;					
			end if;
		end if;
	end process;

-- -----------------------------------------------------------------------
-- Y register
-- -----------------------------------------------------------------------
	process(clk)
	begin
		if rising_edge(clk) then
			if updateRegisters then
				if opcInfo(opcUpdateY) = '1' then
					Y <= aluRegisterOut;
				end if;					

⌨️ 快捷键说明

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