用Verilog设计一个16 位 RISC 处理器
Verilog Code for 16-bit RISC Processor
RISC 处理器是基于其指令集和哈佛型数据通路结构设计的。然后,RISC 处理器在Verilog 中实现并使用 Xilinx ISIM 进行验证。
RISC处理器的指令集:
A. 内存访问指令
1. 加载字:
LD ws, offset(rs1) ws:=Mem16[rs1 + offset]
2. 存储字:
ST rs2, offset(rs1) Mem16[rs1 + offset]=rs2
B. 数据处理说明
Add:
ADD ws, rs1, rs2 ws:=rs1 + rs2
Subtract:
SUB ws, rs1, rs2 ws:=rs1 – rs2
Invert (1's complement):
INV ws, rs1 ws:=!rs1
Logical Shift Left:
LSL ws, rs1, rs2 ws:=rs1 << rs2
Logical Shift Right:
LSR ws, rs1, rs2 ws:=rs1 >> rs2
Bitwise AND:
AND ws, rs1, rs2 ws:=rs1 · rs2
Bitwise OR:
OR ws, rs1, rs2 ws:=rs1 | rs2
Set on Less Than:
SLT ws, rs1, rs2 ws:=1 if rs1 < rs2; ws:=0 if rs1 ≥ rs2
C. 控制流说明
1.等号分支:
BEQ rs1, rs2, offset
Branch to (PC + 2 + (offset << 1)) when rs1 = rs2
不等于分支
BNE rs1, rs2, offset
Branch to (PC + 2 + (offset << 1)) when rs1 != rs2
Jump:
JMP offset Jump to {PC [15:13], (offset << 1)}
RISC处理器的指令格式
处理器控制单元设计
ALU 控制单元设计
RISC 处理器的 Verilog 代码:
1.指令存储器的Verilog 代码
`include "Parameter.v"
// FPGA projects, VHDL projects, Verilog projects
// Verilog code for RISC Processor
// Verilog code for Instruction Memory
module Instruction_Memory(
input[15:0] pc,
output[15:0] instruction
);
reg [`col - 1:0] memory [`row_i - 1:0];
wire [3 : 0] rom_addr = pc[4 : 1];
initial
begin
$readmemb("./test/test.prog", memory,0,14);
end
assign instruction = memory[rom_addr];
endmodule
2.注册文件的Verilog代码:
`timescale 1ns / 1ps
// FPGA projects, VHDL projects, Verilog projects
// Verilog code for RISC Processor
// Verilog code for register file
module GPRs(
input clk,
// write port
input reg_write_en,
input [2:0] reg_write_dest,
input [15:0] reg_write_data,
//read port 1
input [2:0] reg_read_addr_1,
output [15:0] reg_read_data_1,
//read port 2
input [2:0] reg_read_addr_2,
output [15:0] reg_read_data_2
);
reg [15:0] reg_array [7:0];
integer i;
// write port
//reg [2:0] i;
initial begin
for(i=0;i<8;i=i+1)
reg_array[i] <= 16'd0;
end
always @ (posedge clk ) begin
if(reg_write_en) begin
reg_array[reg_write_dest] <= reg_write_data;
end
end
assign reg_read_data_1 = reg_array[reg_read_addr_1];
assign reg_read_data_2 = reg_array[reg_read_addr_2];
endmodule
3. 数据存储器的 Verilog 代码
`include "Parameter.v"
// fpga4student.com
// FPGA projects, VHDL projects, Verilog projects
// Verilog code for RISC Processor
// Verilog code for data Memory
module Data_Memory(
input clk,
// address input, shared by read and write port
input [15:0] mem_access_addr,
// write port
input [15:0] mem_write_data,
input mem_write_en,
input mem_read,
// read port
output [15:0] mem_read_data
);
reg [`col - 1:0] memory [`row_d - 1:0];
integer f;
wire [2:0] ram_addr=mem_access_addr[2:0];
initial
begin
$readmemb("./test/test.data", memory);
f = $fopen(`filename);
$fmonitor(f, "time = %d\n", $time,
"\tmemory[0] = %b\n", memory[0],
"\tmemory[1] = %b\n", memory[1],
"\tmemory[2] = %b\n", memory[2],
"\tmemory[3] = %b\n", memory[3],
"\tmemory[4] = %b\n", memory[4],
"\tmemory[5] = %b\n", memory[5],
"\tmemory[6] = %b\n", memory[6],
"\tmemory[7] = %b\n", memory[7]);
`simulation_time;
$fclose(f);
end
always @(posedge clk) begin
if (mem_write_en)
memory[ram_addr] <= mem_write_data;
end
assign mem_read_data = (mem_read==1'b1) ? memory[ram_addr]: 16'd0;
endmodule
4. ALU 单元的 Verilog 代码:
// fpga4student.com
// FPGA projects, VHDL projects, Verilog projects
// Verilog code for RISC Processor
// Verilog code for ALU
module ALU(
input [15:0] a, //src1
input [15:0] b, //src2
input [2:0] alu_control, //function sel
output reg [15:0] result, //result
output zero
);
always @(*)
begin
case(alu_control)
3'b000: result = a + b; // add
3'b001: result = a - b; // sub
3'b010: result = ~a;
3'b011: result = a<<b;
3'b100: result = a>>b;
3'b101: result = a & b; // and
3'b110: result = a | b; // or
3'b111: begin if (a<b) result = 16'd1;
else result = 16'd0;
end
default:result = a + b; // add
endcase
end
assign zero = (result==16'd0) ? 1'b1: 1'b0;
endmodule
5. RISC处理器的ALU控制单元的Verilog代码:
`timescale 1ns / 1ps
//fpga4student.com: FPGA projects, Verilog projects, VHDL projects
// Verilog code for 16-bit RISC processor
// ALU_Control Verilog code
module alu_control( ALU_Cnt, ALUOp, Opcode);
output reg[2:0] ALU_Cnt;
input [1:0] ALUOp;
input [3:0] Opcode;
wire [5:0] ALUControlIn;
assign ALUControlIn = {ALUOp,Opcode};
always @(ALUControlIn)
casex (ALUControlIn)
6'b10xxxx: ALU_Cnt=3'b000;
6'b01xxxx: ALU_Cnt=3'b001;
6'b000010: ALU_Cnt=3'b000;
6'b000011: ALU_Cnt=3'b001;
6'b000100: ALU_Cnt=3'b010;
6'b000101: ALU_Cnt=3'b011;
6'b000110: ALU_Cnt=3'b100;
6'b000111: ALU_Cnt=3'b101;
6'b001000: ALU_Cnt=3'b110;
6'b001001: ALU_Cnt=3'b111;
default: ALU_Cnt=3'b000;
endcase
endmodule
6. RISC处理器Datapath的Verilog代码:
`timescale 1ns / 1ps
// fpga4student.com
// FPGA projects, VHDL projects, Verilog projects
// Verilog code for RISC Processor
// Verilog code for Data Path of the processor
module Datapath_Unit(
input clk,
input jump,beq,mem_read,mem_write,alu_src,reg_dst,mem_to_reg,reg_write,bne,
input[1:0] alu_op,
output[3:0] opcode
);
reg [15:0] pc_current;
wire [15:0] pc_next,pc2;
wire [15:0] instr;
wire [2:0] reg_write_dest;
wire [15:0] reg_write_data;
wire [2:0] reg_read_addr_1;
wire [15:0] reg_read_data_1;
wire [2:0] reg_read_addr_2;
wire [15:0] reg_read_data_2;
wire [15:0] ext_im,read_data2;
wire [2:0] ALU_Control;
wire [15:0] ALU_out;
wire zero_flag;
wire [15:0] PC_j, PC_beq, PC_2beq,PC_2bne,PC_bne;
wire beq_control;
wire [12:0] jump_shift;
wire [15:0] mem_read_data;
// PC
initial begin
pc_current <= 16'd0;
end
always @(posedge clk)
begin
pc_current <= pc_next;
end
assign pc2 = pc_current + 16'd2;
// instruction memory
Instruction_Memory im(.pc(pc_current),.instruction(instr));
// jump shift left 2
assign jump_shift = {instr[11:0],1'b0};
// multiplexer regdest
assign reg_write_dest = (reg_dst==1'b1) ? instr[5:3] :instr[8:6];
// register file
assign reg_read_addr_1 = instr[11:9];
assign reg_read_addr_2 = instr[8:6];
// GENERAL PURPOSE REGISTERs
GPRs reg_file
(
.clk(clk),
.reg_write_en(reg_write),
.reg_write_dest(reg_write_dest),
.reg_write_data(reg_write_data),
.reg_read_addr_1(reg_read_addr_1),
.reg_read_data_1(reg_read_data_1),
.reg_read_addr_2(reg_read_addr_2),
.reg_read_data_2(reg_read_data_2)
);
// immediate extend
assign ext_im = {{10{instr[5]}},instr[5:0]};
// ALU control unit
alu_control ALU_Control_unit(.ALUOp(alu_op),.Opcode(instr[15:12]),.ALU_Cnt(ALU_Control));
// multiplexer alu_src
assign read_data2 = (alu_src==1'b1) ? ext_im : reg_read_data_2;
// ALU
ALU alu_unit(.a(reg_read_data_1),.b(read_data2),.alu_control(ALU_Control),.result(ALU_out),.zero(zero_flag));
// PC beq add
assign PC_beq = pc2 + {ext_im[14:0],1'b0};
assign PC_bne = pc2 + {ext_im[14:0],1'b0};
// beq control
assign beq_control = beq & zero_flag;
assign bne_control = bne & (~zero_flag);
// PC_beq
assign PC_2beq = (beq_control==1'b1) ? PC_beq : pc2;
// PC_bne
assign PC_2bne = (bne_control==1'b1) ? PC_bne : PC_2beq;
// PC_j
assign PC_j = {pc2[15:13],jump_shift};
// PC_next
assign pc_next = (jump == 1'b1) ? PC_j : PC_2bne;
/// Data memory
Data_Memory dm
(
.clk(clk),
.mem_access_addr(ALU_out),
.mem_write_data(reg_read_data_2),
.mem_write_en(mem_write),
.mem_read(mem_read),
.mem_read_data(mem_read_data)
);
// write back
assign reg_write_data = (mem_to_reg == 1'b1)? mem_read_data: ALU_out;
// output to control unit
assign opcode = instr[15:12];
endmodule
7. RISC 处理器控制单元的 Verilog 代码:
`timescale 1ns / 1ps
// fpga4student.com
// FPGA projects, VHDL projects, Verilog projects
// Verilog code for RISC Processor
// Verilog code for Control Unit
module Control_Unit(
input[3:0] opcode,
output reg[1:0] alu_op,
output reg jump,beq,bne,mem_read,mem_write,alu_src,reg_dst,mem_to_reg,reg_write
);
always @(*)
begin
case(opcode)
4'b0000: // LW
begin
reg_dst = 1'b0;
alu_src = 1'b1;
mem_to_reg = 1'b1;
reg_write = 1'b1;
mem_read = 1'b1;
mem_write = 1'b0;
beq = 1'b0;
bne = 1'b0;
alu_op = 2'b10;
jump = 1'b0;
end
4'b0001: // SW
begin
reg_dst = 1'b0;
alu_src = 1'b1;
mem_to_reg = 1'b0;
reg_write = 1'b0;
mem_read = 1'b0;
mem_write = 1'b1;
beq = 1'b0;
bne = 1'b0;
alu_op = 2'b10;
jump = 1'b0;
end
4'b0010: // data_processing
begin
reg_dst = 1'b1;
alu_src = 1'b0;
mem_to_reg = 1'b0;
reg_write = 1'b1;
mem_read = 1'b0;
mem_write = 1'b0;
beq = 1'b0;
bne = 1'b0;
alu_op = 2'b00;
jump = 1'b0;
end
4'b0011: // data_processing
begin
reg_dst = 1'b1;
alu_src = 1'b0;
mem_to_reg = 1'b0;
reg_write = 1'b1;
mem_read = 1'b0;
mem_write = 1'b0;
beq = 1'b0;
bne = 1'b0;
alu_op = 2'b00;
jump = 1'b0;
end
4'b0100: // data_processing
begin
reg_dst = 1'b1;
alu_src = 1'b0;
mem_to_reg = 1'b0;
reg_write = 1'b1;
mem_read = 1'b0;
mem_write = 1'b0;
beq = 1'b0;
bne = 1'b0;
alu_op = 2'b00;
jump = 1'b0;
end
4'b0101: // data_processing
begin
reg_dst = 1'b1;
alu_src = 1'b0;
mem_to_reg = 1'b0;
reg_write = 1'b1;
mem_read = 1'b0;
mem_write = 1'b0;
beq = 1'b0;
bne = 1'b0;
alu_op = 2'b00;
jump = 1'b0;
end
4'b0110: // data_processing
begin
reg_dst = 1'b1;
alu_src = 1'b0;
mem_to_reg = 1'b0;
reg_write = 1'b1;
mem_read = 1'b0;
mem_write = 1'b0;
beq = 1'b0;
bne = 1'b0;
alu_op = 2'b00;
jump = 1'b0;
end
4'b0111: // data_processing
begin
reg_dst = 1'b1;
alu_src = 1'b0;
mem_to_reg = 1'b0;
reg_write = 1'b1;
mem_read = 1'b0;
mem_write = 1'b0;
beq = 1'b0;
bne = 1'b0;
alu_op = 2'b00;
jump = 1'b0;
end
4'b1000: // data_processing
begin
reg_dst = 1'b1;
alu_src = 1'b0;
mem_to_reg = 1'b0;
reg_write = 1'b1;
mem_read = 1'b0;
mem_write = 1'b0;
beq = 1'b0;
bne = 1'b0;
alu_op = 2'b00;
jump = 1'b0;
end
4'b1001: // data_processing
begin
reg_dst = 1'b1;
alu_src = 1'b0;
mem_to_reg = 1'b0;
reg_write = 1'b1;
mem_read = 1'b0;
mem_write = 1'b0;
beq = 1'b0;
bne = 1'b0;
alu_op = 2'b00;
jump = 1'b0;
end
4'b1011: // BEQ
begin
reg_dst = 1'b0;
alu_src = 1'b0;
mem_to_reg = 1'b0;
reg_write = 1'b0;
mem_read = 1'b0;
mem_write = 1'b0;
beq = 1'b1;
bne = 1'b0;
alu_op = 2'b01;
jump = 1'b0;
end
4'b1100: // BNE
begin
reg_dst = 1'b0;
alu_src = 1'b0;
mem_to_reg = 1'b0;
reg_write = 1'b0;
mem_read = 1'b0;
mem_write = 1'b0;
beq = 1'b0;
bne = 1'b1;
alu_op = 2'b01;
jump = 1'b0;
end
4'b1101: // J
begin
reg_dst = 1'b0;
alu_src = 1'b0;
mem_to_reg = 1'b0;
reg_write = 1'b0;
mem_read = 1'b0;
mem_write = 1'b0;
beq = 1'b0;
bne = 1'b0;
alu_op = 2'b00;
jump = 1'b1;
end
default: begin
reg_dst = 1'b1;
alu_src = 1'b0;
mem_to_reg = 1'b0;
reg_write = 1'b1;
mem_read = 1'b0;
mem_write = 1'b0;
beq = 1'b0;
bne = 1'b0;
alu_op = 2'b00;
jump = 1'b0;
end
endcase
end
endmodule
8. 16 位 RISC 处理器的 Verilog 代码:
`timescale 1ns / 1ps
// fpga4student.com
// FPGA projects, VHDL projects, Verilog projects
// Verilog code for RISC Processor
module Risc_16_bit(
input clk
);
wire jump,bne,beq,mem_read,mem_write,alu_src,reg_dst,mem_to_reg,reg_write;
wire[1:0] alu_op;
wire [3:0] opcode;
// Datapath
Datapath_Unit DU
(
.clk(clk),
.jump(jump),
.beq(beq),
.mem_read(mem_read),
.mem_write(mem_write),
.alu_src(alu_src),
.reg_dst(reg_dst),
.mem_to_reg(mem_to_reg),
.reg_write(reg_write),
.bne(bne),
.alu_op(alu_op),
.opcode(opcode)
);
// control unit
Control_Unit control
(
.opcode(opcode),
.reg_dst(reg_dst),
.mem_to_reg(mem_to_reg),
.alu_op(alu_op),
.jump(jump),
.bne(bne),
.beq(beq),
.mem_read(mem_read),
.mem_write(mem_write),
.alu_src(alu_src),
.reg_write(reg_write)
);
endmodule
9. 16 位 RISC 处理器的 Verilog 测试平台代码:
`timescale 1ns / 1ps
`include "Parameter.v"
// fpga4student.com
// FPGA projects, VHDL projects, Verilog projects
// Verilog code for RISC Processor
// Verilog testbench code to test the processor
module test_Risc_16_bit;
// Inputs
reg clk;
// Instantiate the Unit Under Test (UUT)
Risc_16_bit uut (
.clk(clk)
);
initial
begin
clk <=0;
`simulation_time;
$finish;
end
always
begin
#5 clk = ~clk;
end
endmodule
参数文件:
`ifndef PARAMETER_H_
`define PARAMETER_H_
// fpga4student.com
// FPGA projects, VHDL projects, Verilog projects
// Verilog code for RISC Processor
// Parameter file
`define col 16 // 16 bits instruction memory, data memory
`define row_i 15 // instruction memory, instructions number, this number can be changed. Adding more instructions to verify your design is a good idea.
`define row_d 8 // The number of data in data memory. We only use 8 data. Do not change this number. You can change the value of each data inside test.data file. Total number is fixed at 8.
`define filename "./test/50001111_50001212.o"
`define simulation_time #160
`endif
以上提供了 16 位 RISC 处理器所需的所有 Verilog 代码。现在,只需要创建一个 test.data(数据存储器的初始内容)和 test.prog(指令存储器)。然后,运行仿真以查看该过程如何处理仿真波形和内存文件。
示例指令内存文件:
0000_0100_0000_0000 // load R0 <- Mem(R2 + 0)
0000_0100_0100_0001 // load R1 <- Mem(R2 + 1)
0010_0000_0101_0000 // Add R2 <- R0 + R1
0001_0010_1000_0000 // Store Mem(R1 + 0) <- R2
0011_0000_0101_0000 // sub R2 <- R0 - R1
0100_0000_0101_0000 // invert R2 <- !R0
0101_0000_0101_0000 // logical shift left R2 <- R0<<R1
0110_0000_0101_0000 // logical shift right R2 <- R0>>R1
0111_0000_0101_0000 // AND R2<- R0 AND R1
1000_0000_0101_0000 // OR R2<- R0 OR R1
1001_0000_0101_0000 // SLT R2 <- 1 if R0 < R1
0010_0000_0000_0000 // Add R0 <- R0 + R0
1011_0000_0100_0001 // BEQ branch to jump if R0=R1, PCnew= PC+2+offset<<1 = 28 => offset = 1
1100_0000_0100_0000 // BNE branch to jump if R0!=R1, PCnew= PC+2+offset<<1 = 28 => offset = 0
1101_0000_0000_0000 // J jump to the beginning address
示例数据存储器文件:
0000_0000_0000_0001
0000_0000_0000_0010
0000_0000_0000_0001
0000_0000_0000_0010
0000_0000_0000_0001
0000_0000_0000_0010
0000_0000_0000_0001
0000_0000_0000_0010
参考链接:https://www.fpga4student.com/2016/11/plate-license-recognition-verilogmatlab.html
https://baike.baidu.com/item/%E7%B2%BE%E7%AE%80%E6%8C%87%E4%BB%A4%E9%9B%86%E8%AE%A1%E7%AE%97%E6%9C%BA/661859?fromtitle=risc&fromid=62696&fr=aladdin
NOW现在行动!
点个在看你最好看