找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 967|回复: 2
打印 上一主题 下一主题
收起左侧

这是我制作的vhdl CPU

[复制链接]
跳转到指定楼层
楼主
ID:764193 发表于 2020-5-29 13:33 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
附录A RTL图A1. 控制器的RTL图
file:///C:/Users/Quan/AppData/Local/Temp/msohtmlclip1/01/clip_image002.jpg
图A.1 控制器的RTL图
A2. CPU的RTL图
file:///C:/Users/Quan/AppData/Local/Temp/msohtmlclip1/01/clip_image002.jpg
图A.2 CPU的RTL图


附录B VHDL程序清单
(1)CPU.vhd文件
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.NUMERIC_STD.ALL;
----头文件
PACKAGE cpu_defs IS
TYPE opcode IS(load,sta,add,sub,and1,jmp1,nop);   ----枚举,七组唯一的二进制数值,0-6
CONSTANT word_w : NATURAL := 8;
CONSTANT op_w : NATURAL := 3;
CONSTANT rfill:STD_LOGIC_VECTOR(op_w-1 downto0):= ( others => '0');----三位零常量
--FUNCTIOn slv2op(slv:IN STD_LOGIC_VECTOR)RETURNopcode;
FUNCTION op2slv(op:in opcode)RETURNSTD_LOGIC_VECTOR;
END PACKAGE cpu_defs;
PACKAGE BODY cpu_defs IS
TYPE optable IS ARRAY(opcode) OFSTD_LOGIC_VECTOR(op_w-1 DOWNTO 0);---具有opcode个元素的数组,三位数据
CONSTANTtrans_table:optable:=("000","001","010","011","100","101","110");---七组二进制数与七个操作符一一对应
FUNCTION op2slv(op:IN opcode)RETURNSTD_LOGIC_VECTOR IS
BEGIN
RETURN trans_table(op);
END FUNCTION op2slv;----------输入操作符对应的无符号整数0-6,输出相对应的二进制编码
END PACKAGE BODY cpu_defs;
----源文件
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_unsigned.ALL;
USE IEEE.NUMERIC_STD.ALL;
USE WORK.CPU_DEFS.ALL;
ENTITY CPU IS
PORT( clock:IN STD_LOGIC;-----------时钟输入
     reset:IN STD_LOGIC;-----------置位输入
      mode:IN STD_LOGIC_VECTOR(2 DOWNTO 0);--------三位模式输入
     mem_addr:OUT UNSIGNED(word_w-op_w-3 DOWNTO 0);-------三位内存地址的输入
              output: OUT STD_LOGIC_VECTOR(word_w-1DOWNTO 0);-------八位数据输出
              data_r_out : OUT STD_LOGIC_VECTOR(23DOWNTO 0);--------24位微指令输出
              reg_out:OUT STD_LOGIC_VECTOR(word_w-1DOWNTO 0);
              regg_out: OUT STD_LOGIC_VECTOR(word_w-1 DOWNTO0);
              op_out: OUT STD_LOGIC_VECTOR(op_w-1DOWNTO 0);----------三位操作码输出
              add_r_out:OUT UNSIGNED(4 DOWNTO 0);         ----------五位地址输出
              segctl:OUT STD_LOGIC_VECTOR(3 DOWNTO 0);
              segout:OUT STD_LOGIC_VECTOR(6 DOWNTO 0)
              );
              
