Reading and writing CSV for a simple testbench - verilog

I am trying to read a set of values for my simulation from the input.csv file and writing the results to the output.csv file. I see some inconsistency when I dump the results to the output.csv file.
My module bypass just registers the data to two stages and sends the input to the output.
module bypass (clk, rst, a,b,c,d,w,x,y,z);
input clk, rst;
input [31:0] a, b, c,d;
output reg [31:0] w,x,y,z;
reg [31:0] stg1_a, stg1_b, stg1_c, stg1_d;
reg [31:0] stg2_a, stg2_b, stg2_c, stg2_d;
always #(posedge clk) begin
if (rst) begin
stg1_a <= 0;
stg1_b <= 0;
stg1_c <= 0;
stg1_d <= 0;
stg2_a <= 0;
stg2_b <= 0;
stg2_c <= 0;
stg2_d <= 0;
w <= 0;
x <= 0;
y <= 0;
z <= 0;
end else begin
stg1_a <= a;
stg1_b <= b;
stg1_c <= c;
stg1_d <= d;
stg2_a <= stg1_a;
stg2_b <= stg1_b;
stg2_c <= stg1_c;
stg2_d <= stg1_d;
w <= stg2_a;
x <= stg2_b;
y <= stg2_c;
z <= stg2_d;
end
end
endmodule
Below is my testbench:
`timescale 1ns / 1ps
module tb_bypass();
`define CSV_FILE "input.csv"
`define CSV_OUT_FILE "output.csv"
integer outfile1; //file descriptors
integer i; //index used in "for" loop
reg CLK, RST;
parameter REG_WIDTH = 32;
parameter CSV_COL_DEPTH = 32;
reg [REG_WIDTH-1 : 0] col1[0 : CSV_COL_DEPTH-1];
reg [REG_WIDTH-1 : 0] col2[0 : CSV_COL_DEPTH-1];
reg [REG_WIDTH-1 : 0] col3[0 : CSV_COL_DEPTH-1];
reg [REG_WIDTH-1 : 0] col4[0 : CSV_COL_DEPTH-1];
reg [REG_WIDTH-1 : 0] A, B, C, D;
wire [REG_WIDTH-1 : 0] W, X, Y, Z;
reg [REG_WIDTH-1 : 0] file1, r, scanRet, file2, start;
bypass dut (.clk(CLK),
.rst(RST),
.a(A),.b(B),.c(C),.d(D),
.w(W),.x(X),.y(Y),.z(Z));
always #5 CLK = !CLK;
initial begin
start = 0;
CLK = 0;
RST = 1;
#10 RST = 0;
end
initial begin
file1=$fopen(`CSV_FILE,"r");
file2=$fopen(`CSV_OUT_FILE,"w");
i = 0;
while (i < CSV_COL_DEPTH)
begin
scanRet = $fscanf(file1, "%h, %h, %h, %h", col1[i], col2[i], col3[i], col4[i]);
i = i + 1;
end
for (i = 0; i < CSV_COL_DEPTH; i = i + 1) begin
#(posedge CLK) A = col1[i];
B = col2[i];
C = col3[i];
D = col4[i];
start = 1;
$display("%h, %h, %h, %h",W, X, Y, Z);
$fwrite(file2,"%h, %h, %h, %h\n",W, X, Y, Z);
end
start = 0;
//once writing is finished, close all the files.
$fclose(file1);
$fclose(file2);
//wait and then stop the simulation.
#10000;
$stop;
end
endmodule
The following is the input.csv that I use for my test:
00000000,00000001,00000002,00000003
00000004,00000005,00000006,00000007
00000008,00000009,0000000A,0000000B
0000000C,0000000D,0000000E,0000000F
00000010,00000011,00000012,00000013
00000014,00000015,00000016,00000017
00000018,00000019,0000001A,0000001B
0000001C,0000001D,0000001E,0000001F
00000020,00000021,00000022,00000023
00000024,00000025,00000026,00000027
00000028,00000029,0000002A,0000002B
0000002C,0000002D,0000002E,0000002F
00000030,00000031,00000032,00000033
00000034,00000035,00000036,00000037
00000038,00000039,0000003A,0000003B
0000003C,0000003D,0000003E,0000003F
00000040,00000041,00000042,00000043
00000044,00000045,00000046,00000047
00000048,00000049,0000004A,0000004B
0000004C,0000004D,0000004E,0000004F
00000050,00000051,00000052,00000053
00000054,00000055,00000056,00000057
00000058,00000059,0000005A,0000005B
0000005C,0000005D,0000005E,0000005F
00000060,00000061,00000062,00000063
00000064,00000065,00000066,00000067
00000068,00000069,0000006A,0000006B
0000006C,0000006D,0000006E,0000006F
00000070,00000071,00000072,00000073
00000074,00000075,00000076,00000077
00000078,00000079,0000007A,0000007B
0000007C,0000007D,0000007E,0000007F
The following is my output.csv. I expect the output.csv to be similar to the input.csv, but I see some inconsistency. I am missing the last few lines and a line in the start as shown below.
xxxxxxxx, xxxxxxxx, xxxxxxxx, xxxxxxxx
00000000, 00000000, 00000000, 00000000
00000000, 00000000, 00000000, 00000000
00000000, 00000000, 00000000, 00000000
00000004, 00000005, 00000006, 00000007
00000008, 00000009, 0000000a, 0000000b
0000000c, 0000000d, 0000000e, 0000000f
00000010, 00000011, 00000012, 00000013
00000014, 00000015, 00000016, 00000017
00000018, 00000019, 0000001a, 0000001b
0000001c, 0000001d, 0000001e, 0000001f
00000020, 00000021, 00000022, 00000023
00000024, 00000025, 00000026, 00000027
00000028, 00000029, 0000002a, 0000002b
0000002c, 0000002d, 0000002e, 0000002f
00000030, 00000031, 00000032, 00000033
00000034, 00000035, 00000036, 00000037
00000038, 00000039, 0000003a, 0000003b
0000003c, 0000003d, 0000003e, 0000003f
00000040, 00000041, 00000042, 00000043
00000044, 00000045, 00000046, 00000047
00000048, 00000049, 0000004a, 0000004b
0000004c, 0000004d, 0000004e, 0000004f
00000050, 00000051, 00000052, 00000053
00000054, 00000055, 00000056, 00000057
00000058, 00000059, 0000005a, 0000005b
0000005c, 0000005d, 0000005e, 0000005f
00000060, 00000061, 00000062, 00000063
00000064, 00000065, 00000066, 00000067
00000068, 00000069, 0000006a, 0000006b
0000006c, 0000006d, 0000006e, 0000006f
00000070, 00000071, 00000072, 00000073
I am trying to understand where I am going wrong.

There is a simulation race condition in your testbench. You need to drive the inputs to the dut using nonblocking assignments (<=) instead of blocking assignments (=). For example:
#(posedge CLK) A <= col1[i];
This fixes the missing 0, 1, 2, 3 in your output.
Since your design adds cycles of latency between your input and output, you need to extend the time that you look at your outputs (after you stop driving your inputs).
Here is how the testbench can be changed to get your expected output:
for (i = 0; i < CSV_COL_DEPTH; i = i + 1) begin
#(posedge CLK) A <= col1[i];
B <= col2[i];
C <= col3[i];
D <= col4[i];
start = 1;
#(negedge CLK);
$display("%h, %h, %h, %h",W, X, Y, Z);
$fwrite(file2,"%h, %h, %h, %h\n",W, X, Y, Z);
end
for (i = 0; i < 3; i = i + 1) begin
#(negedge CLK);
$display("%h, %h, %h, %h",W, X, Y, Z);
$fwrite(file2,"%h, %h, %h, %h\n",W, X, Y, Z);
end
start = 0;
Note the 2nd for loop, which only displays and writes to your file.
For the display/fwrites, I changed posedge to negedge to avoid races.

When RST is set, all of the registers in your design are set to 0.
Your bench is sending the first set of values while RST is set.
Additionally, you need to run at least 3 more clocks to sample the remaining values.
The strategy previously posted of separating the driving and monitoring loops is worth considering, although potential problems with blocking assignments is a red herring in this instance.

Related

Problem with VCS simulation for MAC operation

I intended to write and simulate a module performing MAC operation. My code is shown below
module PE # (
parameter DW = 8
)
(
input clk,
input rst_n,
input [DW-1 : 0] cin,
input [DW-1 : 0] w,
output [DW-1 : 0] cin_out,
output [DW-1 : 0] w_out,
output [2*DW : 0] pe_out
);
reg [DW-1 : 0] cin_reg;
reg [DW-1 : 0] w_reg;
reg [2*DW : 0] m_reg;
reg [2*DW : 0] pe_reg;
always #(posedge clk) begin
if(rst_n==1'b0) begin
pe_reg <= 0;
cin_reg <= 0;
w_reg <= 0;
end
else begin
cin_reg <= cin;
w_reg <= w;
m_reg <= cin_reg * w_reg;
pe_reg <= pe_reg + m_reg;
end
end
assign cin_out = cin_reg;
assign w_out = w_reg;
assign pe_out = pe_reg;
endmodule
I used VCS to simulate, however, pe_out kept xxxxxxxx as shown in fig below.
false wave
I have asked my friend to use verilator to simulate, it can work as expected. And if I delete pe_reg <= pe_reg + m_reg, it still works. Therefore, the issue is likely to be caused by the add operation? But I haven't solved it yet.
I'll be appreciate if anyone can give me some instructions. It have confused me for hours.
My tb is written as below.
module tb_PE;
reg clk;
reg rst_n;
reg [7:0] cin;
reg [7:0] w;
wire [7:0] cin_out;
wire [7:0] w_out;
wire [16:0] pe_out;
wire [16:0] pe_out_tmp;
initial begin
clk = 0;
forever begin
#10;
clk = ~clk;
end
end
initial begin
rst_n = 1'b1;
#5;
rst_n = 1'b0;
#10;
rst_n = 1'b1;
#5;
cin = 8'h01;
w = 8'h02;
#15;
cin = 8'h03;
w = 8'h04;
#20;
cin = 8'h05;
w = 8'h03;
#20;
cin = 8'h90;
w = 8'h88;
#20;
cin = 8'h65;
w = 8'h20;
#100;
$finish;
PE PE_U (
.clk(clk),
.rst_n(rst_n),
.cin(cin),
.w(w),
.cin_out(cin_out),
.w_out(w_out),
.pe_out(pe_out)
);
end
As #mkrieger1 mentioned, you have not initialized m_reg. So, the following is happening:
at the first posedge you initialized some of the variables, including pe_reg, while m_reg is still x.
at the second posedge m_reg is still x. Using nonblocking assignment you schedule it to change later, but in this expression pe_reg <= pe_reg + m_reg; it is still x.
as a result, pe_reg becomes x again because m_reg is still x and it will stays same because it is used recursively in the expression.
So, the easiest way to handle it is to initialize m_reg in the same bucket as pe_reg. If for some reason it is not acceptable, you need to delay evaluation of pe_reg for another cycle.

Verilog inout port assignment results in X

I am fairly new to Verilog and I am stuck on a particular problem of doing an assignment operation to an inout wire port. The issue I faced is after the assignment to the inout port -_memd_data in the processor_core module, I get XXXXXXXX as the result in the _memd_data variable when it should be 0x5b78193a.
Line with issue: assign _memd_data = (mem_dWE)? mem_o_data : 32'bz;
Before assigning the data, below are the lines of code that occured before the execution of that line above (can't figure out what is wrong, looks completely fine to me).
STR: //Result store
begin
if(memAddr==7) begin
csmemd = 1;
mem_o_data <= R[R1]; //STR r1, [r2]
mem_dWE = 1;
memAddr <= memAddr + Addr;
Brief explanation of this small project: Basically it simulates the workings of a single cycle processor. The processor_core module should be able to fetch memory from the imem module based on a given address and decode the instruction fetched, then load the data from the data memory which is the dmem module, then condition_uct a XOR operation on the data with an encryption key(0x5a5b5c5d) fetched from the imem instruction address and compute the result and store the resulting data back to the dmem module to replace the old data. Also simulates an encryption of data.
Note: I only need to implement the processor_core module, feels like I am so close, but yet so far from getting it done..
I am using Vivado software to code this.
TestBench
`timescale 1ns / 1ps
module Nexys4_MAT_Top(
//CLK Input
input CLK100MHZ ,
input CPU_RESETN,
//Push Button Inputs
input BTNC ,
// Slide Switch Inputs
input [15:0] SW ,
// LED Outputs
output [15:0] LED ,
// Seven Segment Display Outputs
output CA ,
output CB ,
output CC ,
output CD ,
output CE ,
output CF ,
output CG ,
output [ 7:0] AN ,
output DP
);
//CLK: 100MHz
parameter periodCLK_2 = 5;
parameter perioddump = 10;
parameter delay = 1;
parameter delay_in = 2;
//Clock & reset signals
wire clk_main ;
wire rstn ;
//Processor signals
wire [ 4:0] memAddr ;
wire [31:0] memData_I ;
wire [ 5:0] memAddr_d ;
wire [31:0] _memd_data ;
wire [31:0] _memd_data_cpu ;
wire dmem_wr ;
wire csmemd ;
reg CLK_TB;
reg RSTN;
// CLK_TB //
initial
begin
CLK_TB = 1'b0;
#(perioddump);
CLK_TB = 1'b1;
forever
begin
CLK_TB = !CLK_TB;
#(periodCLK_2);
end
end
initial begin
global_reset();
repeat(1) #(posedge CLK_TB); #delay;
repeat(1) #(posedge CLK_TB); #delay;
repeat(10) #(posedge CLK_TB);#delay;
end
task global_reset;
begin
repeat(2) #(posedge CLK_TB); #delay;
repeat(2) #(posedge CLK_TB); #delay;
RSTN = 1'b0;
repeat(2) #(posedge CLK_TB); #delay;
RSTN = 1'b1;
end
endtask
// Circuit implementation
clkrst u_clkrst(
.CLK100MHZ (CLK_TB ),
.rst_btn (RSTN ),
.clk_out (clk_main ),
.rstn (rstn )
);
processor_core u_processor(
.clk (clk_main ),
.rstn (rstn ),
.memAddr (memAddr ),
.memData_I (memData_I ),
.memAddr_d (_memd_data_cpu ),
._memd_data (_memd_data ),
.mem_dWE (mem_dWE ),
.csmemd (csmemd )
);
imem u_imem(
.clk (clk_main ),
.rstn (rstn ),
.addr (memAddr ),
.cs (1'b1 ),
.we (1'b0 ),
.data (memData_I )
);
dmem u_dmem(
.clk (clk_main ),
.rstn (rstn ),
.addr (_memd_data_cpu ),
.cs (csmemd ),
.we (mem_dWE ),
.data (_memd_data )
);
endmodule
Design sources
`timescale 1ns / 1ps
module processor_core(
input clk ,//Input clock
input rstn ,//Reset signal, low active
output [ 4:0] memAddr ,//instruction memory address
input [31:0] memData_I ,//instruction memory data
output [ 5:0] memAddr_d ,//data memory address
inout [31:0] _memd_data ,
output mem_dWE ,
output csmemd
);
// For I/O signals
reg [ 4:0] memAddr ;
reg [ 5:0] memAddr_d ;
reg mem_dWE ;
reg csmemd ;
// For internal signals
reg [31:0] _memd_data_i ;//The input data from dmem
reg [31:0] mem_o_data ;//The output data for dmem
parameter AND = 4'h2;
parameter SUB = 4'h4;
parameter ORR = 4'h5;
parameter XOR = 4'h1;
parameter ADD = 4'h2;
parameter MOV = 4'h3;
parameter LDR = 4'h5;
parameter STR = 4'h6;
parameter CMP = 4'h4;
parameter N = 3;
parameter Z = 2;
parameter C = 1;
parameter V = 0;
reg [3:0] nzcv_;
parameter Addr = 1;
reg[31:0] condition_;
reg[0:0] condition_tionCarry;
reg[3:0] Aluchk;
reg[3:0]Opcde_chk;
reg[31:0]Br_check;
reg[7:0]IVal;
reg[23:0]branc_offs;
reg[3:0] R1;
reg[3:0] R2;
reg[3:0] R3;
reg[31:0] R[15:0];
reg [31:0] b;
integer index;
integer clk_count;
assign _memd_data = (mem_dWE)? mem_o_data : 32'bz; //Issue with assignment
always # (posedge clk or negedge rstn) begin
if (!rstn) begin
_memd_data_i <= 32'h0;
end
else begin
_memd_data_i <= _memd_data;
end
end
always # (posedge clk or negedge rstn)
begin
if(!rstn) begin
nzcv_[N] = 0;
nzcv_[Z] = 0;
nzcv_[C] = 0;
nzcv_[V] = 0;
Br_check<=32'h0;
IVal<=0;
mem_o_data = 32'h0;
R1<=0;
R2<=0;
R3<=0;
end
else begin
Aluchk = memData_I[31:31];
R1 = memData_I[15:12];
R2 = memData_I[11:8];
R3 = memData_I[7:4];
branc_offs = memData_I[27:4];
Opcde_chk = memData_I[30:28];
Br_check = memData_I[31:0];
IVal = memData_I[27:16];
case(Br_check)
BEQ:
begin
if(nzcv_[Z] == 1'b1) //BEQ Done
$stop;
end
BNE:
begin
if(nzcv_[Z] == 1'b0)
memAddr <= memAddr - branc_offs;
end
case(Aluchk)
1'b1:
begin
case(Opcde_chk)
XOR: //ADD ompute Result
begin
if(memAddr==6) begin
// csmemd = 0;
R[R1] = R[R2] ^ R[R3];
// mem_dWE = 1;
// csmemd = 1;
mem_o_data <= R[R1];
memAddr <= memAddr + Addr;
end
end
ADD:
begin
// mem_dWE = 0;
if(memAddr==8) begin
mem_dWE = 0;
// R[R2]<=R[R2]+IVal;
memAddr_d<=memAddr_d+IVal;
// memAddr_d = R[R2];
memAddr <= memAddr + Addr;
end
end
endcase
end
1'b0:
begin
case(Opcde_chk)
MOV:
begin
clk_count = clk_count + 1;
if(memAddr==0) begin
R[R3][31:24] <= IVal;
end
if(memAddr==4 && clk_count == 5) begin
R[R2] <= IVal;
end
memAddr <= memAddr + Addr;
end
LDR:
begin
if(memAddr==5) begin
csmemd = 1;
R[R1] = 0;
R[R1] = _memd_data_i; //LDR r1, [r2]
memAddr <= memAddr + Addr;
end
end
STR: //Result store
begin
if(memAddr==7) begin
csmemd = 1;
mem_o_data <= R[R1];
mem_dWE = 1;
memAddr <= memAddr + Addr;
// mem_o_data = R[R1];
end
end
endcase
end
endcase
end
end
endmodule
`timescale 1ns / 1ps
module dmem(
input clk ,//Input clock
input rstn ,//Reset signal, low active
input [ 5:0] addr ,//memory address
input cs ,
input we ,
inout [31:0] data
);
// For I/O signals
// For internal signals
reg [31:0] mem[0:63] ;
// Circuit implementation
assign data = (cs) ? mem[addr] : 32'bz;
always # (posedge clk or negedge rstn) begin
if (!rstn) begin
//The hard coded data, or plain text
mem[ 0] <= 32'h43314220;
mem[ 1] <= 32'h42020032;
mem[ 2] <= 32'h00650039;
mem[ 3] <= 32'h01150032;
mem[ 4] <= 32'h01150097;
mem[ 5] <= 32'h01020101;
mem[ 6] <= 32'h00320116;
mem[ 7] <= 32'h01010120;
mem[ 8] <= 32'h01160032;
mem[ 9] <= 32'h01190105;
mem[10] <= 32'h01160104;
mem[11] <= 32'h00320099;
mem[12] <= 32'h01110100;
mem[13] <= 32'h01010032;
mem[14] <= 32'h00480120;
mem[15] <= 32'h00490050;
mem[16] <= 32'h00510052;
mem[17] <= 32'h00330000;
end
else begin
if (we&&cs)
begin
mem[addr] <= data;
end
end
end
endmodule
`timescale 1ns / 1ps
`timescale 1ns / 1ps
module imem(
input clk ,//Input clock
input rstn ,//Reset signal, low active
input [ 4:0] addr ,//memory address
input cs ,
input we ,
inout [31:0] data
);
// For I/O signals
// For internal signals
reg [31:0] mem[0:11] ;
// Circuit implementation
assign data = (cs) ? mem[addr] : 32'bz;
always # (posedge clk or negedge rstn) begin
if (!rstn) begin
//The hard coded instructions
mem[ 0] <= 32'h10330030;
mem[ 1] <= 32'h203f0030;
mem[ 2] <= 32'h30120030;
mem[ 3] <= 32'h40220030;
mem[ 4] <= 32'h30000230;
mem[ 5] <= 32'h50001200;
mem[ 6] <= 32'h90005130;
mem[ 7] <= 32'h10006000;
mem[ 8] <= 32'ha3011430;
mem[ 9] <= 32'h40120400;
mem[10] <= 32'h200000b1;
mem[11] <= 32'h20000000;
end
else begin
if (cs && we)
begin
mem[addr] = data;
end
end
end
endmodule
module clkrst(
input CLK100MHZ ,//On-board input clock
input rst_btn ,//On-board reset from button, HIGH active
output clk_out ,//The working clk for the rest of circuit
output rstn //The working reset for the rest of circuit, LOW active
);
// For I/O signals
reg clk_50m ;
reg clk_25m ;
// For internal signals
// Circuit implementation
assign rstn = rst_btn;
assign clk_out = CLK100MHZ;
endmodule
In your testbench, the dmem_data wire is connected to 2 module instance output ports:
processor_core u_processor(
.dmem_data (dmem_data ),
//...
);
dmem u_dmem(
.data (dmem_data )
//...
);
That is fine, but only if one of them is active. Your problem is that both drivers are active at the same time. These are the 2 drivers:
assign dmem_data = (dmem_we)? dmem_data_o : 32'bz; //Issue with assignment
assign data = (cs) ? mem[addr] : 32'bz;
Since dmem_we and cs are both 1 at the same time (starting at time 145ns, for example), both are trying to drive the same signal with different values. This results in contention which is why you get X (unknown).
Here is one place where the tristate enables are both set to 1:
if(imem_addr==7) begin
dmem_cs = 1;
dmem_data_o <= R[R1]; //STR r1, [r2]
dmem_we = 1;
You need to change this logic.

Why doesn't the up/down counter count down?

I was doing the Logic Design assignment, and I found some problems I can't solve.
I need to design a 6-bit counter, and this counter needs to count with two functions, for up and down respectively.
I have done the up part and down part, but when I run the simulation, the counting down part doesn't work correctly.
The function for counting down: the next a = a - 2^n, where n = 0, 1, 2, 3... eg. a1 = 63, a2 = 63 - 1 = 62, a3 = 62 - 2 = 60, a4 = 56...
But the simulation with my program, it becomes 63, 62, 61(63 - 2), 59(63 - 4)...
By the way, this assignment has a reset feature.
However, my program won't keep counting after being reset.
It should back to zero and continue counting theoretically.
The following is my code:
`timescale 1ns/100ps
module lab2_1(
input clk,
input rst,
output reg [5:0] out
);
reg [5:0] cnt;
wire [5:0] cnt_next;
reg updown;
wire [5:0] out_next;
initial begin
out = 0;
cnt = 1;
updown = 1;
end
assign cnt_next = (out == 6'b111111) ? 0 : cnt + 1;
assign out_next = out - (2**cnt);
always #(*) begin
if(out == 6'b111111)begin
updown = 0;
end
if(out == 6'b000000)begin
updown = 1;
end
if(rst == 1) begin
out = 0;
updown = 1;
cnt = 0;
end
end
always #(posedge clk, posedge rst) begin
if(updown == 1)begin
if(out > cnt)begin
out <= out - cnt;
end
else
out <= out + cnt;
end
else begin
out <= out_next;
end
cnt <= cnt_next;
end
endmodule
The testbench just monitors the output and drives the inpupts.
`timescale 1ns/100ps
module lab2_1_t;
wire [5:0] out;
reg clk;
reg rst;
lab2_1 v(clk, rst, out);
initial begin
clk = 0;
rst = 0;
$monitor($time,":clk = %b, rst = %b, out = %d", clk, rst, out);
end
always #10 clk = ~clk;
always #10000 rst = ~rst;
endmodule
You should not make assignments to the same signal (such as cnt) from multiple blocks. You can assign to cnt from a single always block. I don't think you need both out and cnt.
Here is a simplified version which automatically switches between up and down:
module lab2_1(
input clk,
input rst,
output reg [5:0] cnt
);
reg updown;
always #(posedge clk, posedge rst) begin
if (rst) begin
updown <= 1;
end else if (cnt == 6'b111110) begin
updown <= 0;
end else if (cnt == 6'b000001) begin
updown <= 1;
end
end
always #(posedge clk, posedge rst) begin
if (rst) begin
cnt <= 0;
end else if (updown) begin
cnt <= cnt + 1;
end else begin
cnt <= cnt - 1;
end
end
endmodule
The code shows a more typical use of the reset signal in the sequential always block. See also for more examples.
Here is a modified testbench where the reset is asserted at time 0, then released after a couple clock cycles. At the end, it asserts reset again so you can see that the counter goes to 0.
module lab2_1_t;
wire [5:0] out;
reg clk;
reg rst;
lab2_1 v(clk, rst, out);
initial begin
$monitor($time,":clk = %b, rst = %b, out = %d", clk, rst, out);
clk = 0;
rst = 1;
#40 rst = 0;
#10000 rst = 1;
#1000 $finish;
end
always #10 clk = ~clk;
endmodule

How do you select a range of bits from an expression of registers?

I am trying to take the average of 8 8-bit registers. I was able to do it structurally, by having four 8-> 9-bit adders, two 9-> 10 bit adder, and one 10-> 11-bit adder. This works correctly; however, I was curious if there is a better way/ more efficient way to do this.
For the structural way, all I have to do is have the assign a wire from the 10->11 bit adder to the output.
I'm trying to do something like below, but it says
Index <10> is out of range [7:0] for signal .
I have it index 10, in case all the registers are large like 255.
module avg(
num_in,
clk,
rs,
ave8
) ;
input clk ;
input rs;
input [7:0] num_in ;
output [7:0] ave8 ;
reg [7:0] registers [7:0] ;
always #(posedge clk) begin
if(rs) begin
registers[0] <= 0;
registers[1] <= 0;
registers[2] <= 0;
registers[3] <= 0;
registers[4] <= 0;
registers[5] <= 0;
registers[6] <= 0;
registers[7] <= 0;
end
registers[0] <= num_in;
registers[1] <= registers[0];
registers[2] <= registers[1];
registers[3] <= registers[2];
registers[4] <= registers[3];
registers[5] <= registers[4];
registers[6] <= registers[5];
registers[7] <= registers[6];
end
// This assign function is what I am focused on.
assign ave8 = {registers[0] + registers[1] + registers[2] + registers[3] + registers[4] + registers[5] + registers[6] + registers[7]}[10:3];
One way is to create a sum wire:
wire [10:0] sum = registers[0] + registers[1] + registers[2] + registers[3] + registers[4] + registers[5] + registers[6] + registers[7];
assign ave8 = sum[10:3];
I suggest using for loops:
module avg(
input [7:0] num_in ,
input clk ,
input rs ,
output reg [7:0] ave
);
parameter SIZE = 8;
reg [7:0] registers [SIZE-1:0] ;
reg [10:0] accumulator;
integer i;
always #(posedge clk) begin
if(rs)
for(i=0;i<SIZE;i=i+1)
registers[i] <= 0;
registers[0] <= num_in;
for(i=1;i<SIZE;i=i+1)
registers[i] <= registers[i-1];
accumulator = 0;
for(i=0;i<SIZE;i=i+1)
accumulator = accumulator + registers[i];
ave <= accumulator/SIZE;
end
endmodule
This would be so much easier to write in SystemVerilog, which ISE supports:
module avg(
input [7:0] num_in ,
input clk ,
input rs ,
output logic [7:0] ave
);
parameter SIZE = 8;
logic [7:0] registers [SIZE] ;
always #(posedge clk) begin
if(rs)
registers = '{default:0};
registers <= {num_in, registers[1:$size(registers)-1]};
ave <= registers.sum() with (int'(item))/SIZE;
end
endmodule

Output of multiplication in Verilog not showing in simulate behavior

I've written two different Verilog snippets for combinational and sequential multiplication, which I post below. When I simulate either of the multiplications the multiplier, denoted mult_A and multiplicand, denoted mult_B show their bit-string values, but the resulting product, denoted R shows all Xs. Help in showing the codes multiplication result R would be greatly appreciated.
Combinational
module com_multiplication(mult_A, mult_B, R);
input [15:0] mult_A, mult_B;
output R;
reg [31:0] R;
integer k;
always#(mult_A, mult_B)
begin
R = 0;
for(k = 0; k < 16; k = k + 1)
if(mult_A[k] == 1'b1) R = R + (mult_B << 1);
end
endmodule
Serial
module ser_multiplication(mult_A, mult_B, clk, start, R, finish);
input [15:0] mult_A, mult_B;
input clk, start;
output R, finish;
reg [31:0] R;
reg [15:0] mult_A_duplicate;
reg [31:0] mult_B_duplicate;
reg [4:0] p;
wire finish = !p;
initial p = 0;
always#(posedge clk)
if (finish && start) begin
p = 16;
R = 0;
mult_B_duplicate = {16'd0, mult_B};
mult_A_duplicate = mult_A;
end else if (p) begin
if (mult_A_duplicate[0] == 1'b1) R = R + mult_B_duplicate;
mult_A_duplicate = mult_A_duplicate >> 1;
mult_B_duplicate = mult_B_duplicate << 1;
p = p - 1;
end
endmodule
Testbench
For now the serial part is commented out.
module multiplication_tb;
reg clk, start, finish;
reg [15:0] mult_A, mult_B;
reg [31:0] R;
com_multiplication U0 (
.mult_A (mult_A),
.mult_B (mult_B),
.R (R)
);
/*ser_multiplication U1 (
.clk (clk),
.start (start),
.finish (finish),
.mult_A (mult_A),
.mult_B (mult_B),
.R (R)
); */
initial
begin
$display("time\t clk start finish");
$monitor ("%g\t %b %b %b %b %b %b", $time, clk, start, finish, mult_A,
mult_B, R);
#100 clk = 0;
mult_A =0;
mult_B = 0;
#10 mult_A = 2;
mult_B = 3;
#20 mult_B=2;
#10 mult_B=5;
#100 $finish;
end
always
#5 clk = !clk;
endmodule
I just glanced at your code but it looks like your clock is not toggling. Simple way to make a forever toggling clock is:
initial
begin
clk = 1'b0;
forever
#50 clk = ~clk;
end

Resources