用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. 数据处理说明

  1. Add:

    ADD ws, rs1, rs2 ws:=rs1 + rs2

  2. Subtract:

    SUB ws, rs1, rs2 ws:=rs1 – rs2

  3. Invert (1's complement):

    INV ws, rs1 ws:=!rs1

  4. Logical Shift Left:

    LSL ws, rs1, rs2 ws:=rs1 << rs2

  5. Logical Shift Right:

    LSR ws, rs1, rs2 ws:=rs1 >> rs2

  6. Bitwise AND:

    AND ws, rs1, rs2 ws:=rs1 · rs2

  7. Bitwise OR:

    OR ws, rs1, rs2 ws:=rs1 | rs2

  8. 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

  1. 不等于分支

BNE rs1, rs2, offset
  Branch to (PC + 2 + (offset << 1)) when rs1 != rs2

  1. 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

—— END ——
有你想看的精彩
听大神聊FPGA设计:豁然开朗
ADC/DAC设计经典问答
基于FPGA的快速傅立叶变换
Google版「鸿蒙」,Fuchsia悄悄地来了
日本断供光刻胶,国产迎头赶上!100页国产光刻胶研究框架PPT!
耗时两年,19岁小伙采用230片纯74逻辑芯片搭建出32位Risc-V处理器!可玩贪吃蛇
SPI怎么玩?搞懂时序,运用自如
谈谈Xilinx FPGA设计的实现过程
Verilog_实现任意占空比、任意分频的方法
【FPGA】几种时序问题的常见解决方法
开源DIY墨水屏手表!外观可盐可甜,无线蓝牙计步闹钟一应俱全!
Verilog 版本:Verilog-95、Verilog-2001与System Verilog区别简谈
1202年了,还在使用虚拟机吗?Win10安装Ubuntu子系统及图形化界面详细教程
例说Verilog HDL和VHDL区别,助你选择适合自己的硬件描述语言
FPGA重点知识13条,助你构建完整“逻辑观”之一
FPGA 的重构
ISP(图像信号处理)算法概述、工作原理、架构、处理流程

点个在看你最好看

(0)

相关推荐