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

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_) beginif (reset_ == `ENABLE_) beginfor (i = 0;i < `DATA_D;i = i + 1) beginff[i] <= #1{`DATA_W{1'b0}};endend else beginif (we_ == `ENABLE_) beginff[addr] <= #1 d_in;endendendendmodule

2. ALU

module alu(input [2:0]          a,b,input [1:0]          sel,output   reg [3:0]   out
)always @(a,b,sel) begincase(sel)2'b00: out = a+b;2'b01: out = ~(a+b);2'b10: out = a<<1;2'b11: out = ~a;default:out = 4'b0000;endcaseend
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) beginif (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) beginif (rst) q <= 0;else begin q[7:1] <= q[6:0];q[0] <= data_in;endendendmodule

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

module DFlipFlop (input         clk,input         clr_n, // 异步复位信号,低电平有效input         D,output reg    Q
);always @(posedge clk or negedge clr_n) beginif (!clr_n)Q <= 1'b0; // 异步复位时,输出清零elseQ <= D; // 非复位时,将输入数据加载到输出endendmodulemodule 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) beginif (!clr_n)q <= 6'b0; // 异步复位时,全部位清零elsefor (i = 0; i < 6; i = i + 1)DFlipFlop dff (.clk(clk),.clr_n(clr_n),.D(data_input[i]),.Q(q[i])); // 使用循环实例化六个D触发器endassign 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) beginclk_edge <= ~clk_edge; // 按键按下时切换时钟边沿endalways @(posedge clk_edge or posedge rst) beginif (rst)q <= 8'b0;elsebeginq[7:1] <= q[6:0];q[0] <= data_in;endend// 产生时钟脉冲always @(posedge clk_edge) beginclk_pulse <= 1'b1;endendmodule

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) beginif (srclr)shift_register <= 8'b0; // 异步复位时,寄存器清零elseshift_register <= {shift_register[6:0], serial_in}; // 数据移位endassign 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) beginif (q <= 0) q <= 0;else if (en) q <= q + 1;end
endmodule
//激励关键代码
initial forkckl = 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) beginif (p == N/2-1) beginp = 0;clk_N = ~clk_N;endelse 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) beginif (p == N-1) p <= 0;else p <= p + 1;endalways @(posedge clk) beginif (p == N - 1) clk_p <= ~clk_p;endalways @(negedge clk) beginif (p == (N-1)/2) clk_q <= ~clk_q;endassign 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) beginif (rst) begincount <= 0;end else begincount <= count + 1;endendassign 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) beginif (cnt == 25000000-1) beginclk_1HZ = ~clk_1HZ;cnt <= 0;end else begincnt = cnt + 1;endend
endmodule

计数模块

