6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Mon May 13, 2024 9:56 am

All times are UTC




Post new topic Reply to topic  [ 8 posts ] 
Author Message
PostPosted: Sat Mar 28, 2015 10:28 pm 
Offline

Joined: Tue May 05, 2009 2:49 pm
Posts: 108
I am hoping someone can see the glaring issue I'm encountering working on some CPLD Verilog.

I have a set of 2 8 bit registers holding a 16 bit word:

Code:
register                   bank1_lo_reg(q, !reset, !r_w & bank1_lo_reg_ce, data[7:0], bank_data[7:0]);
register                   bank1_hi_reg(q, !reset, !r_w & bank1_hi_reg_ce, data[7:0], bank_data[15:8]);

And an address from the CPU:

Code:
input [15:0]address;


And, I have created a full adder in Verilog as per the tutorials:

Code:
fulladder #(.WIDTH(13))      add1(bank_offset[12:0], {7'b0, address[15:10]}, 0, bank[12:0], carry);


When I try to synthesize, I am getting the following warning:

Code:
WARNING:NgdBuild:452 - logical net 'add1/b<10>' has no driver
WARNING:NgdBuild:452 - logical net 'add1/b<11>' has no driver
WARNING:NgdBuild:452 - logical net 'add1/b<12>' has no driver
WARNING:NgdBuild:452 - logical net 'add1/b<6>' has no driver
WARNING:NgdBuild:452 - logical net 'add1/b<7>' has no driver
WARNING:NgdBuild:452 - logical net 'add1/b<8>' has no driver
WARNING:NgdBuild:452 - logical net 'add1/b<9>' has no driver


I thought I was setting those bits to 0 via the assignment above.

I am using Xilinx 14.6, and am not sure how to make the system understand I am connecting them to ground. I can get rid of the issue by doing a 6 bit full adder and then manually creating half adders for the rest of the bits, but that looks to blow up the Pterm and FB usage.

The goal was to create as bit of an MMU. The bank would point to any 1kB spot within the 64kB address space, and I wanted to use addition rather than logical operations so that the user had more control of the base (it would not need to sit on 64kB boundaries).

Happy to send a project ZIP if that helps, but I figure I must be missing something easy.

JIm


Top
 Profile  
Reply with quote  
PostPosted: Sat Mar 28, 2015 11:02 pm 
Offline

Joined: Mon Mar 02, 2009 7:27 pm
Posts: 3258
Location: NC, USA
I'll take a stab at it since noone else has responded yet...

