Arithmetic Right Shift without using shift operators - verilog

I want to write a 16 Bit Arithmetic right shift function in verilog without using shift operators.
My Code so far:
module my_shift(Number, Range, Shifted);
input [15:0] Number;
input [3:0] Range;
output[15:0] Shifted;
reg Shifted;
always #(Number)
Shifted = shifted_number(Number, Range);
function[15:0] shifted_number;
input [15:0] number;
input [3:0] Range; //4 bit shift range
integer i;
integer j;
begin
for (i = 0; i < Range; i = i + 1) begin
for (j = 0; j < 15; j = j + 1) begin
shifted_number[j] = number[j+1];
end
end
shifted_number[15] = number[15];
end
endfunction
endmodule
I wrote a simple Testbench to test my function.
I just want to shift three different numbers by 1 bit.
My Testbench:
module test;
reg [15:0] Number;
reg [3:0] Range;
wire[15:0] shifted;
my_shift shift_number(Number, Range,shifted);
initial
$monitor($time," -->Number = %b, shifted = %b, ",Number,shifted);
initial begin
Range = 1;
Number = 3;
#10;
Number = 4;
#10;
Number = 5;
#100 $finish;
end
endmodule
Which gives me the following output:
0 -->Number = 0000000000000011, shifted = 0000000000000001,
10 -->Number = 0000000000000100, shifted = 0000000000000000,
20 -->Number = 0000000000000101, shifted = 0000000000000000,
It compiles but there is a warning at:
my_shift shift_number(Number, Range,shifted);
The warning:
warning: Port sizes don't match in port #3
Why does the compiler give me this warning and why is the output incorrect?

You incorrectly declared Shifted as a 1-bit reg:
Change:
output [15:0] Shifted;
reg Shifted;
to:
output reg [15:0] Shifted;
I now get this output:
0 -->Number = 0000000000000011, shifted = 1000000000000001,
10 -->Number = 0000000000000100, shifted = 1000000000000010,
20 -->Number = 0000000000000101, shifted = 1000000000000010,
I ran your code on 2 different simulators and got much more helpful warning and error messages. You can try your luck on edaplayground.

Related

If statement is not executing properly while trying to create double dabble to convert binary to BCD