END ENTITY;
ARCHITECTURE rtl OF CPU IS
TYPE mem_array IS ARRAY (0 To2**(word_w-op_w-2)-1) OF STD_LOGIC_VECTOR(word_w-1 DOWNTO 0);----八位数组,每个元素为八位二进制数
       SIGNALmem : mem_array;--------------------------------存储器内存储的内容,程序和数据
       CONSTANTprog: mem_array:=(
     0=>op2slv(load)&STD_LOGIC_VECTOR(TO_UNSIGNED(7,word_w-op_w-2))&"00",  --00011100  4-2加载的对象  ---------load内存中内容存到acc
              1=>op2slv(sta)&"001"&"01",                                            --00100101  4-2无作用      ---------sta把acc中内容存到reg1
              2=>op2slv(add)&STD_LOGIC_VECTOR(TO_UNSIGNED(6,word_w-op_w-2))&"00",   --01011000                 ---------add把acc与内存中数据相加给acc
              3=>op2slv(sub)&"001"&"01",                                            --01100101   4-2无作用      ---------sub acc中内容减去reg1中内容 给acc
              4=>op2slv(sta)&"010"&"10",                                            --00101010   4-2无作用      ---------sta把acc中内容存到men(7)
              --5=> op2slv(and1) &"010" & "10",
              5=>op2slv(jmp1)&STD_LOGIC_VECTOR(TO_UNSIGNED(6,word_w-op_w-2))&"00",  --10111000                ---------acc结果为零,跳到空操作,否则跳到第二条指令
              6=>STD_LOGIC_VECTOR(TO_UNSIGNED(4,word_w)),                           --00000010
              7=>STD_LOGIC_VECTOR(TO_UNSIGNED(6,word_w)));                          --00000011
               --7-5本条程序的功能 --4-2下一条程序的位置(具体三位二进制数) 或 本条程序的对象
               -----------------------事先编好的存入存储器的内容
     TYPE microcode_array IS ARRAY (0 To 20) OF STD_LOGIC_VECTOR(23 DOWNTO0);
              CONSTANT code:microcode_array:=(
0=> "000000001001010000000001",
          1=> "000000000000000110000010",
          2=> "000000000110000000000011",
          3=> "000000000001001000011111",
4=>"000000010010000000000000",
          5=>"000100000000000000000000",
6=>"100000000000000000000111",
          7=>"000010000001000000001111",
          8=> "000000000000000110000100",
          9=>"010000000000000000011110",
         10=> "000000000000000110010000",
         11=> "000001000000100000100000",
         12=> "000010000001000000010001",
         13=> "000000000000000110011100",
         14=> "000000000000000000000000",
         15=> "000000000000000100000000",
         16=> "000000000010100001000000",
         17=> "000000000000000110010010",
         18=> "001000000010100000000000",
         19=> "000000100010000000000000",
         20=>"000000000000000000000000");-------------21个元素,24位二进制操作码数组
SIGNAL count:UNSIGNED(word_w-op_w-1 DOWNTO0);--------五位计数值
SIGNAL op:STD_LOGIC_VECTOR(op_w-1 DOWNTO0);------三位指令码
SIGNAL z_flag:STD_LOGIC;------ZF
SIGNAL mdr_out:STD_LOGIC_VECTOR(word_w-1DOWNTO 0);---------八位数据寄存器DR的输出
SIGNAL mar_out:UNSIGNED(word_w-op_w-3 DOWNTO0);----------三位地址寄存器MAR的输出
SIGNAL IR_out:STD_LOGIC_VECTOR(word_w-1DOWNTO 0);----------指令寄存器的八位输出(指令或译码后的操作码)--------波形未输出
SIGNAL acc_out:UNSIGNED(word_w-1 DOWNTO0);----------八位累加器输出
SIGNAL reg1_out:STD_LOGIC_VECTOR(word_w-1DOWNTO 0);
SIGNAL reg2_out:STD_LOGIC_VECTOR(word_w-1DOWNTO 0);
SIGNAL sysbus_out:STD_LOGIC_VECTOR(word_w-1DOWNTO 0);--------八位数据总线输出
SIGNAL mem_addr_r:UNSIGNED(word_w-op_w-3DOWNTO 0);
SIGNAL inclock:STD_LOGIC;-----------内部时钟
SIGNAL period:integer:=50000000;
SIGNAL hcnt:integer:=25000000;
--SIGNAL period:integer:=16;
--SIGNAL hcnt:integer:=8;
SIGNAL cnt:integer:=0;
SIGNAL inclock_c:STD_LOGIC;-----------内部时钟
SIGNAL period_c:integer:=125000;
SIGNAL hcnt_c:integer:=62500;
--SIGNAL period_c:integer:=2;
--SIGNAL hcnt_c:integer:=1;
SIGNAL cnt_c:integer:=0;
SIGNAL databuf:STD_LOGIC_VECTOR(3 DOWNTO 0);
SIGNAL datain:STD_LOGIC_VECTOR(15 DOWNTO 0);
SIGNAL cnt_show:STD_LOGIC_VECTOR(1 DOWNTO0):="00";
BEGIN
PROCESS(clock)
BEGIN
       IFRISING_EDGE(clock) THEN
              IF cnt>period THEN
                     cnt<=0;
                     inclock<='1';
              ELSIF cnt<hcnt THEN
                     inclock<='1';
                     cnt<=cnt+1;
              ELSE
                     inclock<='0';
                     cnt<=cnt+1;
              END IF;
       ENDIF;