Here:
Code:
add1(bank_offset[12:0], {7'b0, address[15:10]}, 0, bank[12:0], carry);

Each of the values between the commas has to be 13 bits wide and aligned to the right if I'm not mistaken.

The following satisfy that criteria:
bank_offset[12:0]
bank[12:0]
{7'b0, address[15:10]}
The rest do not appear to do so:
0
carry

For the 0, I would use 13'b0. Not sure about the carry, not enough information, but if carry is 1 bit, maybe something like {12'b0,carry} or {carry, 12'b0} would work.

I'm no Verilog expert, but that's what stands out to me.

_________________
65Org16:https://github.com/ElEctric-EyE/verilog-6502


Top
 Profile  
Reply with quote  
PostPosted: Sun Mar 29, 2015 12:25 am 
Offline
User avatar

Joined: Mon Apr 23, 2012 12:28 am
Posts: 760
Location: Huntsville, AL
brain:

EEyE spotted your issue. You need to define the sizes of each argument in the argument list to your module.

Although position dependent argument passing is allowed, I don't recommend that approach primarily for the issue that you are encountering. It is better to use the named argument approach. If you'd used that convention, I would've expected a warning to have been issued by the synthesizer that one or more of the widths did not match the actual widths defined for them.

From your example, I recommend that you pass arguments using the named arguments method:

Code:
fulladder #(
                   .WIDTH(13)
              ) add1 (
                   .bank_offset(bank_offset[12:0]),
                   .address({7'b0, address[15:10]}),
                   .bias(13'b0),
                   .bank(bank[12:0]),
                   .carry_in(carry)
              );


But like EEyE said, you really did not provide enough information regarding the fulladder module.

It may require more typing, but the Xilinx tool provides a way to generate the instantiation template with all of the argument names already typed in. You only have to cut and paste the definition/template into your source code.

In the Sources window, select (single click) the module for which you desire the instantiation template, then in the Processes window (below the sources window) select (double click) the View HDL Instantiation Template sub-option under the Design Utilities option. You will have to edit "instance_name" as needed, and add any parameters of the module that you may need to modify.

_________________
Michael A.


Top
 Profile  
Reply with quote  
PostPosted: Sun Mar 29, 2015 3:28 am 
Offline

Joined: Tue May 05, 2009 2:49 pm
Posts: 108
Hmm, I will try the named argument passing, but here is FullAdder:

Code:
module fulladder(a, b, c_in, f, c_out);
parameter WIDTH = 8;

output reg [WIDTH - 1:0] f;
output reg c_out;
input [WIDTH - 1:0] a;
input [WIDTH - 1:0] b;
input c_in;

always @(a, b, c_in)
{c_out, f} = a + b + c_in;
endmodule


Top
 Profile  
Reply with quote  
PostPosted: Sun Mar 29, 2015 3:45 am 
Offline

Joined: Tue May 05, 2009 2:49 pm
Posts: 108
Reworked to use the named parm method, same error

It's like the top 0 bits of operand b are the trigger.


Top
 Profile  
Reply with quote  
PostPosted: Sun Mar 29, 2015 4:12 am 
Offline

Joined: Tue May 05, 2009 2:49 pm
Posts: 108
If I change it to be:

Code:
fulladder #(.WIDTH(5))      add1 (
                              .a(bank_offset[4:0]),
                              .b(address[14:10]),
                              .c_in(0),
                              .result(bank[4:0]),
                              .c_out(carry)
                           );
fulladder #(.WIDTH(8))      add2 (
                              .a(bank_offset[12:5]),
                              .b(0),
                              .c_in(0),
                              .result(bank[12:5]),
                              .c_out(carry2)
                           );


The warnings disappear :-)

For reference, I cleaned up fulladder a bit:

Code:
module fulladder(a, b, c_in, result, c_out);
parameter WIDTH = 8;

output reg [WIDTH - 1:0] result;
output reg c_out;
input [WIDTH - 1:0] a;
input [WIDTH - 1:0] b;
input c_in;

always @(a, b, c_in)
{c_out, result} = a + b + c_in;
endmodule


Last edited by brain on Sun Mar 29, 2015 4:29 am, edited 1 time in total.

Top
 Profile  
Reply with quote  
PostPosted: Sun Mar 29, 2015 4:14 am 
Offline

Joined: Tue May 05, 2009 2:49 pm
Posts: 108
And I just noticed a bit. add2 shuld use carry as carry_in, but when I do that, the pterm count goes from 328 to 464 !.

Jim


Top
 Profile  
Reply with quote  
PostPosted: Sun Mar 29, 2015 1:44 pm 
Offline
User avatar

Joined: Mon Apr 23, 2012 12:28 am
Posts: 760
Location: Huntsville, AL
brain:

I would also recommend the Verilog 2001 argument list syntax:

Code:
module fulladder #(
    parameter WIDTH = 8
)(
    input   [WIDTH - 1:0] a,
    input   [WIDTH - 1:0] b,
    input   c_in,
   
    output reg [WIDTH - 1:0] result,
    output reg c_out
);

always @(*)
    {c_out, result} <= a + b + c_in;

endmodule

It provides a bit more self-contained definition of the module's inputs and outputs, and also allows parameterization of the module argument list.

I know that you recognize a CPLD is a fundamentally different device than an FPGA. It is specifically designed to support wide logic functions. Its input array, the AND array, typically handles the TRUE and COMPLEMENT of at least 36 logic variables. This is a much larger set of combinatorial variables than the four to six that a modern FPGA handles. The CPLD's input array is followed by a summing array, the OR array. This array is where the various product terms (pterms) are combined. The width of the ORs in this array is typically not equal to the number of pterms each CPLD macro cell can generate, i.e. 54 pterms in some architectures. Thus, when the number of pterms needed to defiine a Sum-Of-Products (SOP) combinatorial equation exceeds that fundamental limit, the OR gates must be combined in sum manner. Because the pterms are so wide, (think high capacitance and therefore large delay,) there is a performance penalty to be paid if the output of an OR is fed back into the AND array in order to reach another OR input to combine x pterms with y pterms. Different CPLD architectures solve this issue in various ways, but the issue still remains that CPLDs generally do not have the functionality of PLAs (Programmable Logic Arrays) where the width of the OR gates equals the number of AND terms. This feature of PLAs allows them to implement any SOP equation, but it comes at a significant penalty in overall speed; nothing good is ever free.

For your project, the fundamental architecture of the CPLD is part of your problem. Most FPGAs include specialized circuits in each logic cell which are intended specifically to implement fast adders using specially designed ripple carry logic. I synthesized your module for an FPGA and it yielded 8 LUTs as the logic required to implement an 8-bit full adder. I also synthesized it for the case WIDTH=13, and the synthesizer indicated that 13 LUTs where required. Both of these results are what I would intuitively expect.

No CPLD architecture with which I am familiar provides the built-in adder support features found in most FPGA logic cells. Thus, the synthesizer is left with the task of generating the full adder and inter-bit carry logic directly in the AND-OR arrays. The general limitations I discussed above regarding the architecture will then be evident. As you increase the width, and width no load for the 8-bit component, it will combine the two full adders into a single 13-bit full adder. The combinatorial SOP equations for such a component will use a large number of pterms.

I set your module up in ISE 10.1i SP3 and targeting an XC9572-7PC84 device. With a width of 8, the number of macrocells used was 15/72 and the number of pterms used was 145/360. Increasing the width to 13, yielded 28/72 macrocells and 231/360 pterms. The number of macrocells required to fit your function is reasonable. There appears to be some optimization taking place in the 8-bit case, and some additional growth in the feedback requirements in the 13-bit case.

I think it is instructive to review the generated equations to see if things appear to be as would be expected if you'd generated the equations yourself. (Sometimes you learn something, and sometimes you catch specification errors.) For the 8-bit case, the tool reported the following equations for result[0] and result[7]:
Code:
assign result[0] = !(b[0] XOR (c_in && a[0]) || (!c_in && !a[0]));

The equation for bit 0 above is what I would expect for a full adder. Note the use of the XOR operator. This is an optimization possible because the CPLD macrocell includes an XOR gate just for this type of condition. If I remember the architecture correctly, that XOR gate only has two inputs, so as the number of bits grow, some of the XOR operations required will have to be synthesized with more pterms and OR terms. The equation for bit 7 below is downright scary, and I can imagine its complexity will only increase as the full adder is extended to 13 bits. (I also looked at the equation for the carry out, and my recommendation to you will be to drop the carry out of the last stage of any cascaded modules. I might even go so far as to recommend that you not cascade and 8-bit and a 5-bit module, and just go for a single 13-bit full adder.)
Code:
assign result[7] = Madd_AUX_1_addsub0000_Mxor_Result[7]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<7>__xor0000_D
     XOR (c_in && b[0] && b[1] && a[2] && Madd_AUX_1_addsub0000_Mxor_Result[3]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<3>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[4]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<4>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[5]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<5>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[6]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<6>__xor0000_D)
     || (c_in && b[0] && a[1] && a[2] && Madd_AUX_1_addsub0000_Mxor_Result[3]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<3>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[4]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<4>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[5]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<5>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[6]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<6>__xor0000_D)
     || (b[0] && b[1] && a[0] && a[2] && Madd_AUX_1_addsub0000_Mxor_Result[3]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<3>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[4]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<4>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[5]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<5>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[6]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<6>__xor0000_D)
     || (b[0] && a[0] && a[1] && a[2] && Madd_AUX_1_addsub0000_Mxor_Result[3]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<3>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[4]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<4>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[5]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<5>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[6]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<6>__xor0000_D)
     || (c_in && b[0] && b[1] && b[2] && Madd_AUX_1_addsub0000_Mxor_Result[3]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<3>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[4]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<4>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[5]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<5>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[6]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<6>__xor0000_D)
     || (c_in && b[0] && b[2] && a[1] && Madd_AUX_1_addsub0000_Mxor_Result[3]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<3>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[4]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<4>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[5]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<5>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[6]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<6>__xor0000_D)
     || (c_in && b[1] && a[0] && a[2] && Madd_AUX_1_addsub0000_Mxor_Result[3]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<3>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[4]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<4>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[5]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<5>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[6]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<6>__xor0000_D)
     || (b[0] && b[1] && b[2] && a[0] && Madd_AUX_1_addsub0000_Mxor_Result[3]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<3>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[4]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<4>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[5]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<5>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[6]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<6>__xor0000_D)
     || (b[0] && b[2] && a[0] && a[1] && Madd_AUX_1_addsub0000_Mxor_Result[3]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<3>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[4]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<4>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[5]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<5>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[6]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<6>__xor0000_D)
     || (a[6] && !Madd_AUX_1_addsub0000_Mxor_Result[6]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<6>__xor0000_D)
     || (a[5] && !Madd_AUX_1_addsub0000_Mxor_Result[5]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<5>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[6]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<6>__xor0000_D)
     || (a[4] && !Madd_AUX_1_addsub0000_Mxor_Result[4]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<4>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[5]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<5>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[6]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<6>__xor0000_D)
     || (b[1] && b[2] && a[1] && Madd_AUX_1_addsub0000_Mxor_Result[3]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<3>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[4]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<4>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[5]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<5>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[6]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<6>__xor0000_D)
     || (b[1] && a[1] && a[2] && Madd_AUX_1_addsub0000_Mxor_Result[3]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<3>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[4]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<4>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[5]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<5>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[6]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<6>__xor0000_D)
     || (c_in && b[1] && b[2] && a[0] && Madd_AUX_1_addsub0000_Mxor_Result[3]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<3>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[4]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<4>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[5]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<5>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[6]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<6>__xor0000_D)
     || (c_in && b[2] && a[0] && a[1] && Madd_AUX_1_addsub0000_Mxor_Result[3]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<3>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[4]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<4>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[5]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<5>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[6]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<6>__xor0000_D)
     || (c_in && a[0] && a[1] && a[2] && Madd_AUX_1_addsub0000_Mxor_Result[3]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<3>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[4]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<4>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[5]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<5>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[6]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<6>__xor0000_D)
     || (a[3] && !Madd_AUX_1_addsub0000_Mxor_Result[3]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<3>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[4]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<4>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[5]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<5>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[6]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<6>__xor0000_D)
     || (b[2] && a[2] && Madd_AUX_1_addsub0000_Mxor_Result[3]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<3>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[4]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<4>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[5]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<5>__xor0000_D && Madd_AUX_1_addsub0000_Mxor_Result[6]__xor0000/Madd_AUX_1_addsub0000_Mxor_Result<6>__xor0000_D);

_________________
Michael A.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 8 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 6 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: