Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
12 years ago

Mixed sign math problem

The background: I'm working on QAM modulation from a Cyclone II dev board with a DAC board I made connected to it. Works great as a DDS and everything other than the QAM math.

The main QAM calculation is icos(t)-qsin(t). I implemented sin and cos as lookup tables in a module. The following simulates properly in iverilog:

// leaving out standard stuff, only relevant lines shown (full paste at the end)
input signed   i; // input values
input signed   q;
output  dacval;  // output to the DAC
wire signed   sin;  // the values back from the lookup tables
wire signed   cos;
reg signed  dacfull; // holds the full size value
always @(negedge clk)     
     begin         
          dacfull=(i*cos)-(q*sin);  // the qam value         
          dacval=(dacfull/64)+512;  // scale down, then add to make positive     
     end
endmodule

Here's the problem: the above simulates great, but when I go to synthesize it with Altera, I get the following at the end:

Warning (13410): Pin "dacval" is stuck at GND 
 
Warning (13410): Pin "dacval" is stuck at GND

However, if I change the math section above to just:

dacval=(sin*4)+512; // multiply to full range, then add to make positive 

It synthesizes without error, and runs perfectly in hardware (outputting a beautiful sine).

I spent hours today fooling with different ways to present the signed+unsigned math, but I can't get the Altera synth to like it. What's the proper way?

The sin/cos LUT: http://paste.ubuntu.com/5763310

The IQ mod code: http://paste.ubuntu.com/5763316

Full output from synthesis: http://paste.ubuntu.com/5763317

3 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    The problem is that a signed multiply effectively wastes one bit, which is necessary to avoid an overflow with -128*-128. To effectively utilize the result number range, dacfull must be resized to 15 bit with saturation logic applied, means 0x4000 (-16384) must be truncated to 0x3FFF (-16383).

    ieee.fixed_pkg has a built-in saturation logic feature and is the most convient way to handle these problems. Or write your own functions to handle signed arithmetic with saturation.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    You're right about the extra bit for a full-range multiply, but I handled that problem by generating the LUT to go from -127 to 127.

    The problem gets weirder though... it synthesesizes and runs correctly in hardware if the input vars are registers:

    
    reg signed  ri;
    reg signed  rq;
          dacfull=(ri*cos)-(rq*sin);
          dacval=(dacfull/64)+512;

    I set ri and rq in the initial to exactly the same values I set i and q to in the top-level module. Using the registers like that, the synth figures out that I need multiplication (which it never did without the registers):

    
        Info (278003): Inferred multiplier megafunction ("lpm_mult") from the following logic: "iqmod:myiq|Mult0"

    But here's the weird part: if I set ri and rq to i and q anywhere, it does the same thing it did before: no multiplier infered, and dacval is always 0. I tried "ri=i; rq=q;" just above the math lines, as well as adding a separate block @(i,q) where the registers are set, and both ways fail.

    I verified throughout the code that i+q are exactly the same type as ri and rq (signed 8-bit registers), except ri and rq are defined in this module and i and q are defined in the above level. What am I missing?
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    It looks like if the synth sees that ri and rq can change anywhere, it just gives up and decides the multiplication expression will always be 0. Whenever it decides they don't change (ie, when it works), it notes that one input to the multiplier is constant:

    
    Info (278001): Inferred 1 megafunctions from design logic
        Info (278003): Inferred multiplier megafunction ("lpm_mult") from the following logic: "iqmod:iq0|Mult0"
    Info (12130): Elaborated megafunction instantiation "iqmod:iq0|lpm_mult:Mult0"
    Info (12133): Instantiated megafunction "iqmod:iq0|lpm_mult:Mult0" with the following parameter:
        Info (12134): Parameter "LPM_WIDTHA" = "8"
        Info (12134): Parameter "LPM_WIDTHB" = "8"
        Info (12134): Parameter "LPM_WIDTHP" = "16"
        Info (12134): Parameter "LPM_WIDTHR" = "16"
        Info (12134): Parameter "LPM_WIDTHS" = "1"
        Info (12134): Parameter "LPM_REPRESENTATION" = "SIGNED"
        Info (12134): Parameter "INPUT_A_IS_CONSTANT" = "YES"
        Info (12134): Parameter "INPUT_B_IS_CONSTANT" = "NO"
        Info (12134): Parameter "MAXIMIZE_SPEED" = "5"
    Info (12131): Elaborated megafunction instantiation "iqmod:iq0|lpm_mult:Mult0|multcore:mult_core", which is child of megafunction instantiation "iqmod:iq0|lpm_mult:Mult0"
    Info (12131): Elaborated megafunction instantiation "iqmod:iq0|lpm_mult:Mult0|multcore:mult_core|mpar_add:padder", which is child of megafunction instantiation "iqmod:iq0|lpm_mult:Mult0"
    Info (12131): Elaborated megafunction instantiation "iqmod:iq0|lpm_mult:Mult0|multcore:mult_core|mpar_add:padder|lpm_add_sub:adder", which is child of megafunction instantiation "iqmod:iq0|lpm_mult:Mult0"
    Info (12021): Found 1 design units, including 1 entities, in source file db/add_sub_qfh.tdf
        Info (12023): Found entity 1: add_sub_qfh
    Info (12131): Elaborated megafunction instantiation "iqmod:iq0|lpm_mult:Mult0|altshift:external_latency_ffs", which is child of megafunction instantiation "iqmod:iq0|lpm_mult:Mult0"