时钟
时序逻辑电路的动力, 周期性的输出0或者1

下图时钟周期是0.05, 对应的频率是20HZ

- 时钟可以同步不同的部件
- 控制电路
- 时序控制
一位多路选择器的实现

从多路输入中选择一个作为输出
代码实现
`ifndef MUX_V
`define MUX_V
`include "a_not.v"
`include "a_and.v"
`include "a_or.v"
module mux (output o, input a, b, input sel);
wire n_sel;
a_not not1(n_sel, sel);
wire val1, val2;
a_and and1(val1, a, n_sel);
a_and and2(val2, b, sel);
a_or or1(o, val1, val2);
endmodule;
`endif
测试
`include "mux.v"
module mux_tb;
reg a, b, sel;
wire out;
mux obj(out, a, b, sel);
initial begin
// 将 $monitor 放在最开始,确保能监控到所有变化
$monitor("Time=%0t: a=%b, b=%b, sel=%b, out=%b", $time, a, b, sel, out);
a = 0; b = 0; sel = 0;#10;
a = 0; b = 0; sel = 1;#10;
a = 0; b = 1; sel = 0;#10;
a = 0; b = 1; sel = 1;#10;
a = 1; b = 0; sel = 0;#10;
a = 1; b = 0; sel = 1;#10;
a = 1; b = 1; sel = 0;#10;
a = 1; b = 1; sel = 1;#10;
$finish;
end
endmodule
16位多路选择器的实现
输入输出都是16位
代码实现
`ifndef MUX16_V
`define MUX16_V
`include "mux.v"
module mux16(output [15:0] out, input [15:0] a, b, input sel);
mux m0(out[0], a[0], b[0], sel);
mux m1(out[1], a[1], b[1], sel);
mux m2(out[2], a[2], b[2], sel);
mux m3(out[3], a[3], b[3], sel);
mux m4(out[4], a[4], b[4], sel);
mux m5(out[5], a[5], b[5], sel);
mux m6(out[6], a[6], b[6], sel);
mux m7(out[7], a[7], b[7], sel);
mux m8(out[8], a[8], b[8], sel);
mux m9(out[9], a[9], b[9], sel);
mux m10(out[10], a[10], b[10], sel);
mux m11(out[11], a[11], b[11], sel);
mux m12(out[12], a[12], b[12], sel);
mux m13(out[13], a[13], b[13], sel);
mux m14(out[14], a[14], b[14], sel);
mux m15(out[15], a[15], b[15], sel);
endmodule;
`endif
测试
`include "mux16.v"
module mux16_tb;
reg [15:0] a, b;
reg sel;
wire [15:0] out;
mux16 dut(out, a, b, sel);
initial begin
$monitor("Time=%0t: a=%h, b=%h, sel=%b, out=%h", $time, a, b, sel, out);
// 测试用例1: sel=0时选择a
a = 16'h0000; b = 16'hFFFF; sel = 0; #10;
// 测试用例2: sel=1时选择b
a = 16'h0000; b = 16'hFFFF; sel = 1; #10;
// 测试用例3: 交替模式测试
a = 16'hAAAA; b = 16'h5555; sel = 0; #10;
a = 16'hAAAA; b = 16'h5555; sel = 1; #10;
// 测试用例4: 随机值测试
a = 16'h1234; b = 16'h5678; sel = 0; #10;
a = 16'h1234; b = 16'h5678; sel = 1; #10;
// 测试用例5: 边界值测试
a = 16'h0000; b = 16'h0001; sel = 0; #10;
a = 16'h0000; b = 16'h0001; sel = 1; #10;
// 测试用例6: 全1和全0测试
a = 16'hFFFF; b = 16'h0000; sel = 0; #10;
a = 16'hFFFF; b = 16'h0000; sel = 1; #10;
$finish;
end
endmodule
4Way/8Way 选择器的实现

