合肥工业大学计组实验五

step1 分析命令:

 这十条命令为:CLA、COM、SHR、CSL、STP、ADD、STA、LDA、JMP、BAN
 实现这些命令所需的模块有:PC、ACC、ALU、CU、ROM、RAM

step2 分析模块:

 PC
由于PC需要增加停机功能和跳转功能,所以PC应该增加接口来实现停机与跳转指令。
 ACC
新增模块ACC,ACC为累加器,CLA、COM、SHR、CSL这四条指令直接操作ACC中的数据,ADD指令将ACC作为操作数,所以ACC应该有一个读数据、一个写数据、使写数据能的接口。(后期实验发现忘记给ACC加一个时钟控制信号了,不加时钟控制信号的话ACC中的数据会出错,一个时钟周期内可能被写两次。)
 CU
由于CU要控制ACC和PC完成指令,所以CU应该增加输出来控制ACC和PC。
 ALU
ALU需要完成对ACC最高位的判断,并将判断结果传送给PC以便PC完成BAN指令。
 其余模块无需改变

step3 新增模块图示:

在这里插入图片描述
在这里插入图片描述

step4 cpu数据通路设计:

在这里插入图片描述
除了图中画红线的其余名字一样的连到一起。

Step5 指令设计:

这次实验我将指令的位数更改为13位,[12:9]为操作码,[8:0]为立即数或地址。
在这里插入图片描述

Step6 模块设计:

PC:

1.	module PC(  
2.	    input clk,  
3.	    input rst,  
4.	    input stop,  
5.	    input ban,  
6.	    input p_wr_en,  
7.	    input wire [12:0] jmp,  
8.	    output reg [12:0] pc  
9.	    );  
10.	    reg state;  
11.	    initial begin  
12.	        pc=8'd0;  
13.	        state=1;  
14.	    end  
15.	    always@* begin  
16.	        if(stop==1)  
17.	            state<=0;  
18.	        if(rst==1)  
19.	            pc<=0;  
20.	    end  
21.	    always@(posedge clk) begin  
22.	        if(state==1)  
23.	            pc<=pc+1'd1;  
24.	    end  
25.	    always@(negedge clk) begin  
26.	        if(p_wr_en==1)  
27.	            pc<=jmp-1;  
28.	        if(ban==1)  
29.	            pc<=pc+jmp-1;  
30.	    end  
31.	endmodule 

ROM:

1.	module ROM(  
2.	    input wire [12:0] pc,  
3.	    output reg [15:0] ins  
4.	    );  
5.	      
6.	    reg [15:0] ROM_data [255:0];  
7.	    integer i;  
8.	      
9.	    initial $readmemb("D:/vivadowork/TEN-CPU/ONE_CPU.srcs/sources_1/new/ROM_initial.txt",ROM_data);  
10.	      
11.	    always@(pc) begin  
12.	        ins<=ROM_data[pc];  
13.	    end  
14.	endmodule  

RAM:

1.	module RAM(  
2.	    input clk,  
3.	    input m_wr_en,  
4.	    input wire [15:0] in_data,  
5.	    input wire [8:0] index,  
6.	    output wire [15:0] out_data  
7.	    );  
8.	      
9.	    reg [15:0] initdata [1023:0];  
10.	    integer i;  
11.	    initial $readmemb("D:/vivadowork/TEN-CPU/ONE_CPU.srcs/sources_1/new/RAM_initial.txt",initdata);  
12.	      
13.	    always@(posedge clk ) begin  
14.	        begin if (m_wr_en==0)  
15.	            initdata[index]<=in_data;  
16.	        end  
17.	    end  
18.	      
19.	    assign out_data=initdata[index];  
20.	endmodule 

CU:

根据不同指令输出不同的数据来控制各个模块来完成指令。

