自己设计CPU学习之路——基于《Xilinx FPGA应用开发》
1. 一个32组位宽为32的寄存器堆
- 框图

-
代码
- 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进制计数器

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 结构,该结构用于并发地控制信号 clk、clr 和 en 的变化。以下是对这段代码的详细解释:
-
fork和join:fork和join是一对用于创建并发代码块的关键字。fork标志着代码分支的开始,允许同时执行多个线程。join表示所有分支线程都执行完毕后再继续执行后续的代码。在这个例子中,fork启动了一个并发线程,而join用于结束这个线程。 -
initial块:initial块是Verilog中用于模拟和初始化的代码块。在仿真开始时执行其中的代码。 -
初始化信号:在
initial块的开头,clk、clr、和en这三个信号都被初始化。它们的初始值分别是 0。 -
forever循环:forever关键字用于创建一个无限循环,表示其中的代码将一直执行下去。 -
#10、#25、#55、#35:这些是时间延迟操作符,用于指定等待的时间。#10表示等待 10 个时间单位,#25表示等待 25 个时间单位,以此类推。 -
时钟信号
clk的翻转:#10 clk = ~clk;表示在等待 10 个时间单位后,翻转时钟信号clk的状态,从 0 到 1 或从 1 到 0。这模拟了时钟的周期性振荡。 -
异步复位信号
clr的设置和清除:#25 clr = 1;表示在等待 25 个时间单位后,将异步复位信号clr设置为 1,表示触发异步复位。然后#55 clr = 0;表示在等待 55 个时间单位后,将clr再次设置为 0,表示清除异步复位。 -
使能信号
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%的奇数分频时钟。利用了相位差

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灯显示

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. 设计
- 处理器的组成结构

- 简易处理器的功能
完成 2*(0+1+2+…+10)=?
- 指令系统的设计

- 寄存器传输指令
- 装在指令
- 算术运算指令:完成加减运算
- 逻辑移位指令:完成左移操作
- 存储指令
- 分支指令
所有的指令都包含4位操作码和12位操作数
汇编语言描述

机器码描述

3. 设计实现
3.1 顶层设计

- 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设计

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

- 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
- 数据路径部分细分框图

- 数据路径顶层文件
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

- 异步使能寄存器

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
- 通用寄存器

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
- 二选一多路选择器

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


- 程序存储器
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

- 数据存储器
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

4. 上Vivado


