Recursive instantiation: a synthesis no no?

ABC,

The generated instantiation allows recursion in Verilog.
I was told that's officially allowed in 2005 LRM - haven't seen copy
yet.

For example in the biton_merge module the generate loop instantiates
another two instances biton_merge module (both half the size of the
original one)

Of course you have to terminate recursion by using the if statement.

That's for synthesizable code. You can also use recursion for function
calls and tasks (they should be declared "automatic" to preserve local
signals)

Thanks,
Przemek



Code snipet:

module biton_merge (
data_in,
data_out
);
..
..
generate

if(DATA_ARRAY_SIZE_EXP>1) begin: nest

wire [DATA_UPPER_HALF_OFFSET-1:0] data_merge_1;
wire [DATA_UPPER_HALF_OFFSET-1:0] data_merge_0;


biton_merge
#(
.DATA_WIDTH(DATA_WIDTH),
.DATA_ARRAY_SIZE_EXP(DATA_ARRAY_SIZE_EXP_M1)
)
biton_merge_0
(
.data_in(data_div[ DATA_UPPER_HALF_OFFSET-1:0]),
.data_out(data_merge_0)
);




ABC wrote:
Hi Przemek,
Which statement of verilog allow recursive instantiation?

Best regards,
ABC

bazarnik@hotmail.com wrote:
Dear All,

FYI this issue was confirmed to be a bug in Design Compiler
(hopefully fixed in a next service pack)

I recoded the bitionic sort in an iterative form.
I would not recommend it unless one feels a need for a some of
the "human compiler" type of brain workout.
Actually doing the b.sort with recursion in Verilog is not really
that complex (see below) One just needs to use modules to avoid
too many nested loops and to keep things neat.

I did try Confluence quite some time earlier. It is a nice tool.
I have found the syntax to be quite "peculiar" but still better
than HDCaml bracket flood.
We do not have that much datapath code which would warrant
adding Confluence to our ASIC flow. This may change though.

Ultimately Confluence type languages are thay way HW design must go.
SystemVerilog interfaces and other stuff are another way to introduce
high level hardware design features.

Thanks,
Przemek


PS For you viewing pleasure:
the bitionic sort implemented in Verilog 2001 with recursive
instantiation.

Module list:
system (top level)
biton_sort
biton_merge
biton_bn
biton_reverse

I leave the iterative version as an excercise for the reader :)


module biton_bn (
data_in,
data_out
);

// Global parameters

parameter DATA_WIDTH = 4;
parameter DATA_ARRAY_SIZE_EXP = 2; // array is 2^DATA_ARRAY_SIZE_POW
elements this is equal to N for B(n) bitonic sort operator


// Local parameters
// data organized in following way:
// single long vector: { data3[3:0], data2[3:0], data1[3:0],
data0[3:0]}
parameter DATA_ARRAY_SIZE = (1<<DATA_ARRAY_SIZE_EXP); // array is
2^DATA_ARRAY_SIZE_POW elements
parameter DATA_ARRAY_MSB = (1<<DATA_ARRAY_SIZE_EXP) * DATA_WIDTH -1;


parameter DATA_UPPER_HALF_OFFSET = DATA_WIDTH * (DATA_ARRAY_SIZE>>1);

input [DATA_ARRAY_MSB:0] data_in;
output reg [DATA_ARRAY_MSB:0] data_out;

// ===============


genvar i;

generate for(i=0;i<(DATA_ARRAY_SIZE>>1);i=i+1) begin: comp

always @*
if( data_in[ (i+1)*DATA_WIDTH-1 : i*DATA_WIDTH] > data_in[
(i+1)*DATA_WIDTH-1+DATA_UPPER_HALF_OFFSET :
i*DATA_WIDTH+DATA_UPPER_HALF_OFFSET] ) begin
// swap
data_out[ (i+1)*DATA_WIDTH-1 : i*DATA_WIDTH] = data_in [
(i+1)*DATA_WIDTH-1+DATA_UPPER_HALF_OFFSET :
i*DATA_WIDTH+DATA_UPPER_HALF_OFFSET];
data_out[ (i+1)*DATA_WIDTH-1+DATA_UPPER_HALF_OFFSET :
i*DATA_WIDTH+DATA_UPPER_HALF_OFFSET] = data_in [ (i+1)*DATA_WIDTH-1 :
i*DATA_WIDTH];

end
else begin
// keep the same
data_out[ (i+1)*DATA_WIDTH-1 : i*DATA_WIDTH] = data_in [
(i+1)*DATA_WIDTH-1 : i*DATA_WIDTH];
data_out[ (i+1)*DATA_WIDTH-1+DATA_UPPER_HALF_OFFSET :
i*DATA_WIDTH+DATA_UPPER_HALF_OFFSET] = data_in [
(i+1)*DATA_WIDTH-1+DATA_UPPER_HALF_OFFSET :
i*DATA_WIDTH+DATA_UPPER_HALF_OFFSET];

end
end

endgenerate
endmodule


module biton_merge (
data_in,
data_out
);

// Global parameters

parameter DATA_WIDTH = 4;
parameter DATA_ARRAY_SIZE_EXP = 2; // array is 2^DATA_ARRAY_SIZE_POW
elements this is equal to N for B(n) bitonic sort operator


// Local parameters
// data organized in following way:
// single long vector: { data3[3:0], data2[3:0], data1[3:0],
data0[3:0]}
parameter DATA_ARRAY_SIZE = (1<<DATA_ARRAY_SIZE_EXP); // array is
2^DATA_ARRAY_SIZE_POW elements
parameter DATA_ARRAY_MSB = (DATA_ARRAY_SIZE * DATA_WIDTH) -1;

parameter DATA_ARRAY_SIZE_EXP_M1 = DATA_ARRAY_SIZE_EXP-1;


parameter DATA_UPPER_HALF_OFFSET = DATA_WIDTH * (DATA_ARRAY_SIZE>>1);

input [DATA_ARRAY_MSB:0] data_in;
output [DATA_ARRAY_MSB:0] data_out;

// ===============

wire [DATA_ARRAY_MSB:0] data_div;


biton_bn
#(
.DATA_WIDTH(DATA_WIDTH),
.DATA_ARRAY_SIZE_EXP(DATA_ARRAY_SIZE_EXP)
)
biton_bn_1
(
.data_in(data_in),
.data_out(data_div)
);


generate

if(DATA_ARRAY_SIZE_EXP>1) begin: nest

wire [DATA_UPPER_HALF_OFFSET-1:0] data_merge_1;
wire [DATA_UPPER_HALF_OFFSET-1:0] data_merge_0;


biton_merge
#(
.DATA_WIDTH(DATA_WIDTH),
.DATA_ARRAY_SIZE_EXP(DATA_ARRAY_SIZE_EXP_M1)
)
biton_merge_0
(
.data_in(data_div[ DATA_UPPER_HALF_OFFSET-1:0]),
.data_out(data_merge_0)
);


biton_merge
#(
.DATA_WIDTH(DATA_WIDTH),
.DATA_ARRAY_SIZE_EXP(DATA_ARRAY_SIZE_EXP_M1)
)
biton_merge_1
(
.data_in(data_div[ DATA_ARRAY_MSB:DATA_UPPER_HALF_OFFSET]),
.data_out(data_merge_1)
);

assign data_out = {data_merge_1, data_merge_0};

end
else begin: last

assign data_out = data_div;

end
endgenerate
endmodule


module biton_reverse (
data_in,
data_out
);

// Global parameters

parameter DATA_WIDTH = 4;
parameter DATA_ARRAY_SIZE_EXP = 2; // array is 2^DATA_ARRAY_SIZE_POW
elements this is equal to N for B(n) bitonic sort operator


// Local parameters
// data organized in following way:
// single long vector: { data3[3:0], data2[3:0], data1[3:0],
data0[3:0]}
parameter DATA_ARRAY_SIZE = (1<<DATA_ARRAY_SIZE_EXP); // array is
2^DATA_ARRAY_SIZE_POW elements
parameter DATA_ARRAY_MSB = (DATA_ARRAY_SIZE * DATA_WIDTH) -1;