1.	module CU(  
2.	    input wire [3:0] opcode,  
3.	    output reg p_wr_en,  
4.	    output reg m_wr_en,  
5.	    output reg a_wr_en,  
6.	      
7.	    output reg stop,  
8.	    output reg [3:0] alu_op   
9.	    );  
10.	    always@(opcode)begin  
11.	        case(opcode)  
12.	        4'b0001: begin //cla  
13.	            p_wr_en<=0;  
14.	            stop<=0;  
15.	            m_wr_en<=1;  
16.	            a_wr_en<=1;  
17.	            alu_op<=4'b0111;  
18.	        end  
19.	        4'b0010: begin//com  
20.	            p_wr_en<=0;  
21.	            stop<=0;  
22.	            m_wr_en<=1;  
23.	            a_wr_en<=1;  
24.	            alu_op<=4'b1000;  
25.	        end  
26.	        4'b0011: begin //shr  
27.	            p_wr_en<=0;  
28.	            stop<=0;  
29.	            m_wr_en<=1;  
30.	            a_wr_en<=1;  
31.	            alu_op<=4'b1001;  
32.	        end  
33.	        4'b0100: begin //csl  
34.	            p_wr_en<=0;  
35.	            stop<=0;  
36.	            m_wr_en<=1;  
37.	            a_wr_en<=1;  
38.	            alu_op<=4'b1010;          
39.	        end  
40.	        4'b0101: begin //stp  
41.	            p_wr_en<=0;  
42.	            stop<=1;  
43.	            m_wr_en<=1;  
44.	            a_wr_en<=0;  
45.	        end  
46.	        4'b0110: begin //add  
47.	            p_wr_en<=0;  
48.	            stop<=0;  
49.	            m_wr_en<=1;  
50.	            a_wr_en<=1;  
51.	            alu_op<=4'b0001;  
52.	        end  
53.	        4'b0111: begin //sta  
54.	            p_wr_en<=0;  
55.	            stop<=0;  
56.	            m_wr_en<=0;  
57.	            a_wr_en<=0;  
58.	              
59.	        end  
60.	        4'b1000: begin //lda  
61.	            p_wr_en<=0;  
62.	            stop<=0;  
63.	            m_wr_en<=1;  
64.	            a_wr_en<=1;  
65.	            alu_op<=4'b1011;  
66.	        end  
67.	        4'b1001: begin //jmp  
68.	            p_wr_en<=1;  
69.	            stop<=0;  
70.	            m_wr_en<=1;  
71.	            a_wr_en<=0;  
72.	        end  
73.	        4'b1010: begin //ban  
74.	            p_wr_en<=1;  
75.	            stop<=0;  
76.	            m_wr_en<=1;  
77.	            a_wr_en<=0;   
78.	            alu_op<=4'b1100;             
79.	        end  
80.	        endcase  
81.	    end  
82.	endmodule  

ALU:

1.	module ALU(  
2.	    input wire[15:0] in1,  
3.	    input wire[15:0] in2,  
4.	    input wire[3:0] alu_op,  
5.	    output reg ban,  
6.	    output reg[15:0] z  
7.	    );  
8.	    always @(*)  
9.	    begin  
10.	    case(alu_op)  
11.	    4'b0001: z<=in1+in2;  
12.	    4'b0010: z<=in1-in2;  
13.	    4'b0011: z<=in1&in2;  
14.	    4'b0100: z<=in1|in2;  
15.	    4'b0101: z<=in1<<in2;  
16.	    4'b0110: z<=in1>>in2;  
17.	    4'b0111: z<=0; //cla  
18.	    4'b1000: z<=~in1; //com  
19.	    4'b1001: z<={{in1[15]},in1[15:1]}; //shr  
20.	    4'b1010: z<={{in1[14:0]},in1[15]}; //csl  
21.	    4'b1011: z<=in2;  
22.	    4'b1100: ban<=in1[15]==1 ? 1 : 0;  
23.	//    4'b0111: z<={{6{imm[8]}},imm}+in1;  
24.	//    4'b1000: z<=out_data;  
25.	    endcase  
26.	    end  
27.	endmodule 

ACC:

1.	module ACC(  
2.	    input a_wr_en,  
3.	    input clk,  
4.	    input wire [15:0]in_data,  
5.	    output wire [15:0]acc_data  
6.	    );  
7.	    reg [0:15]acc;  
8.	    initial begin  
9.	        acc=16'd0;  
10.	    end  
11.	    assign acc_data=acc;  
12.	    always@( posedge clk)  
13.	    begin  
14.	        if(a_wr_en==1)  
15.	            acc=in_data;  
16.	    end  
17.	      
18.	      
19.	endmodule  

顶层封装:

