read and write in verilog when having negative numbers and array - io

I am now doing reading input data from txt file and write the results into txt file.
However the results runs in the simulation works well but it fail to link back the the conv module which is o = a+b; the system able to read the values in x.txt and d.txt but cannot link it back to a and b. What is my mistake and how to correct it?
And from the same cases in i found out that the system cannot write out negative decimal value although it is change to "%d\n" in $fwrite. Any method to solve that? Should i use $dumpfile to get negative number as output??
Here is the content in d.txt
56
272
1
-62
75
Content in x.txt
562
2723
14
-620
751
Here is my module code:
module conv (input signed[15:0]a,b,
output signed[15:0] o);
assign o = a + b;
endmodule
My testbench code:
module conv_tb();
reg clk;
reg signed [15:0]a[4:0];
reg signed [15:0]b[4:0];
wire signed [15:0]o[4:0];
integer ai,bi,oo,i;
conv U1(.a(a),.b(b),.o(o));
initial begin
clk <= 1'b0;
forever
#1 clk = ~clk;
end
initial begin
ai = $fopen("x.txt","r");
bi = $fopen("d.txt","r");
oo = $fopen("o.txt","w");
#1;
for (i = 0; i<5; i=i+1)
a <= $fscanf(ai,"%d\n",x);
b <= $fscanf(bi,"%d\n",d);
#4;
$fwrite(oo,"%d\n",o);
end
$fclose(ai);
$fclose(bi);
$fclose(oo);
$finish;
end
endmodule

An example for writing signed number to a text file using fwrite :
module write_signed;
integer out_file;
initial begin
out_file = $fopen("out_file.txt","w");
$fwrite(out_file, "%d\n", 3);
$fwrite(out_file, "%d\n", 2);
$fwrite(out_file, "%d\n", 1);
$fwrite(out_file, "%d\n", 0);
$fwrite(out_file, "%d\n", -1);
$fwrite(out_file, "%d\n", -2);
$fclose(out_file);
end
endmodule
Which generates :
3
2
1
0
-1
-2

An alternative method to solve your issue is to use a hex value input as shown, convert all negative values to corresponding hex value in the text file explicitly is required
module conv ( input signed [15:0] a, b,
output signed [15:0] o);
assign o = a + b;
endmodule
module conv_tb();
reg signed [15:0] a,b,o;
conv u0(.a(a),.b(b),.o(o));
reg [15:0] Mem [0:4];
reg [15:0] Mem1 [0:4];
integer j,k,oo;
initial
begin
$readmemh("x.txt",Mem);
$readmemh("d.txt",Mem1);
oo = $fopen("o.txt","w");
end
initial begin
for (k=0; k<5; k=k+1) begin a= Mem[k]; end
for (j=0; j<5; j=j+1) begin b= Mem1[j]; $fwrite(oo,"%d\n",o); end
end
endmodule

Related

How to convert 1D data into 2D data?

I have a data of 1024 bit stored in A register.
reg [1023:0] A;
reg [7:0] B [0:127]
Now I want to convert it into 2 dimensional register B. How's it possible with minimum coding in Verilog?
In System Verilog a streaming operator could be used for this:
module top;
reg [1023:0] A;
reg [7:0] B [0:127];
always_comb begin
B = {>>{A}};
// this also works:
// {>>{B}} = A;
end
// testing
initial begin
for(int i = 0; i < 128; i++)
A[i*8 +: 8] = i;
#1 $finish;
end
always #* begin
$display("A: %3d %3d %3d", A[7:0], A[15:8], A[1023:1016]);
$display("B: %3d %3d %3d", B[127], B[126], B[0]);
end
endmodule
Just note, due to the B[0:127] declaration, index [0] is the most significant one and maps to A[1023:1016]. If you want an opposite mapping, declare B[127:0].
One way is to use a for loop:
module tb;
reg [1023:0] A;
reg [7:0] B [0:127];
always_comb begin
for (int i=0; i<128; i++) begin
B[i] = A[8*i +: 8];
end
end
endmodule
See also +:

8 bit sequential multiplier using add and shift

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.

Systemverilog recursion update value for next stage