四路选择器代码实现
`ifndef mux4way16_V
`define mux4way16_V
`include "mux16.v"
module mux4way16(output [15:0] o, input [15:0] a, b, c, d, input [1:0] sel);
wire [15:0] val1, val2;
mux16 m0(val1, a, b, sel[0]);
mux16 m1(val2, c, d, sel[0]);
mux16 m2(o, val1, val2, sel[1]);
endmodule;
`endif
测试
`include "mux4way16.v"
module mux4way16_tb;
reg [15:0] a, b, c, d;
reg [1:0] sel;
wire [15:0] out;
mux4way16 dut(out, a, b, c, d, sel);
initial begin
$monitor("Time=%0t: a=%h, b=%h, c=%h, d=%h, sel=%b, out=%h",
$time, a, b, c, d, sel, out);
// 测试用例1: sel=00时选择a
a = 16'h0000; b = 16'h1111; c = 16'h2222; d = 16'h3333; sel = 2'b00; #10;
// 测试用例2: sel=01时选择b
a = 16'h0000; b = 16'h1111; c = 16'h2222; d = 16'h3333; sel = 2'b01; #10;
// 测试用例3: sel=10时选择c
a = 16'h0000; b = 16'h1111; c = 16'h2222; d = 16'h3333; sel = 2'b10; #10;
// 测试用例4: sel=11时选择d
a = 16'h0000; b = 16'h1111; c = 16'h2222; d = 16'h3333; sel = 2'b11; #10;
// 测试用例5: 交替模式测试
a = 16'hAAAA; b = 16'hBBBB; c = 16'hCCCC; d = 16'hDDDD;
sel = 2'b00; #10;
sel = 2'b01; #10;
sel = 2'b10; #10;
sel = 2'b11; #10;
// 测试用例6: 随机值测试
a = 16'h1234; b = 16'h5678; c = 16'h9ABC; d = 16'hDEF0;
sel = 2'b00; #10;
sel = 2'b01; #10;
sel = 2'b10; #10;
sel = 2'b11; #10;
// 测试用例7: 边界值测试
a = 16'h0000; b = 16'h0001; c = 16'hFFFE; d = 16'hFFFF;
sel = 2'b00; #10;
sel = 2'b01; #10;
sel = 2'b10; #10;
sel = 2'b11; #10;
// 测试用例8: 全1和全0测试
a = 16'h0000; b = 16'hFFFF; c = 16'h0000; d = 16'hFFFF;
sel = 2'b00; #10;
sel = 2'b01; #10;
sel = 2'b10; #10;
sel = 2'b11; #10;
$finish;
end
endmodule
八路选择器代码实现
`ifndef mux8way16_V
`define mux8way16_V
`include "mux4way16.v"
`include "mux16.v"
module mux8way16 (output [15:0] o, input [15:0] a, b, c, d, e, f, g, h, input [2:0] sel);
wire [15:0] val1, val2;
mux4way16 m0(val1, a, b, c, d, sel[1:0]);
mux4way16 m1(val2, e, f, g, h, sel[1:0]);
mux16 m2(o, val1, val2, sel[2]);
endmodule;
`endif
测试
`include "mux8way16.v"
module mux8way16_tb;
reg [15:0] a, b, c, d, e, f, g, h;
reg [2:0] sel;
wire [15:0] out;
mux8way16 dut(out, a, b, c, d, e, f, g, h, sel);
initial begin
$monitor("Time=%0t: a=%h, b=%h, c=%h, d=%h, e=%h, f=%h, g=%h, h=%h, sel=%b, out=%h",
$time, a, b, c, d, e, f, g, h, sel, out);
// 测试用例1: sel=000时选择a
a = 16'h0000; b = 16'h1111; c = 16'h2222; d = 16'h3333;
e = 16'h4444; f = 16'h5555; g = 16'h6666; h = 16'h7777;
sel = 3'b000; #10;
// 测试用例2: sel=001时选择b
a = 16'h0000; b = 16'h1111; c = 16'h2222; d = 16'h3333;
e = 16'h4444; f = 16'h5555; g = 16'h6666; h = 16'h7777;
sel = 3'b001; #10;
// 测试用例3: sel=010时选择c
a = 16'h0000; b = 16'h1111; c = 16'h2222; d = 16'h3333;
e = 16'h4444; f = 16'h5555; g = 16'h6666; h = 16'h7777;
sel = 3'b010; #10;
// 测试用例4: sel=011时选择d
a = 16'h0000; b = 16'h1111; c = 16'h2222; d = 16'h3333;
e = 16'h4444; f = 16'h5555; g = 16'h6666; h = 16'h7777;
sel = 3'b011; #10;
// 测试用例5: sel=100时选择e
a = 16'h0000; b = 16'h1111; c = 16'h2222; d = 16'h3333;
e = 16'h4444; f = 16'h5555; g = 16'h6666; h = 16'h7777;
sel = 3'b100; #10;
// 测试用例6: sel=101时选择f
a = 16'h0000; b = 16'h1111; c = 16'h2222; d = 16'h3333;
e = 16'h4444; f = 16'h5555; g = 16'h6666; h = 16'h7777;
sel = 3'b101; #10;
// 测试用例7: sel=110时选择g
a = 16'h0000; b = 16'h1111; c = 16'h2222; d = 16'h3333;
e = 16'h4444; f = 16'h5555; g = 16'h6666; h = 16'h7777;
sel = 3'b110; #10;
// 测试用例8: sel=111时选择h
a = 16'h0000; b = 16'h1111; c = 16'h2222; d = 16'h3333;
e = 16'h4444; f = 16'h5555; g = 16'h6666; h = 16'h7777;
sel = 3'b111; #10;
// 测试用例9: 交替模式测试
a = 16'hAAAA; b = 16'hBBBB; c = 16'hCCCC; d = 16'hDDDD;
e = 16'hEEEE; f = 16'hFFFF; g = 16'h9999; h = 16'h8888;
sel = 3'b000; #10;
sel = 3'b001; #10;
sel = 3'b010; #10;
sel = 3'b011; #10;
sel = 3'b100; #10;
sel = 3'b101; #10;
sel = 3'b110; #10;
sel = 3'b111; #10;
// 测试用例10: 随机值测试
a = 16'h1234; b = 16'h5678; c = 16'h9ABC; d = 16'hDEF0;
e = 16'h2468; f = 16'h1357; g = 16'hFACE; h = 16'hBEEF;
sel = 3'b000; #10;
sel = 3'b001; #10;
sel = 3'b010; #10;
sel = 3'b011; #10;
sel = 3'b100; #10;
sel = 3'b101; #10;
sel = 3'b110; #10;
sel = 3'b111; #10;
// 测试用例11: 边界值测试
a = 16'h0000; b = 16'h0001; c = 16'hFFFE; d = 16'hFFFF;
e = 16'h7FFF; f = 16'h8000; g = 16'hAAAA; h = 16'h5555;
sel = 3'b000; #10;
sel = 3'b001; #10;
sel = 3'b010; #10;
sel = 3'b011; #10;
sel = 3'b100; #10;
sel = 3'b101; #10;
sel = 3'b110; #10;
sel = 3'b111; #10;
$finish;
end
endmodule
多路复用器的实现

代码
`ifndef dmux_V
`define dmux_V
`include "a_not.v"
`include "a_and.v"
module dmux (output o1, o2, input val, input sel);
wire n_sel;
a_not a1(n_sel, sel);
a_and and1(o1, n_sel, val);
a_and and2(o2, sel, val);
endmodule;
`endif
测试
`include "dmux.v"
module dmux_tb;
reg val, sel;
wire o1, o2;
dmux obj(o1, o2, val, sel);
initial begin
$monitor("Time=%0t: val=%b, sel=%b, o1=%b, o2=%b", $time, val, sel, o1, o2);
val = 0; sel = 0; #10;
val = 0; sel = 1; #10;
val = 1; sel = 0; #10;
val = 1; sel = 1; #10;
$finish;
end
endmodule
4Way/8Way多路复用器实现
代码
`ifndef dmux4way_V
`define dmux4way_V
`include "a_not.v"
module dmux4way (output a, b, c, d, input val, input [1:0] sel);
wire n_sel0, n_sel1;
a_not not1(n_sel0, sel[0]);
a_not not2(n_sel1, sel[1]);
assign a = val & n_sel1 & n_sel0;
assign b = val & n_sel1 & sel[0];
assign c = val & sel[1] & n_sel0;
assign d = val & sel[1] & sel[0];
endmodule
`endif
测试
`include "dmux4way.v"
module dmux4way_tb;
reg val;
reg [1:0] sel;
wire a, b, c, d;
dmux4way dut(a, b, c, d, val, sel);
initial begin
$monitor("Time=%0t: val=%b, sel=%b, a=%b, b=%b, c=%b, d=%b",
$time, val, sel, a, b, c, d);
// 测试所有选择情况
val = 1'b0; sel = 2'b00; #10;
val = 1'b0; sel = 2'b01; #10;
val = 1'b0; sel = 2'b10; #10;
val = 1'b0; sel = 2'b11; #10;
val = 1'b1; sel = 2'b00; #10;
val = 1'b1; sel = 2'b01; #10;
val = 1'b1; sel = 2'b10; #10;
val = 1'b1; sel = 2'b11; #10;
$finish;
end
endmodule
8Way多路复用器的实现
使用最高位sel[2]判断最终输出在高四位还是低四位, 记录为val1和val2
代码实现
`ifndef DMUX8WAY_V
`define DMUX8WAY_V
`include "dmux.v"
`include "dmux4way.v"
module dmux8way(output a, b, c, d, e, f, g, h, input val, input [2:0] sel);
wire val1, val2;
dmux dmux1(val1, val2, val, sel[2]);
dmux4way way1(a, b, c, d, val1, sel[1:0]);
dmux4way way2(e, f, g, h, val2, sel[1:0]);
endmodule
`endif
测试
`timescale 1ns/1ps
`include "dmux8way.v"
module dmux8way_tb;
reg val;
reg [2:0] sel;
wire a, b, c, d, e, f, g, h;
// 实例化被测模块
dmux8way uut(
.a(a), .b(b), .c(c), .d(d),
.e(e), .f(f), .g(g), .h(h),
.val(val), .sel(sel)
);
initial begin
// 初始化
$display("Starting dmux8way testbench...");
val = 1'b1;
// 测试所有选择情况
for (sel = 0; sel < 8; sel = sel + 1) begin
#10;
$display("sel=%b, outputs=%b%b%b%b%b%b%b%b",
sel, a, b, c, d, e, f, g, h);
end
// 添加额外的延迟确保所有信号稳定
#20;
$display("Test completed successfully!");
$finish; // 确保程序终止
end
endmodule
SR锁存器存储一位数据
使用两个或非门实现SR锁存器

第一个开关是set, 第二个开关是reset
- 初始状态电灯是关闭
- 接通
set开关, 第一个或非门输出变为0, 第二个或非门输出为1, 电灯点亮, 第二个或非门的输出又作为第一个或非门的输入 - 将
set断开, 发现第一个或非门依旧有一个输入是1, 实现了存储一位数据的功能 - 将
reset开关闭合, 电路被重置到第一个状态
SR锁存器的真值表

当S和R输入都是1, 不符合SR锁存器的设置, 一般要避免这种情况
一般使用时钟控制SR锁存器, 当时钟是1可以进行操作, 时钟是0保持上一个时钟的状态

代码实现
`ifndef SRFF_V
`define SRFF_V
`include "a_and.v"
`include "a_nor.v"
module srff (output q, q_not, input r, c, s);
wire new_s, new_r;
a_and and1(new_s, s, c);
a_and and2(new_r, r, c);
a_nor nor1(q, new_r, q_not);
a_nor nor2(q_not, new_s, q);
endmodule;
`endif
测试
`include "srff.v"
module srff_tb;
reg r, s, c;
wire q, q_not;
// 实例化SR锁存器,正确连接端口
srff obj(q, q_not, r, c, s);
initial begin
$monitor("Time=%0t: c=%b, s=%b, r=%b, q=%b, q_not=%b", $time, c, s, r, q, q_not);
// 初始化
c = 0; s = 0; r = 0; #10;
// 测试时钟为低电平时,输入变化不影响输出
c = 0; s = 1; r = 0; #10;
c = 0; s = 0; r = 1; #10;
c = 1; s = 1; r = 0; #10; // 置位
c = 1; s = 0; r = 0; #10; // 保持
c = 1; s = 0; r = 1; #10; // 复位
c = 1; s = 0; r = 0; #10; // 保持
// 测试禁止状态 (s=1, r=1)
c = 1; s = 1; r = 1; #10;
// 时钟下降沿后测试保持
c = 0; s = 1; r = 0; #10;
c = 0; s = 0; r = 1; #10;
$finish;
end
endmodule
D锁存器
就是将SR锁存器的两个输入变为一个输入, 这样就可以避免将S和R造成相同的输入, 这种也叫电平触发, 当时钟为1的时候, 输出等于输入, 当时钟是0, 保持原来的值


边沿触发的D触发器
时钟从0变成1, 输出等于输入, 其他情况输出不受输入影响

实际就是由两个D触发器构成, 前面的D触发器是时钟在0的时候存储数据, 后面的D触发器是时钟在1的时候存储数据
假设当前时钟是0, 数据为1, 前面的触发器将1存储, 此时下一时刻的时钟信号变为1, 前面的触发器将数据释放并且置0, 后面的触发器将前面触发器释放的数据进行存储, 这样就实现了上升沿的触发器
D触发器的实现

实际使用过程中, 添加一个load, 当load == 0的时候, 输入是原来的输出, 否则才能对该锁存器进行数据写入的操作
代码实现
`ifndef DFF_V
`define DFF_V
`include "a_not.v"
`include "mux.v"
`include "a_and.v"
`include "a_nor.v"
`include "srff.v"
module dff(output q, input d, c, load);
wire val;
mux mux1(val, q, d, load);
wire val_not, c_not;
a_not not1(val_not, val);
a_not not2(c_not, c);
wire tmp, tmp_not, q_not;
srff srff1(tmp, tmp_not, val, c_not, val_not);
srff srff2(q, q_not, tmp, c, tmp_not);
endmodule;
`endif
测试
`include "dff.v"
module dff_tb;
reg in, clk, load;
wire out, out1;
// 实例化D触发器
dff obj(out, in, clk, load);
// 时钟生成:每20个时间单位翻转一次
always #20 clk = ~clk;
initial begin
// 初始化VCD文件用于波形查看
$dumpfile("dff.vcd");
$dumpvars(0, dff_tb);
// 初始化信号
clk = 0;
in = 1;
load = 1;
// 采用第一段代码的测试序列
#10
#10
#10
in = 0;
#10
#10
#10
#10
load = 0;
#10
in = 1;
#10
#10 $finish;
end
initial begin
// 监控信号变化,使用第一段代码的格式
$monitor($time,,,"in=%d clk=%d load=%d out=%d", in, clk, load, out);
end
endmodule
16位寄存器
将16个上述的触发器构造起来变成一个16位的寄存器
代码实现
`ifndef register16_V
`define register16_V
`include "dff.v"
module register16(output [15:0] out, input [15:0] d, input c, load);
dff dff0(out[0], d[0], c, load);
dff dff1(out[1], d[1], c, load);
dff dff2(out[2], d[2], c, load);
dff dff3(out[3], d[3], c, load);
dff dff4(out[4], d[4], c, load);
dff dff5(out[5], d[5], c, load);
dff dff6(out[6], d[6], c, load);
dff dff7(out[7], d[7], c, load);
dff dff8(out[8], d[8], c, load);
dff dff9(out[9], d[9], c, load);
dff dff10(out[10], d[10], c, load);
dff dff11(out[11], d[11], c, load);
dff dff12(out[12], d[12], c, load);
dff dff13(out[13], d[13], c, load);
dff dff14(out[14], d[14], c, load);
dff dff15(out[15], d[15], c, load);
endmodule;
`endif
测试
`include "register16.v"
module register16_tb;
reg [15:0] d;
reg c, load;
wire [15:0] out;
// 实例化16位寄存器
register16 obj(out, d, c, load);
// 时钟生成:每20个时间单位翻转一次
always #20 c = ~c;
initial begin
// 初始化VCD文件用于波形查看
$dumpfile("register16.vcd");
$dumpvars(0, register16_tb);
// 初始化信号
c = 0;
d = 16'h0000;
load = 1;
// 测试序列
#10
d = 16'hAAAA; // 1010101010101010
#10
#10
d = 16'h5555; // 0101010101010101
#10
#10
#10
#10
load = 0; // 禁用加载
#10
d = 16'hFFFF; // 数据变化但load=0,输出不应改变
#10
#10
load = 1; // 重新启用加载
d = 16'h1234; // 新数据
#10
#10 $finish;
end
initial begin
// 监控信号变化
$monitor($time,,,"d=%h c=%d load=%d out=%h", d, c, load, out);
end
endmodule
RAM8随机存储器
将八个寄存器组合成一个RAM8, 通过地址来寻址, 一个二进制数代表一个16位地址
load == 1并且当前波形是上升沿写入数据, 否则是读取数据, address控制写入或者读取的地址
代码实现
`ifndef RAM8_V
`define RAM8_V
`include "register16.v"
`include "dmux8way.v"
`include "mux8way16.v"
module ram8(output [15:0] o, input [15:0] d, input [2:0] address, input c, load);
wire l0, l1, l2, l3, l4, l5, l6, l7;
dmux8way way1(l0, l1, l2, l3, l4, l5, l6, l7, load, address);
wire [15:0] r0, r1, r2, r3, r4, r5, r6, r7;
register16 reg0(r0, d, c, l0);
register16 reg1(r1, d, c, l1);
register16 reg2(r2, d, c, l2);
register16 reg3(r3, d, c, l3);
register16 reg4(r4, d, c, l4);
register16 reg5(r5, d, c, l5);
register16 reg6(r6, d, c, l6);
register16 reg7(r7, d, c, l7);
mux8way16 way2(o, r0, r1, r2, r3, r4, r5, r6, r7, address);
endmodule;
`endif
测试
`include "ram8.v"
module ram8_tb;
reg [15:0] d;
reg [2:0] address;
reg c, load;
wire [15:0] out;
// 实例化RAM8模块
ram8 obj(out, d, address, c, load);
// 时钟生成:每20个时间单位翻转一次
always #20 c = ~c;
initial begin
// 初始化VCD文件用于波形查看
$dumpfile("ram8.vcd");
$dumpvars(0, ram8_tb);
// 初始化信号
c = 0;
d = 16'h0000;
address = 3'b000;
load = 0;
// 测试序列
#10
// 测试1:向不同地址写入数据
$display("=== 写入测试 ===");
load = 1; // 启用写入
// 向地址0写入数据
address = 3'b000;
d = 16'hAAAA;
#40
// 向地址1写入数据
address = 3'b001;
d = 16'h5555;
#40
// 向地址2写入数据
address = 3'b010;
d = 16'h1234;
#40
// 向地址3写入数据
address = 3'b011;
d = 16'h5678;
#40
// 向地址4写入数据
address = 3'b100;
d = 16'h9ABC;
#40
// 向地址5写入数据
address = 3'b101;
d = 16'hDEF0;
#40
// 向地址6写入数据
address = 3'b110;
d = 16'h2468;
#40
// 向地址7写入数据
address = 3'b111;
d = 16'h1357;
#40
// 测试2:读取不同地址的数据(load=0)
$display("=== 读取测试 ===");
load = 0; // 禁用写入,启用读取
// 读取地址0
address = 3'b000;
#40
// 读取地址1
address = 3'b001;
#40
// 读取地址2
address = 3'b010;
#40
// 读取地址3
address = 3'b011;
#40
// 读取地址4
address = 3'b100;
#40
// 读取地址5
address = 3'b101;
#40
// 读取地址6
address = 3'b110;
#40
// 读取地址7
address = 3'b111;
#40
// 测试3:验证写入时读取功能
$display("=== 写入时读取测试 ===");
load = 1; // 启用写入
// 向地址0写入新数据,同时验证输出是否正确
address = 3'b000;
d = 16'hFFFF;
#40
// 读取其他地址,验证数据是否保持
load = 0;
address = 3'b001;
#40
address = 3'b010;
#40
// 测试4:验证load=0时数据不变
$display("=== 写保护测试 ===");
address = 3'b000;
#20
load = 0; // 禁用写入
d = 16'h9999; // 数据变化但load=0,存储器不应改变
#40
load = 1; // 重新启用写入
d = 16'h7777; // 新数据应该被写入
#40
// 最终读取验证所有数据
$display("=== 最终验证 ===");
load = 0;
for (integer i = 0; i < 8; i = i + 1) begin
address = i;
#40;
end
#20 $finish;
end
initial begin
// 监控信号变化
$monitor($time,,,"addr=%b d=%h c=%d load=%d out=%h",
address, d, c, load, out);
end
endmodule
RAM64随机存储器
地址范围[5:0], 使用[5:3]段地址判断在哪个RAM8, 剩余直接调用RAM8模块
代码实现
`ifndef RAM64_V
`define RAM64_V
`include "ram8.v"
`include "dmux8way.v"
`include "mux8way16.v"
module ram64(output [15:0] o, input [15:0] d, input [5:0] address, input c, load);
wire l0, l1, l2, l3, l4, l5, l6, l7;
dmux8way way1(l0, l1, l2, l3, l4, l5, l6, l7, load, address[5:3]);
wire [15:0] r0, r1, r2, r3, r4, r5, r6, r7;
ram8 reg0(r0, d, address[2:0], c, l0);
ram8 reg1(r1, d, address[2:0], c, l1);
ram8 reg2(r2, d, address[2:0], c, l2);
ram8 reg3(r3, d, address[2:0], c, l3);
ram8 reg4(r4, d, address[2:0], c, l4);
ram8 reg5(r5, d, address[2:0], c, l5);
ram8 reg6(r6, d, address[2:0], c, l6);
ram8 reg7(r7, d, address[2:0], c, l7);
mux8way16 way2(o, r0, r1, r2, r3, r4, r5, r6, r7, address[5:3]);
endmodule;
`endif
测试
`include "ram64.v"
module ram64_tb;
reg [15:0] d;
reg [5:0] address;
reg c, load;
wire [15:0] out;
// Instantiate RAM64 module
ram64 obj(out, d, address, c, load);
// Clock generation: toggle every 20 time units
always #20 c = ~c;
initial begin
// Initialize VCD file for waveform viewing
$dumpfile("ram64.vcd");
$dumpvars(0, ram64_tb);
// Initialize signals
c = 0;
d = 16'h0000;
address = 6'b000000;
load = 0;
// Test sequence
#10
// Test 1: Write to same offset in different RAM8 modules
$display("=== Test 1: Different RAM8 modules, same offset ===");
load = 1; // Enable write
// Write to address 0 of 8 different RAM8 modules
address = 6'b000000; // RAM8 module 0, address 0
d = 16'h1111;
#40
address = 6'b001000; // RAM8 module 1, address 0
d = 16'h2222;
#40
address = 6'b010000; // RAM8 module 2, address 0
d = 16'h3333;
#40
address = 6'b011000; // RAM8 module 3, address 0
d = 16'h4444;
#40
address = 6'b100000; // RAM8 module 4, address 0
d = 16'h5555;
#40
address = 6'b101000; // RAM8 module 5, address 0
d = 16'h6666;
#40
address = 6'b110000; // RAM8 module 6, address 0
d = 16'h7777;
#40
address = 6'b111000; // RAM8 module 7, address 0
d = 16'h8888;
#40
// Test 2: Write to different addresses in same RAM8 module
$display("=== Test 2: Same RAM8 module, different addresses ===");
// Write multiple addresses in RAM8 module 0
address = 6'b000001; // RAM8 module 0, address 1
d = 16'hAAAA;
#40
address = 6'b000010; // RAM8 module 0, address 2
d = 16'hBBBB;
#40
address = 6'b000011; // RAM8 module 0, address 3
d = 16'hCCCC;
#40
address = 6'b000100; // RAM8 module 0, address 4
d = 16'hDDDD;
#40
address = 6'b000101; // RAM8 module 0, address 5
d = 16'hEEEE;
#40
address = 6'b000110; // RAM8 module 0, address 6
d = 16'hFFFF;
#40
address = 6'b000111; // RAM8 module 0, address 7
d = 16'h9999;
#40
// Test 3: Read verification
$display("=== Test 3: Read verification ===");
load = 0; // Disable write, enable read
// Verify address 0 of different RAM8 modules
address = 6'b000000; // Should output 1111
#40
address = 6'b001000; // Should output 2222
#40
address = 6'b010000; // Should output 3333
#40
address = 6'b011000; // Should output 4444
#40
address = 6'b100000; // Should output 5555
#40
address = 6'b101000; // Should output 6666
#40
address = 6'b110000; // Should output 7777
#40
address = 6'b111000; // Should output 8888
#40
// Verify all addresses in RAM8 module 0
address = 6'b000000; // address 0: 1111
#40
address = 6'b000001; // address 1: AAAA
#40
address = 6'b000010; // address 2: BBBB
#40
address = 6'b000011; // address 3: CCCC
#40
address = 6'b000100; // address 4: DDDD
#40
address = 6'b000101; // address 5: EEEE
#40
address = 6'b000110; // address 6: FFFF
#40
address = 6'b000111; // address 7: 9999
#40
// Test 4: Boundary address test
$display("=== Test 4: Boundary address test ===");
load = 1;
// Test minimum address
address = 6'b000000;
d = 16'h1234;
#40
// Test maximum address
address = 6'b111111;
d = 16'h5678;
#40
// Test middle address
address = 6'b100011; // RAM8 module 4, address 3
d = 16'h9ABC;
#40
load = 0;
// Verify boundary addresses
address = 6'b000000;
#40
address = 6'b111111;
#40
address = 6'b100011;
#40
// Test 5: Write protection test
$display("=== Test 5: Write protection test ===");
address = 6'b010101; // RAM8 module 2, address 5
#20
load = 0; // Disable write
d = 16'hFFFF; // Data changes but load=0, memory should not change
#40
load = 1; // Re-enable write
d = 16'h5555; // New data should be written
#40
// Final comprehensive verification
$display("=== Final comprehensive verification ===");
load = 0;
// Quick scan of key addresses
address = 6'b000000;
#20
address = 6'b000111;
#20
address = 6'b111000;
#20
address = 6'b111111;
#20
address = 6'b100011;
#20
#20 $finish;
end
initial begin
// Monitor signal changes
$monitor($time,,,"addr=%6b d=%h c=%d load=%d out=%h",
address, d, c, load, out);
end
endmodule
RAM512随机存储器
原理与上述一致, 调用8个RAM64实现
代码实现
`ifndef RAM512_V
`define RAM512_V
`include "ram64.v"
`include "dmux8way.v"
`include "mux8way16.v"
module ram512(output [15:0] o, input [15:0] d, input [8:0] address, input c, load);
wire l0, l1, l2, l3, l4, l5, l6, l7;
dmux8way way1(l0, l1, l2, l3, l4, l5, l6, l7, load, address[8:6]);
wire [15:0] r0, r1, r2, r3, r4, r5, r6, r7;
ram64 reg0(r0, d, address[5:0], c, l0);
ram64 reg1(r1, d, address[5:0], c, l1);
ram64 reg2(r2, d, address[5:0], c, l2);
ram64 reg3(r3, d, address[5:0], c, l3);
ram64 reg4(r4, d, address[5:0], c, l4);
ram64 reg5(r5, d, address[5:0], c, l5);
ram64 reg6(r6, d, address[5:0], c, l6);
ram64 reg7(r7, d, address[5:0], c, l7);
mux8way16 way2(o, r0, r1, r2, r3, r4, r5, r6, r7, address[8:6]);
endmodule;
`endif
测试
`include "ram512.v"
module ram512_tb;
reg [15:0] d;
reg [8:0] address;
reg c, load;
wire [15:0] o;
ram512 uut(o, d, address, c, load);
always #20 c = ~c;
initial begin
$dumpfile("ram512.vcd");
$dumpvars(0, ram512_tb);
c = 0;
d = 16'h0000;
address = 9'b000000000;
load = 0;
#10;
// Test 1: Write to different RAM64 modules
$display("=== Test 1: Write to different RAM64 modules ===");
load = 1;
address = 9'b000000000;
d = 16'h1111;
#40;
address = 9'b001000000;
d = 16'h2222;
#40;
address = 9'b010000000;
d = 16'h3333;
#40;
address = 9'b011000000;
d = 16'h4444;
#40;
address = 9'b100000000;
d = 16'h5555;
#40;
address = 9'b101000000;
d = 16'h6666;
#40;
address = 9'b110000000;
d = 16'h7777;
#40;
address = 9'b111000000;
d = 16'h8888;
#40;
// Test 2: Different addresses within RAM64 module 0
$display("=== Test 2: Different addresses within RAM64 module 0 ===");
address = 9'b000000001;
d = 16'hAAAA;
#40;
address = 9'b000000010;
d = 16'hBBBB;
#40;
address = 9'b000000011;
d = 16'hCCCC;
#40;
address = 9'b000000100;
d = 16'hDDDD;
#40;
// Test 3: Read verification
$display("=== Test 3: Read verification ===");
load = 0;
address = 9'b000000000;
#40;
address = 9'b001000000;
#40;
address = 9'b010000000;
#40;
address = 9'b011000000;
#40;
address = 9'b100000000;
#40;
address = 9'b101000000;
#40;
address = 9'b110000000;
#40;
address = 9'b111000000;
#40;
address = 9'b000000000;
#40;
address = 9'b000000001;
#40;
address = 9'b000000010;
#40;
address = 9'b000000011;
#40;
address = 9'b000000100;
#40;
// Test 4: Boundary address test
$display("=== Test 4: Boundary address test ===");
load = 1;
address = 9'b000000000;
d = 16'h1234;
#40;
address = 9'b111111111;
d = 16'h5678;
#40;
address = 9'b100000011;
d = 16'h9ABC;
#40;
load = 0;
address = 9'b000000000;
#40;
address = 9'b111111111;
#40;
address = 9'b100000011;
#40;
// Test 5: Write protection test
$display("=== Test 5: Write protection test ===");
address = 9'b010000101;
#20;
load = 0;
d = 16'hFFFF;
#40;
load = 1;
d = 16'h5555;
#40;
// Final verification
$display("=== Final verification ===");
load = 0;
address = 9'b000000000;
#20;
address = 9'b111111111;
#20;
address = 9'b100000011;
#20;
#20 $finish;
end
initial begin
$monitor("Time=%0t addr=%9b d=%h c=%b load=%b out=%h",
$time, address, d, c, load, o);
end
endmodule
RAM16K随机存储器
代码实现
代码中reg[15:0] m[0:2**14-1]; , 的意思是声明寄存器组, 地址范围[0, 2 ^ 13]
`ifndef RAM16K_V
`define RAM16K_V
module RAM16K(
output[15:0] out,
input[15:0] d,
input clock,
input load,
input[13:0] address
);
reg[15:0] m[0:2**14-1];
assign out = m[address];
// 时序逻辑:在时钟上升沿执行写入操作
always @(posedge clock) begin
if (load)
m[address] = d;
end
endmodule
`endif

京公网安备 11010502036488号