📄 synchronizer.bsv
字号:
//----------------------------------------------------------------------//// The MIT License // // Copyright (c) 2007 Alfred Man Cheuk Ng, mcn02@mit.edu // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without // restriction, including without limitation the rights to use,// copy, modify, merge, publish, distribute, sublicense, and/or sell// copies of the Software, and to permit persons to whom the// Software is furnished to do so, subject to the following conditions:// // The above copyright notice and this permission notice shall be// included in all copies or substantial portions of the Software.// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR// OTHER DEALINGS IN THE SOFTWARE.//----------------------------------------------------------------------//import Controls::*;import Complex::*;import CORDIC::*;import DataTypes::*;import FIFO::*;import FIFOF::*;import FixedPoint::*;import FixedPointLibrary::*;import Interfaces::*;import Preambles::*;import ShiftRegs::*;import SParams::*;import SynchronizerLibrary::*;import Vector::*;import FPComplex::*;import GetPut::*;import Parameters::*;//`define debug_mode True // uncomment this line for displaying text typedef struct{ ctrlT control; // estimate postion data1T data1; // data1 data2T data2; // data2} SyncData#(type ctrlT, type data1T, type data2T) deriving (Bits, Eq);typedef enum{ Dump = 0, // useless data, don't output Idle = 1, // don't do estimation Collect = 2, // collect correlation and calculate moving average ShortSync = 3, // make coarse estimation LongSync = 4, // make fine estimation TimeOut = 5 // timeout reset} ControlType deriving (Bits, Eq);typedef enum{ SNormal = 0, STrans = 1, LNormal = 2, LTrans = 3} TimeState deriving (Bits, Eq);// type definitions for the input of timing and frequency synchronizer// defintion of CorrPipeT: control = tell timing sync what to do, data1 = original input, data2 = rotated inputtypedef SyncData#(TimeState, FPComplex#(SyncIntPrec,SyncFractPrec), FPComplex#(SyncIntPrec,SyncFractPrec)) CorrPipeT;// defintion of FineTimeInT: data1 = original input, data2 = rotated inputtypedef SyncData#(ControlType, FPComplex#(SyncIntPrec,SyncFractPrec), FPComplex#(SyncIntPrec,SyncFractPrec)) FineTimeInT;// definition of FreqEstInT: data1 = original input, data2 = auto correlation resulttypedef SyncData#(ControlType, FPComplex#(SyncIntPrec,SyncFractPrec), FPComplex#(CorrIntPrec, SyncFractPrec)) FreqEstInT;// definition of FreqRotInT: data1 = original input, data2 = angle to be rotatedtypedef SyncData#(ControlType, FPComplex#(SyncIntPrec,SyncFractPrec), FixedPoint#(SyncIntPrec, SyncFractPrec)) FreqRotInT;// timing synchronizer interface (used for both coarse and fine estimations)interface TimeEstimator; // inputs method Action putCoarTimeIn(FPComplex#(SyncIntPrec,SyncFractPrec) coarTimeIn); method Action putFineTimeIn(FineTimeInT fineTimeIn); // output method ActionValue#(FreqEstInT) getFreqEstIn();endinterface// carrier frequency offset estimator (used for both coarse and fine estimations) interface FreqEstimator; // inputs method Action putFreqEstIn(FreqEstInT freqEstIn); // output method ActionValue#(FreqRotInT) getFreqRotIn();endinterface// carrier frequency offset compensatorinterface FreqRotator; // inputs method Action putFreqRotIn(FreqRotInT freqRotIn); // output method ActionValue#(FineTimeInT) getFineTimeIn();endinterfaceinterface AutoCorrelator; // inputs method Action putInput(FPComplex#(SyncIntPrec,SyncFractPrec) x); method Action setMode(Bool isShortMode); // outputs method ActionValue#(CorrType) getCorrelation();endinterface(* synthesize *)module mkAutoCorrelator(AutoCorrelator); // output buffer FIFO#(CorrType) outQ <- mkFIFO; // delay queues ShiftRegs#(SSLen, FPComplex#(SyncIntPrec,SyncFractPrec)) delayIn <- mkAutoCorr_DelayIn; ShiftRegs#(SSLen, FPComplex#(MulIntPrec,SyncFractPrec)) corrSub <- mkAutoCorr_CorrSub; ShiftRegs#(LSLSSLen, FPComplex#(SyncIntPrec,SyncFractPrec)) extDelayIn <- mkAutoCorr_ExtDelayIn; ShiftRegs#(LSLSSLen, FPComplex#(MulIntPrec,SyncFractPrec)) extCorrSub <- mkAutoCorr_ExtCorrSub; // accumulator Reg#(CorrType) corr <- mkReg(cmplx(0,0)); // mode Reg#(Bool) isShort <- mkReg(True); method Action putInput(FPComplex#(SyncIntPrec,SyncFractPrec) x); begin let conjDelayIn = cmplxConj(delayIn.first); // conjugate of delayed input let curIn = x; FPComplex#(MulIntPrec,SyncFractPrec) corrAdd = fpcmplxTruncate(fpcmplxMult(curIn,conjDelayIn)); let newCorr = corr + fpcmplxSignExtend(corrAdd) - fpcmplxSignExtend(corrSub.first); corr <= newCorr; outQ.enq(newCorr); if (isShort) begin delayIn.enq(curIn); corrSub.enq(corrAdd); `ifdef debug_mode $display("AutoCorr.putInput: isShort"); `endif end else begin extDelayIn.enq(curIn); delayIn.enq(extDelayIn.first); extCorrSub.enq(corrAdd); corrSub.enq(extCorrSub.first); `ifdef debug_mode $display("AutoCorr.putInput: isLong"); `endif end // else: !if(isShort) end endmethod method Action setMode(Bool isShortMode); begin // reset accumulator and shiftregs delayIn.clear; corrSub.clear; extDelayIn.clear; extCorrSub.clear; corr <= cmplx(0,0); isShort <= isShortMode; `ifdef debug_mode $display("AutoCorr.setMode: %d",isShortMode); `endif end endmethod method ActionValue#(CorrType) getCorrelation(); begin outQ.deq; `ifdef debug_mode $write("AutoCorr.getCorrelation:"); cmplxWrite("("," + ","i)",fxptWrite(7),outQ.first); $display(""); `endif return outQ.first; end endmethod endmodule(* synthesize *)module mkTimeEstimator(TimeEstimator); // constants Integer lSStart = valueOf(LSStart); Integer signalStart = valueOf(SignalStart); Integer lSyncPos = valueOf(LSyncPos); Integer freqMeanLen = valueOf(FreqMeanLen); Integer coarTimeCorrPos = valueOf(CoarTimeCorrPos); Integer coarResetPos = valueOf(TimeResetPos); Integer coarTimeAccumDelaySz = valueOf(CoarTimeAccumDelaySz); let fullLongPreambles = insertCP0(getLongPreSigns()); // constant known 160-long preambles Vector#(FineTimeCorrSz, Complex#(Bit#(1))) longPreambles = take(fullLongPreambles); Bit#(FineTimeCorrFullResSz) maxFineTimePowSq = cmplxModSq(singleBitCrossCorrelation(longPreambles,longPreambles)) >> 1; // last maxFineTimeSignal // states // autocorrelator AutoCorrelator autoCorr <- mkAutoCorrelator; // input buffers FIFO#(FPComplex#(SyncIntPrec,SyncFractPrec)) coarTimeInQ <- mkFIFO; // the buffer should be large enough (> whole latency of synchronizer) FIFOF#(FineTimeInT) fineTimeInQ <- mkFIFOF; FIFO#(TimeState) timeStatePipeQ <- mkSizedFIFO(2); FIFO#(FPComplex#(SyncIntPrec,SyncFractPrec)) coarInPipeQ <- mkSizedFIFO(2); FIFO#(FPComplex#(SyncIntPrec,SyncFractPrec)) fineInPipeQ <- mkSizedFIFO(2); FIFO#(FixedPoint#(CoarTimeAccumIntPrec,SyncFractPrec)) coarPowQ <- mkSizedFIFO(2); FIFO#(Bit#(FineTimeCorrFullResSz)) fineTimeCorrQ <- mkSizedFIFO(2); // output buffer FIFO#(FreqEstInT) outQ <- mkFIFO; // delay queues ShiftRegs#(SSLen, FixedPoint#(MulIntPrec,SyncFractPrec)) coarPowSub <- mkTimeEst_CoarPowSub; ShiftRegs#(CoarTimeAccumDelaySz, Bool) coarTimeSub <- mkTimeEst_CoarTimeSub; ShiftRegs#(FineTimeCorrDelaySz, Complex#(Bit#(1))) fineDelaySign <- mkTimeEst_FineDelaySign; //accumulators Reg#(FixedPoint#(CoarTimeAccumIntPrec,SyncFractPrec)) coarPow <- mkReg(0); Reg#(Bit#(CoarTimeAccumIdx)) coarTime <- mkReg(0); // at most add up to 144 //other regs Reg#(Bit#(CounterSz)) coarPos <- mkReg(0); Reg#(Bool) coarDet <- mkReg(False); Reg#(Bit#(CounterSz)) finePos <- mkReg(0); Reg#(Bool) fineDet <- mkReg(False); Reg#(Bool) isProlog <- mkReg(True); // setup at the beginning Reg#(TimeState) status <- mkReg(SNormal); rule procProlog(isProlog); // initial setup begin if (fineTimeInQ.notEmpty) // finish begin isProlog <= False; end else // not yet fill up pipeline, keep sending begin outQ.enq(FreqEstInT{control: Dump, data1: ?, data2: ?}); end `ifdef debug_mode $display("TimeEst.procProlog"); `endif end endrule rule procAutoCorrSN(!isProlog && status == SNormal); begin let curIn = coarTimeInQ.first; coarTimeInQ.deq; fineTimeInQ.deq; coarInPipeQ.enq(curIn); if (fineTimeInQ.first.control == ShortSync) begin status <= LNormal; autoCorr.setMode(False); timeStatePipeQ.enq(STrans); end else begin FixedPoint#(MulIntPrec,SyncFractPrec) coarPowAdd = fxptTruncate(fpcmplxModSq(curIn)); let newCoarPow = coarPow + fxptZeroExtend(coarPowAdd) - fxptZeroExtend(coarPowSub.first); coarPow <= newCoarPow; coarPowQ.enq(newCoarPow); coarPowSub.enq(coarPowAdd); autoCorr.putInput(curIn); timeStatePipeQ.enq(SNormal); end // else: !if(fineTimeInQ.first.control == ShortSync) `ifdef debug_mode $display("TimeEst.procAutoCorrSN"); `endif end endrule rule procAutoCorrLN(!isProlog && status == LNormal); begin let fineSign = toSingleBitCmplx(fineTimeInQ.first.data2); let fineTimeCorrIn = append(fineDelaySign.getVector(), cons(fineSign,nil)); let newFineTimeCorrPow = cmplxModSq(singleBitCrossCorrelation(fineTimeCorrIn, longPreambles)); fineDelaySign.enq(fineSign); fineTimeCorrQ.enq(newFineTimeCorrPow); coarTimeInQ.deq; fineTimeInQ.deq; autoCorr.putInput(fineTimeInQ.first.data2); timeStatePipeQ.enq(LNormal); coarInPipeQ.enq(coarTimeInQ.first); fineInPipeQ.enq(fineTimeInQ.first.data1); `ifdef debug_mode $write("TimeEst.procAutoCorrLN: fineSign: %d + %di,",fineSign.rel,fineSign.img); $write("input: "); cmplxWrite("("," + ","i), ",fxptWrite(7),fineTimeInQ.first.data2); $display(""); $display("TimeEst.procAutoCorrLN: fineTimeCorrIn:%h, ",fineTimeCorrIn); $display("TimeEst.procAutoCorrLN: longPreSigns:%h, ",longPreambles); `endif end endrule rule procAutoCorrLT(!isProlog && status == LTrans); begin fineTimeInQ.deq; timeStatePipeQ.enq(LTrans); fineInPipeQ.enq(fineTimeInQ.first.data1); if (fineTimeInQ.first.control == LongSync || fineTimeInQ.first.control == TimeOut) begin status <= SNormal; autoCorr.setMode(True); end `ifdef debug_mode $display("TimeEst.procAutCorrLT"); `endif end endrule rule procTimeEstSN(!isProlog && timeStatePipeQ.first == SNormal); begin //variables ControlType outControl = Idle; FPComplex#(SyncIntPrec,SyncFractPrec) outData = coarInPipeQ.first; CorrType outCorr = ?; Bit#(CounterSz) newCoarPos; let newCorr <- autoCorr.getCorrelation; let newCoarPow = coarPowQ.first; if (coarDet) begin newCoarPos = coarPos + 1; end else begin FPComplex#(CoarTimeAccumIntPrec, SyncFractPrec) newCoarCorr = fpcmplxTruncate(newCorr); let newCoarCorrPow = fpcmplxModSq(newCoarCorr); let newCoarPowSq = fxptZeroExtend(fxptMult(newCoarPow,newCoarPow)); let coarTimeAdd = newCoarCorrPow > (newCoarPowSq >> 1); let newCoarTime = coarTime + zeroExtend(pack(coarTimeAdd)) - zeroExtend(pack(coarTimeSub.first)); newCoarPos = zeroExtend(newCoarTime) + fromInteger(coarTimeCorrPos - 1); if (newCoarTime == fromInteger(coarTimeAccumDelaySz)) // coar detected begin coarDet <= True; coarTime <= 0; // reset coarTime coarTimeSub.clear; // clear coarTimeSub shiftreg end else begin coarTimeSub.enq(coarTimeAdd); coarTime <= newCoarTime; end end // else: !if(coarDet) // common state transitions timeStatePipeQ.deq; coarPowQ.deq; coarInPipeQ.deq;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -