时钟

时序逻辑电路的动力, 周期性的输出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]判断最终输出在高四位还是低四位, 记录为val1val2
代码实现

`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

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

SR锁存器的真值表

在这里插入图片描述
SR输入都是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锁存器的两个输入变为一个输入, 这样就可以避免将SR造成相同的输入, 这种也叫电平触发, 当时钟为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