本人所写的博客都为开发之中遇到问题记录的随笔,主要是给自己积累些问题。免日后无印象,如有不当之处敬请指正(欢迎进扣群 24849632 探讨问题);
要在不改变NES文件的情况下运行游戏程序,那么需要有一颗可以运行此机器码的CPU,因此我打算从开始重构一颗2A03CPU开始。经过这两天的工作,现在CPU的框架已经完成。
这个版本并没有按8位机的规范进行时序流程的设计,16位地址的计算直接使用两个加法单元,期待在一个时钟周期内,便将6502的绝对地址间接寻址功能完成了地址进行计算、内存取数、间接计算、甚至数据回存都完成。但因为时序逻辑比较混乱,QUARTS II 在生成网表时将所有的逻辑门都优化成了0,因此为了更快的解决问题,因此这一版本的架构直接做废。
第二版本重新对CPU的架构进行了优化,完全按8位机的架构进行设计,以下便将完成框架图中的各个组件,并完成子模块的仿真及设计。
编写PC及最简控制器
stack.vhdl
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
entity stack is
generic (SIZE:INTEGER := 128);
port(
wr : IN std_logic;
cs : IN std_logic;
clk : IN std_logic;
reset : IN std_logic;
addr : INOUT std_logic_vector(15 downto 0)
);
end stack;
architecture arch_stack of stack is
type stack_ARRAY is array (0 to SIZE-1) of std_logic_vector (15 downto 0);
signal stack_body : stack_ARRAY;
signal stack_postion : integer range 0 to 127;
begin
process(clk,reset)
begin
if(reset='1') then
stack_postion <= 0;
elsif(rising_edge(clk)) then
if(cs='1') then
if(wr='1') then --pop
addr <= stack_body(stack_postion);
stack_postion <= stack_postion-1;
else
stack_body(stack_postion) <= addr;
stack_postion <= stack_postion+1;
end if;
end if;
end if;
end process;
end arch_stack;
-- configuration config_stack of stack is
-- for arch_stack
-- end for;
-- end configuration;
rom.vhdl
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
USE WORK.PRJCONFIG.ALL;
entity rom is
generic (SIZE:INTEGER := 256);
port(
clk : IN std_logic;
wr : IN std_logic;
addr : IN std_logic_vector(15 downto 0);
data : IN std_logic_vector(7 downto 0);
code : OUT std_logic_vector(7 downto 0)
);
end rom;
architecture arch_rom of rom is
type rom_ARRAY is array (SIZE-1 downto 0) of std_logic_vector (7 downto 0);
signal rom_body : rom_ARRAY;
begin
process(clk)
variable addr_temp: BYTE;
begin
if(rising_edge(clk)) then
if(addr(15)='1') then
-- address limit at 8000H ~ FFFFH
addr_temp := conv_integer(addr);
if(wr='1') then
rom_body(addr_temp) <= data;
else
code <= rom_body(addr_temp);
end if;
end if;
end if;
end process;
end arch_rom;
-- configuration config_rom of rom is
-- for arch_rom
-- end for;
-- end configuration;
pc.vhdl
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
-- USE IEEE.NUMERIC_STD.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
USE WORK.PRJCONFIG.ALL;
entity pc is
port (
-- input from global
clk : in std_logic;
-- input form nesupdata
reset : in std_logic;
-- input form controller
ent : in std_logic;
load : in std_logic;
model : in std_logic_vector(1 downto 0);
preset : in std_logic_vector(15 downto 0);
-- io to statck
saddr : inout std_logic_vector(15 downto 0);
-- output to rom
pcout : out std_logic_vector(15 downto 0)
);
end pc;
architecture arch_pc of pc is
signal current_pc: WORD := 0;
begin
process(clk,reset,load,model)
begin
-- clock process
if(reset='1') then
-- 【复位信号】为高时清除PC值,回程序起始位置
current_pc <= 0;
elsif(rising_edge(clk)) then
if(model(1)='1') then
-- 【栈地址】保存与恢复
if(load='1') then
-- from stack to pc
current_pc <= CONV_INTEGER(saddr);
else
-- from pc to stack
saddr <= CONV_STD_LOGIC_VECTOR(current_pc,16);
end if;
elsif(model(0)='1') then
if(load='1') then
-- 从地址预设线中加载地址数据
current_pc <= CONV_INTEGER(preset);
elsif(ent='1') then
-- 指向下一指令地址
current_pc <= current_pc+1;
end if;
saddr <= (others=>'Z');
end if;
pcout <= CONV_STD_LOGIC_VECTOR(current_pc,16);
end if;
end process;
end arch_pc;
nesupdata.vhdl
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
USE WORK.PRJCONFIG.ALL;
entity nesupdata is
port(
-- from global
clk : IN std_logic;
reset_n : IN std_logic;
-- avalon jock
avalon_wr : IN std_logic;
avalon_addr: IN std_logic_vector(2 downto 0);
avalon_data: IN std_logic_vector(24 downto 0);
-- output to rom
rom_wr : OUT std_logic;
rom_addr : OUT std_logic_vector(15 downto 0);
rom_data : OUT std_logic_vector(7 downto 0);
-- output to pc
sys_reset : OUT std_logic;
-- output to control
ctr_pause : OUT std_logic
);
end nesupdata;
architecture arch_nesupdata of nesupdata is
begin
process(clk,reset_n)
begin
if(reset_n='0') then
sys_reset <= '1';
ctr_pause <= '1';
elsif(rising_edge(clk)) then
sys_reset <= '0';
if(avalon_wr='0') then
case avalon_addr is
when "000" =>
-- nes 数据下载或停止命令
if(avalon_data(0)='1') then
rom_wr <= '1';
ctr_pause <= '1';
sys_reset <= '1';
else
rom_wr <= '0';
end if;
when "001" =>
-- 下载NES调色板数据
rom_addr <= avalon_data(23 downto 8);
rom_data <= avalon_data(7 downto 0);
when "010" =>
-- 下载NES游戏数据
rom_addr <= avalon_data(23 downto 8);
rom_data <= avalon_data(7 downto 0);
when "011" =>
-- NES游戏开始
rom_wr <= '0';
ctr_pause <= '0';
sys_reset <= '0';
when others => null;
end case;
end if;
end if;
end process;
end arch_nesupdata;
controller.vhdl
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
-- USE IEEE.NUMERIC_STD.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
USE WORK.PRJCONFIG.ALL;
entity controller is
port (
-- input from global
clk : in std_logic;
-- nesupdate to controller
reset : in std_logic;
pause : in std_logic;
-- controller to pc
ent : out std_logic;
load : out std_logic;
abs_addr : out std_logic_vector(15 downto 0);
-- rom to controller
rom_code : in std_logic_vector(7 downto 0);
-- memory & controller
op_cmd : out std_logic_vector(15 downto 0);
mem_addr : out std_logic_vector(15 downto 0);
mem_data : inout std_logic_vector(7 downto 0);
-- register
status : inout std_logic_vector(7 downto 0)
);
end controller;
architecture arch_controller of controller is
signal cmd_type: INDTYPE;
signal acc_temp,x_temp,y_temp: std_logic_vector(7 downto 0);
signal future_state, current_state: PRCSTATU;
begin
process(clk,reset,pause)
begin
if(reset='1') then
future_state <= PRCSTATU_READY;
elsif(rising_edge(clk)) then
if(pause='1') then
-- op_cmd <= "0001000001000001";
op_cmd <= cmdCreate(
OPCMD_FUN_ADD, -- 算式单元功能选择
OPCMD_ITEM_DISENB, -- 算式单元使能
OPCMD_ITEM_DISENB, -- Y寄存器片选
OPCMD_ITEM_DISENB, -- Y寄存器写使能
OPCMD_ITEM_DISENB, -- X寄存器片选
OPCMD_ITEM_DISENB, -- X寄存器写使能
OPCMD_ITEM_ENB, -- ACC寄存器片选
OPCMD_ITEM_DISENB, -- ACC寄存器写使能
OPCMD_ITEM_DISENB, -- RAM存储器写使能
OPCMD_ITEM_DISENB, -- ZPG存储器写使能
OPCMD_ITEM_DISENB, -- PPU存储器写使能
OPCMD_ITEM_DISENB, -- STACK存储器写使能
OPCMD_ITEM_ENB -- PC寄存器写使能
);
end if;
current_state <= future_state;
end if;
end process;
process(current_state,rom_code)
-- rom chip select & postion move signal
-- procedure romshift(rd: in std_logic; mv: in std_logic) is
-- begin
-- pc_cs <= rd;
-- pc_ent <= mv;
-- end romshift;
begin
-- 状态机指令解析
case current_state is
when PRCSTATU_READY => -- 取指令操作码
case rom_code is
when X"6D" => -- ADC abs
cmd_type <= INDT_ABS;
acc_temp <= mem_data;
mem_data <= not(status);
-- when 16#E8# => res := 1; -- INX
-- when 16#C8# => res := 1; -- INY
-- when 16#CA# => res := 1; -- DEX
-- when 16#88# => res := 1; -- DEY
-- when 16#0A# => res := 1; -- ASL
-- when 16#4A# => res := 1; -- LSR
-- when 16#2A# => res := 1; -- ROL
-- when 16#6A# => res := 1; -- ROR
-- when 16#00# => res := 1; -- BRK
-- when 16#40# => res := 1; -- RTI
-- when 16#60# => res := 1; -- RTS
-- when 16#18# => res := 1; -- CLC
-- when 16#D8# => res := 1; -- CLD
-- when 16#58# => res := 1; -- CLI
-- when 16#B8# => res := 1; -- CLV
-- when 16#38# => res := 1; -- SEC
-- when 16#F8# => res := 1; -- SED
-- when 16#78# => res := 1; -- SEI
-- when 16#AA# => res := 1; -- TAX
-- when 16#A8# => res := 1; -- TAY
-- when 16#BA# => res := 1; -- TSX
-- when 16#8A# => res := 1; -- TXA
-- when 16#9A# => res := 1; -- TXS
-- when 16#98# => res := 1; -- TYA
-- when 16#48# => res := 1; -- PHA
-- when 16#08# => res := 1; -- PHP
-- when 16#68# => res := 1; -- PLA
-- when 16#28# => res := 1; -- PLP
-- when 16#EA# => res := 1; -- NOP
-- when 16#6D# => res := 3; -- ADC abs
-- when 16#7D# => res := 3; -- ADC abs,x
-- when 16#79# => res := 3; -- ADC abs,y
-- when 16#EE# => res := 3; -- INC abs
-- when 16#FE# => res := 3; -- INC abs,x
-- when 16#ED# => res := 3; -- SBC abs
-- when 16#FD# => res := 3; -- SBC abs,x
-- when 16#F9# => res := 3; -- SBC abs,y
-- when 16#CE# => res := 3; -- DEC abs
-- when 16#DE# => res := 3; -- DEC abs,x
-- when 16#2D# => res := 3; -- AND abs
-- when 16#3D# => res := 3; -- AND abs,x
-- when 16#39# => res := 3; -- AND abs,y
-- when 16#4D# => res := 3; -- EOR abs
-- when 16#5D# => res := 3; -- EOR abs,x
-- when 16#59# => res := 3; -- EOR abs,y
-- when 16#0D# => res := 3; -- ORA abs
-- when 16#11# => res := 3; -- ORA (abs),y
-- when 16#1D# => res := 3; -- ORA abs,x
-- when 16#19# => res := 3; -- ORA abs,y
-- when 16#2C# => res := 3; -- BIT abs
-- when 16#0E# => res := 3; -- ASL abs
-- when 16#1E# => res := 3; -- ASL abS,x
-- when 16#4E# => res := 3; -- LSR abs
-- when 16#5E# => res := 3; -- LSR abs,x
-- when 16#2E# => res := 3; -- ROL abs
-- when 16#3E# => res := 3; -- ROL abs,x
-- when 16#6E# => res := 3; -- ROR abs
-- when 16#7E# => res := 3; -- ROR abs,x
-- when 16#4C# => res := 3; -- JMP abs
-- when 16#6C# => res := 3; -- JMP (abs)
-- when 16#20# => res := 3; -- JSR oper
-- when 16#CD# => res := 3; -- CMP abs
-- when 16#DD# => res := 3; -- CMP abs,x
-- when 16#D9# => res := 3; -- CMP abs,y
-- when 16#EC# => res := 3; -- CPX abs
-- when 16#CC# => res := 3; -- CPY abs
-- when 16#AD# => res := 3; -- LDA abs
-- when 16#BD# => res := 3; -- LDA abs,x
-- when 16#B9# => res := 3; -- LDA abs,y
-- when 16#AE# => res := 3; -- LDX abs
-- when 16#BE# => res := 3; -- LDX abs,y
-- when 16#AC# => res := 3; -- LDY abs
-- when 16#BC# => res := 3; -- LDY abs,X
-- when 16#8D# => res := 3; -- STA abs
-- when 16#9D# => res := 3; -- STA abs,x
-- when 16#99# => res := 3; -- STA abs,y
-- when 16#8E# => res := 3; -- STX abs
-- when 16#8C# => res := 3; -- STY abs
when others => null;
end case;
when others => NULL;
end case;
end process;
end arch_controller;
简单的编写了CPU架构的ROM读取读取及更新部份,编译后依然得到的逻辑数为0
这就有点儿郁闷了,这个问题是因为什么问题造成的呢?
难不成问题是输入输出引脚间没有对应关系吗?我这是一个CPU,它虽然有输出引脚,但是却是键盘接口与显示器接口,那下面我就先随便的添加一个简单的外部IO试试看是不是因为这个原因吧!