I am trying to build a binary to BCD converter using the double dabble algorithm. I wrote the code for the same, and when I simulated the entire thing, it was observed that my if statement is not getting executed properly.
`timescale 1ns / 1ps
module test_6( input [13:0] bin ,
output reg [3:0] ones, // ones value of the input number
output reg [3:0] tens, // tens value of the input number
output reg [3:0] hundreds, // hundreds value of the input nnumber
output reg [3:0] thousands // thousands value of the input number
);
integer i;
reg [15:0] scratch; // 16 bit register
reg [29:0] combined; // 30 bit concatenated register bin and scratch
always #(bin) begin
scratch = 0;
combined = {scratch[15:0], bin[13:0]}; // concatenating scratch and bin into combined
for (i=0; i<14; i=i+1) begin
combined = combined<<1; // left shift by 1
if (combined[17:14] > 4) begin
combined[17:14] = combined[17:14] + 4'b0011; //check if >4, if yes add 3
end
if (combined[21:18] > 4) begin
combined[21:18] = combined[21:18] + 4'b0011; //check if >4, if yes add 3
end
if (combined[25:22] > 4) begin
combined[25:22] = combined[25:22] + 4'b0011; //check if >4, if yes add 3
end
if (combined[29:26] > 4) begin
combined[29:26] = combined[29:26] + 4'b0011; //check if >4, if yes add 3
end
end
thousands = combined[29:26];
hundreds = combined[25:22];
tens = combined[21:18];
ones = combined[17:14];
$display(ones);
$display(tens);
$display(hundreds);
$display(thousands);
end
endmodule
The testbench is given below.
module test_6_tb;
// Inputs
reg [13:0] bin;
// Outputs
wire [3:0] ones;
wire [3:0] tens;
wire [3:0] hundreds;
wire [3:0] thousands;
// Instantiate the Unit Under Test (UUT)
test_6 uut (
.bin(bin),
.ones(ones),
.tens(tens),
.hundreds(hundreds),
.thousands(thousands)
);
initial begin
// Initialize Inputs
bin = 14'd1157;
// Wait 100 ns for global reset to finish
#100;
// Add stimulus here
end
endmodule
The output on the simulation window was as shown:
The output I am expecting is:
Thousands should have the value 1, hundreds should have the value 1, tens should have the value 5, ones should have the value 7.
The mistake in your code is that you did not follow the double dabble algorithm. From Wikipedia:
The algorithm then iterates n times. On each iteration, any BCD digit
which is at least 5 (0101 in binary) is incremented by 3 (0011); then
the entire scratch space is left-shifted one bit.
You performed the left shift before the add-by-3, but it should be done after.
for (i=0; i<14; i=i+1) begin
if (combined[17:14] > 4) begin
combined[17:14] = combined[17:14] + 4'b0011; //check if >4, if yes add 3
end
if (combined[21:18] > 4) begin
combined[21:18] = combined[21:18] + 4'b0011; //check if >4, if yes add 3
end
if (combined[25:22] > 4) begin
combined[25:22] = combined[25:22] + 4'b0011; //check if >4, if yes add 3
end
if (combined[29:26] > 4) begin
combined[29:26] = combined[29:26] + 4'b0011; //check if >4, if yes add 3
end
combined = combined<<1; // left shift by 1
end
Now I get the expected output: 1157.
After I posted my other answer, I was curious as to how the algorithm worked. So, I decided to try to follow the description as you did.
I searched on EE.SE and found this answer. It contains a link to Wikipedia, which has the following code. I had to fix a typo in the code, but this works:
// parametric Verilog implementation of the double dabble binary to BCD converter
// for the complete project, see
// https://github.com/AmeerAbdelhadi/Binary-to-BCD-Converter
module bin2bcd
#( parameter W = 14) // input width
( input [W-1 :0] bin , // binary
output reg [W+(W-4)/3:0] bcd ); // bcd {...,thousands,hundreds,tens,ones}
integer i,j;
always #(bin) begin
for(i = 0; i <= W+(W-4)/3; i = i+1) bcd[i] = 0; // initialize with zeros
bcd[W-1:0] = bin; // initialize with input vector
for(i = 0; i <= W-4; i = i+1) // iterate on structure depth
for(j = 0; j <= i/3; j = j+1) // iterate on structure width
if (bcd[W-i+4*j -: 4] > 4) // if > 4
bcd[W-i+4*j -: 4] = bcd[W-i+4*j -: 4] + 4'd3; // add 3
end
endmodule
module tb;
reg [13:0] bin;
reg [17:0] bcd;
wire [3:0] ones = bcd[ 3: 0];
wire [3:0] tens = bcd[ 7: 4];
wire [3:0] hundreds = bcd[11: 8];
wire [3:0] thousands = bcd[15:12];
bin2bcd dut (bin, bcd);
initial begin
$monitor(thousands,,hundreds,,tens,,ones);
#5 bin = 14'd1157;
#5 bin = 14'd0045;
#5 bin = 14'd9876;
end
endmodule
Prints:
x x x x
1 1 5 7
0 0 4 5
9 8 7 6
The algorithm is thoroughly explained in the article and in the header comments of the Verilog code in github.

Bits do not get shifted when performing shift operation in Verilog

I am trying to build an SPI module in verilog which transmits 8 bits of data, but when doing the shift operation I have noticed that shifting does not shift bits at all, while MOSI and MISO only take value of zero after the first cycle, which results in data on both side decaying to zero. What can I do to fix this?
Code for master:
module Master(input clk, input MISO,
output reg MOSI, output reg SS);
initial SS = 0;
reg [2:0] counter;
reg [7:0] Master_reg = 8'b11011011;
always # (posedge clk)
begin
if(!SS)
begin
if(^counter === 1'bx)
counter = 0;
else
counter = counter + 1;
MOSI = Master_reg[7];
Master_reg = Master_reg >> 1;
Master_reg[0] = MISO;
end
if(counter == 7)
SS = 1;
end
endmodule
Code for slave:
module Slave(input clk, input MOSI, input SS,
output reg MISO);
reg [2:0] counter;
reg [7:0] Slave_reg = 8'b11111111;
always # (posedge clk)
begin
if(!SS)
begin
if(^counter === 1'bx)
counter = 0;
else
counter = counter + 1;
MISO = Slave_reg[0];
Slave_reg = Slave_reg << 1;
Slave_reg[7] = MOSI;
end
end
endmodule
Transmission of given data (11011011 from master, 11111111 from slave) gives following result:
Edit: I am using EDA Playground as a simulator
There's a mistake in both master and slave. You're sending out the most significant bit of master_reg, but shifting that register to the right. You must shift it left instead.
Same with slave, the bit that's being sent is not the one toward which the data is shifted.
Btw, both the master and slave must shift to the same direction. Otherwise you'll get data reversed between master and slave.

Net 'VectorY[0]', or a directly connected net, is driven by more than one source, and at least one source is a constant net. (ELAB-368)

I am getting this error in VCS synthesizer. I have tried everything but it doesn't make sense to me.
it says VectorY[0], VectorY[1], VectorY[2], VectorY[3], or a directly connected net, is driven by more than one source, and at least one source is a constant net. (ELAB-368)
module control (clk, start, S1S2mux, newDist, CompStart, PEready, VectorX, VectorY, addressR, addressS1, addressS2,completed);
input clk;
input start;
output reg [15:0] S1S2mux;
output reg [15:0] newDist;
output CompStart;
output reg [15:0] PEready;
output reg [3:0] VectorX,VectorY;
output reg [7:0] AddressR;
output reg [9:0] AddressS1,AddressS2;
reg [12:0] count;
output reg completed;
integer i;
assign CompStart = start;
always #(posedge clk) begin
if(start==0) begin
count<= 12'b0;
completed<=0;
newDist<=0;
PEready<=0;
VectorX<=0;
VectorY<=0;
end
else if (completed==0)
count <= count+1'b1;
end
always #(count) begin
for (i = 0; i < 15; i = i+1)
begin
newDist [i] = (count [7:0] == i);
PEready [i] = (newDist [i] && !(count < 8'd256));
S1S2mux [i] = (count [3:0] > i);
end
addressR = count [7:0];
addressS1 = (count[11:8] + count[7:4] >> 4)*5'd32 + count [3:0];
addressS2 = (count[11:8] + count[7:4] >> 4)*4'd16 + count [3:0];
VectorX = count[3:0] - 4'd7;
VectorY = count[11:8] >> 4 - 4'd7;
completed = (count == 4'd16 * (8'd256 + 1));
end
endmodule
You can probably do like this...in systemverilog
create another logic variable
logic [3:0] VectorY_next;
and then in the sequential block, do ..
always_ff begin
if(start==0) begin
count<= 12'b0;
completed<=0;
newDist<=0;
PEready<=0;
VectorX<=0;
VectorY<=0;
end
else if (completed==0) begin
count <= count+1'b1;
VectorY <= VectorY_next;
end
end
And in the combinational block, you can write ...
always_comb begin
VectorY_next = VectorY;
for (i = 0; i < 15; i = i+1)
begin
.....
VectorY_next = count[11:8] >> 4 - 4'd7;
completed = (count == 4'd16 * (8'd256 + 1));
end
endmodule
And probably do the same for other ports too.To run using systemverilog, just use -sv option in the command line.

system verilog slicing arrays

I am still not sure how the array slicing works in System Verilog?
For example, let's say that I have a packed 2D array.
localparam [0:2][4:0] TEMP = {5'd4,5'd9,5'd20};
So my array has three rows and each row is a 5-bit number.
So, when I am trying to do something like this, it doesn't quite work !!!
logic [1:0] arr;
assign arr = TEMP[0][1:0]
How come this doesn't work?
The compiler doesn't complain, but the simulation shows all 'X !!
Here I am including the module that has the issue:
module slice_issue ();
// clock and reset
reg board_resetl;
reg tb_clkh;
parameter CLK_PER = 4;
always #(CLK_PER/2) tb_clkh = ~ tb_clkh;
initial begin: main_process
board_resetl = 0;
tb_clkh = 0;
#100
#(posedge tb_clkh);
board_resetl = 1;
end
localparam logic [4:0] PARAM_1 = 14;
localparam logic [4:0] PARAM_2 = 18;
localparam logic [4:0] PARAM_3 = 26;
localparam [0:2] [4:0] CAND_MODE_LIST = {PARAM_1, PARAM_2, PARAM_3};
logic [1:0] temp;
logic [4:0] temp2;
logic [1:0] in_pred_mode;
logic [4:0] cnt_reg;
always # (posedge tb_clkh or negedge board_resetl)
begin
if (~board_resetl) begin
in_pred_mode <= 0;
cnt_reg <= 0;
end else
cnt_reg <= cnt_reg + 1;
if (cnt_reg == 31) begin
in_pred_mode <= $urandom_range(0, 1);
end
end
// bad
assign temp = CAND_MODE_LIST[in_pred_mode][1:0];
// good
assign temp2 = CAND_MODE_LIST[in_pred_mode];
endmodule
A self contained example could be :
module tb;
localparam [0:2][4:0] TEMP = {5'd4,5'd9,5'd20};
logic [1:0] arr;
assign arr = TEMP[0][1:0];
initial begin
$display("arr : %b", arr);
#1ps;
$display(TEMP[0]);
$display(TEMP[1]);
$display(TEMP[2]);
$display("arr : %b", arr);
end
endmodule
For me this (correctly) outputs:
# KERNEL: arr : 00
# KERNEL: 4
# KERNEL: 9
# KERNEL: 20
# KERNEL: arr : 00
This does not show the error condition from the question, unless the question adds more information, the exact reason for the error can not be determined.
example on EDA Playground
instead of negative points, I should've gotten a positive one. I contacted the vendor (Aldec), and it turned out it is Aldec's simulator issue, and they are going to fixed it in their next revision.

Reduce array to sum of elements

I am trying to reduce a vector to a sum of all it elements. Is there an easy way to do this in verilog?
Similar to the systemverilog .sum method.
Thanks
My combinational solution for this problem:
//example array
parameter cells = 8;
reg [7:0]array[cells-1:0] = {1,2,3,4,5,1,1,1};
//###############################################
genvar i;
wire [7:0] summation_steps [cells-2 : 0];//container for all sumation steps
generate
assign summation_steps[0] = array[0] + array[1];//for less cost starts witch first sum (not array[0])
for(i=0; i<cells-2; i=i+1) begin
assign summation_steps[i+1] = summation_steps[i] + array[i+2];
end
endgenerate
wire [7:0] result;
assign result = summation_steps[cells-2];
Verilog doesn't have any built-in array methods like SV. Therefore, a for-loop can be used to perform the desired functionality. Example:
parameter N = 64;
integer i;
reg [7:0] array [0:N-1]
reg [N+6:0] sum; // enough bits to handle overflow
always #*
begin
sum = {(N+7){1'b0}}; // all zero
for(i = 0; i < N; i=i+1)
sum = sum + array[i];
end
In critiquing the other answers delivered here, there are some comments to make.
The first important thing is to provide space for the sum to be accumulated. statements such as the following, in RTL, won't do that:
sum = sum + array[i]
because each of the unique nets created on the Right Hand Side (RHS) of the expression are all being assigned back to the same signal called "sum", leading to ambiguity in which of the unique nets is actually the driver (called a multiple driver hazard). To compound the problem, this statement also creates a combinational loop issue because sum is used combinationally to drive itself - not good. What would be good would be if something different could be used as the load and as the driver on each successive iteration of the loop....
Back to the argument though, in the above situation, the signal will be driven to an unknown value by most simulator tools (because: which driver should it pick? so assume none of them are right, or all of them are right - unknown!!). That is if it manages to get through the compiler at all (which is unlikely, and it doesn't at least in Cadence IEV).
The right way to do it would be to set up the following. Say you were summing bytes:
parameter NUM_BYTES = 4;
reg [7:0] array_of_bytes [NUM_BYTES-1:0];
reg [8+$clog2(NUM_BYTES):0] sum [NUM_BYTES-1:1];
always #* begin
for (int i=1; i<NUM_BYTES; i+=1) begin
if (i == 1) begin
sum[i] = array_of_bytes[i] + array_of_bytes[i-1];
end
else begin
sum[i] = sum[i-1] + array_of_bytes[i];
end
end
end
// The accumulated value is indexed at sum[NUM_BYTES-1]
Here is a module that works for arbitrarily sized arrays and does not require extra storage:
module arrsum(input clk,
input rst,
input go,
output reg [7:0] cnt,
input wire [7:0] buf_,
input wire [7:0] n,
output reg [7:0] sum);
always #(posedge clk, posedge rst) begin
if (rst) begin
cnt <= 0;
sum <= 0;
end else begin
if (cnt == 0) begin
if (go == 1) begin
cnt <= n;
sum <= 0;
end
end else begin
cnt <= cnt - 1;
sum <= sum + buf_;
end
end
end
endmodule
module arrsum_tb();
localparam N = 6;
reg clk = 0, rst = 0, go = 0;
wire [7:0] cnt;
reg [7:0] buf_, n;
wire [7:0] sum;
reg [7:0] arr[9:0];
integer i;
arrsum dut(clk, rst, go, cnt, buf_, n, sum);
initial begin
$display("time clk rst sum cnt");
$monitor("%4g %b %b %d %d",
$time, clk, rst, sum, cnt);
arr[0] = 5;
arr[1] = 6;
arr[2] = 7;
arr[3] = 10;
arr[4] = 2;
arr[5] = 2;
#5 clk = !clk;
#5 rst = 1;
#5 rst = 0;
#5 clk = !clk;
go = 1;
n = N;
#5 clk = !clk;
#5 clk = !clk;
for (i = 0; i < N; i++) begin
buf_ = arr[i];
#5 clk = !clk;
#5 clk = !clk;
go = 0;
end
#5 clk = !clk;
$finish;
end
endmodule
I designed it for 8-bit numbers but it can easily be adapted for other kinds of numbers too.

Resources