锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

数字集成电路设计-7-一个简单cpu的设计,实现,仿真与综合

时间:2023-12-15 01:37:02 sa12集成电路

引言
经过对OpenRISC经过近一年的分析和研究,我们了解了计算机系统结构设计的主要概念、重要技术和基本思想。我认为现在有必要练习。

本节将设计一个简单的部分cpu,包括ISA模块,模块划分,RTL实现,编写asm汇编程序,用modelsim模拟和使用quartusII的综合。

1.计算器和计算机
我认为,在EDVAC以前的计算机可以被视为计算器。

原因是冯诺依曼对EDVAC在分析过程中,提出了二进制计算和添加存储部件,在此之前,计算机没有存储功能,例如,我们需要计算(1 2)&(3 4)如果使用计算器,其操作步骤如下:

a,先用计算器计算1 结果3,然后人脑自己记住这个数字。

b,用计算器计算3 4的结果7,人脑也自己记住这个数。

c,最后,用计算器计算3&7的结果3。

若采用计算机,其操作过程如下:

首先,我们需要写一个程序,假设程序放在程序存储器的地址0x55、56、57、58四个地址分别放置在数据存储器中。

程序执行如下:

a,将data_mem的0x放55个数据r1。

b,将data_mem的0x数据放在56处r2。

c,执行add r2,r1,结果放在r2里面。

d,将r写入2的内容data_mem的0x60这个地址。

e,将data_mem的0x数据放在57处r3。

f,将data_mem的0x数据放在58处r4。

g,执行add r4,r3,结果放在r4里面。

h,将r4内容写入data_mem的0x61这个地址。

i,将data_mem的0x放60个数据r5。

j,将data_mem的0x数据放在61处r6。

k,执行and r6,r5,结果放在r6里面。

l,将r内容写入6data_mem的0x62这个地址,最终得到计算结果。


我们可以看到,如果用计算机计算,只需要三个步骤,但如果用计算机,需要12个步骤。使用计算机的效率低吗?今天计算机的蓬勃发展使得答案不言而喻。

原因是只要编写程序,计算机的整个计算过程就不需要人为干预。

我认为这就是计算机发展的根本原因,即计算机的出现对人们来说是一个巨大的解放。只要我们以某种方式写程序,然后交给计算机,计算机就会自动完成任务,我们的手就可以做其他事情!

2,架构设计
1>整体设计
通过上面的例子,我们可以体验到计算机的好处。让我们设计一个cpu,来完成1 2的计算。

关于计算机系统结构,我们之前说过足够多的内容。以下几点仅供说明:

a,我们采用harvard结构,即指令和数据的总线是独立的。

b,流水线,我们暂时不采用流水设计,但最终,我给出了五级流水时的数据通路设计框架。

c,至于指令集,由于是学习目的,我们只实现基本的访问和存储指令、操作指令和分支指令。操作不支持乘除和浮点。详见附录。每个指令为16-bit。

d,为我们设计cpu进行仿真和验证,我们需要设计一个简单的soc才行,这个soc只包括指令存储器,cpu内核,数据存储器。

e,core内总线为8-bit。有一个问题,core外是8-bit,但分支指令的目的地地址是11-bit,所以如果超过8-bit,会有问题,还没有解决。

下面是soc整体架构图:让我们给他取个名字,叫 tiny_soc,小cpu简单地称她为tiny_core。

2>模块划分
cpu core结构如下:

整个cpu core由数据通道、控制通道和调试单元组成。

其中数据通路包括:

PC生成模块:genpc

运算模块:alu,在alu前面是多选一个操作数mux。

寄存器堆:regfile模块

还有栈:stack。

控制数据通路模块ctrl_path控制模块,解码控制通道的指令,并产生相应的控制信号。

由于调试单元只是学习目的,调试单元是最简化的,只输出当前的PC值和当前指令内容两个信息。

3.模块划分和界面定义
在体架构设计完成后,需要进一步细化。此时,需要定义具体的模块名称和模块功能。一旦确定了功能,就可以确定具体的模块接口信号。

如果模块功能太大,我们需要将它们分成更小的模块,即top-down设计方法。关于设计方法(top-down,bottom-up),很多资料都有介绍,这里就不赘述了。

一个完整的项目,不同于理论研究,需要处理很多实现细节。下面,我们来介绍一下更重要的部分:

1>genpc模块
需要考虑三点:上电复位PC默认值是多少?执行正常指令时PC如何变化?遇到分支指令时?PC如何变化?

关于上电默认值,我们可以通过一个define设置句子,方便用户以后修改。

关于正常指令的指令,PC是加1、加2还是加4取决于指令存储器的访问方式。我们的指令存储器在每个地址放一个指令,每个指令放两个字节(16-bit),所以我们只需要PC加1就够了。

对于分支指令,我们直接将解码的跳转地址赋予控制通路PC即可。

genpc模块C语言伪代码如下:

genpc module pseudo code

if(rst)
{
pc= boot_addr;
}
else
{
if(branch)
{
pc = branch_target;
}
else
{
pc = pc 1;
}
}


2>alu模块
alu大家都很熟悉模块,是执行单元部件,负责操作指令。

该模块的输入信号是由控制通路解码的操作数和操作码,输出信号是操作结果。

需要注意的是,该模块可以完全组合逻辑电路。

3>rf模块
register file在物理上,模块是一个模块block ram。

从逻辑上讲,该模块对软件程序员透明,寄存器堆和指令集是软件和硬件之间的交互接口。

4>stack
stack(栈)存放在处理分支指令时PC例如,当我们处理子程序调用时,我们需要首先调用当前值PC 1压栈,遇到子程序返回指令时使用。

栈的特点是LIFO(last in first out),这一点与heap(堆)不同。

5>ctrl_path模块
负责控制通道genpc解码模块产生的地址处的指令,并产生相应的操作数、操作代码和控制模型。这部分信号稍多。

6>tiny_soc
为了测试这个cpu我们需要建立一个最小的系统,包括指令只读取存储器insn_rom机器代码存储在模块中。

由于是harvard结构也需要数据存储器ram相当于内存的模块。

当然,如果你想插其他插件,I/O外设,我们只需要定义它的地址空间,需要注意的是I/O外设的地址空间无法与RAM重叠,各个I/O外设不能重叠。

RAM和I/O外设之间可以通过一个arbiter与cpu core实现数据交互。

当然,如果有不止一个地方存储指令,也需要指令arbiter。

4,RTL实现
在完成模块划分、界面定义、仔细分析和考虑模块间时序后,如果没有问题,我们可以编码。

编码,需要注意的是,编码必须标准化,信号命名,代码注释,尽量小心。这里直接给出RTL代码(verilog HDL)

按自上而下顺序给出:

1>tiny_soc顶层模块:soc_top

/*
*
* file name : soc_top.v
* author : Rill
* date : 2013-08-11
*
*/

`timescale 1ns / 1ps

module soc_top
(
input clk,
input rst
);


wire read_e;
wire write_e;
wire [7:0] port_addr;
wire [7:0] core_in;
wire [7:0] core_out;
wire [15:0] instruction;
wire [10:0] inst_addr;

wire [15:0] debug_insn;
wire [10:0] debug_pc;

insn_rom insn_rom
(
.clk (lk),
.rst (rst),
.address (inst_addr),
.instruction (instruction)
);
 
core core
(
.clk (clk),
.rst (rst),
 
.read_e (read_e),
.write_e (write_e),
.port_addr (port_addr),
.data_in (core_in),
.data_out (core_out),
.inst_addr (inst_addr),
.instruction (instruction),
.debug_pc (debug_pc),
.debug_insn (debug_insn)
);
 
ram ram
(
.clk (clk),
.rst (rst),
 
.wr (write_e),
.rd (read_e),
.addr (port_addr),
.din (core_out),
.dout(core_in)
);
 
 
    
endmodule


2>指令存储器:insn_rom

/*
*
* file name    : insn_rom.v
* author    : Rill
* date        : 2013-08-11
*
*/
 
 
 
module insn_rom
(
input clk,
input rst,
input [10:0] address,
output reg [15:0] instruction
);
 
//(* RAM_STYLE="BLOCK" *)
reg [15:0] rom [2047:0];
 
always @(posedge clk)
begin
    if(rst)
        begin
            rom[0] <= 16'h5801;//0:            jmp start
            rom[1] <= 16'h1101;//1:start     mov r1,1
            rom[2] <= 16'h1202;//2:            mov r2,2
            rom[3] <= 16'h3220;//3:            add r2,r1
            rom[4] <= 16'h2237;//4:            str r2,55
            rom[5] <= 16'h5806;//5:            jmp end
            rom[6] <= 16'h5806;//6:end        jmp end*/
        end
    else
        begin
            instruction <= rom[address];
        end
end
 
 
endmodule


3>数据存储器:ram

*
*
* file name    : ram.v
* author    : Rill
* date        : 2013-08-11
*
*/
 
 
module ram(
    input clk,
    input rst,
    
    input [7:0] din,
    input [7:0] addr,
    output reg [7:0] dout,
    input wr,
    input rd
    );
 
   (* RAM_STYLE="DISTRIBUTED" *)
   
    reg [7:0] ram [255:0];
 
   always @(posedge clk)
    begin
        if(rst)
            begin
                dout <= 8'b0;
                ram[0] = 0;
                ram[1] = 1;
                ram[2] = 2;
                ram[32] = 32;
                ram[64] = 64;
 
            end
        else
            begin
            if (wr)
                ram[addr] <= din;
            else if(rd)
                dout <= ram[addr];
        end
    end
 
endmodule


4>CPU核心:core

/*
*
* file name    : core.v
* author    : Rill
* date        : 2013-08-11
*
*/
 
 
 
module core
(
    input clk,
    input rst,
    output [7:0] port_addr,
    output read_e,
    output write_e,
    input [7:0] data_in,
    output [7:0] data_out,
    output [10:0] inst_addr,
    input [15:0] instruction,
    
    output [10:0] debug_pc,//debug i/f
    output [15:0] debug_insn
);
 
wire z,c;
wire insel;
wire we;
wire [2:0] raa;
wire [2:0] rab;
wire [2:0] wa;
wire [2:0] opalu;
wire [2:0] sh;
wire selpc;
wire ldpc;
wire ldflag;
wire [10:0] ninst_addr;
wire selk;
wire [7:0] KTE;
wire [10:0] stack_addr;
wire wr_en, rd_en;
wire [7:0] imm;
wire selimm;
 
 
 
 
control_path control_path
(
.clk (clk),
.rst (rst),
.instruction (instruction),
.z (z),
.c (c),
.port_addr (port_addr),
.write_e (write_e),
.read_e (read_e),
.insel (insel),
.we (we),
.raa (raa),
.rab (rab),
.wa (wa),
.opalu (opalu),
.sh (sh),
.selpc (selpc),
.ldpc (ldpc),
.ldflag (ldflag),
.naddress (ninst_addr),
.selk (selk),
.KTE (KTE),
.stack_addr (stack_addr),
.wr_en (wr_en),
.rd_en (rd_en),
.imm (imm),
.selimm (selimm)
);
 
 
 
data_path data_path_i
(
.clk (clk),
.rst (rst),
.data_in (data_in),
.insel (insel),
.we (we),
.raa (raa),
.rab (rab),
.wa (wa),
.opalu (opalu),
.sh (sh),
.selpc (selpc),
.selk (selk),
.ldpc (ldpc),
.ldflag (ldflag),
.wr_en (wr_en),
.rd_en (rd_en),
.ninst_addr (ninst_addr),
.kte (KTE),
.imm (imm),
.selimm (selimm),
.data_out (data_out),
.inst_addr (inst_addr),
.stack_addr (stack_addr),
.z (z),
.c (c)
);
 
debug debug
(
.pc_in (inst_addr),
.insn_in (instruction),
 
.pc (debug_pc),
.insn (debug_insn)
);
 
 
endmodule


5>调试单元:debug

/*
*
* file name    : debug.v
* author    : Rill
* date        : 2013-08-11
*
*/
 
 
 
module debug
(
input [10:0] pc_in,
input [15:0] insn_in,
 
output [10:0] pc,
output [15:0] insn
);
 
assign pc = pc_in;
assign insn = insn_in;
 
endmodule


6>控制通路:control_path

/*
*
* file name    : control_path.v
* author    : Rill
* date        : 2013-08-11
*
*/
 
 
 
module control_path
(
    input clk,
    input rst,
    input [15:0] instruction,
    input z,
    input c,
    output reg [7:0] port_addr,
    output reg write_e,
    output reg read_e,
    output reg insel,
    output reg we,
    output reg [2:0] raa,
    output reg [2:0] rab,
    output reg [2:0] wa,
    output reg [2:0] opalu,
    output reg [2:0] sh,
    output reg selpc,
    output reg ldpc,
    output reg ldflag,
    output reg [10:0] naddress,
    output reg selk,
    output reg [7:0] KTE,
    input [10:0] stack_addr,
    output reg wr_en, rd_en,
    output reg [7:0] imm,
    output reg selimm
    );
 
 
parameter fetch=    5'd0;
parameter decode=    5'd1;
 
parameter ldi=        5'd2;
parameter ldm=        5'd3;
parameter stm=        5'd4;
parameter cmp=        5'd5;
parameter add=        5'd6;
parameter sub=        5'd7;
parameter andi=        5'd8;
parameter oor=        5'd9;
parameter xori=        5'd10;
parameter jmp=        5'd11;
parameter jpz=        5'd12;
parameter jnz=        5'd13;
parameter jpc=        5'd14;
parameter jnc=        5'd15;
parameter csr=        5'd16;
parameter ret=        5'd17;
 
parameter adi=        5'd18;
parameter csz=        5'd19;
parameter cnz=        5'd20;
parameter csc=        5'd21;
parameter cnc=        5'd22;
parameter sl0=        5'd23;
parameter sl1=        5'd24;
parameter sr0=        5'd25;
parameter sr1=        5'd26;
parameter rrl=        5'd27;
parameter rrr=        5'd28;
parameter noti=        5'd29;
 
parameter nop=        5'd30;
 
wire [4:0] opcode;
reg [4:0] state;
 
assign opcode=instruction[15:11];
 
always@(posedge clk or posedge rst)
begin
    if (rst)
        begin
            state<=decode;
        end
        
    else
        begin
            case (state)
                fetch: 
                    begin
                        state<=decode;
                    end
 
                decode: 
                    begin
                        if(opcode >=ldi && opcode <=nop)
                            state <= opcode;//state just is the opcode now
                        else
                            state <= nop;
                    end
                    
                default:
                    state<=fetch;
            endcase
        end
        
end    
 
 
always@(*)
begin
        port_addr<=0;
        write_e<=0;
        read_e<=0;
        insel<=0;
        we<=0;
        raa<=0;
        rab<=0;
        wa<=0;
        opalu<=4;
        sh<=4;
        selpc<=0;
        ldpc<=1;
        ldflag<=0;
        naddress<=0;
        selk<=0;
        KTE<=0;
        wr_en<=0;
        rd_en<=0;
        imm<=0;
        selimm<=0;
        
        case (state)
            fetch:     begin
                        ldpc<=0;
                    end
 
            decode: begin
                        ldpc<=0;
                        if (opcode==stm)
                            begin
                                raa<=instruction[10:8];
                                port_addr<=instruction[7:0];
                            end
                        else if (opcode==ldm)
                            begin
                                wa<=instruction[10:8];
                                port_addr<=instruction[7:0];
                            end
                        else if (opcode==ret)
                            begin
                                rd_en<=1;
                            end
                    end
                
            ldi:    begin
                        selk<=1;
                        KTE<=instruction[7:0];
                        we<=1;
                        wa<=instruction[10:8];
                    end
                    
            ldm:    begin
                        wa<=instruction[10:8];
                        we<=1;
                        read_e<=1;
                        port_addr<=instruction[7:0];
                    end
                    
            stm:    begin
                        raa<=instruction[10:8];
                        write_e<=1;
                        port_addr<=instruction[7:0];
                    end
                    
            cmp:    begin
                        ldflag<=1;
                        raa<=instruction[10:8];
                        rab<=instruction[7:5];
                        opalu<=6;
                    end
                    
            add:    begin
                        raa<=instruction[10:8];
                        rab<=instruction[7:5];
                        wa<=instruction[10:8];
                        insel<=1;
                        opalu<=5;
                        we<=1;
                    end
                    
            sub:    begin
                        raa<=instruction[10:8];
                        rab<=instruction[7:5];
                        wa<=instruction[10:8];
                        insel<=1;
                        opalu<=6;
                        we<=1;
                    end
                    
            andi:    begin
                        raa<=instruction[10:8];
                        rab<=instruction[7:5];
                        wa<=instruction[10:8];
                        insel<=1;
                        opalu<=1;
                        we<=1;
                    end
                    
            oor:    begin
                        raa<=instruction[10:8];
                        rab<=instruction[7:5];
                        wa<=instruction[10:8];
                        insel<=1;
                        opalu<=3;
                        we<=1;
                    end
                    
            xori:    begin
                        raa<=instruction[10:8];
                        rab<=instruction[7:5];
                        wa<=instruction[10:8];
                        insel<=1;
                        opalu<=2;
                        we<=1;
                    end
                    
            jmp:    begin
                        naddress<=instruction[10:0];
                        selpc<=1;
                        ldpc<=1;
                    end
                    
            jpz:        if (z)
                        begin
                            naddress<=instruction[10:0];
                            selpc<=1;
                            ldpc<=1;
                        end
                                        
            jnz:        if (!z)
                            begin
                                naddress<=instruction[10:0];
                                selpc<=1;
                                ldpc<=1;
                            end
                        
                    
            jpc:    if (c)
                            begin
                                naddress<=instruction[10:0];
                                selpc<=1;
                                ldpc<=1;
                            end
                        
                    
            jnc:    if (!c)
                            begin
                                naddress<=instruction[10:0];
                                selpc<=1;
                                ldpc<=1;
                            end
                            
            csr:    begin
                        naddress<=instruction[10:0];
                        selpc<=1;
                        ldpc<=1;
                        wr_en<=1;
                    end
                    
            ret:    begin
                        naddress<=stack_addr;
                        selpc<=1;
                        ldpc<=1;
                    end
                    
            adi:    begin
                        raa<=instruction[10:8];
                        wa<=instruction[10:8];
                        imm<=instruction[7:0];
                        selimm<=1;
                        insel<=1;
                        opalu<=5;
                        we<=1;
                    end    
                    
            csz:    if (z)
                        begin
                            naddress<=instruction[10:0];
                            selpc<=1;
                            ldpc<=1;
                            wr_en<=1;
                        end
                        
            cnz:    if (!z)
                        begin
                            naddress<=instruction[10:0];
                            selpc<=1;
                            ldpc<=1;
                            wr_en<=1;
                        end
                        
            csc:    if (c)
                        begin
                            naddress<=instruction[10:0];
                            selpc<=1;
                            ldpc<=1;
                            wr_en<=1;
                        end
                        
            cnc:    if (!c)
                        begin
                            naddress<=instruction[10:0];
                            selpc<=1;
                            ldpc<=1;
                            wr_en<=1;
                        end
            
            sl0:    begin    
                        raa<=instruction[10:8];
                        wa<=instruction[10:8];
                        insel<=1;
                        sh<=0;
                        we<=1;
                    end
                    
            sl1:    begin    
                        raa<=instruction[10:8];
                        wa<=instruction[10:8];
                        insel<=1;
                        sh<=5;
                        we<=1;
                    end
                    
            sr0:    begin    
                        raa<=instruction[10:8];
                        wa<=instruction[10:8];
                        insel<=1;
                        sh<=2;
                        we<=1;
                    end
                    
            sr1:    begin    
                        raa<=instruction[10:8];
                        wa<=instruction[10:8];
                        insel<=1;
                        sh<=6;
                        we<=1;
                    end    
 
            rrl:    begin    
                        raa<=instruction[10:8];
                        wa<=instruction[10:8];
                        insel<=1;
                        sh<=1;
                        we<=1;
                    end                        
                    
            rrr:    begin    
                        raa<=instruction[10:8];
                        wa<=instruction[10:8];
                        insel<=1;
                        sh<=3;
                        we<=1;
                    end
                    
            noti:    begin
                        raa<=instruction[10:8];
                        wa<=instruction[10:8];
                        insel<=1;
                        opalu<=0;
                        we<=1;
                    end
 
            nop:    begin
                        opalu<=4;
                    end    
        endcase
end
 
 
endmodule


7>数据通路:data_path

/*
*
* file name    : data_path.v
* author    : Rill
* date        : 2013-08-11
*
*/
 
 
 
module data_path
(
    input clk,
    input rst,
    input [7:0] data_in,
    input insel,
    input we,
    input [2:0] raa,
    input [2:0] rab,
    input [2:0] wa,
    input [2:0] opalu,
    input [2:0] sh,
    input selpc,
    input selk,
    input ldpc,
    input ldflag,
    input wr_en, rd_en,
    input [10:0] ninst_addr,
    input [7:0] kte,
    input [7:0] imm,
    input selimm,
    output [7:0] data_out,
    output [10:0] inst_addr,
    output [10:0] stack_addr,
    output  z,c
);
 
wire [7:0] regmux, muximm;
wire [7:0] portA, portB;
 
wire [7:0] shiftout;
 
assign data_out=shiftout;
 
 
genpc genpc
(
.clk (clk),
.rst (rst),
 
.ldpc (ldpc),
.selpc (selpc),
.ninst_addr (ninst_addr),
 
.inst_addr (inst_addr)
);
 
 
alu_mux alu_mux
(
.selimm (selimm),
.imm (imm),
.portB (portB),
 
.muximm (muximm)
);
 
alu alu
(
.a (portA),
.b (muximm),
.opalu (opalu),
.ldflag (ldflag),
.zero (z),
.carry (c),
.sh (sh),
.dshift (shiftout)
);
 
 
stack stack
(
.clk (clk),
.rst (rst),
.wr_en (wr_en),
.rd_en (rd_en),
.din (inst_addr),
.dout (stack_addr)
);
 
 
regfile_mux regfile_mux
(
.insel (insel),
.selk (selk),
.shiftout (shiftout),
.kte (kte),
.data_in (data_in),
 
.regmux (regmux)
);
 
regfile regfile
(
.datain (regmux),
.clk (clk),
.we (we),
.wa (wa),
.raa (raa),
.rab (rab),
.porta (portA),
.portb (portB)
);
 
 
 
endmodule


8>程序计算器:genpc

/*
*
* file name    : genpc.v
* author    : Rill
* date        : 2013-08-11
*
*/
 
`define boot_addr 0     //boot address after power on
 