END PROCESS;
PROCESS(clock)
BEGIN
       IFRISING_EDGE(clock) THEN
              IF cnt_c>period_c THEN
                     cnt_c<=0;
                     inclock_c<='1';
              ELSIF cnt_c<hcnt_c THEN
                     inclock_c<='1';
                     cnt_c<=cnt_c+1;
              ELSE
                     inclock_c<='0';
                     cnt_c<=cnt_c+1;
              END IF;
       ENDIF;
END PROCESS;
PROCESS(reset,inclock)
BEGIN
       IFreset='0' THEN
              mem_addr<=(OTHERS =>'0');
              mem_addr_r<=(OTHERS =>'0');
       ELSIFRISING_EDGE(inclock) THEN
              mem_addr_r<=mem_addr_r+1;
              mem_addr<=mem_addr_r;
       endif;
END PROCESS;
PROCESS(reset,inclock)
     VARIABLE instr_reg:STD_LOGIC_VECTOR(word_w-1 DOWNTO 0);-----------指令寄存器中的内容
              VARIABLE acc:UNSIGNED(word_w-1 DOWNTO0);----------累加器
     CONSTANT zero:UNSIGNED(word_w-1 DOWNTO 0):=(OTHERS =>'0');----------八位零常量
              VARIABLE mdr:STD_LOGIC_VECTOR(word_w-1DOWNTO 0);----------数据寄存器
              VARIABLE reg1:STD_LOGIC_VECTOR(word_w-1DOWNTO 0);-------------?
              VARIABLE reg2:STD_LOGIC_VECTOR(word_w-1DOWNTO 0);------------?
              VARIABLE mar:UNSIGNED(word_w-op_w-3DOWNTO 0);---------三位地址寄存器
     VARIABLE sysbus : STD_LOGIC_VECTOR(word_w-1 DOWNTO 0);
              VARIABLE microcode :microcode_array;------------24位指令码数组
     VARIABLE add_r: UNSIGNED(4 DOWNTO 0);
     VARIABLE data_r: STD_LOGIC_VECTOR(23 DOWNTO 0);--------------24位指令码
              VARIABLE temp: STD_LOGIC_VECTOR(4 DOWNTO0);-----------五位临时变量