1.	module CPU(  
2.	    input clk,  
3.	    input rst,  
4.	    output stop,  
5.	    output ban,  
6.	    output p_wr_en,  
7.	    output a_wr_en,  
8.	    output wire [12:0] pc,  
9.	    output wire [15:0] ins,  
10.	    output wire [3:0] alu_op,  
11.	    output m_wr_en,  
12.	    output wire [15:0] z,  
13.	    output wire [15:0]acc_data,  
14.	    output wire [15:0]out_data  
15.	    );  
16.	   
17.	      
18.	    PC f_pc(  
19.	        .clk(clk),  
20.	        .rst(rst),  
21.	        .pc(pc),  
22.	        .stop(stop),  
23.	        .ban(ban),  
24.	        .p_wr_en(p_wr_en),  
25.	        .jmp({{4{ins[8]}},ins[8:0]}));  
26.	          
27.	    ROM f_rom(  
28.	        .pc(pc),  
29.	        .ins(ins));  
30.	          
31.	    RAM f_ram(  
32.	        .clk(clk),  
33.	        .m_wr_en(m_wr_en),  
34.	        .in_data(acc_data),  
35.	        .index(ins[8:0]),  
36.	        .out_data(out_data)  
37.	        );  
38.	          
39.	    CU f_cu(  
40.	        .opcode(ins[12:9]),  
41.	        .p_wr_en(p_wr_en),  
42.	        .a_wr_en(a_wr_en),  
43.	        .stop(stop),  
44.	        .alu_op(alu_op),  
45.	        .m_wr_en(m_wr_en) //  
46.	        );  
47.	      
48.	    ALU f_alu(  
49.	        .ban(ban),  
50.	        .in1(acc_data),  
51.	        .in2(out_data),  
52.	        .alu_op(alu_op),  
53.	        .z(z)  
54.	        );  
55.	          
56.	    ACC f_acc(  
57.	        .a_wr_en(a_wr_en),  
58.	        .clk(clk),  
59.	        .in_data(z),  
60.	        .acc_data(acc_data)  
61.	        );  
62.	endmodule  

Step6 模拟仿真

1. 仿真文件


1.	module test_CPU;  
2.	    reg clk;  
3.	    reg rst;   
4.	    wire stop;  
5.	    wire ban;  
6.	    wire p_wr_en;  
7.	    wire a_wr_en;  
8.	    wire [12:0] pc;  
9.	    wire [12:0] ins;  
10.	    wire m_wr_en;  
11.	    wire [3:0] alu_op;  
12.	    wire [15:0] z;  
13.	    wire [15:0] out_data;  
14.	    wire [15:0] acc_data;  
15.	      
16.	    initial begin  
17.	        clk=1'd0;  
18.	        forever #10 clk=~clk;  
19.	    end  
20.	      
21.	    initial begin  
22.	        rst=1'd0;  
23.	        #120 $stop;  
24.	    end  
25.	      
26.	    CPU test(  
27.	        .clk(clk),  
28.	        .rst(rst),  
29.	        .stop(stop),  
30.	        .ban(ban),  
31.	        .p_wr_en(p_wr_en),  
32.	        .acc_data(acc_data),  
33.	        .z(z),  
34.	        .pc(pc),  
35.	        .ins(ins),  
36.	        .a_wr_en(a_wr_en),  
37.	        .alu_op(alu_op),  
38.	        .m_wr_en(m_wr_en),  
39.	        .out_data(out_data)  
40.	        );  
41.	endmodule  

2. 仿真:

(一)第一次仿真

ROM初始化数据为:

1000000000001	//lda
0010000000000  	//com
0011000000000	//shr
0001000000000	//cla
0101000000000	//stp

RAM初始化数据为:

1010001111010100
0000110101110011

仿真结果:
在这里插入图片描述

(二)第二次仿真

ROM初始化数据为:

1000000000000	//lda
0110000000001	//add
0111000000000	//sta	
1000000000011	//lda
1010000000010	//ban 
0101000000000	//stp
1001000001000	//jmp
0101000000000	//stp

RAM初始化数据为:

1010001111010100
0000110101110011
0000000000000010
1111111111111111
0001000000000000

在执行这些指令的过程中我发现了一些错误所以将代码修改了一下:
修改如下:
一.当执行ban指令跳转后,ban值一直为1,所以pc一直在执行ban操作,所以要在ALU的其他操作中增加ban输出为0的操作防止出错。同时cu中有一些操作没有对应的ALU操作为防止执行ban指令后出错,更改cu和ALU。

1.	module ALU(  
2.	    input wire[15:0] in1,  
3.	    input wire[15:0] in2,  
4.	    input wire[3:0] alu_op,  
5.	    output reg ban,  
6.	    output reg[15:0] z  
7.	    );  
8.	    always @(*)  
9.	    begin  
10.	    case(alu_op)  
11.	    4'b0001: begin z<=in1+in2;ban<=0; end  
12.	    4'b0010: begin z<=in1-in2;ban<=0; end  
13.	    4'b0011: begin z<=in1&in2;ban<=0; end  
14.	    4'b0100: begin z<=in1|in2;ban<=0; end  
15.	    4'b0101: begin z<=in1<<in2;ban<=0; end  
16.	    4'b0110: begin z<=in1>>in2;ban<=0; end  
17.	    4'b0111: begin z<=0; ban<=0; end//cla  
18.	    4'b1000: begin z<=~in1; ban<=0; end//com  
19.	    4'b1001: begin z<={{in1[15]},in1[15:1]};ban<=0; end //shr  
20.	    4'b1010: begin z<={{in1[14:0]},in1[15]}; ban<=0; end//csl  
21.	    4'b1011: begin z<=in2;ban<=0; end  
22.	    4'b1100: ban<=in1[15]==1 ? 1 : 0;  
23.	    4'b1101: ban<=0;  
24.	//    4'b0111: z<={{6{imm[8]}},imm}+in1;  
25.	//    4'b1000: z<=out_data;  
26.	    endcase  
27.	    end  
28.	endmodule  

