- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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?- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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?
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page