1 jr指令分析
instruction | op | rs | rt | rd | shamt | func |
---|---|---|---|---|---|---|
jr | 000000 | rs | 00000 | 00000 | 00000 | 001000 |
举例:jr $31
功能:PC <- ($31)
这是个跳转指令,将指定寄存器的值,放入PC中,是无条件跳转。
我们需要
- 更新PC,加一个多路选择器,实现
+4
和PC <- (reg)
两种选择 - 增加控制信号
Jrn
,标识jr
指令
2 新的数据通路
3 器件修改
- 控制器,控制信号输出
Jrn
标识jr
指令 - PC,增加输入信号
jr
和输入数据32位寄存器值
控制信号:
instruction | op | func | ALUop | RegWrite | Sftmd | Jrn |
---|---|---|---|---|---|---|
jr | 000000 | 001000 | 1111 | 0 | 0 | 1 |
4 代码实现
4.1 PC
增加了输入信号和输入数据,更改了原来的pcNew
的名称为pcOrigin
,增加了多路选择器。
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2020/11/12 20:31:59
// Design Name:
// Module Name: pc_1
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module pc_1(
input clk,
input rst_n,
// pc data
input [31:0] pcOrigin, // The PC value is from pcOld.
input [31:0] JrPC, // jr instruction,from reg files.
// pc control
input Jrn, // jr instruction.
output [31:0] pcOld
);
reg [31:0] pc = 0;
assign pcOld = pc;
wire [31:0] pcSelect; // new pc data
assign pcSelect = (Jrn == 0) ? (pcOrigin + 4): JrPC;
// Update PC register
always @(posedge clk)
begin
if(rst_n == 1) // Xilinx 官方推荐:reset 高电平有效
begin
pc <= 0;
end
else
begin
pc <= pcSelect;
end
end
endmodule
4.2 control
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2020/11/14 22:30:48
// Design Name:
// Module Name: control_1
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module control_1(
input [5:0] op,
input [5:0] func,
output reg RegWrite,
output reg Sftmd, // indicate the instruction is sll/srl/sra
output reg [3:0] ALUop,
output reg Jrn // jr instruction
);
always @(*)
begin
if(op == 6'b0)
begin
case (func)
6'b100000: // add
begin
RegWrite <= 1;
Sftmd <= 0;
ALUop <= 4'b0000;
Jrn <= 0;
end
6'b100001: // addu
begin
RegWrite <= 1;
Sftmd <= 0;
ALUop <= 4'b0001;
Jrn <= 0;
end
6'b100010: // sub
begin
RegWrite <= 1;
Sftmd <= 0;
ALUop <= 4'b0010;
Jrn <= 0;
end
6'b100011: // subu
begin
RegWrite <= 1;
Sftmd <= 0;
ALUop <= 4'b0011;
Jrn <= 0;
end
6'b100100: // and
begin
RegWrite <= 1;
Sftmd <= 0;
ALUop <= 4'b0100;
Jrn <= 0;
end
6'b100101: // or
begin
RegWrite <= 1;
Sftmd <= 0;
ALUop <= 4'b0101;
Jrn <= 0;
end
6'b100110: // xor
begin
RegWrite <= 1;
Sftmd <= 0;
ALUop <= 4'b0110;
Jrn <= 0;
end
6'b100111: // nor
begin
RegWrite <= 1;
Sftmd <= 0;
ALUop <= 4'b0111;
Jrn <= 0;
end
6'b101010: // slt
begin
RegWrite <= 1;
Sftmd <= 0;
ALUop <= 4'b1000;
Jrn <= 0;
end
6'b101011: // sltu
begin
RegWrite <= 1;
Sftmd <= 0;
ALUop <= 4'b1001;
Jrn <= 0;
end
6'b000100: // sllv
begin
RegWrite <= 1;
Sftmd <= 0;
ALUop <= 4'b1010;
Jrn <= 0;
end
6'b000110: // srlv
begin
RegWrite <= 1;
Sftmd <= 0;
ALUop <= 4'b1011;
Jrn <= 0;
end
6'b000111: // srav
begin
RegWrite <= 1;
Sftmd <= 0;
ALUop <= 4'b1100;
Jrn <= 0;
end
6'b000000: // sll
begin
RegWrite <= 1;
Sftmd <= 1;
ALUop <= 4'b1010;
Jrn <= 0;
end
6'b000010: // srl
begin
RegWrite <= 1;
Sftmd <= 1;
ALUop <= 4'b1011;
Jrn <= 0;
end
6'b000011: // sra
begin
RegWrite <= 1;
Sftmd <= 1;
ALUop <= 4'b1100;
Jrn <= 0;
end
6'b001000:
begin
RegWrite <= 0;
Sftmd <= 0;
ALUop <= 4'b1111;
Jrn <= 1;
end
default:
begin
RegWrite <= 0;
Sftmd <= 0;
ALUop <= 4'b1111;
Jrn <= 0;
end
endcase
end
else
begin
RegWrite <= 0;
Sftmd <= 0;
ALUop <= 4'b1111;
Jrn <= 0;
end
end
endmodule
4.3 datapath
`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,
output [31:0] result // 测试syntheses,没有输出的模块是恐怖的
);
/******** PC ********/
// pc_1 Inputs
wire Jrn;
wire [31:0] JrPC;
// pc_1 Outputs
wire [31:0] pcOld;
pc_1 u_pc_1 (
.clk ( clk ),
.rst_n ( rst_n ),
.pcOrigin ( pcOld ),
.JrPC ( JrPC ),
.Jrn ( Jrn ),
.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 ( pcOld[15:2] ),
.douta ( instruction )
);
/******** Reg Files ********/
// reg_files_1 Inputs
wire [31:0] ALUresult;
/// 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 = ALUresult;
wire RegWrite;
// reg_files_1 Outputs
wire [31:0] A; // rs
wire [31:0] B; // rt
assign JrPC = A;
reg_files_1 u_reg_files_1 (
.clk ( clk ),
.rst_n ( rst_n ),
.rA ( instruction[25:21] ),
.rB ( instruction[20:16] ),
.rW ( instruction[15:11] ),
.writeData ( ALUresult ),
.RegWrite ( RegWrite ),
.A ( A ),
.B ( B )
);
/******** ALU ********/
// ALU_1 Inputs
// wire [31:0] A;
// wire [31:0] B;
wire [3:0] ALUop;
wire Sftmd;
// ALU_1 Outputs
// wire [31:0] ALUresult = writeData; // 【不能用!传输方向不对】
ALU_1 u_ALU_1 (
.A ( A ),
.B ( B ),
.shamt ( instruction[10:6]),
.ALUop ( ALUop ),
.Sftmd ( Sftmd ),
.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 ( instruction[31:26] ),
.func ( instruction[5:0] ),
.RegWrite ( RegWrite ),
.Sftmd ( Sftmd ),
.ALUop ( ALUop ),
.Jrn ( Jrn )
);
assign result = ALUresult;
endmodule
5 测试
可以观察到跳变了。
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 = 1
and $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) = 11111111111110111
slt $10,$11,$12 # $10 = 11 < 12 = 1 # 应该用负数验证,以后再说
sltu $10,$12,$11 # $10 = 12 > 11 = 0
# sllv $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 应该用负数验证,以后再说
# 上面3条是错误的!我们应该改的不是使用,而是内部运算逻辑
# 对于使用者来说,逻辑就是 $13 << $5
# 而实际的编码是 rt = $13,rs = $5,这与一般的指令不一样
# 因此,我们在ALU运算中 rt--B,rs--A,应该是 【B << A】,而不是 A >> B。
sllv $12,$13,$5 # $12 = 1101 << 1 = 1101_0 = 1A
srlv $12,$13,$5 # $12 = 1101 >> 1 = 110 = 6
srav $14,$15,$5 # $14 = 1111 >>> 1 = 111 = 7 应该用负数验证,以后再说
sll $16,$17,2 # $16 = 1_0001 << 2 = 100_0100 = 44
srl $16,$18,2 # $16 = 1_0010 >> 2 = 0100 = 4
sra $16,$19,2 # 应该用负数验证,以后再说 $16 = 4
jr $16 # PC = 4
编码
memory_initialization_radix = 16;
memory_initialization_vector =
00000000,
00430820,
00811021,
00412022,
00832823,
00e83024,
00c83825,
00c83826,
00e64027,
016c502a,
018b502b,
00ad6004,
00ad6006,
00af7007,
00118080,
00128082,
00138083,
02000008;
测试完成。