Implementing a 2n-bit comparator using cascaded 2-bit comparators - logic

So far I have this code for a 2-bit comparator.
module twobitcomparator(xgtyin,xety,xltyin,x1,x0,y1,y0,xgty,xety,xlty);
//I/O
output xgty, xety, xlty; //xgty - x>y, xlty - x<y, xety - x=y
input x1, x0, y1, y0, xgtyin, xetyin, xltyin;
//specify circuit behavior
assign r = (xgyin);
assign s = (xlyin);
assign t = (xetyin);//not sure if I need an xetyin
assign a = (x1&~y1);
assign b = (x1&x0&~y0);
assign c = (x0&~y1&~y0);
assign xgty = (a|b|c|r);//X>Y
assign d = (~x0&~y0);
assign e = (x0&y0);
assign f = (x1&y1);
assign g = (~x1&~y1);
assign xety = ((d|e)&(f|g));//X=Y
assign h = (~x1&~x0&y0);
assign i = (~x1&y1);
assign j = (~x0&y1&y0);
assign xlty = (h|i|j|s);//X<Y
endmodule
Does this look good? I wrote a testbench for it and looked at the wave and the outputs were correct for the inputs, but I'm not sure if it's the most efficient way.
For the cascading, I know that the highest bit comparator's result (if it is an inequality) will just need to be sent down through the rest of the comparators and that will be the final result. If they are equal, then I just have to find the highest bit comparator where there is an inequality and that needs to be cascaded like I mentioned.
I am stuck on getting them to cascade, I am very new to Verilog and I have no clue how I should get each comparator's result into the next one. Here is my attempt.
module ncompare#( parameter n = 2)(input [2*n-1:0] xgyin, xlyin,
input [2*n-1:0] x1, x0, y1, y0,
output [2*n-1:0] xgy, xey, xly,
output xqyout);
wire xqyin;
assign xqyin = 1'b0;
twobitcomparator s1(.xgyin(xgyin[xqyin]), .xlyin(xlyin[xqyin]),
.x1(x1[2*n-1]), .x0(x0[2*n-2]), .y1(y1[2*n-1]), .y0(y0[2*n-2]),
.xgy(xgy[ripple0]), .xey(xey[ripple1]), .xly(xly[ripple2]));
twobitcomparator s0(.xgyin(xgyin[ripple0]), .xlyin(xlyin[ripple2]),
.x1(x1[1]), .x0(x0[0]), .y1(y1[1]), .y0(y0[0]),
.xgy(xgy[ripple3]), .xey(xey[ripple4]), .xly(xly[ripple5]));
endmodule
I think I need to use a generate statement since I need to make it work for any parameter n but I have no clue how to use generate since all examples I've looked at only have one output and I have three (that are also the next comparator's inputs! Agh!)
Thanks for any and all help!

The 2-bit comparator module can be rewritten as
module twobitcomparator(xgtyin,xltyin,x,y,xgty,xlty,xety);
output xgty, xety, xlty;
input xgtyin, xltyin;
input [1:0] x,y;
assign xgty = xgtyin | (~xltyin & ((x[1] > y[1]) | ((x[1] == y[1]) & (x[0] > y[0]))));
assign xlty = xltyin | (~xgtyin & ((x[1] < y[1]) | ((x[1] == y[1]) & (x[0] < y[0]))));
assign xety = ~(xlty | xgty);
endmodule
I have treated the two bit input as a bus instead of treating them as individual bits (Verilog allows you to do that). I have trimmed out the numerous intermediate results that were present in your code. This makes the code easier to understand as you do not have to keep track of all those temporary wires.
I then simulated this module using Icarus Verilog on EDA Playground. The link is here
https://www.edaplayground.com/x/5KRL
A four-bit comparator that uses these twobitcomparators can be written as follows.
module fourbitcomparator(xgtyin,xltyin,x,y,xgty,xlty,xety);
output xgty, xety, xlty;
input xgtyin, xltyin;
input [3:0] x,y;
wire xgty_1,xlty_1,xety_1;
twobitcomparator u_1 (
.xgtyin(xgtyin),
.xltyin(xltyin),
.x(x[3:2]),
.y(y[3:2]),
.xgty(xgty_1),
.xlty(xlty_1),
.xety(xety_1)
);
twobitcomparator u_0 (
.xgtyin(xgty_1),
.xltyin(xlty_1),
.x(x[1:0]),
.y(y[1:0]),
.xgty(xgty),
.xlty(xlty),
.xety(xety)
);
endmodule
Finally a 2n bit comparator using twobitcomparators, can be generalised as follows
module twoN_bitcomparator #(
parameter N = 2
)(
input xgtyin,
input xltyin,
input [(2*N-1):0]x,
input [(2*N-1):0]y,
output xgty,
output xlty,
output xety
);
wire [N:0] xgty_w,xlty_w,xety_w;
assign xgty_w[N] = xgtyin;
assign xlty_w[N] = xltyin;
generate
genvar i;
for (i=0;i<=(N-1);i=i+1)
begin:TWOBITGEN
twobitcomparator u_1 (
.xgtyin(xgty_w[i+1]),
.xltyin(xlty_w[i+1]),
.x(x[(2*i+1) : (2*i)]),
.y(y[(2*i+1) : (2*i)]),
.xgty(xgty_w[i]),
.xlty(xlty_w[i]),
.xety(xety_w[i])
);
end
endgenerate
assign xgty = xgty_w[0];
assign xlty = xlty_w[0];
assign xety = xety_w[0];
endmodule
The simulation of this generalised module is also available on EDA playground at https://www.edaplayground.com/x/2fbr
The waveform for the small testbench is also available at https://www.edaplayground.com/w/x/27X