BEGIN
     reg2:="00000111";
       IFreset='0' THEN-------------置位端清零
     add_r:=(OTHERS =>'0');
              count<= (OTHERS =>'0');
              instr_reg:=(OTHERS =>'0');
     acc:= (OTHERS =>'0');
              mdr:= (OTHERS =>'0');
              reg1:= (OTHERS =>'0');
              reg2 := (OTHERS =>'0');
              mar := (OTHERS =>'0');
              z_flag<='0';
     mem <= prog;
     sysbus :=(OTHERS=>'0');
       ELSIFRISING_EDGE(inclock) THEN          --microprogram controller 指令控制器
     data_r:=code(TO_INTEGER(add_r));
              IF data_r(4 DOWNTO 0)="11111"THEN   --判断地址
                     temp:="01"&op(2DOWNTO 0);
                     add_r:=UNSIGNED(temp);
              ELSIF data_r(4 DOWNTO0)="11110" THEN
                     IFIR_out(1 downto 0)="10" THEN
                            add_r :="00110";
                     ELSIFIR_out(1 downto 0)="01" THEN
                            add_r :="00101";
                     ENDIF;
              ELSIF data_r(4 DOWNTO 0)="11100"THEN
                     IFz_flag='0' THEN
                            add_r:="10011";
                     ELSE
                            add_r:="10100";
                     ENDIF;
              ELSE
                     add_r:=UNSIGNED(data_r(4 DOWNTO 0));
              END IF;
              data_r_out<=data_r;
              add_r_out<=add_r;
              
              --PC 程序计数器----确定下一条指令的地址
              IF data_r(15)='1' THEN               --PC_bus='T'
                     sysbus:=rfill & STD_LOGIC_VECTOR(count);
              END IF;
              IF data_r(17)='1'THEN              --load_PC='l'  count置数
                     count<= UNSIGNED(mdr(word_w-op_w-1 DOWNTO 0));----------data_r(17)==?
              ELSIF data_r(10)='1' THEN        --INC_PC='l'  ---------data_r(10)=IPC  决定计数器是否加一
                     count<= count+1;
              ELSE
                     count<= count;
     END IF;
              
              --IR 指令寄存器---用来保存当前正在执行的指令,如果是操作码就进行译码
              IF data_r(14)='1'THEN --load_ IR               data_r(14)==IIR
                     instr_reg:=mdr;     
              END IF;    -----------------------------------------保存当前正在执行的指令(mdr是计算的数据)
              IF data_r(9)='1'THEN  --Addr_ bus='l'       判断是否是操作码
                     sysbus:="00"& rfill & instr_reg(word_w-op_w-1 DOWNTO 2);
              END IF;---------------------------------------------------译操作码
     op <= instr_reg(word_w-1 DOWNTO word_w-op_w); -----------第七位到第五位  当前三位操作码
              IR_out<=instr_reg;
              op_out<=op;        
              
              --ALU   算术逻辑单元
     IF data_r(16)='1'THEN --load_ACC='l'     ------------data_r(16)==ESUM 判断是否给acc
                     acc:=UNSIGNED(mdr);------------计算数据结果给acc
              ENd if;
     IF data_r(22)='1'THEN    --ACC_bus='l'
                     sysbus:=STD_LOGIC_VECTOR(acc);-------------判断是否累加结果acc给数据总线
              END IF;
     IF data_r(18)='1'THEN            --REG1_ bus='l'
                     sysbus:=STD_LOGIC_VECTOR(reg1);---------------寄存器reg1的结果给数据总线   
              END IF;
     IF data_r(19)='1'THEN            --REG2_ bus='l'
                     sysbus:= STD_LOGIC_VECTOR(reg2);---------------寄存器reg2的结果给数据总线
              END IF;
     If data_r(20)='1'then          --load_ regl='l'
                     reg1:=sysbus;
                     reg_out<=reg1;----------------reg1获得数据总线上的值并输出
              END IF;
      IF IR_out(1 downto 0)="00" THEN
                     IFdata_r(11)='1'THEN   --ALU_ ACC='l'        data_r(11)==IA
                            IF data_r(6)='1'THEN            --ALU__add='l'    data_r(6) == Iadd
                                   acc:=acc+UNSIGNED(mdr);
                            END IF;
                     ENDIF;
              ELSIF IR_out(1 downto 0)="01"THEN
                     IFdata_r(11)='1'THEN          --ALU_ ACC='l'
                            IF data_r(5)='1'THEN     --ALU_ _sub='l'    data_r(5) == Isub
                                   acc:=acc-UNSIGNED(reg1_out);
                            END IF;
                     ENDIF;
              ELSIF IR_out(1 downto0)="10"THEN
                     IFdata_r(11)='1' THEN --ALU_ ACC='l'
                            IF data_r(21)='1'THEN  --ALU_ and='1'      ata_r(21) == Iand
                                   acc:= acc and UNSIGNED(mdr);
                            END IF;
                     ENDIF;
          END IF;
     IF acc=zero THEN          --根据结果acc设计ZF
                     z_flag<='1';
              ELSE
                     z_flag<='0';
              END IF;
              acc_out<=acc;
              
              --RAM 存储器
              IF data_r(12)='1'THEN           --load_MAR='l'        data_r(12) = IMAR  是否工作
                     mar:=UNSIGNED(sysbus(word_w-op_w-3dOWNTO 0));  ----------获得地址信息
              ELSIF data_r(23)='1' THEN  --load_ MDR='1'        data_r(23) = IMDR
                     mdr:=sysbus;--------------指令或数据给MDR
              ELSIF data_r(8)='1'THEN     --CS='l'
                     IFdata_r(7)='1' THEN          --R_NW='l'读
                            mdr:= mem(TO_INTEGER(mar));
                     ELSE
                            mem(TO_INTEGER(mar)) <= mdr; -- 写数据或指令  
                     ENDIF;
              END IF;
              IF data_r(13)='1'THEN           --MDR_bus='l'         data_r(13) = EMDR
                     sysbus:=mdr;
              END IF;
     mdr_out<= mdr;
     mar_out<= mar;
       ENDIF;
  sysbus_out <= sysbus;
       reg1_out<= reg1;
       reg2_out<= reg2;
  regg_out <= reg2_out;
