自己设计CPU学习之路——基于Xilinx FPGA应用开发

news2024/9/19 10:47:19

1. 一个32组位宽为32的寄存器堆

  • 框图

image-20230906220205462

  • 代码

    • regfile.h
    `ifndef __FEGFILE_HEADER__
        `define __REGFILE_HEADER__
    
        `define HIGH        1'b1
        `define LOW         1'b0
    
        `define ENABLE_     1'b0
        `define DISABLE_    1'b1
    
        `define DATA_W      32
        `define DataBus     31:0
        `define DATA_D      32
    
        `define ADDR_W      5
        `define AddrBus     4:0
    
    `endif
    
    • regfile.v
    `include "regfile2.h"
    
    module regfile2 (
        input   wire            clk,
        input   wire            reset_,
    
        input   wire [`AddrBus] addr,
        input   wire [`DataBus] d_in,
        input   wire            we_,
        output  wire [`DataBus] d_out
    );
    
        reg [`DataBus]          ff [`DATA_D-1:0]; //寄存器序列
        integer                 i;
    
        assign d_out = ff[addr];
    
        always @(posedge clk or negedge reset_) begin
            if (reset_ == `ENABLE_) begin
                for (i = 0;i < `DATA_D;i = i + 1) begin
                    ff[i] <= #1{`DATA_W{1'b0}};
                end
            end else begin
                if (we_ == `ENABLE_) begin
                    ff[addr] <= #1 d_in;
                end
            end
        end
    
    endmodule
    

2. ALU

module alu(
   input [2:0]          a,b,
   input [1:0]          sel,
   output   reg [3:0]   out
)
   always @(a,b,sel) begin
      case(sel)
         2'b00: out = a+b;
         2'b01: out = ~(a+b);
         2'b10: out = a<<1;
         2'b11: out = ~a;
         default:out = 4'b0000;
      endcase
   end
endmodule

3. 同步使能,异步复位的D触发器

module Dff (
   input    clk,
   input    clr,
   input    en,
   input    D,
   output reg  q,
   output      qb
);
   assign qb = ~q;
   always @(posedge clk or posedge clr) begin
      if (clr) q <= 0;//异步复位
      else if (en) q <= D;//同步使能
   end
endmodule

这个Verilog模块实现了一个带有异步复位功能的D触发器。在这个模块中,异步复位由输入信号clr控制。

异步复位的实现方式是,当clr信号为高电平(假定高电平表示复位时),触发器的输出q将被强制置为逻辑0,无论时钟信号clk和使能信号en的状态如何。这意味着,无论何时clr信号变为高电平,都会立即将q复位为0。

以下是对代码的解释:

  • assign qb = ~q; 行将qb定义为q的反相信号,即qb始终是q的逻辑反值。

  • always @(posedge clk or posedge clr) begin 声明一个始终块,该块在时钟上升沿(posedge clk)或异步复位上升沿(posedge clr)时触发。

  • if (clr) q <= 0; 行检查clr信号的状态。如果clr为高电平(即异步复位条件触发),则q被赋值为0,实现了异步复位。

  • else if (en) q <= D; 行在没有异步复位的情况下,检查使能信号en。如果en为高电平,那么q将被赋值为输入信号D,实现了同步使能。

这个模块的功能是,当clr信号为高电平时,无论何时都会将q置为0,而当clr信号为低电平且en信号为高电平时,q会根据输入信号D的值来更新。这使得在需要时可以通过异步复位来立即清除触发器的状态。

4. 移位寄存器

module shift_reg (
   input       clk,
   input       rst,
   input       data_in,
   output reg [7:0] q
);

   always @(posedge clk) begin
      if (rst) q <= 0;
      else begin 
         q[7:1] <= q[6:0];
         q[0] <= data_in;
      end
   end
   
endmodule

5. 使用6个D触发器实现一个6位的寄存器

module DFlipFlop (
   input         clk,
   input         clr_n, // 异步复位信号,低电平有效
   input         D,
   output reg    Q
);

   always @(posedge clk or negedge clr_n) begin
      if (!clr_n)
         Q <= 1'b0; // 异步复位时,输出清零
      else
         Q <= D; // 非复位时,将输入数据加载到输出
   end

endmodule

module SixBitRegister (
   input         clk,
   input         clr_n,
   input [5:0]   data_input,
   output [5:0]  data_output
);

   reg [5:0] q; // 6位寄存器的输出

   integer i;

   always @(posedge clk or negedge clr_n) begin
      if (!clr_n)
         q <= 6'b0; // 异步复位时,全部位清零
      else
         for (i = 0; i < 6; i = i + 1)
            DFlipFlop dff (
               .clk(clk),
               .clr_n(clr_n),
               .D(data_input[i]),
               .Q(q[i])
            ); // 使用循环实例化六个D触发器
   end

   assign data_output = q;

endmodule

6. 按键产生时钟脉冲,移位寄存器

module shift_reg (
   input       btn,      // 按键输入,用于产生时钟脉冲
   output reg  clk_pulse, // 时钟脉冲信号
   input       rst,
   input       data_in,
   output reg [7:0] q
);

   reg clk_edge = 0;

   always @(posedge btn) begin
      clk_edge <= ~clk_edge; // 按键按下时切换时钟边沿
   end

   always @(posedge clk_edge or posedge rst) begin
      if (rst)
         q <= 8'b0;
      else
         begin
            q[7:1] <= q[6:0];
            q[0] <= data_in;
         end
   end

   // 产生时钟脉冲
   always @(posedge clk_edge) begin
      clk_pulse <= 1'b1;
   end

endmodule

7. 串入并出74SL64芯片

module ShiftRegister_74LS164 (
   input        clk,       // 时钟输入
   input        srclr,     // 异步复位输入
   input        serial_in, // 串行输入
   output [7:0] parallel_out // 并行输出
);

   reg [7:0] shift_register; // 移位寄存器存储器件

   always @(posedge clk or posedge srclr) begin
      if (srclr)
         shift_register <= 8'b0; // 异步复位时,寄存器清零
      else
         shift_register <= {shift_register[6:0], serial_in}; // 数据移位
   end

   assign parallel_out = shift_register; // 并行输出与寄存器值关联

endmodule

8.同步使能、异步清零的16进制计数器

image-20230908102933707

module counter_16(
   input          clk,
   input          clr,
   input          en,
   output reg [3:0] q
);

   always @(posedge clk or posedge clr) begin
      if (q <= 0) q <= 0;
      else if (en) q <= q + 1;
   end
endmodule
//激励关键代码
initial fork
   ckl = 0;
   clr = 0;
   en = 0;
   forever begin
      #10 clk = ~clk;
      #25 clr = 1;
      #55 clr = 0;
      #35 en = 1;
   end
join

上面的Verilog代码片段展示了一个 initial 块内的 fork-join 结构,该结构用于并发地控制信号 clkclren 的变化。以下是对这段代码的详细解释:

  1. forkjoinforkjoin 是一对用于创建并发代码块的关键字。fork 标志着代码分支的开始,允许同时执行多个线程。join 表示所有分支线程都执行完毕后再继续执行后续的代码。在这个例子中,fork 启动了一个并发线程,而 join 用于结束这个线程。

  2. initial 块:initial 块是Verilog中用于模拟和初始化的代码块。在仿真开始时执行其中的代码。

  3. 初始化信号:在 initial 块的开头,clkclr、和 en 这三个信号都被初始化。它们的初始值分别是 0。

  4. forever 循环:forever 关键字用于创建一个无限循环,表示其中的代码将一直执行下去。

  5. #10#25#55#35:这些是时间延迟操作符,用于指定等待的时间。#10 表示等待 10 个时间单位,#25 表示等待 25 个时间单位,以此类推。

  6. 时钟信号 clk 的翻转:#10 clk = ~clk; 表示在等待 10 个时间单位后,翻转时钟信号 clk 的状态,从 0 到 1 或从 1 到 0。这模拟了时钟的周期性振荡。

  7. 异步复位信号 clr 的设置和清除:#25 clr = 1; 表示在等待 25 个时间单位后,将异步复位信号 clr 设置为 1,表示触发异步复位。然后 #55 clr = 0; 表示在等待 55 个时间单位后,将 clr 再次设置为 0,表示清除异步复位。

  8. 使能信号 en 的设置和清除:#35 en = 1; 表示在等待 35 个时间单位后,将使能信号 en 设置为 1,表示启用某些操作。请注意,en 之后没有清除,因此在整个仿真期间都会保持为 1。

9. 偶数分频

采用加法计数的方法,知识要对时钟的上升沿进行计数,因为输出波形的改变仅仅发生在时钟上升沿。

module divf_even (
   input       clk,
   output reg  clk_N
);
parameter N = 6;
integer p;
always @(posedge clk) begin
   if (p == N/2-1) begin
      p = 0;
      clk_N = ~clk_N;
   end
   else p = p + 1;
end
endmodule

10. 奇数分频

奇数分频——错位异或法。对于实现占空比为50%的N倍奇数分频,首先进行上升沿出发的模N计数计数到一选定值时进行输出时钟翻转,得到一个占空比为50%的N分频时钟clk1;然后在下降沿,经过与上面选定时刻相差(N-1)/2时刻,反转另一个时钟,这样得到另一个占空比为50%的N分频时钟clk2.将clk1和clk2两个时钟进行异或运算,就得到了占空比为50%的奇数分频时钟。利用了相位差

image-20230907154700527

module divf_oddn(
   input       clk,
   output      clk_N
);
   parameter N = 3;
   integer p = 0;
   reg clk_p = 0,clk_q = 0;
   always @(posedge clk) begin
      if (p == N-1) p <= 0;
      else p <= p + 1;
   end
   always @(posedge clk) begin
      if (p == N - 1) clk_p <= ~clk_p;
   end
   always @(negedge clk) begin
      if (p == (N-1)/2) clk_q <= ~clk_q;
   end
   assign clk_N = clk_p ^ clk_q;
endmodule

11. 2 n 2^n 2n 分频

module divf_2pown (
   input          clk,
   input          rst,
   output         clk2,
   output         clk4,
   output         clk8,
   output         clk16
);
   reg [3:0] count;
   always @(posedge clk) begin
      if (rst) begin
         count <= 0;
      end else begin
         count <= count + 1;
      end
   end
   assign clk2 = count[0];
   assign clk4 = count[1];
   assign clk8 = count[2];
   assign clk16 = count[3];

endmodule

12. 秒计数器

  • 1s实现加1计数,计到59后再从零计数
  • 同步清零,用拨码开关控制同步清零,led灯显示

image-20230907163816716

top 模块

module second_top (
   clk,bmkg0,led
);
input          clk;
input          bmkg0;
output [7:0]   led;
wire [7:0] sec;
wire clk_1HZ;
   second_divf U1(.clk_50MHZ(clk),
                  .clk_1HZ(clk_1HZ));
   second      U2(.clk_1HZ(clk_1HZ),
                  .clr(bmkg0),
                  sec(sec));
   second_disp U3(.sec(sec),
                  .q(led));
endmodule

分频模块 50MHz–> 1Hz

module second_divf (
   clk_50MHZ,clk_1HZ
);
   input       clk_50MHZ;
   output  reg clk_1HZ;
   reg [25:0]  cnt;
   always @(posedge clk_50MHZ) begin
      if (cnt == 25000000-1) begin
         clk_1HZ = ~clk_1HZ;
         cnt <= 0;
      end else begin
         cnt = cnt + 1;
      end
   end
endmodule

计数模块

module second(
   clk_1HZ,clr,sec
);
   input       clk_1HZ;
   input       clr;
   output reg [7:0] sec;
   always @(posedge clk_1HZ or posedge clr) begin
      if (clr) begin
         sec <= 0;
      end else if (sec == 59) sec <= 0;
      else sec <= sec + 1;
   end
endmodule

显示模块

module second_disp (
   sec,q
);
   input    [7:0] sec;
   output   [7:0] q;
   assign q = sec;
endmodule

13. 序列检测器

再连续信号中,检测是否包含“110”序列,当包含该序列时,指示灯就亮,否则指示灯灭。

顶层模块

module SerialTect_top (
   clk,key,led
);
   input          clk;
   input [1:0]    key;
   output         led;
   wire           pulse;
   wire [1:0]     key_debounce;

   IP_smg_divf U1(.clk_50MHz(clk),
                  .clk_190Hz(clk_190Hz));
   IP_key_debounce U2(.key_debounce(key_debounce[0]),
                      .clk_190Hz(clk_190Hz),
                      .key0(key[1]));
   IP_pulse_gen U4(.clk(clk),
                   .key(|key_bounce),
                   .pulse(pulse));
   Serial_compare U5(.clk(pulse),
                     .serialData(key_debounce[1]),
                     .result(led));
endmodule

分频模块

按键消抖模块

脉冲信号模块

序列检测模块


module Serial_compare (
   clk,serialData,result
);
   input          clk;
   input          serialData;
   output         result;
   parameter s0 = 2'b00,s1 = 2'b01,s2 = 2'b10,s3 = 2'b11;
   reg [1:0] next_st = s0;
   always @(posedge clk) begin
      case (next_st)
         s0: if (serialData == 1'b1) next_st = s1;
             else next_st = s0;
         s1: if (serialData == 1'b1) next_st = s2;
             else next_st = s0;
         s2: if (serialData == 1'b1) next_st = s2;
             else next_st = s3;
         s3: if (serialData == 1'b1) next_st = s1;
             else next_st = s0;
         default: next_st = s0;
      endcase
   end
   assign result = (next_st == s3)?1:0;
   
endmodule

14. 简易处理器设计

1. 设计要求

  • 完成处理器指令集的设计
  • 完成处理器的设计,要求能够识别处理指令集中的任何指令
  • 设计一段程序,要求该段程序用到指令集中的所有指令,并通过处理器运行这段程序得到结果

2. 设计

  • 处理器的组成结构

image-20230907195136004

  • 简易处理器的功能

完成 2*(0+1+2+…+10)=?

  • 指令系统的设计

image-20230907195327127

  1. 寄存器传输指令
  2. 装在指令
  3. 算术运算指令:完成加减运算
  4. 逻辑移位指令:完成左移操作
  5. 存储指令
  6. 分支指令

所有的指令都包含4位操作码和12位操作数

汇编语言描述

image-20230907195616404

机器码描述

image-20230907195631224

3. 设计实现

3.1 顶层设计

image-20230907201132790

  • CPU顶层测试模块
module cpu_mem_test (
    clk,rst,key,duan,wei
);
    input           clk,rst;
    input   [1:0]   key;
    output  [7:0]   duan;
    output  [3:0]   wei;
    wire    [39:0]  rf_data;
    wire            start;
    wire    [7:0]   PC;
    wire    [15:0]  IR;
    cpu_mem cpu_mem(
        .clk(clk),
        .rst(rst),
        .start(start),
        .rf_data(rf_data),
        .PC(PC),
        .IR(IF)
    );

    fpag_step_ctrl step_ctrl(
        .clk(clk),
        .rst(rst),
        .key(key),
        .start(start),
        .duan(duan),
        .wei(wei),
        .PC(PC),
        .IR(IR),
        .rf_data(rf_data)
    )  ;
endmodule
  • 含ROM和RAM的CPU设计

image-20230907204014676

module cpu_mem (
    clk,rst,start,rf_data,PC,IR
);
    input           clk,rst;
    input           start;
    output  [39:0]  rf_data;
    output  [7:0]   PC;
    output  [15:0]  IR;

    wire        ROM_en;
    wire [15:0] IR;    
    wire        wr_ram,cs_ram;
    wire [7:0]  addr_ram;
    wire [7:0]  alu_out;
    wire        clk_n;
    assign clk_n = ~clk;
    cpu cpu(
        .clk(clk),
        .rst(rst),
        .start(start),
        .ROM_en(ROM_en),
        .IR(IR),
        .PC(PC),
        .rf_data(rf_data),
        .wr_ram(wr_ram),
        .cs_ram(cs_ram),
        .addr_ram(addr_ram),
        .alu_out(alu_out)
    );
    rom rom_instruction(
        .clk(clk_n),
        .rst(rst),
        .rd(ROM_en),
        .rom_data(IR),
        .rom_addr(PC)
    );
    ram ram_data(
        .clk(clk_n),
        .wr(wr_ram),
        .cs(cs_ram),
        .addr(addr_ram),
        .datain(alu_out)
    );
endmodule
  • 将CPU进一步规划成datapath和controller

image-20230907204731259

  • cpu 内部模块划分——包括数据路径和控制器
module cpu (
    clk,rst,start,ROM_en,IR,
    PC,rf_data,wr_ram,cs_ram,addr_ram,
    alu_out
);
    input           clk,rst;
    input           start;
    input   [15:0]  IR;
    output  [7:0]   PC;
    output          ROM_en;
    output          wr_ram,cs_ram;
    output  [7:0]   addr_ram;
    output  [7:0]   alu_oout;
    output  [39:0]  rf_data;
    wire    [7:0]   imm;
    wire    [3:0]   sel_rf;
    wire    [2:0]   sel_alu;
    wire            sel_mux;
    wire            r_wf,en_rf,en_reg,en_alu,en_imm,alu_zero;
    wire            clk_n;
    assign clk_n = ~clk;
    dp datapath(
        .rst(rst),
        .clk(clk_n),
        .r_wf(r_wf),
        .en_rf(en_rf),
        .en_reg(en_reg),
        .en_alu(en_alu),
        .en_imm(en_imm),
        .sel_rf(sel_rf),
        .sel_alu(sel_alu),
        .sel_mux(sel_mux),
        .imm(imm),
        .alu_zero(alu_zero),
        .alu_out(alu_out),
        .rf_data(rf_data)
    );
    ctrl controller(
        .rst(rst),
        .start(start),
        .clk(clk),
        .alu_zero(alu_zero),
        .r_wf(r_wf),
        .en_rf(en_rf),
        .en_reg(en_reg),
        .en_alu(en_alu),
        .en_imm(en_imm),
        .sel_rf(sel_rf),
        .sel_alu(sel_alu),
        .sel_mux(sel_mux),
        .imm(imm),
        .PC(PC),
        .IR(IR),
        .ROM_en(ROM_en),
        .wr_ram(wr_ram),
        .cs_ram(cs_ram),
        .addr_ram(addr_ram)
    );
endmodule
  • 数据路径部分细分框图

image-20230907205630859

  • 数据路径顶层文件
module dp(
    rst,clk,r_wf,en_rf,en_reg,en_alu,en_imm,sel_rf,
    sel_alu,sel_mux,imm,alu_zero,alu_out,rf_data
);
    input           rst,clk,r_wf,en_rf,en_reg,en_alu,en_imm;
    input   [7:0]   imm;
    input   [2:0]   sel_alu;
    input   [3:0]   sel_rf;
    input           sel_mux;
    output          alu_zero;
    output  [39:0]  rf_data;
    output  [7:0]   alu_out;
    wire    [7:0]   op1,op2,out_imm,out_rf;
    register register0(
        .clk(clk),
        .en(en_reg),
        .in(op1),
        .out(op2)
    )  ;
    register register1(
        .clk(clk),
        .en(en_imm),
        .in(imm),
        .out(out_imm)
    );
    mux21 mux0(
        .sel(sel_mux),
        .in1(out_imm),
        .in2(out_rf),
        .out(op1)
    );
    alu alu0(
        .clk(clk),
        .en(en_alu),
        .sel(sel_alu),
        .in1(op1),
        .in2(op2),
        .out(alu_out),
        .alu_zero(alu_zero)
    );
    rf rf0(
        .rst(rst),
        .clk(clk),
        .r_w(r_wf),
        .enb(en_rf),
        .in(alu_out),
        .sel(sel_rf),
        .out(out_rf),
        .rf_data(rf_data)
    );
endmodule
3.2 基本部件设计
  • ALU
module alu (
    clk,en,sel,in1,in2,out,alu_zero;
);
    input           en,clk;
    input   [2:0]   sel;
    input   [7:0]   in1,in2;
    output  reg[7:0]out;
    output  reg     alu_zero;

    always @(posedge clk) begin
        if (en) 
            case(sel)
                3'b000: out = in1;
                3'b001: if (in1 == 0) alu_zero = 1;else alu_zero = 0;
                3'b010: out = in1 + in2;
                3'b011: out = in1 - in2;
                3'b100: out = in1<<in2;
                default: ;
            endcase 
    end
endmodule

image-20230908101041251

  • 异步使能寄存器

image-20230908101112694

module register (
    clk,en,in,out
);
    input           clk,en;
    input   [7:0]   in;
    output reg[7:0] out;
    reg     [7:0] val;
    always @(posedge clk)
        val <= in;
    always @(en,val) begin
        if (en == 1'b1) out <= val;
        else ;
    end    
endmodule
  • 通用寄存器

image-20230908101154184

module rf (
    rst,clk,r_w,enb,in,sel,out,rf_data
);
    input           rst,clk,enb,r_w;
    input   [7:0]   in;
    input   [3:0]   sel;
    output  reg[7:0]out;
    output  [39:0]  rf_data;
    reg     [7:0]   reg_file[0:15];
    integer i;
    assign rf_data = {reg_file[4],reg_file[3],
    reg_file[2],reg_file[1],reg_file[0]};
    always @(posedge rst or posedge clk) begin
        if (rst) begin
            for (i = 0;i < 15;i = i + 1)
                reg_file[i] <= 0; 
        end else if (enb == 1) begin
            if (r_w == 0) reg_file[sel] <= in;
            else out <= reg_file[sel];
        end
    end
endmodule
  • 二选一多路选择器

image-20230908101238719

module mux21 (
    sel,in1,in2,out
);
    input       sel;
    input [7:0] in1,in2;
    output[7:0] out;
    assign out = (sel)?in2:in1;
endmodule
  • 控制器

控制器提供必要的控制信号,使得数据流通过数据路径后达到预期的功能。控制器部分使用状态机计数来实现,这个状态机根据当前的状态和输入的信号值,输出更新后的状态和相应的控制信号。

module ctrl (
    rst,start,clk,alu_zero,r_wf,en_rf,en_reg,en_alu,en_imm,
    sel_rf,sel_alu,sel_mux,imm,PC,IF,ROM_en,wr_ram,
    cs_ram,addr_ram
);
    input           rst,start,clk;
    input           alu_zero;
    input   [15:0]  IR;
    output  reg     r_wf,en_rf,en_reg,en_alu,en_imm;
    output  reg[3:0]sel_rf;
    output  reg[2:0]sel_alu;
    output  reg     sel_mux;
    output  reg[7:0]imm,PC;
    output  reg     ROM_en;
    output  reg     wr_ram,cs_ram;
    output  reg[7:0]addr_ram;
    parameter s0 = 6'b000000,s1 = 6'b000001,s2 = 6'b000010,
    s3 = 6'b000011,s4 = 6'b000100,s5 = 6'b000101,s5_2 = 6'b000110,s5_3 = 6'b000111,
    s6 = 6'b001000,s6_2 = 6'b001001,s6_3 = 6'b001010,
    s6_4 = 6'b001000,s6_5 = 6'b001100,
    s7 = 6'b001101,s7_2 = 6'b001110,s7_3 = 6'b001111,
    s7_4 = 6'b010000,s7_5 = 6'b010001,
    s8 = 6'b010010,s8_2 = 6'b010011,s8_3 = 6'b010100,
    s9 = 6'b010101,s9_2 = 6'b010110,s9_3 = 6'b010111,
    s10 = 6'b100000,s10_2 = 6'b100001,s10_3 = 6'b100010,
    s11 = 6'b100011,s11_2 = 6'b100100,s11_3 = 6'b100101,
    s11_4 = 6'b100110,s11_5 = 6'b100111,
    s12 = 6'b101000,done = 6'b101001;
    reg [5:0] state;
    parameter loadi = 4'b0011,add = 4'b0100,sub = 4'b0101,
    jz = 4'b0110,store = 4'b1000,shiftL = 4'b0111,reg2reg = 4'b0010,
    halt = 4'b1111;
    reg [3:0] OPCODE;
    reg [7:0] address;
    reg [3:0] register;
    always @(posedge rst or posedge clk) begin
        sel_mux <= 1'b1;
        en_rf <= 1'b0;
        en_reg <= 1'b0;
        en_alu <= 1'b0;
        en_imm <= 1'b0;
        ROM_en <= 1'b0;
        wr_ram <= 1'b0;
        cs_ram <= 1'b0;
        addr_ram <= 0;
        if (rst) begin
            state <= s0;
            PC <= 0;
        end else begin
            case (state)
                s0: begin
                    PC <= 0;
                    state <= s1;
                end  
                s1: begin
                    if (start == 1'b1) begin
                        ROM_en <= 1;
                        state <= s2;
                    end
                    else state <= s1;
                end
                s2: begin
                    OPCODE <= IR[15:12];
                    register <= IR[11:8];
                    address <= IR[7:0];
                    state <= s3;
                end
                s3: begin
                    PC <= PC + 8'b1;
                    state <= s4;
                end
                s4: begin
                    case (OPCODE) 
                    loadi:  state <= s5;
                    add:    state <= s6;
                    sub:    state <= s7;
                    jz:     state <= s8;
                    store:  state <= s9;
                    reg2reg:state <= s10;
                    shiftL: state <= s11;
                    halt:   state <= done;
                    default:state <= s1;
                    endcase
                end
                s5: begin
                    imm <= address;
                    en_imm <= 1;
                    state <= s5_2;
                end
                s5_2:begin
                    sel_mux <= 0;
                    en_alu <= 1;
                    sel_alu <= 3'b000;
                    state <= s5_3;
                end
                s5_3:begin
                    en_rf <= 1;
                    r_wf <= 0;
                    sel_rf <= register;
                    state <= s12;
                end
                s6:begin
                    sel_rf <= IR[7:4];
                    en_rf <= 1;
                    r_wf <= 1;
                    state <= s6_2;
                end
                s6_2:begin
                    en_reg <= 1;
                    state <= s6_3;
                end
                s6_3:begin
                    sel_rf <= register;
                    en_rf <= 1;
                    r_wf <= 1;
                    state <= s6_4;
                end
                s6_4:begin
                    en_alu <= 1;
                    sel_alu <= 3'b010;
                    state <= s6_5;
                end
                s6_5:begin
                    sel_rf <= register;
                    en_rf <= 1;
                    r_wf <= 0;
                    state <= s12;
                end
                s7: begin
                    sel_rf <= IF[7:4];
                    en_rf <=1;
                    r_wf <= 1;
                    state <= s7_2;
                end
                s7_2: begin
                    en_reg <= 1;
                    state <= s7_3;
                end
                s7_3: begin
                    sel_rf <= register;
                    en_rf <= 1;
                    r_wf <= 1;
                    state <= s7_4;
                end
                s7_5: begin
                    sel_rf <= register;
                    en_rf <= 1;
                    r_wf <= 0;
                    state <= s12;
                end
                s8: begin
                    en_rf <= 1;
                    r_wf <= 1;
                    sel_rf <= register;
                    state <= s8_2;
                end
                s8_2: begin
                    en_rf <= 1;
                    sel_alu <= 3'b001;
                    state <= s8_3;
                end
                s8_3: begin
                    if (alu_zero == 1) 
                        PC <= address;
                    state <= s12; 
                end
                s9: begin
                    sel_rf <= register;
                    en_rf <= 1;
                    r_wf <= 1;
                    state <= s9_2;
                end
                s9_2: begin
                    en_alu <= 1;
                    sel_alu <= 3'b000;
                    state <= s9_3;
                end
                s9_3: begin
                    cs_ram <= 1;
                    wr_ram <= 1;
                    addr_ram <= address;
                    state <= s12;
                end
                s10: begin
                    sel_rf <= IR[7:4];
                    en_rf <= 1;
                    r_wf <= 1;
                    state <= s10_2;
                end
                s10_2: begin
                    en_alu <= 1;
                    sel_alu <= 3'b000;
                    state <= s10_3;
                end
                s10_3:begin
                    sel_rf <= register;
                    en_rf <= 1;
                    r_wf <= 0;
                    state <= s12;
                end
                s11: begin
                    imm <= address;
                    en_imm <= 1;
                    state <= s11_2;
                end
                s11_2: begin
                    sel_mux <= 0;
                    en_reg <= 1;
                    state <= s11_3;
                end
                s11_3: begin
                    sel_rf <= register;
                    en_rf <= 1;
                    r_wf <= 1;
                    state <= s11_4;
                end
                s11_4: begin
                    en_alu <= 1;
                    sel_alu <= 3'b100;
                    state <= s11_5;
                end
                s11_5: begin
                    sel_rf <= register;
                    en_rf <= 1;
                    r_wf <= 0;
                    state <= s12;
                end
                s12: state <= s1;
                done: state <= done;
                default:;
            endcase
        end
    end    
endmodule

image-20230908101503801

image-20230908101519238

  • 程序存储器
module rom (
    clk,rst,rd,rom_data,rom_addr
);
    parameter M = 16,N = 8;
    input   clk,rst,rd;
    input   [N-1:0] rom_addr;
    output reg[M-1:0] rom_data;
    reg [M-1:0] memory[0:2**N-1];
    always @(posedge clk or posedge rst) begin
        if (rst) begin:init
            integer i;
            memory[0]=16'b0011_0000 00000000;
            //MOV RO,#0;
            memory[1]=16'b0011_0001 00001010;
            //MOV R1,#10;
            memory[2]=16'b0011_0010_00000001;
            //MOV R2,#1;
            memory[3]=16'b0011 0011 00000000;
            //MOV R3,#0;
            memory[4]=16'b0110_0001 00001000;
            //JZ R1,NEXT;
            memory[5]=16'b0100_0000_00010000;
            //ADD R0,R1;
            memory[6]=16'b0101 0001 00100000;
            //SUB R1,R2;
            memory[7]=16'b0110_0011 00000100;
            //JZ R3,Lo0p
            memory[8]=16'b0010_0100_00000000;
            //MOV R4,R0
            memory[9]=16'b0111_0100_00000001;
            //RLR4,#1
            memory[10]=16'b1000_0100_00001010;//MOV 10H,R4memory[11J=16'b11110000 00001011;
            //halt
            for(i=12;i<(2**N);i=i+1)
            //存储器其余地址存放0
                memory[i] = 0;
        end else begin:read
            if (rf) rom_data = memory[rom_addr];
        end
    end    
endmodule

image-20230908101639294

  • 数据存储器
module ram (
    clk,rd,wf,cs,addr,datain,dataout
);
    parameter M = 8,N = 8;
    input       rd,wr,cs,clk;
    input [N-1:0]addr;
    input [M-1:0]datain;
    output reg[M-1:0] dataout;
    reg [M-1:0] memory [0:2**N-1];
    always @(posedge clk) 
    begin:p0
    if(cs) 
        if (rd) dataout <= memory[addr];
        else if (wr) memory[addr] <= datain;
        else dataout <= 'bz;
    end
endmodule

image-20230908101646370

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/987933.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

谷歌SEO手工外链工具好用吗?

答案是&#xff1a;不建议使用工具做谷歌外链&#xff0c;会被判断为作弊惩罚。 在当今的SEO环境中&#xff0c;外链仍然是一个核心组件&#xff0c;影响着网站的权威性和在搜索引擎结果页面&#xff08;SERP&#xff09;上的排名。 但是&#xff0c;随着时间的推移&#xff…

可视化大屏UI模板,随需切换,一秒生效

善用模板能够最大化地提高效率&#xff0c;美化可视化大屏&#xff0c;同时也能腾出更多时间去做深度数据分析挖掘。奥威BI可视化大屏支持UI模板随需切换&#xff0c;一秒生效。用户可以根据自己的喜好和需求&#xff0c;选择不同的UI模板&#xff0c;快速改变可视化大屏的外观…

密钥协商的几种方式和过程

密钥协商是在通信双方之间建立共享密钥的过程&#xff0c;以确保在通信过程中的数据安全性和机密性。下面将介绍几种常见的密钥协商方式和过程。 对称密钥协商 对称密钥协商是最简单和常见的密钥协商方式。在对称密钥协商中&#xff0c;通信双方通过一个安全的信道交换密钥。这…

如何将DHTMLX Suite集成到Scheduler Lightbox中?让项目管理更可控!

在构建JavaScript调度器时&#xff0c;通常需要为最终用户提供一个他们喜欢的方式来计划事件&#xff0c;这是Web开发人员喜欢认可DHTMLX Scheduler的重要原因&#xff0c;它在这方面提供了完全的操作自由&#xff0c;它带有lightbox弹出窗口&#xff0c;允许通过各种控件动态更…

Qt/C++音视频开发51-推流到各种流媒体服务程序

一、前言 最近将推流程序完善了很多功能,尤其是增加了对多种流媒体服务程序的支持,目前支持mediamtx、LiveQing、EasyDarwin、nginx-rtmp、ZLMediaKit、srs、ABLMediaServer等,其中经过大量的对比测试,个人比较建议使用mediamtx和ZLMediaKit,因为这两者支持的格式众多,不…

[Machine Learning][Day1]监督学习和无监督学习

目录 监督学习(Supervised Learning) 应用1&#xff1a;数据回归拟合 应用2&#xff1a;分类 无监督学习(Unsupervised Learning) 监督学习和无监督学习的区别 练习&#xff1a; 监督学习(Supervised Learning) 通过正确的输入和输出来进行学习的一种模型。输入x和正确的输…

你好,我是百川大模型|国内可开源免费商用Baichuan2揭秘

“ 百川智能发布了新一代语言模型Baichuan2。相比之前的第一代&#xff0c;新版本在各个学科领域的表现都有很大提升&#xff0c;特别是在数学、科学、安全方面的能力得到明显增强。Baichuan2以开源方式对外发布&#xff0c;为大模型领域提供了新的选择和可能。” 01 — 昨天下…

短信过滤 APP 开发

本文字数&#xff1a;7033字 预计阅读时间&#xff1a;42分钟 一直想开发一个自己的短信过滤 APP&#xff0c;但是一直没有具体实施&#xff0c;现在终于静下心来&#xff0c;边开发边记录下整体的开发过程。 01 垃圾短信样本 遇到的第一个问题是&#xff0c;既然要过滤垃圾短信…

JAR will be empty - no content was marked for inclusion!

现象 在对自建pom依赖组件打包时&#xff0c;出现JAR will be empty - no content was marked for inclusion!错误。 方案 在pom中怎么加packaging标签内容为pom&#xff0c;标识只打包pom文件 <?xml version"1.0" encoding"UTF-8"?> ...<grou…

MyBatis的逆向工程

文章目录 前言MyBatis的逆向工程创建逆向工程的步骤添加依赖和插件创建MyBatis的核心配置文件创建逆向工程的配置文件执行MBG插件的generate目标 QBC查询增改 总结 前言 MyBatis的逆向工程 正向工程&#xff1a;先创建Java实体类&#xff0c;由框架负责根据实体类生成数据库表…

《计算机网络安全》DNS与它的具体作用解析

初步了解DNS 个人介绍DNS定义DNS作用DNS的生活加速作用科普 个人介绍 &#x1f338;一名大四备考考研学子&#xff0c;喜欢前端&#xff0c;还有Android和JAVA开发 &#x1f332;爱看书和打游戏还有唱歌 &#x1f352;热爱编程和读古今中外名著 &#x1f33a;座右铭&#xff1…

JMeter 4.0 如何获取cookie

文章目录 前言JMeter 4.0 如何获取cookie1. 修改jmeter.properties 文件2. 添加HTTP Cookie 管理器3. 获取cookie信息 前言 如果您觉得有用的话&#xff0c;记得给博主点个赞&#xff0c;评论&#xff0c;收藏一键三连啊&#xff0c;写作不易啊^ _ ^。   而且听说点赞的人每天…

TikTok运营做不起来?IP如何选择?

作为跨境电商新蓝海&#xff0c;TikTok不断的加快自己推进电商业务的步伐&#xff0c;也吸引了越来越多的跨境商家入驻。但是很多人信心满满注册入驻后&#xff0c;却遇到了0播放&#xff0c;流量少&#xff0c;转化低的问题&#xff0c;Tiktok运营不起来&#xff0c;那你要注意…

大数据技术之Hadoop:MapReduce与Yarn概述(六)

目录 一、分布式计算 二、分布式资源调度 2.1 什么是分布式资源调度 2.2 yarn的架构 2.2.1 核心架构 2.2.2 辅助架构 前面我们提到了Hadoop的三大核心功能&#xff1a;分布式存储、分布式计算和资源调度&#xff0c;分别由Hadoop的三大核心组件可以担任。 即HDFS是分布式…

WebStorm2023新版设置多个窗口,支持同时显示多个项目工程

调整设置 Appearance & Behavior -> System Settings> Project open project in New window&#xff1a;

记录mac虚拟机安装centos7

一. 安装VMWare Fusion&#xff08;略&#xff09; 二. 寻找arm64架构mac能拉起来的centos7镜像&#xff08;略&#xff09; 参考 https://cloud.tencent.com/developer/article/2150583?areaSource106000.2&traceIdkybnG2SKASN5GqSBiSmu9 三. 从origin镜像安装后开始记…

想要获得更多的好评吗?电子商务人不可错过的文章

电子商务评论可以飙升销售额并改善您与客户的关系。积极的客户反馈是任何电子商务成功故事的关键。高客户满意度保证了回头客和新买家&#xff0c;这将使您的公司保持活力。推荐使用SaleSmartly&#xff08;SS客服&#xff09;这一客户服务平台&#xff0c;给您的客户带来更好的…

Geoserver发布shp、tiff、瓦片等格式的GIS数据

这里写目录标题 1 发布shp矢量数据1.1 添加shp作为数据源1.2 发布shp图层1.3 预览服务1.4 配置样式 2 发布Postgres数据库2.2 发布数据 3 发布 tif 栅格数据3.1 添加 tif 数据源3.2 发布tif数据3.3 预览服务3.4 配置地图样式 关于中文标注乱码的问题 1 发布shp矢量数据 发布sh…

归并排序和快速排序的两种实现

在此之前我们已经介绍过归并排序和快速排序&#xff1a;浅谈归并排序与快速排序&#xff0c;但其中的实现都是基于递归的。本文将重新温故这两种算法并给出基于迭代的实现。 目录 1. 归并排序1.1 基于递归1.2 基于迭代 2. 快速排序2.1 基于递归2.2 基于迭代 1. 归并排序 1.1 基…

github网站打不开,hosts文件配置

首先获取github官网的ip地址&#xff0c; 打开cmd&#xff0c;输入ping github.com 配置&#xff1a; #github 140.82.114.4 github.com 199.232.69.194 github.global.ssl.fastly.net 185.199.108.153 assets-cdn.github.com 185.199.110.153 assets-cdn.github.com 185.199…