跑出来了,不知道对不对
相关文章:
自己设计CPU学习之路——基于《Xilinx FPGA应用开发》
1. 一个32组位宽为32的寄存器堆 框图 代码 regfile.h ifndef __FEGFILE_HEADER__define __REGFILE_HEADER__define HIGH 1b1define LOW 1b0define ENABLE_ 1b0define DISABLE_ 1b1define DATA_W 32define DataBus 31:0define DATA_D 32d…...
数据结构与算法:树
目录 树 定义 结构 二叉树 定义 结构 形式 满二叉树 完全二叉树 存储 链式存储结构 数组 孩子节点 父节点 应用 查找 维持相对顺序 遍历 深度优先遍历 前序遍历 中序遍历 后序遍历 广度优先遍历 层序遍历 二叉堆 定义 自我调整 操作 插入加点 删…...
Spark 【Spark SQL(一)DataFrame的创建、保存与基本操作】
前言 今天学习Spark SQL,前面的RDD编程要想熟练还是得通过项目来熟练,所以先把Spark过一遍,后期针对不足的地方再加强,这样效率会更高一些。 简介 在RDD编程中,我们使用的是SparkContext接口,接下来的Spar…...
026-从零搭建微服务-文件服务(二)
写在最前 如果这个项目让你有所收获,记得 Star 关注哦,这对我是非常不错的鼓励与支持。 源码地址(后端):https://gitee.com/csps/mingyue 源码地址(前端):https://gitee.com/csps…...
Jenkins 页面部分显示Http状态403 被禁止
前言 生产环境Jenkins部署了一段时间了,结果今天在流水线配置中,部分页面显示Jenkins 页面部分显示Http状态403 被禁止,修改配置点击保存之后偶尔也会出现这个。 问题 以下是问题图片 解决 在全局安全配置里面,勾选上启用代…...
ajax day4
1、promise链式调用 /*** 目标:把回调函数嵌套代码,改成Promise链式调用结构* 需求:获取默认第一个省,第一个市,第一个地区并展示在下拉菜单中*/let pname axios({url: http://hmajax.itheima.net/api/province,}).t…...
8.Spring EL与ExpressionParser
Spring EL与ExpressionParser 文章目录 Spring EL与ExpressionParser介绍**使用SpEL来计算评估文字字符串表达式**使用SpEL来计算评估 bean 属性 – “item.name” 介绍 Spring表达式语言(SpEL)支持多种功能,并且可以测试这个特殊的“ExpressionParser”接口的表达…...
Go和Java实现迭代器模式
Go和Java实现迭代器模式 1、迭代器模式 迭代器模式是 Java 和 .Net 编程环境中非常常用的设计模式。这种模式用于顺序访问集合对象的元素,不需要知道 集合对象的底层表示。 迭代器模式属于行为型模式。 意图:提供一种方法顺序访问一个聚合对象中各个…...
如何在 Vue.js 和 Nuxt.js 之间做出选择?
开篇 今天看了一位国外大佬的文章,主要是他对在项目中如何选择 Vue.js 或 Nuxt.js 的看法,欢迎大家在评论区发表看法,以下内容是他关于这个问题看法的整理,由于翻译水平有限,欢迎大家指正。 国外大佬的看法 Vue.js在开…...
(二十三)大数据实战——Flume数据采集之采集数据聚合案例实战
前言 本节内容我们主要介绍一下Flume数据采集过程中,如何把多个数据采集点的数据聚合到一个地方供分析使用。我们使用hadoop101服务器采集nc数据,hadoop102采集文件数据,将hadoop101和hadoop102服务器采集的数据聚合到hadoop103服务器输出到…...
Linux: network: dhcp: mtu 这个里面也有关于网卡的MTU设置;
https://linux.die.net/man/5/dhcp-options 需注意这个DHCP配置选项。 option interface-mtu uint16; This option specifies the MTU to use on this interface. The minimum legal value for the MTU is 68. 假如在网卡的配置文件中设置了dhcp获取IP信息,可能导…...
Android中使用图片水印,并且能够在线下载字体并应用于水印
Android中使用图片水印,并且能够在线下载字体并应用于水印 要在Android中使用图片水印,并且能够在线下载字体并应用于水印,可以按照以下步骤进行: 1.使用Picasso、Glide或其他图片加载库加载图片: ImageView imageV…...
HTTP文件服务
在工作中,往往会需要将文件同时共享给很多台电脑。 本篇介绍HHDESK的HTTP文件服务功能,通过浏览器,将本地资源共享给任意主机。 1 共享文件 首页——资源管理——服务端——“”,在弹出框中选择HTTP文件服务。 填写各项内容。…...
nginx配置获取客户端的真实ip
场景描述: 访问路径: A机器 - > B机器的 ->C虚拟机 : A机器为客户端用户,本地地址为 192.168.0.110 B机器为服务端反向代理服务器 本地地址为192.168.0.128 –>(192.168.56.1) C机器为B主机安…...
1990-2022上市公司董监高学历工资特征信息数据/上市公司高管信息数据
1990-2022上市公司董监高学历工资特征信息数据/上市公司高管信息数据 1、时间:1990-2022年(统计截止日期为 2022年7月) 2、指标:证券代码、统计截止日期、姓名、国籍、籍贯、籍贯所在地区代码、出生地、出生地所在地区代码、性别…...
Java程序连接 Mysql 超时问题 - 数据包过大,导致超时,# 配置网络超时时间 socketTimeout: 1800000
问题 Java程序连接 Mysql 超时问题 解决方法 如果存在 yml 等类似的配置文件,那么可以配置一下 socket 连接超时的参数,例如 # 配置网络超时时间 半小时,计算公式 60秒*1000毫秒*30分钟 socketTimeout: 1800000...
c++分层最短路(洛谷飞行路线)acwing版
分层最短路算法是在SPFA算法的基础上,将每个点分成若干层,从而使得每个点之间的转移只在同一层次或上下两个相邻层次之间进行,减少了每轮的迭代次数,优化了算法的效率。 #include <iostream> #include <cstdio> #inc…...
Python bs4 BeautifulSoup库使用记录
目录 介绍 安装 初始化 解析器 使用方法 优势 Python标准库 lxml HTML lxml XML html5lib 格式化输出 对象 tag Name 多值属性 其他方法 NavigableString BeautifulSoup Comment 遍历 子节点 父节点 兄弟节点 回退和前进 搜索 过滤器 字符串 正则表达…...
Jmeter系列-插件安装(5)
前言 jmeter4.0以上,如现在最新的5.2.1版本是有集成插件的只需要在官网下载 plugins-manager.jar 包,放在jmeter安装路径的lib/ext目录下即可使用:https://jmeter-plugins.org/install/Install/但并不能满足所有需求,仍然需要安装…...
spring aop源码解析
spring知识回顾 spring的两个重要功能:IOC、AOP,在ioc容器的初始化过程中,会触发2种处理器的调用, 前置处理器(BeanFactoryPostProcessor)后置处理器(BeanPostProcessor)。 前置处理器的调用时机是在容器基本创建完成时ÿ…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...
【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...
Frozen-Flask :将 Flask 应用“冻结”为静态文件
Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是:将一个 Flask Web 应用生成成纯静态 HTML 文件,从而可以部署到静态网站托管服务上,如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...
【Go】3、Go语言进阶与依赖管理
前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课,做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程,它的核心机制是 Goroutine 协程、Channel 通道,并基于CSP(Communicating Sequential Processes࿰…...
深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南
🚀 C extern 关键字深度解析:跨文件编程的终极指南 📅 更新时间:2025年6月5日 🏷️ 标签:C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言🔥一、extern 是什么?&…...
NPOI操作EXCEL文件 ——CAD C# 二次开发
缺点:dll.版本容易加载错误。CAD加载插件时,没有加载所有类库。插件运行过程中用到某个类库,会从CAD的安装目录找,找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库,就用插件程序加载进…...
如何应对敏捷转型中的团队阻力
应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中,明确沟通敏捷转型目的尤为关键,团队成员只有清晰理解转型背后的原因和利益,才能降低对变化的…...
小木的算法日记-多叉树的递归/层序遍历
🌲 从二叉树到森林:一文彻底搞懂多叉树遍历的艺术 🚀 引言 你好,未来的算法大神! 在数据结构的世界里,“树”无疑是最核心、最迷人的概念之一。我们中的大多数人都是从 二叉树 开始入门的,它…...
react菜单,动态绑定点击事件,菜单分离出去单独的js文件,Ant框架
1、菜单文件treeTop.js // 顶部菜单 import { AppstoreOutlined, SettingOutlined } from ant-design/icons; // 定义菜单项数据 const treeTop [{label: Docker管理,key: 1,icon: <AppstoreOutlined />,url:"/docker/index"},{label: 权限管理,key: 2,icon:…...
使用VMware克隆功能快速搭建集群
自己搭建的虚拟机,后续不管是学习java还是大数据,都需要集群,java需要分布式的微服务,大数据Hadoop的计算集群,如果从头开始搭建虚拟机会比较费时费力,这里分享一下如何使用克隆功能快速搭建一个集群 先把…...
