Intel® Quartus® Prime Software
Intel® Quartus® Prime Design Software, Design Entry, Synthesis, Simulation, Verification, Timing Analysis, System Design (Platform Designer, formerly Qsys)
Announcements
FPGA community forums and blogs on community.intel.com are migrating to the new Altera Community and are read-only. For urgent support needs during this transition, please visit the FPGA Design Resources page or contact an Altera Authorized Distributor.

First verilog project

Altera_Forum
Honored Contributor II
5,714 Views

This is my first work on any FPGA. I have a piece of verilog code I'd like input on. This is a rough start on a module to track an RF signal based on carrier removal and gold code removal. It is assuming input from 2 PLL which it will have to provide feedback to the control logic of.  

 

//correlation module time domain //------------------------------------------------------ module Correlator_Time_Domain (sampleClock, clk, DIFin, genCodeIn, sinLUT, cosLUT, DLLout, PLLout, DATAout); parameter SRsize = 32; input sampleClock; input clk; input DIFin; input genCodeIn; input sinLUT; input cosLUT; output real DLLout; output real PLLout; output DATAout; reg srIl; reg srIe; reg srIp; reg srQl; reg srQe; reg srQp; reg newData; reg Real, Imag; reg Ecode, Pcode, Lcode; reg Ereal, Preal, Lreal, Eimag, Pimag, Limag; integer sumIe, sumIp, sumIl, sumQe, sumQp, sumQl, p; always @ (posedge sampleClock) //4.096Mhz sampleClock with NCO //may change this begin Real = DIFin ^ sinLUT; Imag = DIFin ^ cosLUT; Ereal = Real ^ Ecode; Preal = Real ^ Pcode; Lreal = Real ^ Lcode; Eimag = Imag ^ Ecode; Pimag = Imag ^ Pcode; Limag = Imag ^ Lcode; newData = 1; end always @ (posedge clk) //50Mhz main reference begin if( newData == 1) begin //shift new samples into shift register for summation srIl = srIl; srIl = Lreal; srIe = srIe; srIe = Ereal; srIp = srIp; srIp = Preal; srQl = srQl; srQl = Limag; srQe = srQe; srQe = Eimag; srQp = srQp; srQp = Pimag; //sum shift register values for(p = 1; p < SRsize; p = p+1) begin sumIe = srIe + srIe; sumIp = srIp + srIp; sumIl = srIl + srIl; sumQe = srQe + srQe; sumQp = srQp + srQp; sumQl = srQl + srQl; end //compute outputs assign DLLout = ((sumIe*sumIe + sumQe*sumQe)-(sumIl*sumIl + sumQl*sumQl)) / 2; //early - late error value assign PLLout = atan(sumQp / sumIp); //0-90 degree phase error //sum nav data //need to add still newData = 0; end end endmodule  

 

Please let me know if I have syntax errors or other issues
0 Kudos
9 Replies
Altera_Forum
Honored Contributor II
4,530 Views

I believe you haven't compiled the code. Quartus will report most errors, especially syntax related. 

 

Some fatal syntax errors are, 

- "assign" cannot be placed in procedural blocks, such as within the "always" 

- "real" outputs cannot be synthesized 

- atan is likely unsupported 

 

Non-fatal but violate RTL rules, 

- Procedural block with edged sensitivity list "always @(posedge...)" should use non-blocking assignments, ie <= instead of = 

 

Non-syntactical but likely not what you want 

- The loop of sumIe...sumQ1 has only the last p index useful. All those p=1 to SRsize-2 are overwritten 

- Integer data type should not be used as nodes. How wide the bus you need for, say sumIe? 

- Direct use of multiplier (*) may not fit well in FPGA without multipliers. It will be large and slow 

 

Logical errors, 

- The 2 clks are not phase related, the use of "newdata" in 2nd "always" needs proper synchronization. 

- Both clks update "newdata", what do you want it to synthesize? A flip-flop with 2 clks?
0 Kudos
Altera_Forum
Honored Contributor II
4,530 Views

I see the logic error in the for loops changed to  

