搜索
bottom↓
回复: 14

发个极简单8位CPU的实现代码,只有通用寄存器,IO指令,跳转指令和空指令,可以学习用~

[复制链接]

出0入0汤圆

发表于 2011-8-8 19:41:33 | 显示全部楼层 |阅读模式
如题,自己做的,还不完善,没RAM,只有通用寄存器,指令只有取指,IO指令,跳转指令和空指令(因为有这几个指令就可以FPGA验证in,out看结果了),自然没法用,可以给学习Verilog的同学和学习CPU结构的同学用~

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Engineer: LJT
// Create Date:    08:53:12 11/21/2010
// Module Name:    top_modu
//////////////////////////////////////////////////////////////////////////////////
module top_modu(clk,rst,P1_IN,P1_OUT);
//IO Part
input clk;
input rst;
input [7:0] P1_IN;
output [7:0] P1_OUT;

//BUS
wire [7:0] DB_IN;   //data bus
wire [7:0] DB_OUT;  
wire [7:0] ABUS;    //address bus
wire [7:0] CBUS; // ctrl bus

//各模块间互连线
wire [7:0]irdb_out;
wire [7:0]iodb_in;
wire [7:0]iodb_out;

//Ctrl_Unit
ctrl_unit ctrl_unit (
    .clk(clk),
    .rst(rst),
    .DB_IN(DB_IN),
    .DB_OUT(DB_OUT),
    .ABUS(ABUS),
    .CBUS(CBUS)
    );
         
//instruction rom
instru_rom instru_rom (
    .clk(clk),
    .addr(ABUS),
    .db_out(irdb_out)
    );
         
//bus interface module
bus_if_modu bus_if_modu (
    .CBUS(CBUS),
    .DB_IN(DB_IN),
    .DB_OUT(DB_OUT),
    .irdb_out(irdb_out),
    .iodb_in(iodb_in),
    .iodb_out(iodb_out)
    );
//io interface
io_modu io_modu (
    .clk(clk),
    .db_in(iodb_in),
    .db_out(iodb_out),
    .P1_IN(P1_IN),
    .P1_OUT(P1_OUT)
    );

Endmodule











`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: SDU
// Engineer: Lijiangtao
// Create Date:    22:28:42 11/16/2010
// Module Name:    Ctrl_Unit
// Revision 0.01
//////////////////////////////////////////////////////////////////////////////////
module ctrl_unit(clk,rst,DB_IN,DB_OUT,ABUS,CBUS);

//IO part
input clk;
input rst;
input [7:0] DB_IN;
output reg [7:0] DB_OUT;
output reg [7:0] ABUS;//address bus
output [7:0]CBUS;
reg [3:0] CBUS_IN;// ctrl bus in&out
reg [3:0] CBUS_OUT;

assign CBUS[3:0]=CBUS_IN[3:0];
assign CBUS[7:4]=CBUS_OUT[3:0];

//important register
reg [7:0] PC;
reg [7:0] IR;
reg [7:0] MSR;

//general reg
reg [7:0] A;
reg [7:0] B;
reg [7:0] C;
reg [7:0] D;

//Instruction Cycle Count
reg [2:0] In_Cy;

//A Temp register
reg [7:0] RTMP;

//instructions
parameter[7:0] NOP = 8'b01100000;
parameter[7:0] JMP = 8'b01100001;   
parameter[7:0] IN = 8'b01100010;
parameter[7:0] OUT = 8'b01100011;
parameter[7:0] MOV1 = 8'b10000001;
parameter[7:0] MOV2 = 8'b10000010;

//4 bits, @bus address---挂在总线上的外设ID
parameter[3:0] CUID = 4'h1;   //Contrl Uint
parameter[3:0] ROMID = 4'h6;  //instrution@  ---Harward Architecture
parameter[3:0] RAMID = 4'he;  //data
parameter[3:0] INID = 4'h4;   //IO
parameter[3:0] OUTID = 4'h5;   

/////////////////////////////////////////////////////////////////////////////
//PC description
//In_Cy==1 取指; 0时 PC+1
always@(posedge clk)
begin
  if(rst==1)
    PC<=0;
  else if(IR==JMP&&In_Cy==1)  //JMP instruction
    PC<=DB_IN;
  else if(MSR[7]==1||In_Cy==0)        //取指 or 取操作数 --at next cycle
    PC<=PC+1;
  else  
    PC<=PC;  
end

//In_Cy description: instruction cycle count
always@(posedge clk)
begin
  if(rst==1)
    In_Cy<=3;  //In_Cy==0时,PC++,In_Cy==1时取指         
  else if(In_Cy==0)
    In_Cy<=IR[7:5];
         //IR[7:5]设置为该指令的(执行周期数-1),不大于32条指令(实际上可以更多)的情况下可以减小译码所占用面积
  else          
    In_Cy<=In_Cy-1;
end

//IR description : instruction register
always@(posedge clk)
begin
  if(In_Cy==1)                                        //取指
    begin
         IR<=DB_IN;
         end
  else
    IR<=IR;
end

///////////////////////////////////////////////////////////////////////////////////
//Here Describ:   reg ABCD, RTMP, ABUS, CBUS_IN, CBUS_OUT, DB_OUT , MSR[7]
//the main frame is here
//the most important part of this deaign
//In_Cy--    4:...    3:PC->abus    2:CBUS   1:取指   0:PC+1  
///////////////////////////////////////////////////////////////////////////////////  
always@(posedge clk)
begin
  if(rst||In_Cy==2)  //下周期取指
    begin
         CBUS_IN<=CUID;
         CBUS_OUT<=ROMID;
         MSR[7]<=0;
         ABUS<=PC;
         end
  else
    begin
         //指令译码
    case (IR)         
           //在不同的机器周期(IN_CY)内执行不同的操作
                //3时改变地址总线,2时选通指令存储器,1时取指,0时PC加1;  
                //2,1时无法执行其他操作,3,0时可以同时执行其他操作,但要注意地址总线和没变的PC值
                NOP:        case (In_Cy)    //上次1时取指NOP,上次是0时incy被赋值1,然后直接取指下一条,因此在0时准备取指   4T
                        3'd0:
                                    begin
                                    CBUS_IN<=CUID;
                                    CBUS_OUT<=ROMID;
                                    end
              3'd3:
                                    begin
                                    ABUS<=PC;
                                    end                                  
                                endcase  
                JMP:        case (In_Cy)   //上次1时取指JMP,上次是0时incy被赋值1,然后直接取指下一条   4T
                        3'd0:        //准备取操作数
                                    begin
                                         CBUS_OUT<=ROMID;
                                         CBUS_IN<=CUID;
                                         end  
              3'd3:       //操作数给PC在PC的描述里,取操作数--注意指令存储器的设计               
                                    begin
                                         ABUS<=PC;
                                         end                    
                                endcase  
                IN:        case (In_Cy)  //IN=>寄存器A   4T       
              3'd0:
                                    begin
                                         CBUS_OUT<=INID;
                                         CBUS_IN<=CUID;
                                         end            
                        3'd3:
                                    begin
                                         A<=DB_OUT;
                                         ABUS<=PC;
                                         end
                                endcase                       
                OUT:        case (In_Cy)   //取寄存器A,给OUT        4T
              3'd0:
                                    begin
                                         CBUS_OUT<=CUID;
                                         CBUS_IN<=OUTID;
                                         DB_OUT<=A;  
                                         end                    
                        3'd3:        //IO要在这个时钟周期锁存
                                    begin
                                         ABUS<=PC;
                                         end  
                                endcase               
                MOV1:        case (In_Cy)   //未完成
              3'd0:        //准备取操作数
                                    begin
                                         CBUS_OUT<=ROMID;
                                         CBUS_IN<=CUID;
                                         ABUS<=PC;
                                         MSR[7]<=1;
                                         end  
              3'd4:        //取操作数       
                                    begin
                                         RTMP<=DB_IN;
                                         MSR[7]<=0;
                                         CBUS_OUT<=INID;
                                         CBUS_IN<=RAMID;
                                         A<=DB_IN;
                                         B<=DB_IN;
                                         end                            
                        3'd3:
                                    begin
                                         CBUS_OUT<=RAMID;
                                         CBUS_IN<=CUID;
                                         ABUS<=PC;
                                         MSR[7]<=1;
                                         C<=DB_IN;
                                         D<=DB_IN; end
                                endcase                               
    endcase      //指令译码部分结束
    end
end

endmodule









`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Engineer: LJT
//////////////////////////////////////////////////////////////////////////////////
module instru_rom(clk,addr, db_out);
input clk;
input [7:0]addr;
output [7:0]db_out;

wire [10:0] addr11;

IN_ROM IN_ROM (
    .addr_11(addr11),
    .data_8(db_out),
    .clk(clk)
    );

assign addr11[10:8]=0;
assign addr11[7:0]=addr[7:0];

endmodule








module IN_ROM(addr_11,
              data_8,
            clk);
         input clk;
         input [10:0] addr_11;
         output [7:0] data_8;
