Verilog always@(..) 输出未按预期工作

Verilog always@(..) output not working as expected

所以,我正在尝试合成我的 verilog 代码以从 ps2 键盘 ->fpga->vga 发送数据。只是为了代码的背景,我想按下按钮“1”,它会出现在屏幕中央(称为display_area)

我意识到有些东西没有按预期工作。 经过仔细调试,我发现问题出在将rom的并行数据总线转换为串行输出,为每个像素赋值的模块。

代码本身非常简单,我只是提供尽可能多的信息。

我们需要时钟的上升沿才能进入始终区域(或复位)。如果值 display_area_enable 为 1,我们将激活一个从 7 到 0(8 个周期)的计数器来索引 rom 中的数据。

然而,在第一个时钟上,如果显示区域在 vga_clk 脉冲变为 1 的确切时刻变为 1,则计数器获得应有的值,但 one_bit_output(模块的输出)没有。 One_bit_output 在第二次访问 always 块时获得第一个正确值。因此我们需要 9 个周期来访问 8 位总线。

我将提供代码和 modelsim 测试平台

module shifter(reset,char_rom_data_out,vga_clk,display_area_enable,one_bit_output,counter);
input [7:0]char_rom_data_out;
input vga_clk,display_area_enable,reset;
output reg one_bit_output;
output reg [2:0]counter;
always @(posedge vga_clk or posedge reset)
begin
if (reset)
    begin
        counter=3'd7;
        one_bit_output=0;
    end
    else if (display_area_enable==1)
        begin 
        one_bit_output<=(char_rom_data_out[counter]==1);
        counter<=counter-1;
        end
    else if (display_area_enable==0) 
    begin
    counter<=3'd7;
    one_bit_output<=0;
   end
end
endmodule

module testbz();
reg reset,vga_clk,display_area_enable;
reg [7:0]char_rom_data_out;
wire [2:0] counter;
wire one_bit_output;

shifter dignitas(reset,char_rom_data_out,vga_clk,display_area_enable,one_bit_output,counter);

initial 
begin
reset<=1; char_rom_data_out<=8'b11110001; vga_clk<=0;display_area_enable=0; //sto 10 skaei o prwtos kyklos, kai meta ana 20
#5 reset<=0; display_area_enable<=0;
#5 display_area_enable<=1;
#160 display_area_enable<=0;
end
always
begin
 #10 vga_clk=~vga_clk;
 end

endmodule

模拟是:

有人可以向我解释为什么在 vga_clk 的第一个脉冲时,输出不是预期的吗?

更改one_bit_output,使其相对于时钟边沿不发生变化,但相对于display_area_enable是异步的。计数器跟踪要输出的元素。这本质上是一个以 display_area_enable 作为选择器的多路复用器,或者更可能是一个输入为 display_area_enable 的与门。

正如 toolic 所说,同步 one_bit_output 不能在与其激活信号相同的周期内改变。这是因为触发器的建立时间,信号必须在时钟边沿之前稳定一段时间。现在,如果您使用 one_bit_output 来驱动某个触发器,那么它必须在下一个边沿更新。不要试图通过使用锁存器来避免这种情况,这会使综合变得非常困难。

module shifter(reset,char_rom_data_out,vga_clk,display_area_enable,one_bit_output,counter);
input [7:0]char_rom_data_out;
input vga_clk,display_area_enable,reset;
output reg one_bit_output;
output reg [2:0]counter;
always @(posedge vga_clk or posedge reset)
begin
if (reset)
    begin
        counter<=3'd7;
        //one_bit_output<=0;
    end
    else if (display_area_enable==1)
        begin 
        //one_bit_output<=(char_rom_data_out[counter]==1);
        counter<=counter-1;
        end
    else if (display_area_enable==0) 
    begin
    counter<=3'd7;
    //one_bit_output<=0;
   end
end

  assign one_bit_output = display_area_enable ? char_rom_data_out[counter] : 0;


endmodule