//sum shift register values sumIe = srIe; sumIp = srIp; sumIl = srIl; sumQe = srQe; sumQp = srQp; sumQl = srQl; for(p = 1; p < SRsize; p = p+1) begin sumIe = sumIe + srIe; sumIp = sumIp + srIp; sumIl = sumIl + srIl; sumQe = sumQe + srQe; sumQp = sumQp + srQp; sumQl = sumQl + srQl; end  

 

When I try a compile in Quartus2 vers 13.1 I get this current build errors 

 

--- Quote Start ---  

Info (12021): Found 3 design units, including 3 entities, in source file basestation1.v 

Info (12023): Found entity 1: search 

Info (12023): Found entity 2: Correlator_Time_Domain 

Info (12023): Found entity 3: NCO 

Info (12021): Found 1 design units, including 1 entities, in source file basestation.bdf 

Info (12023): Found entity 1: Basestation 

Info (12021): Found 1 design units, including 1 entities, in source file codegenerator.v 

Info (12023): Found entity 1: CACODE 

Warning (10236): Verilog HDL Implicit Net warning at Basestation1.v(118): created implicit net for "sine_lookup_output" 

Error (12007): Top-level design entity "Basestation1" is undefined 

Info (144001): Generated suppressed messages file C:/Altera/projects/output_files/Basestation1.map.smsg 

Error: Quartus II 32-bit Analysis & Synthesis was unsuccessful. 1 error, 2 warnings 

Error: Peak virtual memory: 345 megabytes 

Error: Processing ended: Sun Apr 20 22:23:13 2014 

Error: Elapsed time: 00:00:02 

Error: Total CPU time (on all processors): 00:00:01 

Error (293001): Quartus II Full Compilation was unsuccessful. 3 errors, 2 warnings 

 

--- Quote End ---  

 

 

 

Can I not run 2 operations in the same module? I know the calculation part will take more reference clock cycles than the signal input so I was trying to use "newData" essentially as a boolean value with the always block running at the reference clock checking to see "IF" it was set to 1 by the input block. Can I not work it that way? 

I'm completely new to FPGA design.
0 Kudos
Altera_Forum
Honored Contributor II
4,530 Views

FPGA is not the problem. I think the biggest skill you lack is RTL coding. 

 

Get a book about Verilog that discusses RTL. It should not be difficult to pick up assumming you have digital logic design background. 

 

We can go with specific problem here. Without foundation in HDL, I see that it will take a long while to talk through all problems. 

 

In the mean time, about what you posted, 

- HDL is not software programming. We don't normally code cummulative sumIe in RTL using loop because not all synthesis tools accept this. Not sure about Quartus 

- The Quartus error was about missing Basestation1, which was indicated as top-level design. I guess basestation.bdf is your top-level file. If so, use basestation as top-level design name 

- As of newData, think about what you want the circuit to be, then translate it to code. Remember, HDL does not behave like software. Metastability has be considered transferring signal across asynchrounous clock domains
0 Kudos
Altera_Forum
Honored Contributor II
4,530 Views

I appreciate your responses 

I'm trying to keep it on a logic circuit flow. I'v split some of the functions down into seperate modules. Hopefully I can keep it better organized. It is fully compiling as it is with only a few errors. Pins incomplete IO assignments, I have not run through the pin placement yet. No clocks in design, i still have to figure out how to go about setting those up. Verilog HDL assignment warning at Basestation1.v(75): truncated value with size 4096 to match size of target (4095). I am not certain where I've got it wrong with that one. Those warnings apply to all of my shift registers. 

module Correlator_Time_Domain_CA (sampleClock, DIFin, sinLUT, cosLUT, chipIN, IEout, IPout, ILout, QEout, QPout, QLout); input sampleClock; //4.096Mhz input DIFin, sinLUT, cosLUT; input chipIN; output IEout, IPout, ILout, QEout, QPout, QLout; reg chip; reg result; always @ (posedge sampleClock) begin chip <= {chip, chipIN}; //shift in new early chip to lsb result <= DIFin ^ sinLUT ^ chip; result <= DIFin ^ sinLUT ^ chip; result <= DIFin ^ sinLUT ^ chip; result <= DIFin ^ cosLUT ^ chip; result <= DIFin ^ cosLUT ^ chip; result <= DIFin ^ cosLUT ^ chip; end assign ILout = result; assign IPout = result; assign IEout = result; assign QLout = result; assign QPout = result; assign QEout = result; endmodule  

Then this is the next step, an adder module 

 

module code_ADDER# (parameter N = 4096)(IL, IP, IE, QE, QP, QL, sysclk, codeNCOctl, phaseNCOctl); input sysclk; //50Mhz input IL, IP, IE, QL, QP, QE; output codeNCOctl; output phaseNCOctl; integer n; reg Iearly; reg Iprompt; reg Ilate; reg Qearly; reg Qprompt; reg Qlate; reg IEtotal, IPtotal, ILtotal, QEtotal, QPtotal, QLtotal; reg codeAdvance; reg phaseAdvance; always @ (posedge sysclk) begin Iearly <= {Iearly, IE}; Iprompt <= {Iprompt, IP}; Ilate <= {Ilate, IL}; Qearly <= {Qearly, QE}; Qprompt <= {Qprompt, QP}; Qlate <= {Qlate, QL}; //do averaging IEtotal <= 32'b00000000000000000000000000000000; IPtotal <= 32'b00000000000000000000000000000000; ILtotal <= 32'b00000000000000000000000000000000; QEtotal <= 32'b00000000000000000000000000000000; QPtotal <= 32'b00000000000000000000000000000000; QLtotal <= 32'b00000000000000000000000000000000; for(n=0; n<4096; n= n+1) begin IEtotal <= IEtotal + Iearly; IPtotal <= IPtotal + Iprompt; ILtotal <= ILtotal + Ilate; QEtotal <= QEtotal + Qearly; QPtotal <= QPtotal + Qprompt; QLtotal <= QLtotal + Qlate; end IPtotal <= IPtotal / N; QEtotal <= QEtotal / N; QPtotal <= QPtotal / N; QLtotal <= QLtotal / N; //calculate control if(IEtotal/N > ILtotal/N) begin codeAdvance <= 2'b11; end else if(IEtotal/N < ILtotal/N) begin codeAdvance <= 2'b01; end else begin codeAdvance <= 2'b00; end if(QEtotal * QLtotal > 1) begin phaseAdvance <= 2'b11; //control bits to advance or retard NCO module end else if (QEtotal < 1) begin phaseAdvance <= 2'b01; end else begin phaseAdvance <= 2'b00; end end assign codeNCOctl = codeAdvance; assign phaseNCOctl = phaseAdvance; endmodule  

 

I'm wondering about the adder function. Is there a good model to follow in syncronizing one module to the next when one does accumulate and averaging operations?
0 Kudos
Altera_Forum
Honored Contributor II
4,530 Views

The accumulate and average codes do not work. Maybe you can run simulation to understand better. 

 

When the same node is updated multiple times in LHS of non-blocking assignments, only the last one takes effect. 

In the code, IEtotal gets reduced to effectively single statement of "IEtotal <= IEtotal + Iearly[4095];". IEtotal is always X without reset. Similarly for the other regs in the loop. 

 

For summation of IEtotal, you can create intermediate combinatorial adder before feeding it to IEtotal. Break it into 2 "always" blocks. Something like, 

 

always @(posedge sysclk) 

begin 

... 

IEtotal <= IEtotal_intermediate; 

... 

end 

 

always @* 

begin 

IEtotal_intermediate = 32'h00000000; 

for(n = 0; n < 4096; n = n +1) 