input [DATA_ARRAY_MSB:0] data_in;
output [DATA_ARRAY_MSB:0] data_out;

// ===============

genvar i;

generate for(i=0;i<DATA_ARRAY_SIZE;i=i+1) begin: rev
assign data_out[ (i+1)*DATA_WIDTH-1 : i*DATA_WIDTH] = data_in[
(DATA_ARRAY_SIZE-i)*DATA_WIDTH-1 : (DATA_ARRAY_SIZE-i-1)*DATA_WIDTH];
end

endgenerate
endmodule




module biton_sort (
data_in,
data_out
);

// Global parameters

parameter DATA_WIDTH = 4;
parameter DATA_ARRAY_SIZE_EXP = 2; // array is 2^DATA_ARRAY_SIZE_POW
elements this is equal to N for B(n) bitonic sort operator


// Local parameters
// data organized in following way:
// single long vector: { data3[3:0], data2[3:0], data1[3:0],
data0[3:0]}
parameter DATA_ARRAY_SIZE = (1<<DATA_ARRAY_SIZE_EXP); // array is
2^DATA_ARRAY_SIZE_POW elements
parameter DATA_ARRAY_MSB = (DATA_ARRAY_SIZE * DATA_WIDTH) -1;

parameter DATA_ARRAY_SIZE_EXP_M1 = DATA_ARRAY_SIZE_EXP-1;


parameter DATA_UPPER_HALF_OFFSET = DATA_WIDTH * (DATA_ARRAY_SIZE>>1);

input [DATA_ARRAY_MSB:0] data_in;
output [DATA_ARRAY_MSB:0] data_out;

// ===============

wire [DATA_ARRAY_MSB:0] data_conq;




generate

if(DATA_ARRAY_SIZE_EXP>1) begin: nest

wire [DATA_UPPER_HALF_OFFSET-1:0] data_sort_1;
wire [DATA_UPPER_HALF_OFFSET-1:0] data_sort_0;

wire [DATA_UPPER_HALF_OFFSET-1:0] data_rev_0;
wire [DATA_UPPER_HALF_OFFSET-1:0] data_rev_1;


biton_sort
#(
.DATA_WIDTH(DATA_WIDTH),
.DATA_ARRAY_SIZE_EXP(DATA_ARRAY_SIZE_EXP_M1)
)
biton_sort_0
(
.data_in(data_in[ DATA_UPPER_HALF_OFFSET-1:0]),
.data_out(data_sort_0)
);


biton_reverse
#(
.DATA_WIDTH(DATA_WIDTH),
.DATA_ARRAY_SIZE_EXP(DATA_ARRAY_SIZE_EXP_M1)
)
biton_reverse_1_0
(
.data_in(data_in[ DATA_ARRAY_MSB:DATA_UPPER_HALF_OFFSET]),
.data_out(data_rev_0)
);


biton_sort
#(
.DATA_WIDTH(DATA_WIDTH),
.DATA_ARRAY_SIZE_EXP(DATA_ARRAY_SIZE_EXP_M1)
)
biton_sort_1
(
.data_in(data_rev_0),
.data_out(data_rev_1)
);


biton_reverse
#(
.DATA_WIDTH(DATA_WIDTH),
.DATA_ARRAY_SIZE_EXP(DATA_ARRAY_SIZE_EXP_M1)
)
biton_reverse_1_1
(
.data_in(data_rev_1),
.data_out(data_sort_1)
);



assign data_conq = {data_sort_1, data_sort_0};

end
else begin: last

assign data_conq = data_in;

end

endgenerate


biton_merge
#(
.DATA_WIDTH(DATA_WIDTH),
.DATA_ARRAY_SIZE_EXP(DATA_ARRAY_SIZE_EXP)
)
biton_merge_1
(
.data_in(data_conq),
.data_out(data_out)
);

endmodule




module system;

