哪些网站论坛做推广好,河南网站建设yipinpai,公司网站后台模板,高明骏域网站建设待办事项 时钟频率高#xff0c;取指周期长#xff0c;远大于执行周期#xff0c;如何处理#xff1f; 不可综合逻辑的处理 接上一篇 【计算机系统设计】实践笔记#xff08;2#xff09;数据通路构建#xff1a;第一类R型指令分析#xff08;1#xff09;
8.2 ALU运…待办事项 时钟频率高取指周期长远大于执行周期如何处理 不可综合逻辑的处理 接上一篇 【计算机系统设计】实践笔记2数据通路构建第一类R型指令分析1
8.2 ALU运算器
timescale 1ns / 1ps
//
// Engineer:jht
// Create Date: 2020/11/14 22:30:23
// Module Name: ALU_1
//module ALU_1(// datainput [31:0] A,input [31:0] B,// controlinput [3:0] ALUop,output reg [31:0] ALUresult);// convert A and B to signed numbers
wire signed [31:0] A_signed A;
wire signed [31:0] B_signed B;always (*)
begincase (ALUop)4b0000: // addbeginALUresult A B;end4b0001: // addubeginALUresult A B;end4b0010: // subbeginALUresult A - B;end4b0011: // sububeginALUresult A - B;end4b0100: // andbeginALUresult A B;end4b0101: // orbeginALUresult A | B;end4b0110: // xorbeginALUresult A ^ B;end4b0111: // norbeginALUresult ~(A | B);end4b1000: // slt // note:********signed********//beginif(A_signed B_signed)ALUresult 1;elseALUresult 0;end4b1001: // sltubeginif(A B)ALUresult 1;elseALUresult 0;end4b1010: // sllvbeginALUresult A B;end4b1011: // srlvbeginALUresult A B;end4b1100: // srav // note: ******signed*******//beginALUresult A_signed B;enddefault:beginALUresult 0;endendcase
endendmodule测试文件tb_ALU_1.v
timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2020/11/27 10:36:19
// Design Name:
// Module Name: tb_ALU_1
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//module tb_ALU_1;// ALU_1 Inputs
reg [31:0] A 0 ;
reg [31:0] B 0 ;
reg [3:0] ALUop 0 ;// ALU_1 Outputs
wire [31:0] ALUresult ;ALU_1 u_ALU_1 (.A ( A [31:0] ),.B ( B [31:0] ),.ALUop ( ALUop [3:0] ),.ALUresult ( ALUresult [31:0] ));initial
begin#10ALUop 0;A 1;B 4;#10ALUop 1;A 1;B 5;#10ALUop 2;A 4;B 1;#10ALUop 3;A 4;B 2;// and#10ALUop 4;A 32b1001111;B 32b1001001;#10ALUop 5;A 32b1001111;B 32b1001001;#10ALUop 6;A 32b1001111;B 32b1001001;#10ALUop 7;A 32b1001111;B 32b1001001;// slt#30ALUop 8;A -1;B 3;#10ALUop 9;A -1;B 3;#10ALUop 9;A 1;B 3;// sllv#30ALUop 10;A 32b1001111;B 32d4;#10ALUop 11;A 32hABCDabcd;B 32d4;// srav#30ALUop 12;A 32hABCDabcd;B 32d4;#40ALUop 4b1111;endendmodule
功能仿真成功
8.2.1 注意事项有无符号数的运算和比较
主要针对slt sltu srlv srav这几条指令中涉及到的对有无符号数进行的操作。
原则Verilog默认都是无符号数需要显式地声明signed才能进行带符号数运算。
对于slt sltu前者是带符号数比较后者是无符号数比较只有当比较的值显式地声明为signed时候slt使用比较运算符才进行带符号比较否则还是无符号比较。对于srlv srav主要是srav对于带符号数使用首位生成1通用应该显式地声明signed否则会与srlv指令没区别。
注意代码中的
// convert A and B to signed numbers
wire signed [31:0] A_signed A;
wire signed [31:0] B_signed B;这是将无符号数声明为带符号数的方法。
8.3 Register Files 寄存器堆
reg_files.v
timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2020/11/14 22:31:09
// Design Name:
// Module Name: reg_files_1
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//module reg_files_1(input clk,input rst_n,/*** read port 1 ***/input [4:0] rA, // rs fieldoutput reg [31:0] A,/*** read port 2 ***/input [4:0] rB, // rtoutput reg [31:0] B,/*** write port ***/input [4:0] rW, // rd or rtinput [31:0] writeData, // datainput RegWrite // if RegWrite 1,you can write data to reg files);// reg files
reg [31:0] register [0:31];
integer i;
initial
beginfor (i 0;i 32;i i 1)beginregister[i] 0;end
end/******* write operation *******/always (posedge clk) // sequential logic
beginif(rst_n 0) // reset is invalidbeginif((RegWrite 1b1) (rW ! 5b0)) // write is valid and address is not equal zerobeginregister[rW] writeData;endelse;endelse;
end/******* rA read operation *******/
always (*) // combinational logic
beginif(rst_n 1)beginA 32b0;endelse if(rA 5b0)beginA 32b0;endelsebeginA register[rA];end
end/******* rB read operation *******/
always (*) // combinational logic
beginif(rst_n 1)beginB 32b0;endelse if(rB 5b0) // $zerobeginB 32b0;endelsebeginB register[rB];end
endendmodule测试文件tb_reg_files_1.v
timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2020/11/27 10:11:14
// Design Name:
// Module Name: tb_reg_files_1
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//module tb_reg_files_1;// reg_files_1 Parameters
parameter PERIOD 10;// reg_files_1 Inputs
reg clk 0 ;
reg rst_n 1 ;
reg [4:0] rA 0 ;
reg [4:0] rB 0 ;
reg [4:0] rW 0 ;
reg [31:0] writeData 0 ;
reg RegWrite 0 ;// reg_files_1 Outputs
wire [31:0] A ;
wire [31:0] B ;initial
beginforever#(PERIOD/2) clk~clk;
endinitial
begin#(PERIOD*2) rst_n 0;
endreg_files_1 u_reg_files_1 (.clk ( clk ),.rst_n ( rst_n ),.rA ( rA [4:0] ),.rB ( rB [4:0] ),.rW ( rW [4:0] ),.writeData ( writeData [31:0] ),.RegWrite ( RegWrite ),.A ( A [31:0] ),.B ( B [31:0] ));initial
begin#20RegWrite 1;rW 0;writeData 32hff;#10rW 1;writeData 32hff;#10rA 1;#10rB 1;#10rA 0;rB 0;
endendmodule初步功能仿真成功
9 连接已有器件
9.1 增加ROM
使用IP核参考东南大学计算机系统设计MOOC9.1节的做法。
9.2 将已有部件连接起来
timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2020/11/27 11:41:34
// Design Name:
// Module Name: datapath_1
// Project Name:
// Target Devices:
// Tool Versions:
// Description: 仅仅实现了几个简单的R类指令的最简单的数据通路不与外界交互
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//module datapath_1(input clk,input rst_n);/******** PC ********/// pc_1 Outputs
wire [31:0] pcOld;pc_1 u_pc_1 (.clk ( clk ),.rst_n ( rst_n ),.pcNew ( pcOld ), // pcNew pcOld 4; no selection.pcOld ( pcOld ));/******** Instruction ROM ********/// blk_mem_gen_0 Inputs
wire [13:0] addra pcOld[15:2];// blk_mem_gen_0 Outputs // instructions
wire [31:0] instruction;blk_mem_gen_0 u_blk_mem_gen_0 (.clka ( clk ),.addra ( addra ),.douta ( instruction ));/******** Reg Files ********/// reg_files_1 Inputs
wire [4:0] rA instruction[25:21];
wire [4:0] rB instruction[20:16];
wire [4:0] rW instruction[15:11];
wire [31:0] writeData;
wire RegWrite;// reg_files_1 Outputs
wire [31:0] A;
wire [31:0] B;reg_files_1 u_reg_files_1 (.clk ( clk ),.rst_n ( rst_n ),.rA ( rA ),.rB ( rB ),.rW ( rW ),.writeData ( writeData ),.RegWrite ( RegWrite ),.A ( A ),.B ( B )
);/******** ALU ********/// ALU_1 Inputs
// wire [31:0] A;
// wire [31:0] B;
wire [3:0] ALUop;// ALU_1 Outputs
wire [31:0] ALUresult writeData;ALU_1 u_ALU_1 (.A ( A ),.B ( B ),.ALUop ( ALUop ),.ALUresult ( ALUresult )
);/******** controler ********/// control_1 Inputs
wire [5:0] op instruction[31:26];
wire [5:0] func instruction[5:0];// control_1 Outputs
// wire RegWrite
// wire [3:0] ALUop;control_1 u_control_1 (.op ( op ),.func ( func ),.RegWrite ( RegWrite ),.ALUop ( ALUop )
);endmodule
9.3 测试我们的数据通路
由于寄存器堆初始全是0最开始又没有写入的指令因此修改下以方便测试
// reg files
reg [31:0] register [0:31];
integer i;
initial
beginfor (i 0;i 32;i i 1)begin// 为了方便初步测试 ///register[i] i; end
end注意赋值的是i而不是0了。
写入一些指令测试我们的数据通路
测试文件如下
timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2020/11/27 12:12:14
// Design Name:
// Module Name: tb_datapath_1
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//module tb_datapath_1;// datapath_1 Parameters
parameter PERIOD 10;// datapath_1 Inputs
reg clk 0 ;
reg rst_n 1 ;// datapath_1 Outputsinitial
beginforever #(PERIOD/2) clk~clk;
endinitial
begin#(PERIOD*2) rst_n 0;
enddatapath_1 u_datapath_1 (.clk ( clk ),.rst_n ( rst_n )
);endmoduleRTL优化
测试指令如下 以上错误因为一次性连接了太多器件不符合单元测试原则重新开始重要的是ROM的IP核没有测试
9.4 构建取值模块
我们先把PC和ROM连接起来测试。
然后发现……很诡异PC似乎对ROM不起作用? 这个IP核……居然有延迟不是瞬间取得指令……需要等一个周期后再等待上升沿才能取指。也就是说ROM的取指需要等待一个额外的时钟周期这才是真实世界。
9.5 插叙带延迟的ROM
实际上访存时间更长取指比较慢这个事实我们都知道现在我们真地面临这个问题了。
理想取指的时序图与带一个时钟周期延迟的时序图是不一样的
在单周期CPU中
理想瞬间取指那么更新PC值需要是下降沿而写寄存器堆需要是上升沿带一个时钟周期延迟的就可以都是上升沿因为取下一条指令的过程占一个时钟周期此时CPU就讲当前指令执行完了也就是取下一条指令和CPU执行当前指令同步进行。
特别注意默认值0的指令会比较诡异
在我们的设计中pc默认是0因此……0号地址的指令会被直接取出来但是如果没有复位也是不能指令的这个情况下其实可以用nop指令全是0作为0号地址的指令。
9.6 完整数据通路的实现与测试
让我们返回看看。
datapath_1.v
timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2020/11/27 11:41:34
// Design Name:
// Module Name: datapath_1
// Project Name:
// Target Devices:
// Tool Versions:
// Description: 仅仅实现了几个简单的R类指令的最简单的数据通路不与外界交互
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//module datapath_1(input clk,input rst_n);/******** PC ********/// pc_1 Outputs
wire [31:0] pcOld;pc_1 u_pc_1 (.clk ( clk ),.rst_n ( rst_n ),.pcNew ( pcOld ), // pcNew pcOld 4; no selection.pcOld ( pcOld ));/******** Instruction ROM ********/// blk_mem_gen_0 Inputs
wire [13:0] addra pcOld[15:2];// blk_mem_gen_0 Outputs // instructions
wire [31:0] instruction;blk_mem_gen_0 u_blk_mem_gen_0 (.clka ( clk ),.addra ( addra ),.douta ( instruction ));/******** Reg Files ********/// reg_files_1 Inputs
wire [4:0] rA instruction[25:21];
wire [4:0] rB instruction[20:16];
wire [4:0] rW instruction[15:11];
wire [31:0] writeData;
wire RegWrite;// reg_files_1 Outputs
wire [31:0] A;
wire [31:0] B;reg_files_1 u_reg_files_1 (.clk ( clk ),.rst_n ( rst_n ),.rA ( rA ),.rB ( rB ),.rW ( rW ),.writeData ( writeData ),.RegWrite ( RegWrite ),.A ( A ),.B ( B ));/******** ALU ********/// ALU_1 Inputs
// wire [31:0] A;
// wire [31:0] B;
wire [3:0] ALUop;// ALU_1 Outputs
// wire [31:0] ALUresult writeData;【】【为什么不能用?】ALU_1 u_ALU_1 (.A ( A ),.B ( B ),.ALUop ( ALUop ),.ALUresult ( writeData ));/******** controler ********/// control_1 Inputs
wire [5:0] op instruction[31:26];
wire [5:0] func instruction[5:0];// control_1 Outputs
// wire RegWrite
// wire [3:0] ALUop;control_1 u_control_1 (.op ( op ),.func ( func ),.RegWrite ( RegWrite ),.ALUop ( ALUop ));endmoduleRTL优化
测试文件 tb_datapath_1.v
timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2020/11/27 12:12:14
// Design Name:
// Module Name: tb_datapath_1
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//module tb_datapath_1;// datapath_1 Parameters
parameter PERIOD 10;// datapath_1 Inputs
reg clk 0 ;
reg rst_n 1 ;// datapath_1 Outputsinitial
beginforever #(PERIOD/2) clk~clk;
endinitial
begin#(PERIOD*2) rst_n 0;
enddatapath_1 u_datapath_1 (.clk ( clk ),.rst_n ( rst_n )
);endmodule仿真结果 测试指令
nop
add $1,$2,$3 # $1 2 3 5
addu $2,$4,$1 # $2 4 5 9
sub $4,$2,$1 # $4 9 - 5 4
subu $5,$4,$3 # $5 4 - 3 1and $6,$7,$8 # $6 0111 and 1000 0
or $7,$6,$8 # $7 0 or 1000 8
xor $7,$6,$8 # $7 0000 xor 1000 1000 8
nor $8,$7,$6 # $8 not (1000 or 0) 11111111111110111slt $10,$11,$12 # $10 11 12 1 # 应该用负数验证以后再说
sltu $10,$12,$11 # $10 12 11 0sllv $12,$5,$13 # $12 1101 1 1101_0 1A 【注意此处的倒置问题 sllv rd,rt,rs】
srlv $12,$5,$13 # $12 1101 1 110 6
srav $14,$5,$15 # $14 1111 1 111 7 应该用负数验证以后再说指令编码
00000000
00430820
00811021
00412022
00832823
00e83024
00c83825
00c83826
00e64027
016c502a
018b502b
01a56004
01a56006
01e57007注意事项
sllv srlv srav指令的使用方法是sllv rd,rt,rs它们的rs和rt与一般指令顺序不一样是反着的使用的时候需要注意第一条指令使用nop是因为PC默认地址是0此时ROM将会读出0号地址的指令这里其实不写空指令也无妨注意ROM指令读取延迟1个周期此处有两个负数验证的指令暂时没有验证以后再说敲重点writeData与ALUresult的连接问题
10 惊人的事实我们已经构建了完整的数据通路
你可能感到惊讶但这就是事实我们已经构建好了一个CPU并且它能够执行13条指令
这简直太酷了不是吗难以想象……你可能会说这……就完成了是的没错如果我们只需要13条指令的CPU并且不需要与外界交互的话真的已经完成了当然……这个CPU没什么价值不过后续我们会改进它的不是吗这很有趣的
我们会一步步地完成一个完整的CPU最终变成五级流水线CPU这简直太棒了让我们一起加油
来看看示意图注意只是示意图pc的位宽并不是标准的32位而是8位总之这就是完整的数据通路了。 只不过这个CPU还不能与外界交互……但是它的确能够执行指令了不是吗后续我们慢慢改进就是了。
10.1 构建我们的第一个CPU
在上面我们已经运行测试过了不再重复。
综合实现看下面
实践笔记2插叙综合与实现
10.2 值得优化的点
在有些时候我们的指令没有准备好但是Reg已经读取出去了可能有隐患我们可以给Reg Files加上读使能信号但是本次不加了。
11 数据流建模传输问题不止连线
数据流建模传输问题赋值传输有方向
经验教训RTL建模看不出来传输方向 行为仿真很必要呀
12 取指延迟
我们都知道访存是很慢的相比于CPU执行在本次示例中ROM取指需要2个时钟周期因此我们的单周期CPU更新PC和更新寄存器堆都可以上升沿触发。
PC也能够保存下一条指令的地址在取下一条指令的同时当前指令也在执行取完下一条指令当前指令也执行完成了。
我们看时序图从PC更新到取得PC对应的指令需要2个时钟周期。 也就是说向内存发出指令地址之后需要两个时钟周期指令才能被取得在此期间CPU内的指令还是原来的指令该指令也已经在一个时钟周期执行完成执行一条指令需要三个时钟周期。
你可能疑惑那pc每个时钟周期更新一次两个时钟周期才能够取到指令不会冲突吗?当然不会。想象一下高速公路的汽车 pc发出的时间不一样是可以排队的没关系的不会超车插队另外数据变化需要时间的暂时浅显理解即可。
13 疑惑点
当取指非常慢的时候由应该如何处理此时如果仍然每个周期PC 4但是10个周期假设才能取指是否仍然可行
我们试试将周期改为2ns也就是500MHz的时钟频率。 好吧……看起来没有问题这个问题以后再解决。
500MHz都没问题了那基本就没事了其实。
开发板使用的100MHz也就是时钟周期是10ns足够满足本科阶段需求了这个细节问题目前不需要关注无伤大雅应当先抓住主要矛盾。