IEtotal_intermediate = IEtotal_intermediate + {31'h00000000, Iearly[n]}; 

end
0 Kudos
Altera_Forum
Honored Contributor II
4,530 Views

So from what I've read so long as the "IEtotal_intermediate" variable is only used inside of the "always" block then use of the blocking "=" operator will work as an accumulator(would you call it a deterministic local variable?) , but if it was also used outside of that always block it would be used as a flip flop as if it had been a non blocking "<=" operator to start with?(non-deterministic?) 

Is it important to also make the distiction you did in the example of + {31 bits , 1 bit input}? Is it just a better notation or will lack of being specific and just adding + 1 bit input cause a problem? 

 

Thanks again
0 Kudos
Altera_Forum
Honored Contributor II
4,530 Views

Blocking(=) and non-blocking(<=) assignments are different in Verilog. 

 

Non-blocking assignments have RHS evaluated immediately, but the results are updated at the end of time step. When there are multiple assignments to the same node in the same time step, the last one overrides. The IEtotal depends on uninitialized IEtotal, that makes it undeterministic. 

 

Blocking assignments are evaluated sequentially. LHS is updated immediately before moving on to evaluate the next statement. Accumulator loop will work. 

 

In RTL, we do not mix blocking and non-blocking in the same "always" block. This rule is set to ensure consistent behavior comparing simulator with synthesized logic. You can actually change the <= to = in the old code and notice correct simulation behavior, but it will not work on hardware. Most likely a warning is generated during synthesis. 

 

About the {31'h0000000, Iearly[n]}, it is a good practise to keep both sides of an equation having the same bus width. Also to get rid of annoying warnings.
0 Kudos
Altera_Forum
Honored Contributor II
4,530 Views

So as long as I split them up and do the blocking assignment int intermediate variable seperate it should function.  

 

 

 

always @ (posedge sysclk) begin //do averaging IEint = 32'h00000000; IPint = 32'h00000000; ILint = 32'h00000000; QEint = 32'h00000000; QPint = 32'h00000000; QLint = 32'h00000000; for(n=0; n<N; n= n+1) begin IEint = IEint + Iearly; IPint = IPint + Iprompt; ILint = ILint + Ilate; QEint = QEint + Qearly; QPint = QPint + Qprompt; QLint = QLint + Qlate; end end always @ (posedge sysclk) begin IEtotal <= IEint / N; IPtotal <= IPint / N; ILtotal <= ILint / N; QEtotal <= QEint / N; QPtotal <= QPint / N; QLtotal <= QLint / N; //calculate control  

 

My next question would be on an NCO. This is based on a simple sawtooth example I found for fixed freq output. If I feed the output to a sin and cos LUT I should be able to get my mixer values to quadrature split and remove carrier drift from the PRN. Does this code look correct? 

 

module NCOcarrier(sampleclk, NCOout, control); input sampleclk; input control; //how to apply control? + or - to IF output NCOout; //control 00 stay, 01 increase, 11 decrease chip rate reg signalOut = 32'd0; integer IF = 12000000; //set to center IF always @ (posedge sampleclk) begin if(control == 2'b01) begin rate = rate + 1; //how much to advance or retard end if(control == 2'b11) begin rate = rate - 1; end end always @ (posedge sampleclk) begin signalOut <= signalOut + IF * 64'h100000000 / 50000000; end assign NCOout = signalOut; //use signalOut as input value for LUT sin and cos endmodule  

How would I handle roll over of the 32 bit signalOut value? Seems like the value should be kept within 0-90degrees or equivelent to, so as to keep the LUT as small as possible. I'm going to have to think on that one a while.
0 Kudos
Altera_Forum
Honored Contributor II
4,530 Views

Of the first piece of code, its sensitivity list should not be edge triggered to model combinatorial logic. Make it "always @*". 

 

As of the NCO, 

- Both rate and signalOut are uninitialized. Keep in mind that registers are unknowns upon circuit power-up. All branches in the assignments have dependency on old content. Therefore, both registers cannot get meaningful value. You need to find a way to reset or load the registers 

- rate should use <= in assignment 

- The module has only one output, NCOout. Not sure why the rate and control need to be there. They cannot affect NCOout in any way. 

 

About the truncation of NCOout, it depends how many LUT entries you can afford, effectively the trigo's resolution. You can't be having 2^32 entries. Why not reduce the width of signalOut?
0 Kudos
Reply