Splitting a bit array in Verilog - algorithm

I am designing a basic AES algorithm on verilog, and I need to split a 128 bits array into 16 parts each one of 8 bits.
For example (basic 8 bit example), if I receive 10111011 I need to generate 4 outputs 10 11 10 11

Retrieving bytes from an array is straight forward:
module huge_array (
input [128-1:0] data
);
wire [7:0] first_byte,
assign first_byte = data[7:0];
wire [7:0] second_byte,
assign second_byte = data[8*2-1:8*1];
endmodule
It would be much easier if the data was formatted into a memory.
module huge_array2 (
input [7:0] data [0:16]
);
wire [7:0] first_byte,
assign first_byte = data[0];
wire [7:0] second_byte,
assign second_byte = data[1];
endmodule

A double packed array works:
reg [127:0] in;
wire [15:0] [7:0] out_1 = in; // msb in entry 15
wire [0:15] [7:0] out_2 = in; // msb in entry 0
If only one byte is needed to be read at a time, it can be done Verilog-2001 or SystemVerilog as:
reg [127:0] in;
reg [3:0] idx;
wire [7:0] out = in[8*idx +: 8];

Related

VHDL to Verilog [duplicate]

This question already has answers here:
What is the difference between reg and wire in a verilog module?
(3 answers)
Closed 2 years ago.
I have some code in VHDL I am trying to convert to Verilog.
The VHDL code works fine
library ieee;
use ieee.std_logic_1164.all;
entity find_errors is port(
a: bit_vector(0 to 3);
b: out std_logic_vector(3 downto 0);
c: in bit_vector(5 downto 0));
end find_errors;
architecture not_good of find_errors is
begin
my_label: process (a,c)
begin
if c = "111111" then
b <= To_StdLogicVector(a);
else
b <= "0101";
end if;
end process;
end not_good;
The Verilog code I have, gets errors "Illegal reference to net "bw"."
and
Register is illegal in left-hand side of continuous assignment
module find_errors(
input [3:0]a,
output [3:0]b,
input [5:0]c
);
wire [0:3]aw;
wire [3:0]bw;
reg [5:0]creg;
assign aw = a;
assign b = bw;
assign creg = c;
always #(a,c)
begin
if (creg == 4'b1111)
bw <= aw;
else
bw <= 4'b0101;
end
endmodule
It looks pretty close but there are a few things that are problems/errors that need to be fixed, see inline comments in fixed code:
module find_errors(
input wire [3:0] a, // Better to be explicit about the types even if
// its not strictly necessary
output reg [3:0] b, // As mentioned in the comments, the error youre
// seeing is because b is a net type by default; when
// describing logic in any always block, you need to
// use variable types, like reg or logic (for
// SystemVerilog); see the comment for a thread
// describing the difference
input wire [5:0] c);
// You dont really need any local signals as the logic is pretty simple
always #(*) begin // Always use either always #(*), assign or
// always_comb (if using SystemVerilog) for combinational logic
if (c == 6'b111111)
b = a; // For combinational logic, use blocking assignment ("=")
// instead of non-blocking assignment ("<="), NBA is used for
// registers/sequential logic
else
b = 4'b0101;
end
endmodule
aw and creg are unnecessary, and bw needs to be declared as reg.
module find_errors(
input [3:0] a,
output [3:0] b,
input [5:0] c
);
reg [3:0] bw;
assign b = bw;
always #(a,c)
begin
if (c == 4'b1111)
bw <= a;
else
bw <= 4'b0101;
end
endmodule
Since there is no sequential logic, you don't even need an always block:
module find_errors(
input [3:0] a,
output [3:0] b,
input [5:0] c
);
assign b = (c == 4'b1111) ? a : 4'b0101;
endmodule

Verilog code: initializing an 2D array using nested for loop

I'm recently trying to store a 2D array whose elements are consisted of 8-bit integers(0~4) by first input its elements row by row (treating it as an 1D array) and then access the values in the 1D array.
my procedure is as follow:
1.initialize an 2048-bits-1D (8*16*16) array (Row1 in the code) in test bench as input
2.cut the 1D array every 8 bits and assign the 8-bit number to the elements in the 2D array
3.use another 1D array (Row2 in the code) to observe the final result, because an array cannot be used as an instance output
So actually i'm turning an 1D array with 256 8-bit elements into a 2D array with 16*16 8-bit elements.
the problem is that after running the simulation,
it seems that most of the elements in the 2D array is in a high z state,
while the last of them have been assigned new value correctly.
Can anyone explain what's going on and how can i fix it?
To be clear, i put my verilog code below:
`timescale 1ns / 1ps
module convPE(
input clk,
input reset,
input [2048:1] Row1,
output [2048:1] Row2
);
wire [7:0] arr[17:0][17:0];
generate
genvar i,j;
for(i=16;i>=1;i=i-1)
begin:gen1
for(j=16;j>=1;j=j-1)
begin:gen2
assign arr[i][j]=Row1[(8*i*j) -: 8];
assign Row2[(8*i*j) -: 8]=arr[i][j];
end
end
end generate
endmodule
And here is the test bench :
`timescale 1ns / 1ps
module testbench;
// Inputs
reg [2048:1] Row1;
reg Clk;
reg Reset;
wire [2048:1] Row2;
convPE uut (
.clk(Clk),
.reset(Reset),
.Row1(Row1),
.Row2(Row2)
);
initial begin
// Initialize Inputs
Row1=2048'd0;
Row1[1784:1777]=8'd1;//1
Row1[1584:1577]=8'd1;
Row1[944:937]=8'd1;
Row1[376:369]=8'd1;
//2
Row1[1720:1713]=8'd2;
Row1[1600:1593]=8'd2;
Row1[1488:1481]=8'd2;
Row1[1480:1473]=8'd2;
Row1[1368:1361]=8'd2;
Row1[1344:1337]=8'd2;
Row1[1336:1329]=8'd2;
Row1[1120:1113]=8'd2;
Row1[1112:1105]=8'd2;
Row1[1080:1073]=8'd2;
Row1[1072:1065]=8'd2;
Row1[1056:1049]=8'd2;
Row1[984:977]=8'd2;
Row1[936:929]=8'd2;
Row1[856:849]=8'd2;
Row1[808:801]=8'd2;
Row1[728:721]=8'd2;
Row1[680:673]=8'd2;
Row1[608:601]=8'd2;
Row1[592:585]=8'd2;
Row1[584:577]=8'd2;
Row1[576:569]=8'd2;
Row1[568:561]=8'd2;
Row1[560:553]=8'd2;
Row1[544:537]=8'd2;
Row1[472:465]=8'd2;
Row1[424:417]=8'd2;
Row1[416:409]=8'd2;
//3
Row1[1712:1705]=8'd3;
Row1[1592:1585]=8'd3;
Row1[1472:1465]=8'd3;
Row1[1360:1353]=8'd3;
Row1[1352:1345]=8'd3;
Row1[1240:1233]=8'd3;
Row1[1208:1201]=8'd3;
Row1[1200:1193]=8'd3;
Row1[1064:1057]=8'd3;
Row1[992:985]=8'd3;
Row1[928:921]=8'd3;
Row1[864:857]=8'd3;
Row1[736:729]=8'd3;
Row1[600:593]=8'd3;
Row1[464:457]=8'd3;
Row1[456:449]=8'd3;
Row1[448:441]=8'd3;
Row1[440:433]=8'd3;
Row1[432:425]=8'd3;
//4
Row1[800:793]=8'd4;
Row1[672:665]=8'd4;
Row1[552:545]=8'd4;
#100
Reset=1'b1;
#100
Reset=1'b0;
Clk=1'b1;
// Add stimulus here
end
always
#50 Clk=~Clk;
endmodule
This (8*i*j) does not work. You have two nested loops so i in the second loop must increment in steps of 16. (The size of the inner loop) Try 8*(i*16+j)-1
Your code is somewhat inconsistent in that you sometimes use 0 and sometimes 1 as lowest index. I suggest you make all your arrays and vectors start from 0. [2047:0] It is the Verilog convention.
I have converted your code using the Verilog conventions I use. I also removed all superfluous signals like clock and reset. With the following code there are no X-es or Z-es in either Row2 or in arr.
`timescale 1ns / 1ps
module convPE(
input [2047:0] Row1,
output [2047:0] Row2
);
wire [7:0] arr[15:0][15:0];
generate
genvar i,j;
for(i=0; i<16; i=i+1)
begin:gen1
for(j=0; j<16; j=j+1)
begin:gen2
assign arr[i][j]=Row1[(8*(i*16+j)) +: 8];
assign Row2[(8*(i*16+j)) +: 8] =arr[i][j];
end
end
endgenerate
endmodule
`timescale 1ns / 1ps
module testbench;
// Inputs
reg [2047:0] Row1;
wire [2047:0] Row2;
convPE uut (
.Row1(Row1),
.Row2(Row2)
);
initial begin
#100; // I want to see X-es first
// Initialize Inputs
Row1=2048'd0;
#100;
$stop;
end
endmodule
The reason I use my method is because it is the standard way of mapping N-dimensional arrays of a certain type onto memory (which is linear) like e.g. C compilers do.
You can use 2048:1 but then you have to think much harder how to convert the indexes to a one-dimensional array. Probably replace the i and j in my formula with something like i-1,j-1.

add and shift in verilog

Here's my verilog code about add and shift multiplying
when I compile and Initialze and adding the inputs and outputs to get waveforms and simulating them, I dont see any results, everything is z... what is the problem?
module multi(a, b, ans);
input [3:0] a;
input [3:0] b;
output reg [15:0] ans;
reg [15:0] aa;
reg [15:0] bb;
reg [15:0] tmp=0;
reg flag = 1'b1;
always #( a, b)
begin
aa = a;
bb = b;
while ( flag == 1'b1 )
begin
if( bb[0] == 1'b1 )
tmp = tmp + aa;
aa = aa << 1;
bb = bb >> 1;
if ( bb==0 )
flag = 1'b0;
end
ans = tmp;
end
endmodule
There are a number of things that look strange with this code.
First is that you have no clock input, but are attempting to do everything with combinatorial logic.
Second is that setting flag to 1 in the reg statement will mean that your module is only capable of doing a single multiplication. By the way, it is more normal (especially for ASIC design) to use a reset signal than use this initialisation in a reg line.
Third is that a 4 bit number times a 4 bit number will result in an 8bit answer, not 16bit.
In any case, unless you are working at very high speeds you should be able to perform a multiply in a single cycle.
Here are a couple of ways of writing this code more naturally:
Combinatorial Style
module multi(a, b, ans);
input [3:0] a;
input [3:0] b;
output reg [7:0] ans;
always #(*)
begin
ans = a * b;
end
endmodule
Clocked style
module multi(clk, a, b, ans);
input [3:0] a;
input [3:0] b;
output reg [7:0] ans;
always #(posedge clk)
begin
ans <= a * b;
end
endmodule
Your input is 4 bits wide and your assigning to a 16 bit variable, the top 12 bits are unassigned ie x.
input [3:0] a;
reg [15:0] aa;
//...
aa = a;
To assign all bits of aa try some thing like:
aa = {12'b0, a};
//{} is bit concatenation
Or to sign extend a to 16 bits, repeat the MSB 12 times using {width{value}} replication:
aa = {{12{a[3]}}, a};

How to find MAX or MIN in Verilog coding?

the question is simple, I heared that assign out = (a>b)?a:b is wrong. is it wrong? if it is, is there another way to find MAX?
It's right if and only if out is a wire. If it's a register, then you have to do something like this:
always #* begin
if (a>b)
out = a;
else
out = b;
end
Take into account that in Verilog, a variable of type reg can infer either a wire or a latch, or a true register. It depends on how you specify the behaviour of the module that uses that reg:
Combinational (out is implemented as a wire although it's a reg)
module max (input [7:0] a,
input [7:0] b,
output reg [7:0] out);
always #* begin
if (a>b)
out = a;
else
out = b;
end
endmodule
Combinational (out is implemented as a wire and it's defined as a wire)
module max (input [7:0] a,
input [7:0] b,
output [7:0] out);
assign out = (a>b)? a : b;
endmodule
Latch (out is a reg, and it's implemented as a latch which stores the last produced result if conditions don't make it change, i.e. if a==b, which btw, may not provide a correct output in that case)
module max (input [7:0] a,
input [7:0] b,
output reg [7:0] out);
always #* begin
if (a>b)
out = a;
else if (a<b)
out = b;
end
endmodule
Register (out is implemented as a true register, clock edge triggered)
module max (input clk,
input [7:0] a,
input [7:0] b,
output reg [7:0] out);
always #(posedge clk) begin
if (a>b)
out <= a;
else if (a<=b)
out <= b;
end
endmodule
What you have there looks correct to me. There isn't really any other way to do it.
this works with 3 input values
module max(
input [7:0] v1,
input [71:0] v2,
input [7:0] v3,
output [7:0] max
);
wire [7:0] v12;
wire [7:0] v23;
assign v12 = v1>=v2 ? v1 : v2;
assign v23 = v2>=v3 ? v2 : v3;
assign m = v12>=v23 ? v12 : v23;
endmodule
You can do this by using subtractor. Using a subtractor is less area cost expensive and faster - if fpga have sub/add components or arithmetic sub/add operation support and do not have comperator components.
https://polandthoughts.blogspot.com/2020/04/the-4-bit-signed-comparator.html
Check boolean function at the end. You check only 3 bits.
Sorry for my English.

bit vector range selection with runtime value in system verilog

Let's say I have a vector value[6:0] and an input vector input[3:0]. The problem is I want to set a number of bit in value vector to 1 base on value of input, e.g.:
input = 0011 (3 in dec) then value = 000111 (set 3 bits to 1)
input = 0101 (5 in dec) then value = 011111 (set 5 bits to 1)
As we can do this easy only when the value in constant, but here it is run-time change. Any ideas on solve this?
There's no need to select a range here.
wire [3:0] input;
wire [7:0] shifted;
wire [6:0] value; //This can only hold 0 to 7
//Assign 2^input then subtract 1
assign shifted = 1'b1 << input;
assign value = shifted - 1;
This could be as simple as this:
wire [3:0] input;
wire [31:0] constant_value = 32'h0000_FFFF;
wire [15:0] output;
assign output = constant_value[ input +: 16 ];
Note "+:" range selection.

Resources