parameter DATA_WIDTH = 4;
parameter DATA_ARRAY_SIZE_EXP = 3; // array is 2^DATA_ARRAY_SIZE_POW
elements

// ==================

// data organized in following way:
// single long vector: { data3[3:0], data2[3:0], data1[3:0],
data0[3:0]}

parameter DATA_ARRAY_MSB = (1<<DATA_ARRAY_SIZE_EXP) * DATA_WIDTH -1;

wire [DATA_ARRAY_MSB:0] data_in = {4'h1, 4'h3, 4'h5, 4'h2, 4'hf, 4'hb,
4'h0, 4'ha };
wire [DATA_ARRAY_MSB:0] data_out;



biton_sort
#(
.DATA_WIDTH(DATA_WIDTH),
.DATA_ARRAY_SIZE_EXP(DATA_ARRAY_SIZE_EXP)
)
biton_sort_1
(
.data_in(data_in),
.data_out(data_out)
);

/*

biton_merge
#(
.DATA_WIDTH(DATA_WIDTH),
.DATA_ARRAY_SIZE_EXP(DATA_ARRAY_SIZE_EXP)
)
biton_merge_1
(
.data_in(data_in),
.data_out(data_out)
);

biton_bn
#(
.DATA_WIDTH(DATA_WIDTH),
.DATA_ARRAY_SIZE_EXP(DATA_ARRAY_SIZE_EXP)
)
biton_bn_1
(
.data_in(data_in),
.data_out(data_out)
);
*/

endmodule
 
bazarnik@hotmail.com wrote:
Andy,

Thanks for hdcaml version!
I guess you win - yours is definitely shorter :)

To my defense I have to say that I deliberatly did not use +: notation
(we have found those breaking the Xilinx synthesis).
Array ports would also help with tersness (but that's SystemVerilog)


....and then you there's your linter, formal equivalency checker...

Wouldn't it be nice if there was an industry standard test suite that
each of these tools was tested against so that we knew EXACTLY what was
and wasn't supported (and could choose our tools appropriately) rather
than this crazy situation of perfectly good code working sometimes?


Also I could dispute that hdcaml verison is still recursive
(merge calls itself) but then iterative verison was for masochists
anyway :).

The hdcaml version still uses recursion. But that's ok as the verilog
it outputs does not.

Cheers,

Andy.
 
Hi Przemek,
So, it is unapproved version of verilog LRM. Thanks for the info. :)

Best regards,
ABC

bazarnik@hotmail.com wrote:
ABC,

The generated instantiation allows recursion in Verilog.
I was told that's officially allowed in 2005 LRM - haven't seen copy
yet.

For example in the biton_merge module the generate loop instantiates
another two instances biton_merge module (both half the size of the
original one)

Of course you have to terminate recursion by using the if statement.

That's for synthesizable code. You can also use recursion for function
calls and tasks (they should be declared "automatic" to preserve local
signals)

Thanks,
Przemek



Code snipet:

module biton_merge (
data_in,
data_out
);
.
.
generate

if(DATA_ARRAY_SIZE_EXP>1) begin: nest

wire [DATA_UPPER_HALF_OFFSET-1:0] data_merge_1;
wire [DATA_UPPER_HALF_OFFSET-1:0] data_merge_0;


biton_merge
#(
.DATA_WIDTH(DATA_WIDTH),
.DATA_ARRAY_SIZE_EXP(DATA_ARRAY_SIZE_EXP_M1)
)
biton_merge_0
(
.data_in(data_div[ DATA_UPPER_HALF_OFFSET-1:0]),
.data_out(data_merge_0)
);





ABC wrote:
Hi Przemek,
Which statement of verilog allow recursive instantiation?

Best regards,
ABC

bazarnik@hotmail.com wrote:
Dear All,

FYI this issue was confirmed to be a bug in Design Compiler
(hopefully fixed in a next service pack)

I recoded the bitionic sort in an iterative form.
I would not recommend it unless one feels a need for a some of
the "human compiler" type of brain workout.
Actually doing the b.sort with recursion in Verilog is not really
that complex (see below) One just needs to use modules to avoid
too many nested loops and to keep things neat.