Related

Applying simple inversion (NOT function) to OBUFDS

I am a newbie here to ask a question, that is too easy for you to answer, but I am not familiar with.
I have "cabletester_prbs15_bytegenerator" IP in my BD, which has "data_out_p" and "data_out_n" connected to OBUFDS ports.
In my situation I have an OBUFDS connected to "data_out_p", but assign to NEGATIVE DIFFERENTIAL LEG in implementation. At the moment, after successful synthesis, when I try to assign it to IO_##_N in synthesis design, It gives error message "cannot set LOC property of ports, the negative port (N-side) of a differential pair can not be placed on a positive Pin"
Long story short, I need to invert polarity of OBUFDS.
cabletester_prbs15_bytegenerator IP uses module "prbs15_bytegenerator" like below.
module cabletester_prbs15_bytegenerator_0_0 (
clk,
clk_div4,
resetb,
data_out_p,
data_out_n
);
(* X_INTERFACE_PARAMETER = "XIL_INTERFACENAME clk, ASSOCIATED_RESET resetb:reset, FREQ_HZ 640000000, FREQ_TOLERANCE_HZ 0, PHASE 0.0, CLK_DOMAIN cabletester_clk_wiz_0_0_clk_320, INSERT_VIP 0" *)
(* X_INTERFACE_INFO = "xilinx.com:signal:clock:1.0 clk CLK" *)
input wire clk;
input wire clk_div4;
(* X_INTERFACE_PARAMETER = "XIL_INTERFACENAME reset, POLARITY ACTIVE_LOW, INSERT_VIP 0" *)
(* X_INTERFACE_INFO = "xilinx.com:signal:reset:1.0 reset RST" *)
input wire resetb;
output wire data_out_p;
output wire data_out_n;
prbs15_bytegenerator inst (
.clk(clk),
.clk_div4(clk_div4),
.resetb(resetb),
.data_out_p(data_out_p),
.data_out_n(data_out_n)
);
endmodule
In prbs15_bytegenerator, you can see OBUFDS relevant part at the end
OSERDESE3 #(
.DATA_WIDTH(8),
.IS_CLKDIV_INVERTED(0),
.IS_CLK_INVERTED(0),
.IS_RST_INVERTED(1),
.SIM_DEVICE("ULTRASCALE_PLUS")
)
oserdes_inst
(
.OQ(data_out),
.CLK(clk),
.CLKDIV(clk_div4),
.D(prbsbyte),
.RST(resetb)
);
OBUFDS outputbuf
(
.I(data_out),
.O(data_out_p),
.OB(data_out_n)
);
endmodule
Is inverting the polarity just as simple as putting ~ in front of .O(data_out_p)?
I would really appreciate if one could show what the code should exactly look like cuz I know very little about Verilog.....
Thank you so much....
You probably want to keep the polarity of the OBUFDS correctly orientated. P to positive leg, and N to negative leg. Instead, try invering the input to the OBUFDS by making the following tweak.
OBUFDS outputbuf
(
.I(~data_out), // This will invert the input and cause the
.O(data_out_p), // output to logically invert.
.OB(data_out_n)
);
You might have a problem with your pin assignment. You should review the XDC constraint file.
Or, here post your constraint with the device part number.

