设计 module single_port_sync_ram #(参数ADDR_WIDTH =4,参数DATA_WIDTH =32,参数DEPTH =16)(输入时钟,输入[ADDR_WIDTH-1:0] addr, inout [DATA_WIDTH-1:0] 数据, 输入 cs, 输入 we, 输入 oe ); reg [DATA_WIDTH-1:0] tmp_data; reg [DATA_WIDTH-1:0] mem [DEPTH]; always @ (posedge clk) begin if (cs &we) mem[addr] <=data; end always @ (p
加法器是执行两个数字相加的数字组件。它是处理器 ALU 中的主要组件,用于递增地址、表索引、缓冲区指针以及许多其他需要添加的地方。 全加器将进位输入与其他输入二进制数相加,以产生和和进位输出。 真值表 A B Cin Cout 总和 0 0 0 0 0 0 0 1 0 1 0 1 0 0 1 0 1 1 1 0 1 0 0 0 1 1 0 1 1 0 1 1 0 1 0 1 1 1 1 1 设计 下面显示了一个 4 位加法器的例子,它通过信号 a 和 b 接受两个二进制数,信号 a 和 b 都是 4 位宽。由于加法器是一个组合电路,因此可以使用带有
什么是多路复用器或多路复用器? 多路复用器或 mux 简而言之,是一个数字元件,它根据选择信号将数据从 N 个输入之一传输到输出。下面显示的情况是当 N 等于 4 时。例如,一个 4 位多路复用器将有 N 个输入,每一个 4 位,其中每个输入都可以通过使用选择信号传输到输出。 sel 是一个 2 位输入,可以有四个值。选择线上的每个值都允许将其中一个输入发送到输出引脚。 sel a b c d out 0 3 7 1 9 3 1 3 7 1 9 7 2 3 7 1 9 1 3 3 7 1 9 9 4x1 多路复用器可以通过多种方式实现,这里您将看到两种最常见的方式: 使用assi
设计 模块 pr_en ( input [7:0] a, input [7:0] b, input [7:0] c, input [7:0] d,输入[1:0] sel,输出reg [7:0] out);总是@(a 或 b 或 c 或 d 或 sel) 开始 if (sel ==2b00) out <=a; else if (sel ==2b01) out <=b; else if (sel ==2b10) out <=c;否则出 <=d;结束模块 硬件原理图 测试平台 模块 tb_4to1_mux; reg [7:0] a; reg [7:0] b; reg [7:0] c;
在数字电子产品中,移位寄存器 是一个级联触发器,其中输出引脚 q 一个触发器的连接到下一个的数据输入引脚(d)。因为所有触发器都在同一个时钟上工作,所以存储在移位寄存器中的位数组将移位一位。例如,如果一个 5 位右移寄存器的初始值是 10110,并且移位寄存器的输入被绑定到 0,那么下一个模式将是 01011 和下一个 00101。 设计 该移位寄存器设计有五个输入和一个 n 位输出,并且该设计使用 parameter 进行参数化 MSB 表示移位寄存器的宽度。如果 n 为 4,则它成为一个 4 位移位寄存器。如果n为8,则成为8位移位寄存器。 这个移位寄存器有几个关键特性: 可以
设计 module gray_ctr # (参数 N =4) ( input clk, input rstn, output reg [N-1:0] out); reg [N-1:0] q;总是@ (posedge clk) begin if (!rstn) begin q <=0;出 <=0;结束其他开始 q <=q + 1; `ifdef FOR_LOOP for (int i =0; i
设计 module modN_ctr #(参数N =10,参数WIDTH =4)(输入clk,输入rstn,输出reg[WIDTH-1:0] out );总是@ (posedge clk) begin if (!rstn) begin out <=0; end else begin if (out ==N-1) out <=0;否则出 <=出 + 1;结束结束模块 测试平台 模块 tb;参数 N =10;参数宽度 =4;注册时钟;注册;线 [WIDTH-1:0] 输出; modN_ctr u0 ( .clk(clk), .rstn(rstn), .out(out));总是 #10 c
设计 module johnson_ctr #(parameter WIDTH=4) ( input clk, input rstn, output reg [WIDTH-1:0] out );总是@ (posedge clk) begin if (!rstn) out <=1;否则开始 [WIDTH-1] <=~out[0]; for (int i =0; i
设计 module ring_ctr #(parameter WIDTH=4) ( input clk, input rstn, output reg [WIDTH-1:0] out );总是@ (posedge clk) begin if (!rstn) out <=1;否则开始 [WIDTH-1] <=out[0]; for (int i =0; i
涟漪 counter 是一个异步计数器,其中除了第一个触发器之外的所有触发器都由前一个触发器的输出计时。 设计 模块dff(输入d,输入clk,输入rstn,输出reg q,输出qn);总是@ (posedge clk 或 negedge rstn) if (!rstn) q <=0;否则 q <=d;分配 qn =~q;endmodulemodule 纹波(输入时钟,输入 rstn,输出 [3:0] 输出);线 q0;线 qn0;线 q1;线 qn1;线 q2;线材qn2;线 q3;线材qn3; dff dff0 ( .d (qn0), .clk (clk), .rstn (rstn)
4 位计数器从 4b0000 开始递增到 4h1111,然后返回到 4b0000。只要有运行时钟和复位保持高电平,它就会一直计数。 当最终添加的最高有效位被丢弃时,就会发生翻转。当计数器达到最大值 4b1111 并再收到一个计数请求时,计数器尝试达到 5b10000,但由于它只能支持 4 位,因此将丢弃 MSB,结果为 0。 0000 0001 0010 ... 1110 1111 滚动到 0000 0001 ... 该设计包含两个输入,一个用于时钟,另一个用于低电平有效复位。低电平有效复位是指当复位引脚的值为 0 时设计被复位的复位。有一个 4 位输出被调用,它基本上提供计数器值。
触发器在时钟的正沿或负沿捕获其输入端的数据。需要注意的重要一点是,在时钟边沿之后直到下一个时钟边沿发生的任何数据都不会反映在输出中。 闩锁 另一方面,不会在时钟边缘捕获,而是只要使能引脚有效,输出就会跟随输入。 设计 在本例中,我们将构建一个具有三个输入和一个输出的锁存器。输入 d 代表可以是 0 或 1 的数据,rstn 代表低电平有效复位和 en 代表使能,用于使输入数据锁存到输出。复位为低电平仅意味着设计元素将在此输入变为 0 时复位,或者换句话说,复位在其值为低时有效。输出值 q 由输入 d 决定 , zh 和 rstn . module d_latch ( input d,
设计 模块 tff(输入时钟,输入 rstn,输入 t,输出 reg q);总是@ (posedge clk) 开始如果 (!rstn) q <=0;否则如果 (t) q <=~q;否则 q <=q;结束模块 测试平台 模块 tb;注册时钟;注册;注册 t; tff u0 ( .clk(clk), .rstn(rstn), .t(t), .q(q));总是 #5 clk =~clk;初始开始 {rstn, clk, t} <=0; $monitor (T=%0t rstn=%0b t=%0d q=%0d, $time, rstn, t, q);重复(2)@(posedge clk);
D触发器 是跟随输入引脚 d 的顺序元素 在时钟的给定边沿。 设计 #1:使用异步低电平有效复位 模块dff(输入d,输入rstn,输入clk,输出reg q);总是@ (posedge clk 或 negedge rstn) if (!rstn) q <=0;否则 q <=d;endmodule 硬件原理图 测试平台 模块 tb_dff;注册时钟;注册号;注册; reg [2:0] 延迟; dff dff0 ( .d(d), .rsnt (rstn), .clk (clk), .q (q)); // 始终生成时钟 #10 clk =~clk; // 测试用例初始开始 clk <
设计 模块 jk_ff(输入 j,输入 k,输入 clk,输出 q); reg q;总是@ (posedge clk) case ({j,k}) 2b00 :q <=q; 2b01 :q <=0; 2b10 :q <=1; 2b11 :q <=~q; endcaseendmodule 硬件原理图 测试平台 模块 tb_jk; reg j; reg k;注册时钟;总是 #5 clk =~clk; jk_ff jk0 ( .j(j), .k(k), .clk(clk), .q(q));初始开始 j <=0; k <=0; #5 j <=0; k <=1; #20 j <=1; k
最好从一个非常简单的例子开始,除了“Hello World!”之外,没有一个例子能达到最好的目的。 // 单行注释以双斜杠“//”开头// Verilog 代码总是写在模块内部,每个模块代表一个数字块带有一些功能模块 tb; // 初始块是另一种结构,通常用于初始化信号网络和仿真初始变量 // Verilog 支持在屏幕上显示信号值,以便设计人员可以调试他们的电路有什么问题 // 出于我们的目的,我们将简单地显示“ Hello World $display(Hello World!);endmodule 模块 称为 tb 的没有输入输出端口的模块作为模拟的顶层模块。 初始 块在时间
Verilog 具有系统任务和函数,可以打开文件、将值输出到文件中、从文件中读取值以及加载到其他变量和关闭文件。 打开和关闭文件 模块 tb; // 声明一个变量来存储文件处理程序整数 fd;初始开始 // 打开一个名为“my_file.txt”的新文件 // 具有“写”权限,并将文件 // 处理程序指针存储在变量“fd”中 fd =$fopen(my_file.txt, w ); // 关闭“fd”指向的文件句柄 $fclose(fd);结束模块 打开文件模式 参数 说明 r 或 rb 开放阅读 w 或 wb 创建一个新文件用于写入。如果文件存在,将其截断为零长度并覆盖它
默认时间刻度 尽管 Verilog 模块应该在模块之前定义一个时间刻度,但模拟器可能会插入一个默认时间刻度。可以使用系统任务 $printtimescale 打印在 Verilog 详细层次结构中的任何范围内应用的实际时间刻度 它接受范围作为参数。 模块 tb; initial begin // 打印此模块的时间刻度 $printtimescale(tb); // $printtimescale($root);结束模块 请注意,即使在此模块之前未放置时间刻度指令,模拟器最终还是应用了 1ns/1ns 时间刻度值。 模拟日志 (tb) 的运行时间尺度为 1ns / 1nsxmsim:
Verilog timescale 指令指定模拟的时间单位和精度。 Verilog $timeformat 系统函数指定%t $display 等显示语句中的格式说明符报告样式 和 $strobe . 语法 $timeformat(, , , ); unit_number 是所有`timescale中最小的时间精度 源代码中使用的指令 精度 表示当前时间刻度的小数位数 suffix_string 是在实时值旁边显示比例的选项 单元号 时间单位 -3 1ms -6 1us -9 1ns -12 1ps -15 1fs 示例 #1:1ns/1ps 以
Verilog 数学函数可用于代替常量表达式并支持整数 和真实 数学。 整数数学函数 函数 $clog2 返回给定参数的 log2 的上限。这通常用于计算寻址给定大小的内存所需的最小宽度。 例如,如果设计有 7 个并行加法器,则表示所有 7 个加法器所需的最小位数为 $clog2 7 产生 3。 module des #(parameter NUM_UNITS =7) // 使用这个系统函数有助于减少 // 这个模块的输入线数(输入[$clog2(NUM_UNITS)-1:0] active_unit);初始 $monitor(active_unit =%d, active_unit)
Verilog