module data_error_injector (input clk, // 时钟信号,50MHzinput reset, // 复位信号,高有效input DIN_EN, // 数据输入使能,高有效input [7:0] ERROR_LEVEL, // 错误等级,8位output reg [7:0] DOUT, // 输出数据output reg DOUT_EN, // 数据输出使能,高有效output reg [31:0] frame_counter,// 帧计数输出信号output reg [9:0] byte_counter, // 字节计数output reg [9:0] byte_counter_w
);// 状态定义reg [1:0] current_state, next_state;localparam STATE_INIT = 2'b00;localparam STATE_STORE_FIRST_512 = 2'b01;localparam STATE_STORE_AND_READ = 2'b10;// RAM端口A的接口(用于写操作)reg [9:0] ram_addr_a; // RAM地址,10位地址线对应1024深度reg [7:0] ram_din_a; // RAM数据输入reg ram_we_a; // RAM写使能// RAM端口B的接口(用于读操作)reg [9:0] ram_addr_b; // RAM地址,10位地址线对应1024深度wire [7:0] ram_dout_b; // RAM数据输出// ROM的接口reg [9:0] rom_addr; // ROM地址wire [7:0] rom_dout; // ROM数据输出// 错误注入控制reg inject_error; // 是否注入错误reg [31:0] inject_frame; // 需要注入错误的帧号// 内部寄存器用于存储从ROM读取的数据
// reg [7:0] DIN; // 从ROM读取并存储到DIN寄存器// ROM实例化(通过Vivado生成的ROM IP核)blk_mem_gen_0 rom (.clka(clk), // 时钟信号.addra(rom_addr), // 地址信号.douta(rom_dout) // 数据输出);// 双端口RAM实例化(通过Vivado生成的RAM IP核)blk_mem_gen_1 ram (.clka(clk), // 写端口时钟.wea(ram_we_a), // 写端口写使能.addra(ram_addr_a), // 写端口地址.dina(ram_din_a), // 写端口数据输入.douta(), // 写端口数据输出 (未使用).clkb(clk), // 读端口时钟.web(1'b0), // 读端口写使能(置为0,表示仅读).addrb(ram_addr_b), // 读端口地址.dinb(8'b0), // 读端口数据输入(未使用).doutb(ram_dout_b) // 读端口数据输出);// 状态机逻辑always @(posedge clk or posedge reset) beginif (reset) begincurrent_state <= STATE_INIT;rom_addr <= 0;ram_addr_a <= 0;ram_addr_b <= 0;ram_we_a <= 0;byte_counter <= 0;byte_counter_w <= 0;frame_counter <= 0;DOUT_EN <= 0;DOUT <= 8'b0;inject_error <= 0;
// DIN <= 8'b0; // 初始化DIN寄存器end else begincurrent_state <= next_state;case (current_state)STATE_INIT: begin// 初始化,等待数据输入使能if (DIN_EN) beginnext_state <= STATE_STORE_FIRST_512;endendSTATE_STORE_FIRST_512: begin// 写入前512字节数据到RAMif (byte_counter_w < 512) begin
// DIN <= rom_dout;
// ram_din_a <= DIN;ram_din_a <=rom_dout;ram_we_a <= 1;ram_addr_a <= ram_addr_a+1;rom_addr <= rom_addr + 1;byte_counter_w <= byte_counter_w + 1;byte_counter <= byte_counter + 1;end else begin
// ram_we_a <= 0; // 停止写入next_state <= STATE_STORE_AND_READ; // 转入下一个状态ram_addr_b <= 0; // 准备从RAM地址0开始读取
// rom_addr <= 512; // ROM地址从512开始byte_counter_w <= 0; // 重置计数器byte_counter <=0;DOUT_EN <= 1;
// ram_addr_a<=512;ram_we_a <= 1;endendSTATE_STORE_AND_READ: begin// 从ROM中读取数据到RAM并从RAM读取数据输出if (byte_counter_w <= 1023) begin// 写入数据到RAM
// DIN <= rom_dout;
// ram_din_a <= DIN;ram_din_a <=rom_dout; ram_addr_a <= (byte_counter_w < 512) ? (513 + byte_counter_w) : byte_counter_w - 512;rom_addr <= rom_addr + 1;// 更新字节计数器和读取操作byte_counter <= byte_counter + 1;byte_counter_w <= byte_counter_w + 1; ram_addr_b <= ram_addr_b + 1;if (byte_counter_w == 1023) beginbyte_counter_w <= 0;frame_counter <= frame_counter + 1;if (frame_counter == inject_frame) beginframe_counter <= 0; // 当帧计数达到 inject_frame 时复位为 0end // 检查是否需要注入错误end else if (frame_counter == inject_frame && ram_addr_b == 4) begin// 在第五个字节注入错误DOUT <= ram_dout_b ^ 8'b00000001; // 对第五个字节进行简单的位翻转end else beginDOUT <= ram_dout_b;end// 当达到最大计数时复位 end else beginram_we_a <= 0;DOUT_EN <= 0;endendendcaseendend// 根据ERROR_LEVEL设置需要注入错误的帧号always @(ERROR_LEVEL) begincase (ERROR_LEVEL)8'b00000000: inject_frame = 1; // 全 FF 输出,逻辑可在输出时处理8'b00000001: inject_frame = 2; // 误码率 10^-48'b00000010: inject_frame = 13; // 误码率 10^-58'b00000011: inject_frame = 122; // 误码率 10^-68'b00000100: inject_frame = 1220; // 误码率 10^-78'b00000101: inject_frame = 12207; // 误码率 10^-88'b00000110: inject_frame = 122070; // 误码率 10^-98'b00000111: inject_frame = 1220707; // 误码率 10^-10default: inject_frame = 32'hFFFFFFFF; // 默认不注入错误endcaseend
endmodule
不同误码率的逻辑,有不同的实现方法。本方法以1bit的错误,计算最小帧数,然后插入错误bit。