Octave: matrix multiplication over a group

I'd like to simply compute multiplication of two matrices.
But instead of real numbers I'd like to use elements of a finite group in the matrix.
Namely I want to use elements of F4={0,1,x,1+x} (so i only have 4 possible elements). In this group, addition and multiplication are well-defined, and the relations x^2=1+x, 1+1=0 and x+x=0 hold.
Since I'm a beginner at programming in Octave, I have no idea how to compute operations with something different than real numbers.
My idea was, that if it's possible to define some operations on a certain set of elements (here F4), then it's maybe possible to use these operations when multiplicating matrices.
I think the most efficient way to do arithmetic with a finite group of possible values and non-standard addition and multiplication is by table lookup.
Table lookup requires matrices to be encoded such that the elements are indices into the list of group elements. And since indexing starts at 1, you'll need to represent {0,1,x,x+1} as {1,2,3,4}.
But aside the awkward mapping of 1=0, 2=1, things are quite straightforward with table lookup. This is some example code I cooked up, it seems to work but I might have made some mistake (and I might have misunderstood the exact arithmetic rules):
function out = group_mtimes(lhs,rhs)
[I,K] = size(lhs);
[K2,J] = size(rhs);
if K~=K2, error('Inner dimensions must agree'), end
out = zeros(I,J);
for j=1:J
for i=1:I
v = 1;
for k=1:K
v = group_scalar_add(v, group_scalar_times(lhs(i,k),rhs(k,j)));
end
out(i,j) = v;
end
end
disp('lhs = ')
group_print(lhs)
disp('rhs = ')
group_print(rhs)
disp('lhs * rhs = ')
group_print(out)
end
function group_print(in)
names = {'0','1','x','1+x'};
disp(names(in)) % Quick-and-dirty, can be done much better!
end
function out = group_scalar_add(lhs,rhs)
table = [
1,2,3,4
2,1,4,3
3,4,1,2
4,3,2,1
];
out = table(lhs,rhs);
end
function out = group_scalar_times(lhs,rhs)
table = [
1,1,1,1
1,2,3,4
1,3,4,2
1,4,2,3
];
out = table(lhs,rhs);
end
For example:
>> lhs=[1,2,3,4;2,3,1,4]';
>> rhs=[2,3;4,1];
>> group_mtimes(lhs,rhs);
lhs =
'0' '1'
'1' 'x'
'x' '0'
'1+x' '1+x'
rhs =
'1' 'x'
'1+x' '0'
lhs * rhs =
'1+x' '0'
'0' 'x'
'x' '0'
'x' '1'
There is no input checking in this code, if the input contains a 5, you'll get and index out of range error.
As I mentioned in a comment, you could make a class that encapsulates arrays of this type. You could then overload plus, times and mtimes (for operators +, .* and *, respectively), as well as disp to write out the values properly. You would define the constructor so that objects of this class always have valid values, this would prevent lookup table indexing errors. Such a class would make working with these functions a lot simpler.
For the special case of Galois fields of even characteristic, such as F4, you can use the functions provided by the communications package from Octave Forge:
Functions reference: Galois Fields of Even Characteristic
Galois fields of odd charactristic are not implemented yet:
Functions reference: Galois Fields of Odd Characteristic

DMux.hdl failure when in=1, sel=0

I'm writing the hdl code for a DMux based on the Nand2Tetris course.
CHIP DMux {
IN in, sel;
OUT a, b;
PARTS:
And(a = sel, b = in, out = b);
Not(in = sel, out = selNot);
And(a = in, b = selNot, out = a);
}
For some reason, this code fails on the test script values of in = 1 and sel = 0. It evaluates a and b both to 0 in this case.
I have written out the gates multiple times, and I can't figure out why the result is not a = 1 and b = 0
Can someone explain to me what is happening?
I have a feeling your Not implementation may have a problem.
Try replacing the Not with a Nand:
Nand(a=sel,b=sel,out=notSel); // notSel = ! sel
If this works, then your Not.hdl is incorrect.
Also, on a style point, it's clearer if you define your intermediates before your final outputs (ie: put the Nand first), and be consistent in your input ordering (ie: a=in, b=sel or notSel, out = a or b). Helps reduce the chance you will misread something.
Not sure that anything is wrong with your code. It looks to be the same as mine, which works. Have you tested your other And and Not gates?
My code:
Not(in=sel, out=notsel);
And(a=notsel, b=in, out=a);
And(a=in, b=sel, out=b);