module genpc
(
input clk,
input rst,
 
input ldpc,
input selpc,
input [10:0] ninst_addr,
 
output [10:0] inst_addr
);
 
reg [10:0] pc;
 
assign inst_addr=pc;
 
always@(posedge clk or posedge rst)
begin
    if (rst)
        pc <=`boot_addr;
    else
        if (ldpc)    
            if(selpc)
                pc<=ninst_addr;
            else
                pc<=pc+1;
end
 
 
endmodule
 
 


9>运算单元:alu ,alu_mux


/*
*
* file name    : alu_mux.v
* author    : Rill
* date        : 2013-08-11
*
*/
 
 
 
module alu_mux
(
input selimm,
input [7:0] imm,
input [7:0] portB,
 
output [7:0] muximm
);
 
assign muximm = selimm? imm : portB;//result : imm if ldi insn,portb if ldm insn
 
 
endmodule


/*
*
* file name    : alu.v
* author    : Rill
* date        : 2013-08-11
*
*/
 
 
 
module alu
(
input [7:0] a,
input [7:0] b,
input [2:0] opalu,
input ldflag,
output zero,
output carry,
input [2:0] sh,
output reg [7:0] dshift
);
 
reg [7:0] resu;
 
assign zero=ldflag?(resu==0):1'b0;
 
assign carry=ldflag?(a  
always@(*)
    case (opalu)
        0: resu <= ~a;
        1: resu <= a & b;
        2: resu <= a ^ b;
        3: resu <= a | b;
        4: resu <= a;
        5: resu <= a + b;
        6: resu <= a - b;
        default: resu <= a + 1;
    endcase
    
    
always@*
        case (sh)
            0: dshift <= {resu[6:0], 1'b0};
            1: dshift <= {resu[6:0], resu[7]};
            2: dshift <= {1'b0, resu[7:1]};
            3: dshift <= {resu[0], resu[7:1]};
            4: dshift <= resu;
            5: dshift <= {resu[6:0], 1'b1};
            6: dshift <= {1'b1, resu[7:1]};
            default: dshift <= resu;
        endcase
 
endmodule


10>寄存器堆:regfile,regfile_mux

/*
*
* file name    : regfile_mux.v
* author    : Rill
* date        : 2013-08-11
*
*/
 
 
 
module regfile_mux
(
input insel,
input selk,
input [7:0] shiftout,
input [7:0] kte,
input [7:0] data_in,
 
output [7:0] regmux
);
 
wire [7:0] muxkte;
 
assign regmux=insel? shiftout : muxkte;
assign muxkte=selk? kte : data_in;
 
 
endmodule


/*
*
* file name    : regfile.v
* author    : Rill
* date        : 2013-08-11
*
*/
 
 
 
module regfile(
    input [7:0] datain,
    input clk, we,
    input [2:0] wa,
    input [2:0] raa,
    input [2:0] rab,
    output [7:0] porta,
    output [7:0] portb
    );
 
 
reg [7:0] mem [7:0];//r0 ~r255
 
always@(posedge clk)
begin
    mem[0]<=0;//r0 always is 0
        
    if(we)
        mem[wa]<=datain;
end     
    
assign porta=mem[raa];
assign portb=mem[rab];
 
 
endmodule


11>栈:stack

/*
*
* file name    : stack.v
* author    : Rill
* date        : 2013-08-11
*
*/
 
 
 
module stack(
    input clk,
     input rst,
    input wr_en,
    input rd_en,
    input [10:0] din,
    output [10:0] dout
    );
 
 
   (* RAM_STYLE="DISTRIBUTED" *)
reg [3:0] addr;
reg [10:0] ram [15:0];
 
assign dout = ram[addr] +1;
 
always@(posedge clk)
begin
    if (rst)
        addr<=0;
    else 
        begin 
            if (wr_en==0 && rd_en==1)  //leer
                if (addr>0)
                    addr<=addr-1;
            if (wr_en==1 && rd_en==0)  //guardar
                if (addr<15)
                    addr<=addr+1;
        end
end
        
always @(posedge clk)
begin
    if (wr_en)
        ram[addr] <= din;
end
 
endmodule


5,modelsim仿真
1>编写testbench
要进行仿真,需要编写对应的testbench,由于咱们这个cpu很简单,所以测试激励也很简单,代码如下:

/*
*
* file name    : tiny_soc_tb.v
* atthor    : Rill
* date        : 2013-08-11
*
*/
 
`timescale 1ns / 1ps
 
module tiny_soc_tb;
 
 
reg clk;
reg rst;
 
 
always #5 clk = ~clk;
 
initial
begin
    #0 
        clk = 0;
        rst = 0;
    #15 
        rst = 1;
    #10 
        rst = 0;
        
    #1000
        $stop;
end
 
soc_top soc_top
(
.clk (clk),
.rst (rst)
);
 
 
endmodule


2>编写汇编代码及手动汇编
当然还要编写其汇编代码,如下:

然后我们要手动汇编成机器码,指令集都是自己定义的,所以是没有现成的compiler,只能手动汇编了,还好手动汇编要比手动反汇编轻松多了(之前,我们手动反汇编过OpenRISC的启动代码)。

汇编完成后,我们将机器码放到指令存储器里,如下,共七条指令。

3>仿真结果
完成上面的工作之后,我们就可以用仿真工具进行仿真了,下面是我用modelsim仿真的结果。

从波形可以清晰的看出七条指令的执行过程。在运算完成后拉高write_e信号并将1+2的运算结果3写到了ram地址是55(0x37)的地方

锐单商城拥有海量元器件数据手册IC替代型号,打造电子元器件IC百科大全!

相关文章