I am trying to simulate the following code for an asynchronous ram in verilog. But dout remains xxxx all the time.
The first time I tried the code dout was equal to din for the time when write signal was 1.After that it was all xxxx.Can anyone tell me the problem?It'd be great if you could suggest a better code.
module ram(cs,wr,addr,din,dout);
parameter adds = 10, wsize =16, memsize =1024;
input cs,wr;
input [adds-1:0] addr;
input [wsize-1 : 0]din;
output [wsize-1:0]dout;
reg [wsize-1:0] mem [memsize-1:0];
assign dout = mem[addr];
always #(cs or wr)
begin
if(wr) mem[addr]= din;
end
endmodule
The test bench for the above code is :
module ramtest;
// Inputs
reg cs;
reg wr;
reg [9:0] addr;
reg [15:0] din;
// Outputs
wire [15:0] dout;
integer k,myseed;
// Instantiate the Unit Under Test (UUT)
ram uut (
.cs(cs),
.wr(wr),
.addr(addr),
.din(din),
.dout(dout)
);
initial begin
for(k = 0; k<=1023; k = k+1)
begin
din = k % 256; wr = 1; cs= 1;addr= k ;
end
repeat(20)
begin
#2 addr = $random(myseed) % 1024 ;
wr = 0; cs =1;
$display("Address = %5d, data = %4d",addr,dout);
end
end
initial myseed = 35 ;
endmodule
Several errors:
Your wr and cs do not change so the always #( cs or wr) is only
entered once for write and once for read.
Your 'write' code in
the testbench for(k = 0; k<=1023; k = k+1) does not have a delay.
So there is no time for the write to actually happen.
However the biggest danger is that you 'just' add the address to the sensitivity list and it all 'works':
always #(cs or wr or addr)
It would probably have helped you if you had first looked up a datasheet of an async RAM. They do not work the way you model it. There data is stored when the CS or Write goes away (which ever first). The data and address have to be stable a certain time before and after that.
In your model you change the address whilst keeping the WR and CS active. In real life the address does not change from one value to another instantaneous. It will go from for example 0000 to 000F but the bits will change one at a time: 0000 => 0004 => 0005 => 000D ==> 000F. Thus you could have messed up the contents of 5 different addresses.
Make a write signal from CS and WR: do_write = cs & wr; Do the actual write when that signal goes away: always #(negedge do_write) .....`.
It appears that you are trying to write an asynchronous RAM. In that case, you need to also add addr and din to your sensitivity list. Also, dout should get mem[addr] when cs is high and wr is low. In your testbench, you need to add a delay in your for loop before supplying the next input. One possible implementation is as follows:
module ram(oe, cs, wr, addr, din, dout);
parameter adds = 6,
wsize = 16,
memsize = 1 << adds;
input cs, wr;
input oe; // output enable
input [adds-1:0] addr;
input [wsize-1:0] din;
output [wsize-1:0] dout;
reg [wsize-1:0] dout;
reg [wsize-1:0] mem [memsize-1:0];
always #(cs, wr, oe, addr, din)
begin
if (cs) begin
if (wr) mem[addr] <= din;
else if (oe) dout <= mem[addr];
end
end
endmodule
And corresponding testbench could be:
module ram_tb;
parameter adds = 6,
wsize = 16,
memsize = 1 << adds;
reg cs, wr;
reg oe; // output enable
reg [adds-1:0] addr;
reg [wsize-1:0] din;
wire [wsize-1:0] dout;
integer k, myseed;
// Instantiate the Unit Under Test (UUT)
ram uut (
.cs(cs),
.wr(wr),
.oe(oe),
.addr(addr),
.din(din),
.dout(dout)
);
initial myseed = 35;
initial begin
for(k = 0; k < memsize; k = k+1) begin
#2
din <= k % 256;
wr <= 1;
cs <= 1;
addr <= k;
oe <= 0;
end
repeat(20) begin
#2
addr <= ($random(myseed)) % memsize ;
wr <= 0;
cs <= 1;
oe <= 1;
$display("Address = %5d, data = %4d", addr, dout);
end
#10 $finish;
end
endmodule
Related
I'm new to verilog. I write a 3-8 decoder and a testbench for it. This is 38_decoder_tb.v:
module decoder_38(input [2:0] in, output reg [7:0] out);
always #* begin
case (in) //Switch based on concatenation of control signals
3'b000 : out = 8'b00000001;
3'b001 : out = 8'b00000010;
3'b010 : out = 8'b00000100;
3'b011 : out = 8'b00001000;
3'b100 : out = 8'b00010000;
3'b101 : out = 8'b00100000;
3'b110 : out = 8'b01000000;
3'b111 : out = 8'b10000000;
endcase
end
endmodule
This is 38_decoder_tb.v:
`timescale 1ns / 1ns
module tb_decoder_38;
// decoder_38 Parameters
parameter PERIOD = 20;
// decoder_38 Inputs
reg [2:0] in ;
// decoder_38 Outputs
wire [7:0] out ;
reg clk;
integer i;
initial
begin
clk = 0;
forever #(PERIOD/2) clk=~clk;
end
decoder_38 u_decoder_38 (
.in ( in [2:0] ),
.out ( out [7:0] )
);
initial
begin
in = 0;
#(PERIOD*2);
for (i = 3'd0; i < 3'd8; i=i+1) begin
in = i;
#PERIOD;
end
end
endmodule
I stimulate the testbench module with ModelSim 10.5. As you can see, the signal just doesn't update. What's the problem? Does it have something to do with the for loop?
Yes, the issue is with the loop.
Your problem is in definition of 3'd8. 8 is the same as 1000 in binary presentation and requires 4 bits. Therefore, 3-bits of it (as you requested) yield 000. As a result your loop does not run at all, looking like the following: for (i = 3'd0; i < 0; i++).
Variable i is defined as integer. An integer type is a 4-state data type, 32-bit signed integer. So, rewriting loop as for(i = 0; i < 8; i++) will solve your issues. There is absolutely no need to define sizes for the constants in this loop.
And, to avoid infinite loop, you need to use $finish when appropriate, as suggested in the other answer.
The posted testbench has an infinite loop because of the forever loop with nothing to stop it.
I added a #30 delay to see the last clock of data, and $finish to stop it.
After that the code behaves as expected.
All 4 simulators on EDA Playground show the same.
initial
begin
in = 0;
#(PERIOD*2);
for (i = 3'd0; i <= 3'd7; i=i+1) begin
in = i;
#PERIOD;
end
//
#30;
$finish;
end
Here is a link playground I put together https://www.edaplayground.com/x/aZYL
I'm writing an ALU for a processor I'm designing (first RTL project) and I'm getting a high impedance output on ALU_out when I run my testbench, even though the flags do get set and are output correctly.
module alu(
input clk,
input reset,
input [7:0] A, B,
input [3:0] Op_Sel,
output [7:0] ALU_out,
output C, V, N, Z
);
reg [8:0] Result = 0;
reg [8:0] cn_temp = 0;
reg [7:0] v_temp = 0;
reg carry = 0;
reg overflow = 0;
reg negative = 0;
reg zero = 0;
assign ALU_Out = Result[7:0];
assign C = carry;
assign V = overflow;
assign N = negative;
assign Z = zero;
always #*
begin
if (reset)
begin
Result = 0;
cn_temp = 0;
v_temp = 0;
carry = 0;
overflow = 0;
negative = 0;
zero = 0;
end
end
always #(posedge clk)
begin
case(Op_Sel)
4'b0000: // Addition
begin
Result = A + B;
negative = Result[7];
zero = (Result[7:0] == 8'b00000000);
carry = Result[8];
v_temp = A[6:0] + B[6:0];
overflow = v_temp[7] ^ carry;
end
.
.
//The rest of the instructions
.
.
.
endcase
end
endmodule
//My testbench
module alu_testbench();
reg clk;
reg reset;
reg [7:0] A;
reg [7:0] B;
reg [3:0] Op_Sel;
wire [7:0] ALU_out;
wire C, V, N, Z;
always begin
#1
clk = ~clk;
end
initial begin
clk = 0;
reset = 0;
#1
reset = 1;
#1
reset = 0;
end
initial begin
#10
A=2;
B=3;
Op_Sel = 4'b0000;
#10
A=1;
end
alu alu (
.clk(clk),
.A(A),
.B(B),
.Op_Sel(Op_Sel),
.ALU_out(ALU_out),
.C(C),
.V(V),
.N(N),
.Z(Z));
endmodule
I believe I connected up the module to the testbench (through a wire), so why am I getting high impedance on ALU_out?
This was a tricky typo. You mistakenly used an upper-case "O" in the ALU_Out signal name. Since Verilog is case-sensitive, this is a different signal from ALU_out. It is not mandatory to declare all signals in Verilog. However, you can use the following compiler directive in your code to help catch this type of common problem:
`default_nettype none
Your simulator should generate an error.
To fix it, change:
assign ALU_Out = Result[7:0];
to:
assign ALU_out = Result[7:0];
My simulators also generated a warning message because you didn't drive the reset input of alu. Here is the fix:
alu alu (
.clk(clk),
.reset(reset), /// <------ add this
.A(A),
.B(B),
.Op_Sel(Op_Sel),
.ALU_out(ALU_out),
.C(C),
.V(V),
.N(N),
.Z(Z));
I'm designing an 8-bit signed sequential multiplier using Verilog. The inputs are clk (clock), rst (reset), a (8 bit multiplier), b (8 bit multiplicand), and the outputs are p (product) and rdy (ready signal, indicating multiplication is over). For negative inputs, I do a sign extension and save it in the 15 bit register variables multiplier and multiplicand. Here's my code:
module seq_mult (p, rdy, clk, reset, a, b);
input clk, reset;
input [7:0] a, b;
output [15:0] p;
output rdy;
reg [15:0] p;
reg [15:0] multiplier;
reg [15:0] multiplicand;
reg rdy;
reg [4:0] ctr;
always #(posedge clk or posedge reset) begin
if (reset)
begin
rdy <= 0;
p <= 0;
ctr <= 0;
multiplier <= {{8{a[7]}}, a};
multiplicand <= {{8{b[7]}}, b};
end
else
begin
if(ctr < 16)
begin
if(multiplier[ctr]==1)
begin
multiplicand = multiplicand<<ctr;
p <= p + multiplicand;
end
ctr <= ctr+1;
end
else
begin
rdy <= 1;
end
end
end //End of always block
endmodule
And here's my testbench:
`timescale 1ns/1ns
`define width 8
`define TESTFILE "test_in.dat"
module seq_mult_tb () ;
reg signed [`width-1:0] a, b;
reg clk, reset;
wire signed [2*`width-1:0] p;
wire rdy;
integer total, err;
integer i, s, fp, numtests;
// Golden reference - can be automatically generated in this case
// otherwise store and read from a file
wire signed [2*`width-1:0] ans = a*b;
// Device under test - always use named mapping of signals to ports
seq_mult dut( .clk(clk),
.reset(reset),
.a(a),
.b(b),
.p(p),
.rdy(rdy));
// Set up 10ns clock
always #5 clk = !clk;
// A task to automatically run till the rdy signal comes back from DUT
task apply_and_check;
input [`width-1:0] ain;
input [`width-1:0] bin;
begin
// Set the inputs
a = ain;
b = bin;
// Reset the DUT for one clock cycle
reset = 1;
#(posedge clk);
// Remove reset
#1 reset = 0;
// Loop until the DUT indicates 'rdy'
while (rdy == 0) begin
#(posedge clk); // Wait for one clock cycle
end
if (p == ans) begin
$display($time, " Passed %d * %d = %d", a, b, p);
end else begin
$display($time, " Fail %d * %d: %d instead of %d", a, b, p, ans);
err = err + 1;
end
total = total + 1;
end
endtask // apply_and_check
initial begin
// Initialize the clock
clk = 1;
// Counters to track progress
total = 0;
err = 0;
// Get all inputs from file: 1st line has number of inputs
fp = $fopen(`TESTFILE, "r");
s = $fscanf(fp, "%d\n", numtests);
// Sequences of values pumped through DUT
for (i=0; i<numtests; i=i+1) begin
s = $fscanf(fp, "%d %d\n", a, b);
apply_and_check(a, b);
end
if (err > 0) begin
$display("FAIL %d out of %d", err, total);
end else begin
$display("PASS %d tests", total);
end
$finish;
end
endmodule // seq_mult_tb
I also created a file called test_in.dat in which the test cases are stored (first line indicates number of test cases):
10
5 5
2 3
10 1
10 2
20 20
-128 2
10 -128
-1 -1
10 0
0 2
Now the problem is: the code works for only the first two inputs and for the last two inputs. For the remaining inputs, I get a different number than is expected. Can someone point out any logical error in my code that is causing this? Or if there's a much simpler strategy for doing the same, please let me know of that as well.
multiplicand is shifted to the left by ctr in each iteration if multiplier[ctr] is 1.
But ctr already includes the previous shift amounts, so you are shifting too far.
You should just shift multiplicand by 1 in every iteration unconditionally:
multiplicand <= multiplicand << 1;
if (multiplier[ctr] == 1)
begin
p <= p + multiplicand;
end
ctr <= ctr + 1;
You should also use nonblocking assignment for multiplicand. You might need to move the shifting to after adding it to p.
I tried to flatten an array with numbers into a variable in order to pass it as an input to a module in verilog. But, I get the error:
Port 1 (DATA_IN) of process_data expects 64 bits, got 4096. Pruning
4032 high bits of the expression.
I know that my module process_data in not ready yet and hence it does not work properly, but my problem for now is that the input is a lot more bits than it should.
Do you know how could I fix it?
module process_data(input wire [63:0] DATA_IN , input wire [6:0]AdrR , input wire [6:0]AdrW, input R_W , input Cen, input clk, input reset, output reg [63:0]Reg_Data_Out);
integer i;
reg [63:0]Memory[63:0]; //64 * 64 bit array
initial
begin
i=0;
//++for
repeat (64)
begin
Memory[i]=64'd1; //64 = number of the thesis that the vector has
i=i+1;
end
end
always #(negedge(clk))
//initial AdrR ,AdrW = 0; // 7'b0000_000;
begin
if(Cen == 1'b1) begin // cen = chip enabled
case (R_W)
1'b1:
//++check if not empty
Reg_Data_Out = Memory[AdrR]; // (read) out put memory context
1'b0:
//++check if not full
Memory[AdrW] = DATA_IN; // write input to memory
default:
Reg_Data_Out = 64'bxxxxxxxx;
endcase
end
end
endmodule
module TOP();
reg [63:0] inputdata1 [0:127]; //array
reg [64*64-1:0] flattened_inputdata1;
reg [6:0] AddressR,AddressW;
reg cen,clk, R_W, reset;
wire [63:0] Data_Out;
//pass the numbers
integer count;
initial
begin
count = 0;
while (count < 128) // Execute loop till count is 127. exit at count 128
begin
// every timh that the integer variable count takes must be also passed into reg inputdata1
inputdata1[count] = count;
count = count + 1;
end
end
//flattening
initial
begin
count = 0;
while (count < 128) // Execute loop till count is 127. exit at count 128
begin
flattened_inputdata1[64*count +: 64] = inputdata1[count];
//flattened_inputdata1[(64*count) +63) : (64*count)] = inputdata1[count]; //declare a number is dekadikos
count = count + 1;
end
end
//call module for data I/O
process_data process_data( flattened_inputdata1, AddressR, AddressW, R_W , cen, clk, reset, Data_Out); //reset does not do anything yet
always #10 clk=~clk;
initial
begin
$display("flattenedinputdata1=%d", flattened_inputdata1);
cen=1'b1; //chip enabled
#50
R_W=1'b1; //read
AddressR=7'b0000_000;
#50
//R_W=1'b1; //read
//AddressR=7'b0000_001;
$finish; //#50 $finish;
end
endmodule
edaplayground link
You can see from the declarations that the sizes are different:
input wire [63:0] DATA_IN
and the thing you're passing in to it:
reg [64*64-1:0] flattened_inputdata1;
DATA_IN is 64 bits and flattened_inputdata1 is 4096 bits. So you'll need to change one of them so that the two sizes match.
I am making an average that resets every period on EDA Playground. No errors are displayed on the simulator, Icarus Verilog, but the outputs are continually unassigned (which, of course, is not what I intended).
Here is my design:
module shift
(
input [13:0] in,
input clock,
output [31:0] sum,
output [14:0] avg);
integer reset;
reg [31:0] sum_reg;
reg [14:0] avg_reg;
always #(posedge clock)
if (reset == 8) begin
avg_reg = sum_reg >> 3;
sum_reg = 0;
reset = 0;
end else begin
sum_reg = sum_reg + in;
reset = reset + 1;
end
assign sum = sum_reg;
assign avg = avg_reg;
endmodule
Here is my testbench:
module shift_tb;
reg [13:0] in;
reg clock = 1'b0;
reg reset;
wire [31:0] sum;
wire [14:0] avg;
shift s
(
.in(in),
.clock(clock),
.sum(sum),
.avg(avg));
integer f;
initial begin
for (f = 9000; f < 10000; f = f + 10) begin
in = f;
$display("in = %d, sum = %d, avg = %d", in, sum, avg);
end
end
always
#1 clock = ~clock;
endmodule
What is wrong with this code?
One problem is reset is an integer that is initially x and stays that way. You need a way of initializing it to 0.
Another problem is your testbench for-loop has no delay. You should add #(nedgedge clk)