module second(clk_1HZ,clr,sec
);input       clk_1HZ;input       clr;output reg [7:0] sec;always @(posedge clk_1HZ or posedge clr) beginif (clr) beginsec <= 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) begincase (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;endcaseendassign 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) beginif (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) beginif (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) beginif (rst) beginfor (i = 0;i < 15;i = i + 1)reg_file[i] <= 0; end else if (enb == 1) beginif (r_w == 0) reg_file[sel] <= in;else out <= reg_file[sel];endend
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) beginsel_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) beginstate <= s0;PC <= 0;end else begincase (state)s0: beginPC <= 0;state <= s1;end  s1: beginif (start == 1'b1) beginROM_en <= 1;state <= s2;endelse state <= s1;ends2: beginOPCODE <= IR[15:12];register <= IR[11:8];address <= IR[7:0];state <= s3;ends3: beginPC <= PC + 8'b1;state <= s4;ends4: begincase (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;endcaseends5: beginimm <= address;en_imm <= 1;state <= s5_2;ends5_2:beginsel_mux <= 0;en_alu <= 1;sel_alu <= 3'b000;state <= s5_3;ends5_3:beginen_rf <= 1;r_wf <= 0;sel_rf <= register;state <= s12;ends6:beginsel_rf <= IR[7:4];en_rf <= 1;r_wf <= 1;state <= s6_2;ends6_2:beginen_reg <= 1;state <= s6_3;ends6_3:beginsel_rf <= register;en_rf <= 1;r_wf <= 1;state <= s6_4;ends6_4:beginen_alu <= 1;sel_alu <= 3'b010;state <= s6_5;ends6_5:beginsel_rf <= register;en_rf <= 1;r_wf <= 0;state <= s12;ends7: beginsel_rf <= IF[7:4];en_rf <=1;r_wf <= 1;state <= s7_2;ends7_2: beginen_reg <= 1;state <= s7_3;ends7_3: beginsel_rf <= register;en_rf <= 1;r_wf <= 1;state <= s7_4;ends7_5: beginsel_rf <= register;en_rf <= 1;r_wf <= 0;state <= s12;ends8: beginen_rf <= 1;r_wf <= 1;sel_rf <= register;state <= s8_2;ends8_2: beginen_rf <= 1;sel_alu <= 3'b001;state <= s8_3;ends8_3: beginif (alu_zero == 1) PC <= address;state <= s12; ends9: beginsel_rf <= register;en_rf <= 1;r_wf <= 1;state <= s9_2;ends9_2: beginen_alu <= 1;sel_alu <= 3'b000;state <= s9_3;ends9_3: begincs_ram <= 1;wr_ram <= 1;addr_ram <= address;state <= s12;ends10: beginsel_rf <= IR[7:4];en_rf <= 1;r_wf <= 1;state <= s10_2;ends10_2: beginen_alu <= 1;sel_alu <= 3'b000;state <= s10_3;ends10_3:beginsel_rf <= register;en_rf <= 1;r_wf <= 0;state <= s12;ends11: beginimm <= address;en_imm <= 1;state <= s11_2;ends11_2: beginsel_mux <= 0;en_reg <= 1;state <= s11_3;ends11_3: beginsel_rf <= register;en_rf <= 1;r_wf <= 1;state <= s11_4;ends11_4: beginen_alu <= 1;sel_alu <= 3'b100;state <= s11_5;ends11_5: beginsel_rf <= register;en_rf <= 1;r_wf <= 0;state <= s12;ends12: state <= s1;done: state <= done;default:;endcaseendend    
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) beginif (rst) begin:initinteger 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,Lo0pmemory[8]=16'b0010_0100_00000000;//MOV R4,R0memory[9]=16'b0111_0100_00000001;//RLR4,#1memory[10]=16'b1000_0100_00001010;//MOV 10H,R4memory[11J=16'b11110000 00001011;//haltfor(i=12;i<(2**N);i=i+1)//存储器其余地址存放0memory[i] = 0;end else begin:readif (rf) rom_data = memory[rom_addr];endend    
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:p0if(cs) if (rd) dataout <= memory[addr];else if (wr) memory[addr] <= datain;else dataout <= 'bz;end
endmodule

image-20230908101646370

4. 上Vivado

image-20230908151717453
image-20230908165019429

跑出来了,不知道对不对

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

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

相关文章

正中优配:月线macd指标参数设置?

随着投资者长期持有股票的越来越受欢迎&#xff0c;月线MACD目标已成为识别趋势和交易信号的重要东西。但是&#xff0c;许多投资者在设置MACD目标参数时仍然感到困惑。本文将从多个视点剖析&#xff0c;为您解答月线MACD目标参数设置的问题。 什么是MACD目标&#xff1f; MAC…

vue中v-for循环数组使用方法中splice删除数组元素(错误:每次都删掉点击的下面的一项)

总结&#xff1a;平常使用v-for的key都是使用index&#xff0c;这里vue官方文档也不推荐&#xff0c;这个时候就出问题了&#xff0c;我们需要key为唯一标识&#xff0c;这里我使用了时间戳&#xff08;new Date().getTime()&#xff09;处理比较复杂的情况&#xff0c; 本文章…

Spring-Cloud-Openfeign如何做熔断降级?

微服务系统中为了防止服务雪崩问题&#xff0c;服务之间相互调用的时候一般需要开启熔断与降级&#xff0c;下面就来看下feign如何集成hystrix来做熔断与降级。 依赖 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-c…

Full authentication is required to access this resource解决办法

我们在使用postman调接口时候&#xff0c;有的时候需要权限才可以访问&#xff0c;否则可能会报下面这个错误 {"success": false,"message": "Full authentication is required to access this resource","code": 401,"result&q…

浏览器缓存机制及其分类

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 强缓存&#xff08;Cache-Control 和 Expires&#xff09;⭐ 协商缓存&#xff08;ETag 和 Last-Modified&#xff09;⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几…

四川百幕晟科技:抖音新店怎么快速起店?

抖音作为全球最大的短视频平台&#xff0c;拥有庞大的用户基础和强大的影响力&#xff0c;成为众多商家宣传产品、增加销量的理想选择。那么&#xff0c;如何快速开店并成功运营呢&#xff1f;下面描述了一些关键步骤。 1、如何快速开新店&#xff1f; 1、确定产品定位&#x…

JVM GC垃圾回收

一、GC垃圾回收算法 标记-清除算法 算法分为“标记”和“清除”阶段&#xff1a;标记存活的对象&#xff0c; 统一回收所有未被标记的对象(一般选择这种)&#xff1b;也可以反过来&#xff0c;标记出所有需要回收的对象&#xff0c;在标记完成后统一回收所有被标记的对象 。它…

geopandas笔记:汇总连接两个区域的边

比如这样的两个区域&#xff0c;我们想知道从蓝到绿、从绿到蓝都有哪些边 1 读取openstreetmap import osmnx as ox import geopandas as gpdGox.graph_from_place(Singapore,simplifyTrue,network_typedrive)ox.plot_graph(G) 2 得到对应的边的信息 nodes,edgesox.graph_to_…

正中优配:股票出现xd是好还是坏?

近年来&#xff0c;股票市场的日渐成熟和开展使得出资者们关于股票价格的涨跌也愈加灵敏&#xff0c;特别是股票呈现XD之后&#xff0c;更是引起了一系列热议。那么&#xff0c;股票呈现XD是好还是坏&#xff1f;本文将从多个角度进行剖析。 首要&#xff0c;需要清晰XD的定义…

2023年9月制造业NPDP产品经理国际认证报名来这错不了

产品经理国际资格认证NPDP是新产品开发方面的认证&#xff0c;集理论、方法与实践为一体的全方位的知识体系&#xff0c;为公司组织层级进行规划、决策、执行提供良好的方法体系支撑。 【认证机构】 产品开发与管理协会&#xff08;PDMA&#xff09;成立于1979年&#xff0c;是…

java Math类中的random方法和Random类中方法的区别

文章目录 Math类中的random()方法Random类 Math类中的random()方法 Math类中的random()方法没有参数&#xff0c;它会默认返回等于0.0、小于1.0的double类型随机数。对double()方法返回的数字稍加处理&#xff0c;即可实现任意范围随机数的功能 public class MathTest {publi…

vue 前端 问题整理

列表显示字典数据 template里面的vue代码 <el-table-column label"性别" align"center" prop"sex"><template #default"scope"> <!-- <dict-tag :optionssysUserSex :value"scope.row.sex&quo…

Redis持久化、主从与哨兵架构详解

Redis持久化 RDB快照&#xff08;snapshot&#xff09; 在默认情况下&#xff0c; Redis 将内存数据库快照保存在名字为 dump.rdb 的二进制文件中。 你可以对 Redis 进行设置&#xff0c; 让它在“ N 秒内数据集至少有 M 个改动”这一条件被满足时&#xff0c; 自动保存一次数…

【Linux】让笔记本发挥余热,Ubuntu20.04设置WiFi热点

Ubuntu20.04设置WiFi热点 由于卧室距离客厅较远&#xff0c;wifi信号太弱&#xff0c;体验极差。鉴于卧室的笔记本电脑是通过网线连接的客厅路由器&#xff0c;因此考虑将这台老破笔记本作为“路由器”&#xff0c;以便发挥它的余热。实验证明&#xff0c;上网速度提升数十倍&a…

Kubectl 使用详解——k8s陈述式资源管理

目录 一、kubectl 简介 二、kubectl 的使用 1.基础用法 &#xff08;1&#xff09;配置kubectl自动补全 &#xff08;2&#xff09;查看版本信息 &#xff08;3&#xff09;查看资源对象信息 &#xff08;4&#xff09;查看集群信息 &#xff08;5&#xff09;查看日志…

taro vue3 ts nut-ui 项目

# 使用 npm 安装 CLI $ npm install -g tarojs/cli 查看 Taro 全部版本信息​ 可以使用 npm info 查看 Taro 版本信息&#xff0c;在这里你可以看到当前最新版本 npm info tarojs/cli 项目初始化​ 使用命令创建模板项目&#xff1a; taro init 项目名 taro init myApp …

英飞凌TC3xx--深度手撕HSM安全启动(三)--TC3xx HSM系统架构

今天聊TC3xx HSM系统,包括所用内核、UCB相关信息、Host和HSM交互方式。 1、HSM系统架构 下图来源于英飞凌官网培训材料。 TC3xx的HSM内核是一颗32位的ARM Cortex M3,主频可达100MHz,支持对称算法AES128、非对称算法PKC(Public Key Crypto) ECC256、Hash SHA2,以及T…

算法通关村第十七关:白银挑战-贪心高频问题

白银挑战-贪心高频问题 1. 区间问题 所有的区间问题&#xff0c;参考下面这张图 1.1 判断区间是否重叠 LeetCode252 https://leetcode.cn/problems/meeting-rooms/ 思路分析 因为一个人在同一时刻只能参加一个会议&#xff0c;因此题目的本质是判断是否存在重叠区间 将区…

30天入门Python(基础篇)——第2天:Python安装(保姆级)与IDE的认识与选择+详细安装教程

文章目录 专栏导读上一节课回顾1、Python解释器的安装查看各个版本的Python解释器①、ok,双击安装②、这里我们选择【自定义】安装&#xff0c; 下面的【将Python添加在环境变量】大家一定要打个勾③、点击【Next】进行下一步④、这里不建议安装在C盘, 点击【Browse】我在F盘创…

C++ 多态

引例&#xff1a; #include<iostream> using namespace std; class Animal { public:void speak(){cout<<"动物在说话"<<endl;} }; class Cat:public Animal { public:void speak(){cout<<"小猫在说话"<<endl;} }; void Do…