CU

1.	module CU(  
2.	    input wire [3:0] opcode,  
3.	    output reg p_wr_en,  
4.	    output reg m_wr_en,  
5.	    output reg a_wr_en,  
6.	      
7.	    output reg stop,  
8.	    output reg [3:0] alu_op   
9.	    );  
10.	    always@(opcode)begin  
11.	        case(opcode)  
12.	        4'b0001: begin //cla  
13.	            p_wr_en<=0;  
14.	            stop<=0;  
15.	            m_wr_en<=1;  
16.	            a_wr_en<=1;  
17.	            alu_op<=4'b0111;  
18.	        end  
19.	        4'b0010: begin//com  
20.	            p_wr_en<=0;  
21.	            stop<=0;  
22.	            m_wr_en<=1;  
23.	            a_wr_en<=1;  
24.	            alu_op<=4'b1000;  
25.	        end  
26.	        4'b0011: begin //shr  
27.	            p_wr_en<=0;  
28.	            stop<=0;  
29.	            m_wr_en<=1;  
30.	            a_wr_en<=1;  
31.	            alu_op<=4'b1001;  
32.	        end  
33.	        4'b0100: begin //csl  
34.	            p_wr_en<=0;  
35.	            stop<=0;  
36.	            m_wr_en<=1;  
37.	            a_wr_en<=1;  
38.	            alu_op<=4'b1010;          
39.	        end  
40.	        4'b0101: begin //stp  
41.	            p_wr_en<=0;  
42.	            stop<=1;  
43.	            m_wr_en<=1;  
44.	            a_wr_en<=0;  
45.	            alu_op<=4'b1101;  
46.	        end  
47.	        4'b0110: begin //add  
48.	            p_wr_en<=0;  
49.	            stop<=0;  
50.	            m_wr_en<=1;  
51.	            a_wr_en<=1;  
52.	            alu_op<=4'b0001;  
53.	        end  
54.	        4'b0111: begin //sta  
55.	            p_wr_en<=0;  
56.	            stop<=0;  
57.	            m_wr_en<=0;  
58.	            a_wr_en<=0;  
59.	            alu_op<=4'b1101;  
60.	        end  
61.	        4'b1000: begin //lda  
62.	            p_wr_en<=0;  
63.	            stop<=0;  
64.	            m_wr_en<=1;  
65.	            a_wr_en<=1;  
66.	            alu_op<=4'b1011;  
67.	        end  
68.	        4'b1001: begin //jmp  
69.	            p_wr_en<=1;  
70.	            stop<=0;  
71.	            m_wr_en<=1;  
72.	            a_wr_en<=0;  
73.	            alu_op<=4'b1101;  
74.	        end  
75.	        4'b1010: begin //ban  
76.	            p_wr_en<=1;  
77.	            stop<=0;  
78.	            m_wr_en<=1;  
79.	            a_wr_en<=0;   
80.	            alu_op<=4'b1100;             
81.	        end  
82.	        endcase  
83.	    end  
84.	endmodule  

二.Pc执行停机指令时是在任何一个时钟周期内都可以进行,这样会使jmp或ban指令出错,所以我将器更改为仅在时钟周期上沿时可以停机。
PC

1.	module PC(  
2.	    input clk,  
3.	    input rst,  
4.	    input stop,  
5.	    input ban,  
6.	    input p_wr_en,  
7.	    input wire [12:0] jmp,  
8.	    output reg [12:0] pc  
9.	    );  
10.	    reg state;  
11.	    initial begin  
12.	        pc=8'd0;  
13.	        state=1;  
14.	    end  
15.	    always@(posedge clk) begin  
16.	        if(stop==1)  
17.	            state<=0;  
18.	        if(rst==1)  
19.	            pc<=0;  
20.	    end  
21.	    always@(posedge clk) begin  
22.	        if(state==1)  
23.	            pc<=pc+1'd1;  
24.	    end  
25.	    always@(negedge clk) begin  
26.	        if(p_wr_en==1)  
27.	            pc<=jmp-1;  
28.	        if(ban==1)  
29.	            pc<=pc+jmp-1;  
30.	    end  
31.	endmodule  

仿真结果:

在这里插入图片描述

  • 1
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值