I am trying to create a recursive logic in Systemverilog but I seem to be missing the right logic to carry the output of one iteration to the next.
Here is an example of the problem:
parameter WIDTH=4;
module test_ckt #(parameter WIDTH = 4)(CK, K, Z);
input CK;
input [WIDTH-1:0] K;
output reg Z;
wire [WIDTH/2-1:0] tt;
wire [WIDTH-1:0] tempin;
assign tempin = K;
genvar i,j;
generate
for (j=$clog2(WIDTH); j>0; j=j-1)
begin: outer
wire [(2**(j-1))-1:0] tt;
for (i=(2**j)-1; i>0; i=i-2)
begin
glitchy_ckt #(.WIDTH(1)) gckt (tempin[i:i], tempin[(i-1):i-1], tt[((i+1)/2)-1]);
end
// How do I save the value for the next iteration?
wire [(2**(j-1))-1:0] tempin;
assign outer[j].tempin = outer[j].tt;
end
endgenerate
always #(posedge CK)
begin
// How do I use the final output here?
Z <= tt[0];
end
endmodule
module glitchy_ckt #(parameter WIDTH = 1)(A1, B1, Z1);
input [WIDTH-1:0] A1,B1;
output Z1;
assign Z1 = ~A1[0] ^ B1[0];
endmodule
Expected topology:
S1 S2
K3--<inv>--|==
|XOR]---<inv>----|
K2---------|== |
|==
<--gckt---> |XOR]
|==
K1--<inv>--|== |
|XOR]------------|
K0---------|== <-----gckt---->
Example input and expected outputs:
Expected output:
A - 1010
----
S1 0 0 <- j=2 and i=3,1.
S2 1 <- j=1 and i=1.
Actual output:
A - 1010
----
S1 0 0 <- j=2 and i=3,1.
S2 0 <- j=1 and i=1. Here, because tempin is not updated, inputs are same as (j=2 & i=1).
Test-bench:
`timescale 1 ps / 1 ps
`include "test_ckt.v"
module mytb;
reg CK;
reg [WIDTH-1:0] A;
wire Z;
test_ckt #(.WIDTH(WIDTH)) dut(.CK(CK), .K(A), .Z(Z));
always #200 CK = ~CK;
integer i;
initial begin
$display($time, "Starting simulation");
#0 CK = 0;
A = 4'b1010;
#500 $finish;
end
initial begin
//dump waveform
$dumpfile("test_ckt.vcd");
$dumpvars(0,dut);
end
endmodule
How do I make sure that tempin and tt get updated as I go from one stage to the next.
Your code does not have any recursion in it. You were trying to solve it using loops, but generate blocks are very limited constructs and, for example, you cannot access parameters defined in other generate iterations (but you can access variables or module instances).
So, the idea is to use a real recursive instantiation of the module. In the following implementation the module rec is the one which is instantiated recursively. It actually builds the hierarchy from your example (I hope correctly).
Since you tagged it as system verilog, I used the system verilog syntax.
module rec#(WIDTH=1) (input logic [WIDTH-1:0]source, output logic result);
if (WIDTH <= 2) begin
always_comb
result = source; // << generating the result and exiting recursion.
end
else begin:blk
localparam REC_WDT = WIDTH / 2;
logic [REC_WDT-1:0] newSource;
always_comb // << calculation of your expression
for (int i = 0; i < REC_WDT; i++)
newSource[i] = source[i*2] ^ ~source[(i*2)+1];
rec #(REC_WDT) rec(newSource, result); // << recursive instantiation with WIDTH/2
end // else: !if(WIDTH <= 2)
initial $display("%m: W=%0d", WIDTH); // just my testing leftover
endmodule
The module is instantiated first time from the test_ckt:
module test_ckt #(parameter WIDTH = 4)(input logic CK, input logic [WIDTH-1:0] K, output logic Z);
logic result;
rec#(WIDTH) rec(K, result); // instantiate first time )(top)
always_ff #(posedge CK)
Z <= result; // assign the results
endmodule // test_ckt
And your testbench, a bit changed:
module mytb;
reg CK;
reg [WIDTH-1:0] A;
wire Z;
test_ckt #(.WIDTH(WIDTH)) dut(.CK(CK), .K(A), .Z(Z));
always #200 CK = ~CK;
integer i;
initial begin
$display($time, "Starting simulation");
CK = 0;
A = 4'b1010;
#500
A = 4'b1000;
#500 $finish;
end
initial begin
$monitor("Z=%b", Z);
end
endmodule // mytb
Use of $display/$monitor is more convenient than dumping traces for such small examples.
I did not do much testing of what I created, so there could be issues, but you can get basic ideas from it in any case. I assume it should work with any WIDTH which is power of 2.

problem with flattening an array in verilog

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.

verilog code for ram

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

Resources