I did try Confluence quite some time earlier. It is a nice tool.
I have found the syntax to be quite "peculiar" but still better
than HDCaml bracket flood.
We do not have that much datapath code which would warrant
adding Confluence to our ASIC flow. This may change though.

Ultimately Confluence type languages are thay way HW design must go.
SystemVerilog interfaces and other stuff are another way to introduce
high level hardware design features.

Thanks,
Przemek


PS For you viewing pleasure:
the bitionic sort implemented in Verilog 2001 with recursive
instantiation.

Module list:
system (top level)
biton_sort
biton_merge
biton_bn
biton_reverse

I leave the iterative version as an excercise for the reader :)


module biton_bn (
data_in,
data_out
);

// Global parameters

parameter DATA_WIDTH = 4;
parameter DATA_ARRAY_SIZE_EXP = 2; // array is 2^DATA_ARRAY_SIZE_POW
elements this is equal to N for B(n) bitonic sort operator


// Local parameters
// data organized in following way:
// single long vector: { data3[3:0], data2[3:0], data1[3:0],
data0[3:0]}
parameter DATA_ARRAY_SIZE = (1<<DATA_ARRAY_SIZE_EXP); // array is
2^DATA_ARRAY_SIZE_POW elements
parameter DATA_ARRAY_MSB = (1<<DATA_ARRAY_SIZE_EXP) * DATA_WIDTH -1;


parameter DATA_UPPER_HALF_OFFSET = DATA_WIDTH * (DATA_ARRAY_SIZE>>1);

input [DATA_ARRAY_MSB:0] data_in;
output reg [DATA_ARRAY_MSB:0] data_out;

// ===============


genvar i;

generate for(i=0;i<(DATA_ARRAY_SIZE>>1);i=i+1) begin: comp

always @*
if( data_in[ (i+1)*DATA_WIDTH-1 : i*DATA_WIDTH] > data_in[
(i+1)*DATA_WIDTH-1+DATA_UPPER_HALF_OFFSET :
i*DATA_WIDTH+DATA_UPPER_HALF_OFFSET] ) begin
// swap
data_out[ (i+1)*DATA_WIDTH-1 : i*DATA_WIDTH] = data_in [
(i+1)*DATA_WIDTH-1+DATA_UPPER_HALF_OFFSET :
i*DATA_WIDTH+DATA_UPPER_HALF_OFFSET];
data_out[ (i+1)*DATA_WIDTH-1+DATA_UPPER_HALF_OFFSET :
i*DATA_WIDTH+DATA_UPPER_HALF_OFFSET] = data_in [ (i+1)*DATA_WIDTH-1 :
i*DATA_WIDTH];

end
else begin
// keep the same
data_out[ (i+1)*DATA_WIDTH-1 : i*DATA_WIDTH] = data_in [
(i+1)*DATA_WIDTH-1 : i*DATA_WIDTH];
data_out[ (i+1)*DATA_WIDTH-1+DATA_UPPER_HALF_OFFSET :
i*DATA_WIDTH+DATA_UPPER_HALF_OFFSET] = data_in [
(i+1)*DATA_WIDTH-1+DATA_UPPER_HALF_OFFSET :
i*DATA_WIDTH+DATA_UPPER_HALF_OFFSET];

end
end

endgenerate
endmodule


module biton_merge (
data_in,
data_out
);

// Global parameters

parameter DATA_WIDTH = 4;
parameter DATA_ARRAY_SIZE_EXP = 2; // array is 2^DATA_ARRAY_SIZE_POW
elements this is equal to N for B(n) bitonic sort operator


// Local parameters
// data organized in following way:
// single long vector: { data3[3:0], data2[3:0], data1[3:0],
data0[3:0]}
parameter DATA_ARRAY_SIZE = (1<<DATA_ARRAY_SIZE_EXP); // array is
2^DATA_ARRAY_SIZE_POW elements
parameter DATA_ARRAY_MSB = (DATA_ARRAY_SIZE * DATA_WIDTH) -1;