END PROCESS;
PROCESS(mode,inclock)
VARIABLE output_t:STD_LOGIC_VECTOR(15 DOWNTO0);
BEGIN
     --mode=0-> sysbus
              --mode=1-> PC
     --mode=2-> result of ALU
              --mode=3-> IR
     --mode=4-> MAR
     --mode=5-> MDR
     --mode=6 -> mem
     output_t := (OTHERS =>'0');
              CASE mode is
     WHEN "000" =>output_t(7 downto 0):=sysbus_out;
     WHEN "001" =>output_t(word_w-op_w-1 DOWNTO 0):=STD_LOGIC_VECTOR(count);
              WHEN "010" =>output_t(7downto 0):=STD_LOGIC_VECTOR(acc_out);
              WHEN "011" =>output_t(7downto 0):= IR_out;
              WHEN "100"=>output_t(word_w-op_w-3 DOWNTO 0):=STD_LOGIC_VECTOR(mar_out);
              WHEN "101" =>output_t(7downto 0) := mdr_out;
              WHEN "110" =>output_t(7downto 0):= mem(TO_INTEGER(mem_addr_r));
              WHEN others =>output_t(7 downto 0):=(OTHERS=>'Z');
              END CASE;
              output<=output_t(7 downto 0);
              datain<=output_t;
END PROCESS;
PROCESS(inclock_c)
BEGIN
      IF RISING_EDGE(inclock_c) THEN  
                     cnt_show<= cnt_show + "01";
              END IF;
END PROCESS;
PROCESS(inclock_c)
BEGIN
     IF RISING_EDGE(inclock_c) THEN  
                     casecnt_show IS
                     when"00"=>
                            databuf<=datain(3 downto 0);
                            segctl<="1110";
                     when"01"=>
                            databuf<=datain(7 downto 4);
                            segctl<="1101";
                     when"10"=>
                            databuf<=datain(11 downto 8);
                            segctl<="1011";
                     when"11"=>
                            databuf<=datain(15 downto 12);
                            segctl<="0111";
                     WHENothers =>segctl<="0000";
                     ENDCASE;
              END IF;
END PROCESS;
PROCESS(databuf)
BEGIN
       casedatabuf IS
       when"0000"=>
              segout<="0000001";
       when"0001"=>
              segout<="1001111";
       when"0010"=>
              segout<="0010010";
       when"0011"=>
              segout<="0000110";
       when"0100"=>
              segout<="1001100";
       when"0101"=>
              segout<="0100100";
       when"0110"=>
              segout<="0100000";
       when"0111"=>
              segout<="0001111";
       when"1000"=>
              segout<="0000000";
       when"1001"=>
              segout<="0000100";
       when"1010"=>
              segout<="0001000";
       when"1011"=>
              segout<="1100000";
       when"1100"=>
              segout<="0110001";
       when"1101"=>
              segout<="1000010";
       when"1110"=>
              segout<="0110000";
       when"1111"=>
              segout<="0111000";
       WHENothers =>segout<= (OTHERS=>'0');
end case;
END PROCESS;
END ARCHITECTURE;


附录C 微指令解析
file:///C:/Users/Quan/AppData/Local/Temp/msohtmlclip1/01/clip_image002.jpg
图C.121微指令解析
file:///C:/Users/Quan/AppData/Local/Temp/msohtmlclip1/01/clip_image001.png
图C.2 21条微指令的作用
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:1 发表于 2020-6-1 01:28 | 只看该作者
本帖需要重新编辑补全电路原理图,源码,详细说明与图片即可获得100+黑币(帖子下方有编辑按钮)
回复

使用道具 举报

板凳
ID:764193 发表于 2020-6-1 09:42 | 只看该作者
admin 发表于 2020-6-1 01:28
本帖需要重新编辑补全电路原理图,源码,详细说明与图片即可获得100+黑币(帖子下方有编辑按钮)

图片发不上去啊。。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表