Verilog 时序和时钟 - 输入和输出问题
Verilog timing and clocking - input and output issues
我用verilog写了这段代码,但我的代码有问题!
我想要做的是将数字 0 - 127 作为输入,这样它们就可以写在 mem 中,然后读取它们并查看输出。根据结果,我已将时钟设置为每 5 次从 0 变为 1,这正在发生。但是这些数字在记忆中不止一次出现。
我该如何解决这个问题,以便数字只写一次?这可能是计时问题吗?
一开始输出的数据是0,因为我要先写数据再读。
另外,我想知道我需要更改什么,以便当内存的最后一个位置填满数字 127 时,我的程序将理解内存的其他位置没有空着!!
我是运行 EDA Playground 的代码
module process_data(
input wire [63:0] DATA_IN , //input data
input QUE_Mode, //fifo or filo
//input wire [6:0] AdrR , //pointers for read, write
//input wire [6:0] AdrW,
input R_W ,
input Cen,
input clk,
input reset,
output reg [63:0]Reg_Data_Out, //output data
output reg Que_Full, //state of the queue
output reg Que_Last,
output reg Que_Empty);
integer i;
reg [63:0] Memory [0:127]; //array
reg [6:0] AdrW;
reg [6:0] AdrR;
initial begin //initialization
Que_Full= 1'b0; //when Que_Full = 1'b0, the queue is not full
Que_Last = 1'b0; //when Que_Last = 1'b0, this is not the last item of the list that can be added to
Que_Empty = 1'b0; //when Que_Empty = 1'b0, the queue is empty.
AdrR=7'b0000_000;
AdrW=7'b0000_000;
i=0;
repeat (128) //initialization of memory
begin
Memory[i]=64'd1; //64 bits/ position , 127 positions
i=i+1;
end
end
always @* begin
$display("AdrR=%d",AdrR);
$display("AdrW=%d",AdrW);
end
always @(negedge(clk))
begin
if(Cen == 1'b1) begin // cen = chip enabled , when 1=> chip is enabled => circuit works
case (R_W)
1'b1:
begin
if(Que_Empty == 1'b1 )begin //check if queue not empty
// Return the value from the FIFO foun at the read address
Reg_Data_Out <= Memory[AdrR]; // (read) out put memory context
AdrR<=AdrR+7'b0000_001; //assign AdrR [6:0] <= AdrR [6:0] +7'b0000_001;
end
end
1'b0:
begin
if( Que_Full == 1'b0 )begin //check if queue not full
if(AdrW >= 7'b0000_000) begin
Memory[AdrW] <= DATA_IN ; // write input to memory , On any write -> update the memory
AdrW <= AdrW+7'b0000_001; //non blocking statements to avoid race conditions
Que_Empty = 1'b1; //when Que_Empty = 1'b1, the queue is NOT empty
if(AdrW==7'b1111_111)begin
//AdrW <= 7'b0000_000;
Que_Full= 1'b1; //when Que_Full = 1'b1, the queue IS full
Que_Last = 1'b1; //when Que_Last = 1'b0, this IS the last item of the list that can be added to
end
end
end
end
default:
Reg_Data_Out = 64'bxxxxxxxx;
endcase
end
end
endmodule
module clock(output reg clk);
initial
clk=1'b0;
always
#5 clk=~clk;
endmodule
module TOP();
parameter ENDTIME=40000;
reg [63:0] inputdata1; // is an 63-bit "register", or variable
wire [6:0] AddressR,AddressW;
reg cen, R_W, reset; //clk=1'b0 ,
reg QUE_Mode;
wire [63:0] Data_Out;
integer count;
integer i;
wire Que_Full, Que_Last, Que_Empty;
wire clk;
//call module for data I/O
process_data process_data(
inputdata1,
QUE_Mode,
//AddressR,
//AddressW,
R_W ,
cen,
clk,
reset,
Data_Out,
Que_Full,
Que_Last,
Que_Empty); //reset, Que_Full, Que_Last, Que_Empty do not do anything yet
clock MyClock(clk);
initial
begin
$dumpfile("ALU.vcd");
$dumpvars(0);
$display("\t\t\t\t\t\t\t\t\tSIMULATION RESULT ");
$display("\t\ttime\tclk\t\t\tinputdata1\t\tData_Out\tQUE_Mode\t\tAddressR\t\tAddressW\t\tQue_Full\t\Que_Last\t\Que_Empty");
$monitor($time, "\t%d\t%d\t%d\t%d",clk,inputdata1,Data_Out,QUE_Mode,AddressR,AddressW,Que_Full,Que_Last,Que_Empty);
cen=1'b1; //chip enabled
count = 0;
R_W = 1'b0; //write
QUE_Mode = 1'b0; // QUE_Mode = 1'b0 => FIFO MODE
i=0;
//input
for (i = 0; i < 128; i = i + 1) begin //input
R_W=1'b0; //write
inputdata1 = i;
#20;
end
#10
for (i = 0; i < 128; i = i + 1) begin //output
#20;
R_W=1'b1; //read => output
#20;
end
$display("-------------- THE SIMULATION FINISHED ------------");
$finish;
end
endmodule
结果:
SIMULATION RESULT
time clk inputdata1 Data_Out QUE_Mode AddressR AddressW Que_Full Que_Last Que_Empty
AdrR= 0
AdrW= 0
AdrR= 0
AdrW= 1
0 0 0 x 0 z z001
5 1 0 x 0 z z001
AdrR= 0
AdrW= 2
10 0 0 x 0 z z001
15 1 0 x 0 z z001
AdrR= 0
AdrW= 3
20 0 1 x 0 z z001
25 1 1 x 0 z z001
AdrR= 0
AdrW= 4
30 0 1 x 0 z z001
35 1 1 x 0 z z001
AdrR= 0
AdrW= 5
40 0 2 x 0 z z001
45 1 2 x 0 z z001
AdrR= 0
AdrW= 6
50 0 2 x 0 z z001
55 1 2 x 0 z z001
AdrR= 0
AdrW= 7
60 0 3 x 0 z z001
65 1 3 x 0 z z001
AdrR= 0
AdrW= 8
70 0 3 x 0 z z001
75 1 3 x 0 z z001
AdrR= 0
AdrW= 9
80 0 4 x 0 z z001
85 1 4 x 0 z z001
AdrR= 0
AdrW= 10
90 0 4 x 0 z z001
95 1 4 x 0 z z001
AdrR= 0
AdrW= 11
100 0 5 x 0 z z001
105 1 5 x 0 z z001
AdrR= 0
AdrW= 12
110 0 5 x 0 z z001
115 1 5 x 0 z z001
AdrR= 0
AdrW= 13
120 0 6 x 0 z z001
125 1 6 x 0 z z001
AdrR= 0
AdrW= 14
130 0 6 x 0 z z001
135 1 6 x 0 z z001
......................
AdrR=121
AdrW= 0
7630 0 127 60 0 z z111
7635 1 127 60 0 z z111
AdrR=122
AdrW= 0
7640 0 127 60 0 z z111
7645 1 127 60 0 z z111
AdrR=123
AdrW= 0
7650 0 127 61 0 z z111
7655 1 127 61 0 z z111
AdrR=124
AdrW= 0
7660 0 127 61 0 z z111
7665 1 127 61 0 z z111
AdrR=125
AdrW= 0
7670 0 127 62 0 z z111
7675 1 127 62 0 z z111
AdrR=126
AdrW= 0
7680 0 127 62 0 z z111
7685 1 127 62 0 z z111
-------------- THE SIMULATION FINISHED ------------
AdrR=127
7690 0 127 63 0 z z111
Done
您需要以两倍的速度更改输入数据。将 #20
更改为 #10
:
//input
for (i = 0; i < 128; i = i + 1) begin //input
R_W=1'b0; //write
inputdata1 = i;
// #20;
#10;
end
这会将 0 写入地址 0,将 1 写入地址 1,... 127 写入地址 127。
第一次写入是在时间=0 时写入地址0。但是,initial
和 always
块之间存在竞争条件,这可能导致在不同的模拟器上出现不同的行为。
日志文件显示 clk
的每个边上的输出,包括 posedge 和 negedge,因为您在 $monitor
语句中有 clk
。但是,数据每个时钟周期仅更改一次(根据需要)。
我用verilog写了这段代码,但我的代码有问题! 我想要做的是将数字 0 - 127 作为输入,这样它们就可以写在 mem 中,然后读取它们并查看输出。根据结果,我已将时钟设置为每 5 次从 0 变为 1,这正在发生。但是这些数字在记忆中不止一次出现。 我该如何解决这个问题,以便数字只写一次?这可能是计时问题吗?
一开始输出的数据是0,因为我要先写数据再读。
另外,我想知道我需要更改什么,以便当内存的最后一个位置填满数字 127 时,我的程序将理解内存的其他位置没有空着!! 我是运行 EDA Playground 的代码
module process_data(
input wire [63:0] DATA_IN , //input data
input QUE_Mode, //fifo or filo
//input wire [6:0] AdrR , //pointers for read, write
//input wire [6:0] AdrW,
input R_W ,
input Cen,
input clk,
input reset,
output reg [63:0]Reg_Data_Out, //output data
output reg Que_Full, //state of the queue
output reg Que_Last,
output reg Que_Empty);
integer i;
reg [63:0] Memory [0:127]; //array
reg [6:0] AdrW;
reg [6:0] AdrR;
initial begin //initialization
Que_Full= 1'b0; //when Que_Full = 1'b0, the queue is not full
Que_Last = 1'b0; //when Que_Last = 1'b0, this is not the last item of the list that can be added to
Que_Empty = 1'b0; //when Que_Empty = 1'b0, the queue is empty.
AdrR=7'b0000_000;
AdrW=7'b0000_000;
i=0;
repeat (128) //initialization of memory
begin
Memory[i]=64'd1; //64 bits/ position , 127 positions
i=i+1;
end
end
always @* begin
$display("AdrR=%d",AdrR);
$display("AdrW=%d",AdrW);
end
always @(negedge(clk))
begin
if(Cen == 1'b1) begin // cen = chip enabled , when 1=> chip is enabled => circuit works
case (R_W)
1'b1:
begin
if(Que_Empty == 1'b1 )begin //check if queue not empty
// Return the value from the FIFO foun at the read address
Reg_Data_Out <= Memory[AdrR]; // (read) out put memory context
AdrR<=AdrR+7'b0000_001; //assign AdrR [6:0] <= AdrR [6:0] +7'b0000_001;
end
end
1'b0:
begin
if( Que_Full == 1'b0 )begin //check if queue not full
if(AdrW >= 7'b0000_000) begin
Memory[AdrW] <= DATA_IN ; // write input to memory , On any write -> update the memory
AdrW <= AdrW+7'b0000_001; //non blocking statements to avoid race conditions
Que_Empty = 1'b1; //when Que_Empty = 1'b1, the queue is NOT empty
if(AdrW==7'b1111_111)begin
//AdrW <= 7'b0000_000;
Que_Full= 1'b1; //when Que_Full = 1'b1, the queue IS full
Que_Last = 1'b1; //when Que_Last = 1'b0, this IS the last item of the list that can be added to
end
end
end
end
default:
Reg_Data_Out = 64'bxxxxxxxx;
endcase
end
end
endmodule
module clock(output reg clk);
initial
clk=1'b0;
always
#5 clk=~clk;
endmodule
module TOP();
parameter ENDTIME=40000;
reg [63:0] inputdata1; // is an 63-bit "register", or variable
wire [6:0] AddressR,AddressW;
reg cen, R_W, reset; //clk=1'b0 ,
reg QUE_Mode;
wire [63:0] Data_Out;
integer count;
integer i;
wire Que_Full, Que_Last, Que_Empty;
wire clk;
//call module for data I/O
process_data process_data(
inputdata1,
QUE_Mode,
//AddressR,
//AddressW,
R_W ,
cen,
clk,
reset,
Data_Out,
Que_Full,
Que_Last,
Que_Empty); //reset, Que_Full, Que_Last, Que_Empty do not do anything yet
clock MyClock(clk);
initial
begin
$dumpfile("ALU.vcd");
$dumpvars(0);
$display("\t\t\t\t\t\t\t\t\tSIMULATION RESULT ");
$display("\t\ttime\tclk\t\t\tinputdata1\t\tData_Out\tQUE_Mode\t\tAddressR\t\tAddressW\t\tQue_Full\t\Que_Last\t\Que_Empty");
$monitor($time, "\t%d\t%d\t%d\t%d",clk,inputdata1,Data_Out,QUE_Mode,AddressR,AddressW,Que_Full,Que_Last,Que_Empty);
cen=1'b1; //chip enabled
count = 0;
R_W = 1'b0; //write
QUE_Mode = 1'b0; // QUE_Mode = 1'b0 => FIFO MODE
i=0;
//input
for (i = 0; i < 128; i = i + 1) begin //input
R_W=1'b0; //write
inputdata1 = i;
#20;
end
#10
for (i = 0; i < 128; i = i + 1) begin //output
#20;
R_W=1'b1; //read => output
#20;
end
$display("-------------- THE SIMULATION FINISHED ------------");
$finish;
end
endmodule
结果:
SIMULATION RESULT
time clk inputdata1 Data_Out QUE_Mode AddressR AddressW Que_Full Que_Last Que_Empty
AdrR= 0
AdrW= 0
AdrR= 0
AdrW= 1
0 0 0 x 0 z z001
5 1 0 x 0 z z001
AdrR= 0
AdrW= 2
10 0 0 x 0 z z001
15 1 0 x 0 z z001
AdrR= 0
AdrW= 3
20 0 1 x 0 z z001
25 1 1 x 0 z z001
AdrR= 0
AdrW= 4
30 0 1 x 0 z z001
35 1 1 x 0 z z001
AdrR= 0
AdrW= 5
40 0 2 x 0 z z001
45 1 2 x 0 z z001
AdrR= 0
AdrW= 6
50 0 2 x 0 z z001
55 1 2 x 0 z z001
AdrR= 0
AdrW= 7
60 0 3 x 0 z z001
65 1 3 x 0 z z001
AdrR= 0
AdrW= 8
70 0 3 x 0 z z001
75 1 3 x 0 z z001
AdrR= 0
AdrW= 9
80 0 4 x 0 z z001
85 1 4 x 0 z z001
AdrR= 0
AdrW= 10
90 0 4 x 0 z z001
95 1 4 x 0 z z001
AdrR= 0
AdrW= 11
100 0 5 x 0 z z001
105 1 5 x 0 z z001
AdrR= 0
AdrW= 12
110 0 5 x 0 z z001
115 1 5 x 0 z z001
AdrR= 0
AdrW= 13
120 0 6 x 0 z z001
125 1 6 x 0 z z001
AdrR= 0
AdrW= 14
130 0 6 x 0 z z001
135 1 6 x 0 z z001
......................
AdrR=121
AdrW= 0
7630 0 127 60 0 z z111
7635 1 127 60 0 z z111
AdrR=122
AdrW= 0
7640 0 127 60 0 z z111
7645 1 127 60 0 z z111
AdrR=123
AdrW= 0
7650 0 127 61 0 z z111
7655 1 127 61 0 z z111
AdrR=124
AdrW= 0
7660 0 127 61 0 z z111
7665 1 127 61 0 z z111
AdrR=125
AdrW= 0
7670 0 127 62 0 z z111
7675 1 127 62 0 z z111
AdrR=126
AdrW= 0
7680 0 127 62 0 z z111
7685 1 127 62 0 z z111
-------------- THE SIMULATION FINISHED ------------
AdrR=127
7690 0 127 63 0 z z111
Done
您需要以两倍的速度更改输入数据。将 #20
更改为 #10
:
//input
for (i = 0; i < 128; i = i + 1) begin //input
R_W=1'b0; //write
inputdata1 = i;
// #20;
#10;
end
这会将 0 写入地址 0,将 1 写入地址 1,... 127 写入地址 127。
第一次写入是在时间=0 时写入地址0。但是,initial
和 always
块之间存在竞争条件,这可能导致在不同的模拟器上出现不同的行为。
日志文件显示 clk
的每个边上的输出,包括 posedge 和 negedge,因为您在 $monitor
语句中有 clk
。但是,数据每个时钟周期仅更改一次(根据需要)。