parameter DATA_ARRAY_SIZE_EXP_M1 = DATA_ARRAY_SIZE_EXP-1;


parameter DATA_UPPER_HALF_OFFSET = DATA_WIDTH * (DATA_ARRAY_SIZE>>1);

input [DATA_ARRAY_MSB:0] data_in;
output [DATA_ARRAY_MSB:0] data_out;

// ===============

wire [DATA_ARRAY_MSB:0] data_div;


biton_bn
#(
.DATA_WIDTH(DATA_WIDTH),
.DATA_ARRAY_SIZE_EXP(DATA_ARRAY_SIZE_EXP)
)
biton_bn_1
(
.data_in(data_in),
.data_out(data_div)
);


generate

if(DATA_ARRAY_SIZE_EXP>1) begin: nest

wire [DATA_UPPER_HALF_OFFSET-1:0] data_merge_1;
wire [DATA_UPPER_HALF_OFFSET-1:0] data_merge_0;


biton_merge
#(
.DATA_WIDTH(DATA_WIDTH),
.DATA_ARRAY_SIZE_EXP(DATA_ARRAY_SIZE_EXP_M1)
)
biton_merge_0
(
.data_in(data_div[ DATA_UPPER_HALF_OFFSET-1:0]),
.data_out(data_merge_0)
);


biton_merge
#(
.DATA_WIDTH(DATA_WIDTH),
.DATA_ARRAY_SIZE_EXP(DATA_ARRAY_SIZE_EXP_M1)
)
biton_merge_1
(
.data_in(data_div[ DATA_ARRAY_MSB:DATA_UPPER_HALF_OFFSET]),
.data_out(data_merge_1)
);

assign data_out = {data_merge_1, data_merge_0};

end
else begin: last

assign data_out = data_div;

end
endgenerate
endmodule


module biton_reverse (
data_in,
data_out
);

// Global parameters

parameter DATA_WIDTH = 4;
parameter DATA_ARRAY_SIZE_EXP = 2; // array is 2^DATA_ARRAY_SIZE_POW
elements this is equal to N for B(n) bitonic sort operator


// Local parameters
// data organized in following way:
// single long vector: { data3[3:0], data2[3:0], data1[3:0],
data0[3:0]}
parameter DATA_ARRAY_SIZE = (1<<DATA_ARRAY_SIZE_EXP); // array is
2^DATA_ARRAY_SIZE_POW elements
parameter DATA_ARRAY_MSB = (DATA_ARRAY_SIZE * DATA_WIDTH) -1;


input [DATA_ARRAY_MSB:0] data_in;
output [DATA_ARRAY_MSB:0] data_out;

// ===============

genvar i;

generate for(i=0;i<DATA_ARRAY_SIZE;i=i+1) begin: rev
assign data_out[ (i+1)*DATA_WIDTH-1 : i*DATA_WIDTH] = data_in[
(DATA_ARRAY_SIZE-i)*DATA_WIDTH-1 : (DATA_ARRAY_SIZE-i-1)*DATA_WIDTH];
end

endgenerate
endmodule




module biton_sort (
data_in,
data_out
);

// Global parameters

parameter DATA_WIDTH = 4;
parameter DATA_ARRAY_SIZE_EXP = 2; // array is 2^DATA_ARRAY_SIZE_POW
elements this is equal to N for B(n) bitonic sort operator


// Local parameters
// data organized in following way:
// single long vector: { data3[3:0], data2[3:0], data1[3:0],
data0[3:0]}
parameter DATA_ARRAY_SIZE = (1<<DATA_ARRAY_SIZE_EXP); // array is
2^DATA_ARRAY_SIZE_POW elements
parameter DATA_ARRAY_MSB = (DATA_ARRAY_SIZE * DATA_WIDTH) -1;

parameter DATA_ARRAY_SIZE_EXP_M1 = DATA_ARRAY_SIZE_EXP-1;