RAMB16_S9 #(
      .INIT(9'h000),  // Value of output RAM registers at startup
      .SRVAL(9'h000), // Output value upon SSR assertion
      .WRITE_MODE("WRITE_FIRST"), // WRITE_FIRST, READ_FIRST or NO_CHANGE

      // The following INIT_xx declarations specify the initial contents of the RAM
      // Address 0 to 511
      .INIT_00(256'h62_63_62_63_61_00_61_00_61_00_00_00_00_00_0(后面全为0)
          ) RAMB16_S9_inst (
      .DO(data_8),      // 8-bit Data Output--------------------
      .DOP(DOP),    // 1-bit parity Output --to a reg
      .ADDR(addr_11),  // 11-bit Address Input  -----------------change to 8bit,others 0.
      .CLK(clk),    // Clock
      .DI(DI),      // 8-bit Data Input --0  
      .DIP(DIP),    // 1-bit parity Input  --0
      .EN(EN),      // RAM Enable Input --1
      .SSR(SSR),    // Synchronous Set/Reset Input --0
      .WE(WE)       // Write Enable Input --0
   );

//End of RAMB16_S9_inst instantiation
//assign addr_8=ADDR[7:0];
//assign ADDR[10:8]=0;
assign DI=0;
assign DIP=0;
assign EN=1;
assign SSR=0;
assign WE=0;

endmodule











`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
// Create Date:    16:14:41 11/21/2010
// Module:    Bus_Interface_Module
//////////////////////////////////////////////////////////////////////////////////
module bus_if_modu(CBUS,
                   DB_IN,DB_OUT,
                   irdb_out,  //instru rom
                                                 iodb_in,iodb_out   //io
                                                 );
                                               
input [7:0] CBUS;
input [7:0] DB_OUT;
output reg [7:0] DB_IN;

input [7:0] irdb_out;

input [7:0] iodb_out;
output reg [7:0] iodb_in;

//挂在总线上的外设ID
parameter[3:0] CUID = 4'h1;   //Contrl Uint
parameter[3:0] ROMID = 4'h6;  //instrution@  ---Harward Architecture
parameter[3:0] RAMID = 4'he;  //data
parameter[3:0] INID = 4'h4;   //IO
parameter[3:0] OUTID = 4'h5;   
                               

always @ (CBUS[7:4]) begin
        case (CBUS[7:4])               
                ROMID: DB_IN <= irdb_out;
                INID:  DB_IN <= iodb_out;
                RAMID: DB_IN <= irdb_out;
        endcase
end

always @ (CBUS[3:0]) begin
        case (CBUS[3:0])
           OUTID: iodb_in <= DB_OUT;
                RAMID: iodb_in <= DB_OUT;
        endcase
end

endmodule







`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Design Name:
// Module Name:    io_modu
//////////////////////////////////////////////////////////////////////////////////
module io_modu(clk,
               db_in,
               db_out,
                                        P1_IN,
                                        P1_OUT
               );
input clk;
input [7:0] P1_IN;
input [7:0] db_in;
output reg [7:0] P1_OUT;
output reg [7:0] db_out;

always@(posedge clk)
begin
  P1_OUT[7:0]<=db_in[7:0];
  db_out[7:0]<=P1_IN[7:0];
end

endmodule

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入0汤圆

发表于 2011-8-8 22:24:31 | 显示全部楼层
做个简单的 讲解或贴个仿真图就更好了

出0入0汤圆

发表于 2011-8-8 23:18:52 | 显示全部楼层
想起来ZPU,是个很小的堆栈机

出0入0汤圆

发表于 2011-11-9 17:26:50 | 显示全部楼层
学习,正想学习学习CPU的结构自己写代码

出0入0汤圆

发表于 2011-11-9 17:41:04 | 显示全部楼层
学习不错!不过可以看看FREEARM的代码,几千行的代码,就可以用FPGA跑UCLINUX了

出0入0汤圆

发表于 2011-11-13 11:13:58 | 显示全部楼层
收藏

出0入0汤圆

发表于 2011-11-14 11:24:29 | 显示全部楼层
怎么不是用VHDL写的呢?Verilog没有学过呀!

出0入0汤圆

 楼主| 发表于 2011-11-15 23:02:37 | 显示全部楼层
回复【4楼】jiangchun9981  
学习不错!不过可以看看freearm的代码,几千行的代码,就可以用fpga跑uclinux了
-----------------------------------------------------------------------

这么犀利。。。。。我看看

出0入0汤圆

发表于 2011-11-15 23:13:34 | 显示全部楼层
楼主威武。。

出0入0汤圆

发表于 2011-12-24 22:32:39 | 显示全部楼层
楼主不错,能做个图文解说就更好了

出0入0汤圆

 楼主| 发表于 2012-2-4 20:53:19 | 显示全部楼层
回复【9楼】.oOo.
楼主不错,能做个图文解说就更好了
-----------------------------------------------------------------------

主要的部分注释写的很详细 ,而且又简单, 呵呵。应该比较容易看懂

出20入186汤圆

发表于 2012-2-9 12:41:48 | 显示全部楼层
我想问楼主,P1_IN P1_OUT 在外部是同一个引脚么?还是单独的?
最近在搞CPLD的INOUT,老是出问题~

出0入0汤圆

发表于 2012-2-9 13:54:58 | 显示全部楼层
可以,加油!

出0入0汤圆

发表于 2012-2-10 12:49:56 | 显示全部楼层
收藏,有空学习下!

出0入0汤圆

 楼主| 发表于 2012-2-10 16:59:07 | 显示全部楼层
回复【11楼】yuyu87 雨
我想问楼主,p1_in p1_out 在外部是同一个引脚么?还是单独的?
最近在搞cpld的inout,老是出问题~
-----------------------------------------------------------------------

这个是单独的

一般INOUT子模块内还是in和out单独的,外面加个三态门控制成INOUT吧
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-7-24 11:17

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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