自己设计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.rhkb.cn/news/125999.html

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

相关文章

socket编程

网络协议指的是计算机网络中互相通信的对等实体之间交换信息时所必须遵守的规则的集合。一般系统网络协议包括五个部分&#xff1a;通信环境&#xff0c;传输服务&#xff0c;词汇表&#xff0c;信息的编码格式&#xff0c;时序、规则和过程。 Socket是应用层和TIP/IP协议簇通…

Middleware ❀ Kafka功能与使用详解

文章目录 1. 概述1.1. 消息队列1.2. 应用场景1.3. 工作模式1.4. 基础结构1.4.1. 结构组件1.4.2. 数据同步1.4.3. ACK机制1.4.4. 分区机制1.4.4.1. 使用Partition Key写入1.4.4.2. 轮询写入 - 默认规则1.4.4.3. 指定Partition写入 1.4.5. Offset偏移量1.4.5.1. 消息顺序性1.4.5.…

linux系统中驱动框架基本分析

大家好&#xff0c;今天分享一篇Linux驱动软件设计思想的文章。由于文章较长&#xff0c;可以先收藏后再慢慢看。 一、Linux驱动的软件架构 1.1 出发点 为适应多种体系架构的硬件&#xff0c;增强系统的可重用和跨平台能力。 1.2 分离思想 为达到一个驱动最好一行都不改就…

Apache DolphinScheduler - 快速扩展 TaskPlugin 从入门到放弃

目前在大数据生态中&#xff0c;调度系统是不可或缺的一个重要组件。Apache DolphinScheduler 作为一个顶级的 Apache 项目&#xff0c;其稳定性和易用性也可以说是名列前茅的。而对于一个调度系统来说&#xff0c;能够支持的可调度的任务类型同样是一个非常重要的因素&#xf…

国内访问香港服务器选择什么路线?

​  国内访问香港服务器可以选择多种路线。首先&#xff0c;我们了解下各个线路的速度延迟。 一、CN2直连&#xff1a;解决了不同互联网服务提供商之间访问的难题&#xff0c;不需要绕到国际网络再从中国的三个网络入口进入。 二、优化直连&#xff1a;全国平均延迟60ms&…

Ubuntu----Linux命令-----防火墙(查看、关闭、启动)

一、查看防火墙状态 命令&#xff1a;ufw status 说明&#xff1a; 活动&#xff1a;防火墙是开启的 不活动&#xff1a;防火墙是关闭的 二、开启防火墙 命令&#xff1a;sudo ufw enable 开启防火墙后&#xff0c;可以查看防火墙状态 三、关闭防火墙 命令&#xff1a;sud…

如何通过构建遥感光谱反射信号与地表参数之间的关系模型来准确估算植被参数?植被参数光学遥感反演方法(Python)及遥感与生态模型数据同化算法

目录 专题一 植被参数遥感反演理论 专题二 植被叶片及冠层反射率模拟与处理 专题三 植被遥感模型参数敏感性分析 专题四 基于查找表(LUT)方法反演植被参数 专题五 基于优化算法反演植被参数 专题六 基于机器学习反演植被参数 专题七 遥感数据同化理论 专题八 同化遥感反…

单目标应用:基于成长优化算法(Growth Optimizer,GO)的微电网优化调度MATLAB

一、微网系统运行优化模型 微电网是由分布式电源、储能装置和能量转换装置等组成的小型发配电系统&#xff0c;具有成本低、电压低、污染小等特点。由于环保和能源压力&#xff0c;清洁可再生能源和分布式能源工业发展潜力巨大。微电网控制器可实现对电网的集中控制&#xff0…

Canonical 发布公告,Ubuntu可以在 Windows 10 商店找到

导读Canonical 前几天正式发布公告称&#xff0c;“Windows 10 Loves Ubuntu”&#xff0c;其 Ubuntu 16.04 LTS 在 Windows 10 商店中以应用的方式出现&#xff0c;这是继 openSUSE 及 SLES 之后&#xff0c;又一款可以从 Windows 10 商店中下载的 Linux 操作系统。 一些用户已…

GO语言网络编程(并发编程)并发介绍,Goroutine

GO语言网络编程&#xff08;并发编程&#xff09;并发介绍&#xff0c;Goroutine 1、并发介绍 进程和线程 A. 进程是程序在操作系统中的一次执行过程&#xff0c;系统进行资源分配和调度的一个独立单位。 B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更…

Apache Linki 1.3.1+DataSphereStudio+正常启动+微服务+端口号

我使用的是一键部署容器化版本&#xff0c;官方文章 默认会启动6个 Linkis 微服务&#xff0c;其中下图linkis-cg-engineconn服务为运行任务才会启动,一共七个 LINKIS-CG-ENGINECONN:38681 LINKIS-CG-ENGINECONNMANAGER:9102 引擎管理服务 LINKIS-CG-ENTRANCE:9104 计算治理入…

Linux常用命令——convertquota命令

在线Linux命令查询工具 convertquota 把老的配额文件转换为新的格式 补充说明 convertquota命令用于将老的磁盘额数据文件&#xff08;“quota.user”和“quota.group”&#xff09;转换为新格式的文件&#xff08;“quota.user”和“quota.group”&#xff09;。 语法 c…

C/C++输出绝对值 2019年9月电子学会青少年软件编程(C/C++)等级考试一级真题答案解析

目录 C/C输出绝对值 一、题目要求 1、编程实现 2、输入输出 二、解题思路 1、案例分析 三、程序代码 四、程序说明 五、运行结果 六、考点分析 C/C输出绝对值 2019年9月 C/C编程等级考试一级编程题 一、题目要求 1、编程实现 输入一个浮点数&#xff0c;输出这个…

cpolar内网穿透

目录 一、引言二、什么是cpolar三、内网穿透四、如何使用cpolar1、下载cpolar软件安装包2、注册cpolar账号3、使用cpolar 一、引言 当我们完成了一个tomcat的web项目之后&#xff0c;如果我们想让其他电脑访问到这个项目&#xff0c;我们可以让其他电脑和本机连接到同一个局域…

git标签基础

打标签:git可以给仓库历史中某个提交打上标签,以示重要,比较有代表人们会使用这个功能来标记发布结点(V1.0,V2.0) 列出本地标签: git tag --list git tag -l "V1.85*" 列出远端仓库的中所有标签 git ls-remote --tags给标签添加一些描述信息 git tag -a v1.3 -m …

【文字到语音的论文总结】

1.文字到语音的整个过程 文字到语音的一般整体结构 主要是下面这个流程&#xff0c;每个网络可能会把其中两者或是三者融合在一起来&#xff1b; 长度不同的问题 生成的语音可能和文字的长度并不一样&#xff0c;因此需要解决这个问题 Tactron使用的是交叉注意力的方式解…

【数学建模】2023数学建模国赛C题完整思路和代码解析

C题第一问代码和求解结果已完成&#xff0c;第一问数据量有点大&#xff0c;经过编程整理出来了单品销售额的汇总数据、将附件2中的单品编码替换为分类编码&#xff0c;整理出了蔬菜各品类随着时间变化的销售量&#xff0c;并做出了这些疏菜品类的皮尔森相关系数的热力图&#…

MySQL——select语句的简单介绍和查询时常用的参数

select语句详解 基本的select语句 select 要查询的列名 from 要查询的表 where 限制条件; 如果要查询表的所有内容&#xff0c;则把要查询的列名用—个星号*号表示(之间的案例中都已经使用过)&#xff0c;代表要查询表中所有的列。 而大多数情况&#xff0c;我们只需要查看…

AI绘画:StableDiffusion实操教程-完美世界-魔女(附高清图下载)

前段时间我分享了StableDiffusion的非常完整的教程&#xff1a;“AI绘画&#xff1a;Stable Diffusion 终极宝典&#xff1a;从入门到精通 ” 尽管如此&#xff0c;还有读者反馈说&#xff0c;尽管已经成功安装&#xff0c;但生成的图片与我展示的结果相去甚远。真实感和质感之…

【Mysql】给查询记录增加序列号方法

在MySQL 8.0版本中&#xff0c;你可以使用ROW_NUMBER()函数来添加序号。以下是一个示例查询&#xff0c;演示如何添加序号&#xff1a; SELECT ROW_NUMBER() OVER (ORDER BY column_name) AS serial_number,column1, column2, ... FROMyour_table;请将column_name替换为你想要…