parameter DATA_UPPER_HALF_OFFSET = DATA_WIDTH * (DATA_ARRAY_SIZE>>1);

input [DATA_ARRAY_MSB:0] data_in;
output [DATA_ARRAY_MSB:0] data_out;

// ===============

wire [DATA_ARRAY_MSB:0] data_conq;




generate

if(DATA_ARRAY_SIZE_EXP>1) begin: nest

wire [DATA_UPPER_HALF_OFFSET-1:0] data_sort_1;
wire [DATA_UPPER_HALF_OFFSET-1:0] data_sort_0;

wire [DATA_UPPER_HALF_OFFSET-1:0] data_rev_0;
wire [DATA_UPPER_HALF_OFFSET-1:0] data_rev_1;


biton_sort
#(
.DATA_WIDTH(DATA_WIDTH),
.DATA_ARRAY_SIZE_EXP(DATA_ARRAY_SIZE_EXP_M1)
)
biton_sort_0
(
.data_in(data_in[ DATA_UPPER_HALF_OFFSET-1:0]),
.data_out(data_sort_0)
);


biton_reverse
#(
.DATA_WIDTH(DATA_WIDTH),
.DATA_ARRAY_SIZE_EXP(DATA_ARRAY_SIZE_EXP_M1)
)
biton_reverse_1_0
(
.data_in(data_in[ DATA_ARRAY_MSB:DATA_UPPER_HALF_OFFSET]),
.data_out(data_rev_0)
);


biton_sort
#(
.DATA_WIDTH(DATA_WIDTH),
.DATA_ARRAY_SIZE_EXP(DATA_ARRAY_SIZE_EXP_M1)
)
biton_sort_1
(
.data_in(data_rev_0),
.data_out(data_rev_1)
);


biton_reverse
#(
.DATA_WIDTH(DATA_WIDTH),
.DATA_ARRAY_SIZE_EXP(DATA_ARRAY_SIZE_EXP_M1)
)
biton_reverse_1_1
(
.data_in(data_rev_1),
.data_out(data_sort_1)
);



assign data_conq = {data_sort_1, data_sort_0};

end
else begin: last

assign data_conq = data_in;

end

endgenerate


biton_merge
#(
.DATA_WIDTH(DATA_WIDTH),
.DATA_ARRAY_SIZE_EXP(DATA_ARRAY_SIZE_EXP)
)
biton_merge_1
(
.data_in(data_conq),
.data_out(data_out)
);

endmodule




module system;

parameter DATA_WIDTH = 4;
parameter DATA_ARRAY_SIZE_EXP = 3; // array is 2^DATA_ARRAY_SIZE_POW
elements

// ==================

// data organized in following way:
// single long vector: { data3[3:0], data2[3:0], data1[3:0],
data0[3:0]}

parameter DATA_ARRAY_MSB = (1<<DATA_ARRAY_SIZE_EXP) * DATA_WIDTH -1;

wire [DATA_ARRAY_MSB:0] data_in = {4'h1, 4'h3, 4'h5, 4'h2, 4'hf, 4'hb,
4'h0, 4'ha };
wire [DATA_ARRAY_MSB:0] data_out;



biton_sort
#(
.DATA_WIDTH(DATA_WIDTH),
.DATA_ARRAY_SIZE_EXP(DATA_ARRAY_SIZE_EXP)
)
biton_sort_1
(
.data_in(data_in),
.data_out(data_out)
);

/*

biton_merge
#(
.DATA_WIDTH(DATA_WIDTH),
.DATA_ARRAY_SIZE_EXP(DATA_ARRAY_SIZE_EXP)
)
biton_merge_1
(
.data_in(data_in),
.data_out(data_out)
);

biton_bn
#(
.DATA_WIDTH(DATA_WIDTH),
.DATA_ARRAY_SIZE_EXP(DATA_ARRAY_SIZE_EXP)
)
biton_bn_1
(
.data_in(data_in),
.data_out(data_out)
);
*/

endmodule
 
