在FPGA开发板上玩《超级玛丽》之笔记 -(2)重构2A03CPU

本人所写的博客都为开发之中遇到问题记录的随笔,主要是给自己积累些问题。免日后无印象,如有不当之处敬请指正(欢迎进扣群 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试试看是不是因为这个原因吧!

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

晶通物控

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值