Assigning values of 4*4 matrix

I'm trying to create a 4*4 matrix in this form:
2 3 1 1
1 2 3 1
1 1 2 3
3 1 1 2
Then I need to assign the values element in each location to multiply by 4 inputs each one 8 bits.
a0, a1, a2, a3
I have tried to write this code :
module Mix_Nibbles_Matriex(
out_0,out_1,out_2,out_3,nibble_0,nibble_1,nibble_2,nibble_3,
clk,rst,load
);
input clk,rst,load ;
output reg [7:0] out_0,out_1,out_2,out_3;
input [7:0] nibble_0,nibble_1,nibble_2,nibble_3;
//wire matrix[3:0][0:3];
reg [1:0][7:0] a_unpacked_array[4];
always #( posedge clk or negedge rst)
if (!rst)
a_unpacked_array[0][0]=0;
else if (load)
assign a_unpacked_array[0][0]=2;
assign a_unpacked_array[0][1]=3;
assign a_unpacked_array[0][2]=1;
assign a_unpacked_array[0][3]=1;
assign a_unpacked_array[1][0]=2;
assign a_unpacked_array[1][1]=3;
assign a_unpacked_array[1][2]=1;
assign a_unpacked_array[1][3]=1;
assign a_unpacked_array[2][0]=2;
assign a_unpacked_array[2][1]=3;
assign a_unpacked_array[2][2]=1;
assign a_unpacked_array[2][3]=1;
assign a_unpacked_array[3][0]=2;
assign a_unpacked_array[3][1]=3;
assign a_unpacked_array[3][2]=1;
assign a_unpacked_array[3][3]=1;
//display ("a_unpacked_array = %b", a_unpacked_array);
endmodule
I'm still have these errors:
ERROR:HDLCompiler:939 - "D:/Embedded_Project/Mix_Nibbles_Matriex.v" Line 38: Single value range is not allowed in this mode of verilog
ERROR:HDLCompiler:1439 - "D:/Embedded_Project/Mix_Nibbles_Matriex.v" Line 38: Multiple packed dimensions are not allowed in this mode of verilog
ERROR:HDLCompiler:1417 - "D:/Embedded_Project/Mix_Nibbles_Matriex.v" Line 44: Bit-select or part-select is not allowed in a assign statement for non-net a_unpacked_array
ERROR:HDLCompiler:598 - "D:/Embedded_Project/Mix_Nibbles_Matriex.v" Line 27: Module ignored due to previous errors.
There are couple problems with your code.
Verilog doesn't support multiple packed dimensions. You'd need to use SystemVerilog to make this construct work. You can also follow #Greg suggestion to use unpacked dimension.
reg [1:0][7:0] a_unpacked_array[4]; - compiler tries to treat 4 as range, but single value range are not allowed. Maybe what you meant is [3:0]? Also [1:0] should be probably [3:0].
Your always block has some issues: missing begin-end, unnecessary assign keywords, etc.:
always #(posedge clk or negedge rst)
if (!rst) begin
a_unpacked_array[0][0] <= 0;
//...
end else if (load) begin
a_unpacked_array[0][0] <= 2;
//...
end

Xilinx warnings (FF/Latch trimming) in Verilog for a MSB downsampling

In this other question I asked I got some general advice regarding my module.
Now I seek advice here since I noted that the Verilog community has more users.
I am trying to implement into an existing framework a Most Significant Bit (MSB) operation.
The idea is as follows: I am getting 32 bit complex samples in from ddc_out_strobe, which are 16 bit I and 16 bit Q.
My idea is to combine 4 "cutted" samples into a new sample to feed to the output bb_sample. This is done by getting the 4 MSB out of I0,Q0,I1,Q1,I2,Q2,I3,Q3 (4*8 = 32 bit total) and wiring them every 4th bb_strobe to bb_sample.
Here you can see my implementation:
module my_rx_dsp0_custom
#(
//frontend bus width
parameter WIDTH = 24
)
(
//control signals
input clock, //dsp clock
input reset, //active high synchronous reset
input clear, //active high on packet control init
input enable, //active high when streaming enabled
//user settings bus, controlled through user setting regs API
input set_stb, input [7:0] set_addr, input [31:0] set_data,
//full rate inputs directly from the RX frontend
input [WIDTH-1:0] frontend_i,
input [WIDTH-1:0] frontend_q,
//full rate outputs directly to the DDC chain
output [WIDTH-1:0] ddc_in_i,
output [WIDTH-1:0] ddc_in_q,
//strobed samples {I16,Q16} from the RX DDC chain
input [31:0] ddc_out_sample,
input ddc_out_strobe, //high on valid sample
output ddc_out_enable, //enables DDC module
//strobbed baseband samples {I16,Q16} from this module
output [31:0] bb_sample,
output bb_strobe //high on valid sample
);
reg [3:0] i_msb;
reg [3:0] q_msb;
reg [31:0]temp_buff = 0;
reg [31:0]my_zeros = 0;
reg [1:0] count = 0;
always #(posedge clock)
if(ddc_out_strobe) begin
i_msb <= ddc_out_sample[31:28];
q_msb <= ddc_out_sample[15:12];
temp_buff <= {i_msb,q_msb,temp_buff[31:24]};
// to avoid if-else conditions
count <= (count==2'd3) ? 2'd0 : (count+1);
end
// to avoid if-else conditions
assign bb_strobe = (count==2'd3) ? 1'b1 : 1'b0;
assign bb_sample = (count==2'd3) ? temp_buff : my_zeros;
assign ddc_out_enable = enable;
assign ddc_in_i = frontend_i;
assign ddc_in_q = frontend_q;
endmodule //my_rx_dsp0_custom
(1) When trying to build the FPGA images I get the following warning (I just show you the one for 23, but it is the same for other ones):
WARNING:Xst:1896 - Due to other FF/Latch trimming, FF/Latch <temp_buff_23> has a constant value of 0 in block <my_rx_dsp0_custom>. This FF/Latch will be trimmed during the optimization process
I have searched this problem in SE and found some good explanations on what might be going wrong, here or here for example.
What I understand is the following: temp_buff <= {i_msb,q_msb,temp_buff[31:24]}; is a conflictive line since the <= operator is getting the old values from i_msb and q_msb, and not the ones from the MSB operation.
(2) I tried avoiding if-else conditions to allow me to declare some things out of the always #* block (this way I avoid having a wire on the LHS of an always block, which is not allowed).
Are my conditionals correct?
As I explained before, I want only every 4th bb_sample to be assigned.
Is assign bb_strobe = (count==2'd3) ? 1'b1 : 1'b0; getting the effect I want despite not being in the always #(posedge clock) block?
If other infos are needed, please let me know. This is part of a much bigger project that I am trying to modify for my purposes.
(1) The trimmed FF/Latch warning is not due to non-blocking assignments. It is from 24 bits of the temp_buff register always being assigned to zeros. The RHS is 16bits; i_msb (4 bits), q_msb (4 bits), and temp_buff[31:24] (8 bits). And you are assigning it to a 32bit value. The assignment:
temp_buff <= {i_msb,q_msb,temp_buff[31:24]};
Is equivalent to:
temp_buff <= {16'h0000, i_msb,q_msb,temp_buff[31:24]};
This means temp_buff[31:16] will always be zero can can be optimized out. temp_buff[7:0] can also be optimized out to constant zeros because it is assigned to temp_buff[31:24] which is a constant 0. Perhaps you meant you shift right 8 bits like so:
temp_buff <= {i_msb,q_msb,temp_buff[31: 8 ]};
(2) You are correct that wires should not be assigned with any always block (or initial block). However you could have turned the wire to a reg. It is a miss conception that reg is for registers only (FF/Latches). reg in a properly coded combinational block will create combinational logic (no FF or Latches). Property meaning the reg is assigned within every branching condition withing the always block, else it infers a latch. Example
module my_rx_dsp0_custom
/* ... your original code ... */
output reg [31:0] bb_sample,
output reg bb_strobe //high on valid sample
);
/* ... your original code ... */
always #(posedge clock)
if(ddc_out_strobe) begin
temp_buff <= {i_msb,q_msb,temp_buff[31:8]};
count <= (count==2'd3) ? 2'd0 : (count+1);
end
always #*
begin
i_msb = ddc_out_sample[31:28];
q_msb = ddc_out_sample[15:12];
bb_strobe = (count==2'd3);
bb_sample = bb_strobe ? temp_buff : 32'd0;
end
assign ddc_out_enable = enable;
/* ... your original code ... */

Resources