I'm trying to understand this example (to see how I could solve
it using MyHDL). After some hacking (on Linux) I was able to run it,
but I got Verilog code with an interface with only outputs, except
clock and reset. Can't be right I guess. The interface starts
as follows:

--
module bitonic (reset, clock, o7, o6, o5, o4, o3, o2, o1, o0);
input reset, clock;
output [3:0] o7;
output [3:0] o6;
output [3:0] o5;
output [3:0] o4;
output [3:0] o3;
output [3:0] o2;
output [3:0] o1;
output [3:0] o0;
wire _126;
wire _120;
...
--

Jan


Hi Jan,

In the code there's a bit

(* let inputs = map (fun x -> input ("i" ^ (string_of_int x)) 4)
[ 0; 1; 2; 3; 4; 5; 6; 7 ] in *)
let inputs = map (fun x -> const x)
[ "0001"; "0011"; "0101"; "0010";
"1111"; "1011"; "0000"; "1010" ] in

This applies constants as the input to the circuit so it can be run
without a testbench. This matches what the module "system" does in
Przemek's post.

To get some proper inputs use this instead:

let inputs = map (fun x -> input ("i" ^ (string_of_int x)) 4)
[ 0; 1; 2; 3; 4; 5; 6; 7 ] in
(* let inputs = map (fun x -> const x)
[ "0001"; "0011"; "0101"; "0010";
"1111"; "1011"; "0000"; "1010" ] in *)

Cheers,

Andy.
 
Andy Ray wrote:
PS For you viewing pleasure:
the bitionic sort implemented in Verilog 2001 with recursive
instantiation.

I leave the iterative version as an excercise for the reader :)



I'll take you up on that !

The output is verilog with no recursion (or iteration for that matter).

Cheers,

Andy
I'm trying to understand this example (to see how I could solve
it using MyHDL). After some hacking (on Linux) I was able to run it,
but I got Verilog code with an interface with only outputs, except
clock and reset. Can't be right I guess. The interface starts
as follows:

--
module bitonic (reset, clock, o7, o6, o5, o4, o3, o2, o1, o0);
input reset, clock;
output [3:0] o7;
output [3:0] o6;
output [3:0] o5;
output [3:0] o4;
output [3:0] o3;
output [3:0] o2;
output [3:0] o1;
output [3:0] o0;
wire _126;
wire _120;
...
--

Jan

--
Jan Decaluwe - Resources bvba - http://www.jandecaluwe.com
Losbergenlaan 16, B-3010 Leuven, Belgium
From Python to silicon:
http://myhdl.jandecaluwe.com
 
bazarnik@hotmail.com wrote:
Dear All,

FYI this issue was confirmed to be a bug in Design Compiler
(hopefully fixed in a next service pack)

I recoded the bitionic sort in an iterative form.
I would not recommend it unless one feels a need for a some of
the "human compiler" type of brain workout.
Actually doing the b.sort with recursion in Verilog is not really
that complex (see below) One just needs to use modules to avoid
too many nested loops and to keep things neat.

I did try Confluence quite some time earlier. It is a nice tool.
I have found the syntax to be quite "peculiar" but still better
than HDCaml bracket flood.
We do not have that much datapath code which would warrant
adding Confluence to our ASIC flow. This may change though.

Ultimately Confluence type languages are thay way HW design must go.
SystemVerilog interfaces and other stuff are another way to introduce
high level hardware design features.
I have successfully coded the bitonic sort example in "structural"
MyHDL, using lists of signals and recursion. The nice thing is that
the code stays fairly close to the original Java reference
implementation. From the code, you can generate elaborated
(= non-hierarchical, non-recursive) Verilog code, which I have
verified and synthesized all right.

I'm preparing a web page on these results. As this thread is
getting old, I'll do a fresh announcement post about it.

Regards, Jan

--
Jan Decaluwe - Resources bvba - http://www.jandecaluwe.com
Losbergenlaan 16, B-3010 Leuven, Belgium
From Python to silicon:
http://myhdl.jandecaluwe.com
 

Welcome to EDABoard.com

Sponsor

Back
Top