代码如下

test文件

`timescale 1ns / 1ps

module sin_frecontrol_test(
    input sys_clk,       // 系统时钟 (97.65ns ≈ 10.24MHz)
    input rom_clk,       // ROM时钟
    input rst_n,         // 复位,低电平有效
    input ena,           // ROM使能端
    output reg [7:0] rom_data, // ROM输出数据
    output reg [7:0] rom_addr, // ROM地址
    input [4:0] fre,      // 频率控制字 (00001=1kHz, 10100=20kHz)
    input  [1:0] choose
);

// 内部寄存器
reg [31:0] clk_counter;
reg [31:0] clk_divider;

wire [7:0] rom_data_sin;
wire [7:0] rom_data_train;
wire [7:0] rom_data_square;
wire [7:0] rom_data_sawtooth;


// 计算时钟分频系数
always @(*) begin
    // 基础计算: (1/(freq*256)) / 97.65ns
    // 对于1kHz: 1/(1000*256) ≈ 3.906μs per sample → 3.906μs/97.65ns ≈ 40
    // 对于20kHz: 1/(20000*256) ≈ 195.3ns per sample → 195.3ns/97.65ns ≈ 2
    // 因此分频系数 = 40/fre (where fre=1 for 1kHz, fre=20 for 20kHz)
    clk_divider = 40 / (fre == 0 ? 1 : fre); // 防止除以0
end

// 地址生成逻辑
always @(posedge sys_clk or negedge rst_n) begin
    if(!rst_n) begin
        clk_counter <= 0;
        rom_addr <= 0;
    end else if(ena) begin
        if(clk_counter >= clk_divider - 1) begin
            clk_counter <= 0;
            rom_addr <= rom_addr + 1; // 自动在255回绕到0
        end else begin
            clk_counter <= clk_counter + 1;
        end
    end
end

// 实例化ROM
rom_sin rom_ip_sin (
    .clka(rom_clk),
    .addra(rom_addr),
    .douta(rom_data_sin),
    .ena(ena)
);

// 实例化ROM
rom_train rom_ip_train (
    .clka(rom_clk),
    .addra(rom_addr),
    .douta(rom_data_train),
    .ena(ena)
);
rom_square rom_ip_square (
    .clka(rom_clk),
    .addra(rom_addr),
    .douta(rom_data_square),
    .ena(ena)
);
// 实例化ROM
sawtooth rom_ip_sawtooth (
    .clka(rom_clk),
    .addra(rom_addr),
    .douta(rom_data_sawtooth),
    .ena(ena)
);
// 实例化ROM

always @(*) begin
    case (choose)
        2'b00: rom_data <= rom_data_sin;
        2'b01: rom_data <= rom_data_train;
        2'b10: rom_data <= rom_data_square;
        2'b11: rom_data <= rom_data_sawtooth;
        default: rom_data <= 8'b0;
    endcase
end

endmodule

testbench文件

`timescale 1ns / 1ps

module tb_sin;

// Inputs
reg sys_clk;
reg rom_clk;
reg rst_n;
wire [7:0] rom_data;
wire [7:0] rom_addr;
reg ena;
reg [4:0] fre;
reg [1:0] choose;

// Instantiate the Unit Under Test (UUT)
sin_frecontrol_test uut (
    .sys_clk(sys_clk),
    .rom_clk(rom_clk),
    .rst_n(rst_n),
    .rom_data(rom_data),
    .rom_addr(rom_addr),
    .ena(ena),
    .fre(fre),
    .choose(choose)
);

integer i;

initial begin
    // Initialize Inputs
    sys_clk = 0;
    rom_clk = 0;
    rst_n = 0;
    ena = 0;
    fre = 5'b00001; // 初始1kHz
    choose =2'b11;

    #50 ena = 1;
    #81 rst_n = 1;

    // 使用for循环测试不同频率
   
        
 

   
end

// 系统时钟生成 (97.65ns周期,对应20kHz时每个点195.3ns)
always #48.825 sys_clk = ~sys_clk;

// ROM时钟生成 (100MHz)
always #5 rom_clk = ~rom_clk;

// 监视信号变化
initial begin
    $monitor("Time = %tns, Freq = %0dkHz, Addr = %h", 
             $time, fre, rom_addr);
end

endmodule

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