Digital Modulation





/*++

                RELEASED FOR ACADEMIC AND NON-COMMERCIAL USE ONLY

                Module Name:

                   DeltaSigmaMod.v

                Abstract:

                   This module implements a Delta-Sigma Modulator logic for analog signal output.
                   
                   When the output of this module is connected to an RC filter, the output is of an analog value
                   that is dependent on the duty cycle of the digital output waveform.

                Author:

                   Stephanos Ioannidis (root@stephanos.io)  18-Aug-2016

                Revision History:

               --*/

               module DeltaSigmaMod(
                   // Base System
                   input               Reset_n,
                   input               Clk,

                   // Delta-Sigma Modulator
                   input   [7:0]       In,
                   output              Out
                   );

                   //\\\\\\\\\\\\\\\\\\\\\\\\\\\\\//
                   // Delta-Sigma Modulator Block //
                   //\\\\\\\\\\\\\\\\\\\\\\\\\\\\\//

                   reg [8:0] Accum;

                   always @ (posedge Clk or negedge Reset_n)
                   begin
                       //
                       // This block generates the modulated digital waveform for digital signal generation.
                       //
                       // The core of this Delta-Sigma modulator implementation is the accumulator. The input value
                       // is added to the lower 7 bits of the accumulator from the last cycle, and the MSB of the
                       // accumulator is used to drive the output. Note that the MSB will be high only if the
                       // IN + Accum[7:0] overflows.
                       //
                       // The value of the input determines how fast the accumulator overflows and hence the number
                       // of high levels output- a high input value would result in the accumulator overflowing
                       // faster and therefore more high outputs.
                       //
                       // This implementation compares to the classic Delta Sigma Modulator topology as follows:
                       //  * the differentiator (delta) corresponds to the wrap-around effect of the register
                       //      overflow
                       //  * the integrator (sigma) corresponds to the accumulator register.
                       //  * the comparator corresponds to the bit length of the accumulator register.
                       //

                       if (!Reset_n)
                       begin
                           //
                           // A reset has been issued. Clear the accumulator.
                           //

                           Accum <= 0;
                       end
                       else
                       begin
                           //
                           // Add the lower 7 bits of the accumulator to the input value.
                           //

                           Accum <= Accum[7:0] + In;
                       end
                   end

                   //
                   // Assign the output value to be the 8th bit of the accumulator.
                   //
                   // Note that the output value will be high only when the existing accumulator value added to
                   // the input value overflows.
                   //

                   assign Out = Accum[8];

               endmodule
               

/*++

                   RELEASED FOR ACADEMIC AND NON-COMMERCIAL USE ONLY

                   Module Name:

                      Adc.v

                   Abstract:

                      This module implements the control logic for the parallel 8-bit Analog-to-Digital Converter.

                   Author:

                      Stephanos Ioannidis (root@stephanos.io)  17-Oct-2016

                   Revision History:
                   
                      Stephanos Ioannidis (root@stephanos.io)  13-Mar-2017
                          Ported this module for use with prototype boards.

                  --*/

                  module Adc(
                      // Base System
                      input               Clk,
                      input               Reset_n,

                      // ADC Input
                      input   [7:0]       Data,

                      // ADC Control Signals
                      output              nOE,
                      output              ClkOut,

                      // Data Output
                      output  [7:0]       DataOut
                      );

                      //\\\\\\\\\\\\\\\\\\\\\\\\\//
                      // ADC Output Driver Block //
                      //\\\\\\\\\\\\\\\\\\\\\\\\\//

                      reg nOEDrv;
                      assign nOE = nOEDrv;

                      always @ (posedge Clk or negedge Reset_n)
                      begin
                          //
                          // This block drives the output enable signal for the ADC module.
                          //

                          if (!Reset_n)
                          begin
                              //
                              // A reset has been issued. Disable the ADC module output.
                              //

                              nOEDrv <= 1;
                          end
                          else
                          begin
                              //
                              // Enable the ADC module output.
                              //

                              nOEDrv <= 0;
                          end
                      end

                      //\\\\\\\\\\\\\\\\\\\\\\\\\\\//
                      // ADC Clock Generator Block //
                      //\\\\\\\\\\\\\\\\\\\\\\\\\\\//

                      //
                      // NOTE: F_div = F_Clk / 2 / (ADCClkDIV + 1)
                      //

                      parameter AdcClkDiv = 9;

                      reg ClkOutDrv;
                      assign ClkOut = ClkOutDrv;

                      reg [7:0] AdcClkDivCnt;

                      always @ (posedge Clk or negedge Reset_n)
                      begin
                          //
                          // This block generates 10MHz ADC clock from the 200MHz internal PLL clock.
                          //

                          if (!Reset_n)
                          begin
                              //
                              // A reset has been issued. Reset the counter and clock output.
                              //

                              ClkOutDrv <= 1;
                              AdcClkDivCnt <= 0;
                          end
                          else if (AdcClkDivCnt == AdcClkDiv)
                          begin
                              //
                              // Flip the clock bit once the counter reaches a pre-set value.
                              //

                              ClkOutDrv <= ~ClkOutDrv;
                              AdcClkDivCnt <= 0;
                          end
                          else
                          begin
                              //
                              // Increment the ADC clock divider counter.
                              //

                              AdcClkDivCnt <= AdcClkDivCnt + 1;
                          end
                      end

                      //\\\\\\\\\\\\\\\\\\\\\\//
                      // ADC Data Latch Block //
                      //\\\\\\\\\\\\\\\\\\\\\\//

                      reg [7:0] AdcData;

                      assign DataOut = AdcData;

                      always @ (posedge ClkOut or negedge Reset_n)
                      begin
                          //
                          // This block latches the ADC data at every rising edge of the clock cycle
                          // (ADC data is valid at the rising edge of every clock).
                          //

                          if (!Reset_n)
                          begin
                              //
                              // A reset has been issued. Clear the internal ADC data buffer.
                              //

                              AdcData <= 0;
                          end
                          else
                          begin
                              //
                              // Latch the ADC data line to the internal ADC data buffer.
                              //

                              AdcData <= Data;
                          end
                      end

                  endmodule
                  

/*++

                      RELEASED FOR ACADEMIC AND NON-COMMERCIAL USE ONLY

                      Module Name:

                         Modulator.v

                      Abstract:

                         This module implements a Binary Phase Shift Keying (BPSK) modulator.

                      Author:

                         Stephanos Ioannidis (root@stephanos.io)  22-Aug-2016

                      Revision History:

                     --*/

                     //
                     // NOTE: When this module outputs a constant 0 on its output, the delta sigma modulator output
                     //       driven by Out of this module is also constant zero. Since there is a DC blocking capacitor
                     //       in the line coupler, as long as there is no change in voltage over time, no output goes
                     //       through.
                     //

                     module BpskMod(
                         // Base System
                         input                       Clk,
                         input                       Reset_n,

                         // Data Control Signals
                         input   [2:0]               OutDiv,
                         input   [31:0]              Data [0:15],
                         input                       Int,
                         output                      Done,

                         // Modulator Output Signals
                         output  [7:0]               Out
                         );

                         //\\\\\\\\\\\\\\\\\\\//
                         // Module Parameters //
                         //\\\\\\\\\\\\\\\\\\\//

                         //
                         // Carrier Sequencer Divisor:
                         //      This parameter specifies the division ratio for the carrier sequencer clock.
                         //      The resultant carrier frequency is calculated as follows:
                         //          F_out = Clk / 2 / (CSEQDiv + 1) / CSEQElemCnt
                         //

                         parameter CSEQDiv = 4;

                         //
                         // Modulation Index:
                         //      This parameter specifies the phase modulation index for the carrier wave.
                         //      The higher the modulation index number, the less frequently modulated the carrier wave is.
                         //

                         parameter ModIdx = 2;

                         //\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\//
                         // Transmit Done Signal Driver Block //
                         //\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\//

                         reg DoneDrv;

                         assign Done = DoneDrv & Int;

                         //\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\//
                         // Carrier Sequencer Clock Generator Block //
                         //\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\//

                         reg CSEQ_Clk;
                         reg [15:0] CSEQClkDivCnt;

                         always @ (posedge Clk or negedge Reset_n)
                         begin
                             //
                             // This block divides the main input clock by a pre-set factor to generate carrier
                             // sequencer clock.
                             //

                             if (!Reset_n)
                             begin
                                 //
                                 // A reset has been issued. Reset the counter and clock output.
                                 //

                                 CSEQ_Clk <= 0;
                                 CSEQClkDivCnt <= 0;
                             end
                             else if (CSEQClkDivCnt == CSEQDiv)
                             begin
                                 //
                                 // Flip the clock bit once the counter reaches a pre-set value.
                                 //

                                 CSEQ_Clk <= ~CSEQ_Clk;
                                 CSEQClkDivCnt <= 0;
                             end
                             else
                             begin
                                 //
                                 // Increment the ADC clock divider counter.
                                 //

                                 CSEQClkDivCnt <= CSEQClkDivCnt + 1;
                             end
                         end

                         //\\\\\\\\\\\\\\\\\\\\\\\\\//
                         // Carrier Sequencer Block //
                         //\\\\\\\\\\\\\\\\\\\\\\\\\//

                         reg [4:0] SeqSel;
                         reg [7:0] SeqOut;

                         always @ (posedge CSEQ_Clk or negedge Reset_n)
                         begin
                             //
                             // This block sequences the carrier waveform value.
                             //

                             if (!Reset_n)
                             begin
                                 //
                                 // A reset has been issued. Set the sequence element selector index to 0.
                                 //

                                 SeqSel <= 0;
                             end
                             else
                             begin
                                 //
                                 // Output value based on the sequence element selector index.
                                 //

                                 case (SeqSel)
                                     0:  SeqOut = 127;
                                     1:  SeqOut = 166;
                                     2:  SeqOut = 202;
                                     3:  SeqOut = 230;
                                     4:  SeqOut = 248;
                                     5:  SeqOut = 254;
                                     6:  SeqOut = 248;
                                     7:  SeqOut = 230;
                                     8:  SeqOut = 202;
                                     9:  SeqOut = 166;
                                     10: SeqOut = 127;
                                     11: SeqOut = 88;
                                     12: SeqOut = 52;
                                     13: SeqOut = 24;
                                     14: SeqOut = 6;
                                     15: SeqOut = 0;
                                     16: SeqOut = 6;
                                     17: SeqOut = 24;
                                     18: SeqOut = 52;
                                     19: SeqOut = 88;
                                 endcase

                                 //
                                 // Reset the sequence element selector index to 0 once the selector index reaches 19.
                                 //

                                 if (SeqSel == 19)
                                     SeqSel <= 0;
                                 else
                                     SeqSel <= SeqSel + 1;
                             end
                         end

                         //\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\//
                         // Transmit Interrupt Edge Detector Block //
                         //\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\//

                         reg [1:0] TIDetect;

                         always @ (posedge Clk or negedge Reset_n)
                         begin
                             //
                             // This block detects the transmit interrupt by storing last three bits and comparing their
                             // values to the latest values.
                             //

                             if (!Reset_n)
                             begin
                                 //
                                 // A reset has been issued. Clear all edge detection buffer bits.
                                 //

                                 TIDetect <= 0;
                             end
                             else
                             begin
                                 //
                                 // Shift the detector buffer left and insert the latest RX bit.
                                 //

                                 TIDetect <= (TIDetect << 1) | Int;
                             end
                         end

                         //
                         // Detect the rising edge on the transmit interrupt line.
                         //

                         wire TIRisingEdge = !TIDetect[1] & TIDetect[0];

                         //
                         // Synchronise the transmit interrupt rising edge signal to sequencer clock.
                         //

                         reg [7:0] TIDetectedSyncCnt;
                         reg TIDetected;

                         always @ (posedge Clk or negedge Reset_n)
                         begin
                             if (!Reset_n)
                             begin
                                 //
                                 // Initialise sync counter and TIDetected signal.
                                 //

                                 TIDetectedSyncCnt <= 0;
                                 TIDetected <= 0;
                             end
                             else
                             begin
                                 if (TIRisingEdge && (TIDetectedSyncCnt == 0))
                                 begin
                                     //
                                     // If a rising edge is detected and the counter is not started, assert TIDetected
                                     // and begin synchronisation.
                                     //

                                     TIDetected <= 1;
                                     TIDetectedSyncCnt <= 1;
                                 end
                                 else if (TIDetectedSyncCnt != 0)
                                 begin
                                     //
                                     // Wait for the Clk-CSEQ_Clk division ratio cycles in Clk domain.
                                     //

                                     if (TIDetectedSyncCnt == ((CSEQDiv + 1) * 2))
                                     begin
                                         TIDetected <= 0;
                                         TIDetectedSyncCnt <= 0;
                                     end
                                     else
                                     begin
                                         TIDetectedSyncCnt <= TIDetectedSyncCnt + 1;
                                     end
                                 end
                             end
                         end

                         //\\\\\\\\\\\\\\\\\\\\\\\\\\\//
                         // Carrier Phase Shift Block //
                         //\\\\\\\\\\\\\\\\\\\\\\\\\\\//

                         reg Phase;
                         reg OutEnable;

                         //
                         // Out output value is dependent on the Phase register value.
                         //
                         // If the Phase register contains 0, the Out output is simply the sequencer output value.
                         // If the Phase register contains 1, the Out output is the inverted value of the sequencer
                         // output value.
                         //
                         // Output is always zero regardless of the carrier sequencer output when OutEnable is inactive.
                         //

                         wire [7:0] PhaseModSeqOut = (Phase == 0) ? (SeqOut) >> OutDiv : (254 - SeqOut) >> OutDiv;

                         assign Out = (OutEnable == 0) ? 0 : PhaseModSeqOut;

                         //\\\\\\\\\\\\\\\\\\\\\\//
                         // Data Sequencer Block //
                         //\\\\\\\\\\\\\\\\\\\\\\//

                         reg [9:0] WaitCnt;
                         reg [10:0] BitIndex;     // NOTE: Make sure to change this when the data bit length changes.
                         reg [1:0] ModIdxCnt;
                         reg [31:0] Checksum;

                         wire [0:63] MagicPattern = 64'hB5A6FFFF9BE37C39;

                         always @ (posedge CSEQ_Clk or negedge Reset_n)
                         begin
                             //
                             // This block inverts the sequencer output value based on the phase value.
                             //

                             if (!Reset_n)
                             begin
                                 //
                                 // A reset has been issued. Reset the phase to 0 deg and modulation index counter to 0.
                                 // Also disable modulator analog output upon reset.
                                 //

                                 ModIdxCnt <= 0;
                                 Phase <= 0;
                                 OutEnable <= 0;
                                 DoneDrv <= 0;
                                 Checksum <= 0;
                             end
                             else if (TIDetected && !OutEnable)
                             begin
                                 //
                                 // A transmit interrupt has been detected. Latch the transmit data and enable modulator
                                 // output. Also initialise the wait counter value for warm-up cycles.
                                 //

                                 OutEnable <= 1;
                                 WaitCnt <= 0;
                                 BitIndex <= 0;
                                 DoneDrv <= 0;

                                 //
                                 // Compute the data frame checksum by XOR-ing all data words.
                                 //

                                 Checksum <=
                                     Data[0]  ^ Data[1]  ^ Data[2]  ^ Data[3]  ^
                                     Data[4]  ^ Data[5]  ^ Data[6]  ^ Data[7]  ^
                                     Data[8]  ^ Data[9]  ^ Data[10] ^ Data[11] ^
                                     Data[12] ^ Data[13] ^ Data[14] ^ Data[15];
                             end
                             else if (OutEnable)
                             begin
                                 //
                                 // This block executes when a transmit cycle is active.
                                 //

                                 if (SeqSel == 0)
                                 begin
                                     //
                                     // This block executes at the beginning of each carrier cycle.
                                     //

                                     if (WaitCnt < 1000)
                                     begin
                                         //
                                         // Increment the wait counter until 100 carrier cycles have been driven. This
                                         // allows the receiver Costas Loop to lock on the transmitted carrier.
                                         //

                                         WaitCnt <= WaitCnt + 1;
                                     end
                                     else
                                     begin
                                         //
                                         // If a transmit cycle is active and the wait counter value (of 100) is reached,
                                         // begin modulating the output data.
                                         //

                                         if (ModIdxCnt == (ModIdx - 1))
                                         begin
                                             //
                                             // Modulation index counter hit the preset index.
                                             //

                                             if (BitIndex < 64)
                                             begin
                                                 //
                                                 // Bit index is less than 16. Transmit "magic" bit pattern.
                                                 //

                                                 Phase <= MagicPattern[BitIndex];
                                                 BitIndex <= BitIndex + 1;
                                             end
                                             else if (BitIndex < 576) // 64 + (32 * 16)
                                             begin
                                                 //
                                                 // Modify the carrier phase based on the data value and increment the
                                                 // bit index.
                                                 //

                                                 Phase <= Data[(BitIndex - 64) >> 5][31 - ((BitIndex - 64) & 11'h1F)];
                                                 BitIndex <= BitIndex + 1;
                                             end
                                             else if (BitIndex < 608) // 576 + 32
                                             begin
                                                 //
                                                 // Transmit data frame checksum.
                                                 //

                                                 Phase <= Checksum[607 - BitIndex];
                                                 BitIndex <= BitIndex + 1;
                                             end
                                             else
                                             begin
                                                 //
                                                 // Reached the last word. Disable the carrier output and activate
                                                 // the transmit done signal.
                                                 //

                                                 OutEnable <= 0;
                                                 DoneDrv <= 1;
                                             end

                                             ModIdxCnt <= 0;
                                         end
                                         else
                                         begin
                                             //
                                             // One carrier period has elapsed. Increment the modulation index counter.
                                             //

                                             ModIdxCnt <= ModIdxCnt + 1;
                                         end
                                     end
                                 end
                             end
                         end

                     endmodule
                     









/*++

                         RELEASED FOR ACADEMIC AND NON-COMMERCIAL USE ONLY

                         Module Name:

                            Demodulator.v

                         Abstract:

                            This module implements a Binary Phase Shift Keying (BPSK) demodulator.

                         Author:

                            Stephanos Ioannidis (root@stephanos.io)  30-Aug-2016

                         Revision History:

                        --*/

                        module BpskDemod(
                            // Base System
                            input                       Clk,            // We assume 200MHz clock input by default.
                            input                       Reset_n,

                            // Demodulator Input Signals
                            input                       AdcClk,
                            input   [9:0]               AdcIn,          // Q9:0

                            // Data Control Signals
                            output                      Int,
                            output  [31:0]              Data [0:15],
                            input                       Ack
                            );

                            parameter ModemBusClkDiv = 4;

                            integer i;

                            //\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\//
                            // Module-wide State Signals and Registers //
                            //\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\//

                            wire signed [17:0] mSig;        // Input BPSK Modulated Signal
                            reg [8:0] NcoPhase;             // Phase of NCO

                            // Sign-extend Data in Q9.0 format to Q17.0.
                            assign mSig = { { 8{AdcIn[9]} }, AdcIn[9:0] };

                            //\\\\\\\\\\\\\\\\\\\\\\\\//
                            // Sinusoid Look-up Table //
                            //\\\\\\\\\\\\\\\\\\\\\\\\//

                            //
                            // NOTE: This look-up table consists of 255 entries that equate to 0 - 179.3 degree output of
                            //       the sine function. Each value is encoded in Q7.10 fixed-point format.
                            //

                            wire signed [17:0] SinLUT[0:255] /* synthesis ramstyle = "auto" */;

                            assign SinLUT[0] = 18'b0000000_0000000000;
                            assign SinLUT[1] = 18'b0000000_0000001100;
                            assign SinLUT[2] = 18'b0000000_0000011001;
                            assign SinLUT[3] = 18'b0000000_0000100101;
                            assign SinLUT[4] = 18'b0000000_0000110010;
                            assign SinLUT[5] = 18'b0000000_0000111110;
                            assign SinLUT[6] = 18'b0000000_0001001011;
                            assign SinLUT[7] = 18'b0000000_0001010111;
                            assign SinLUT[8] = 18'b0000000_0001100100;
                            assign SinLUT[9] = 18'b0000000_0001110000;
                            assign SinLUT[10] = 18'b0000000_0001111101;
                            assign SinLUT[11] = 18'b0000000_0010001001;
                            assign SinLUT[12] = 18'b0000000_0010010110;
                            assign SinLUT[13] = 18'b0000000_0010100010;
                            assign SinLUT[14] = 18'b0000000_0010101111;
                            assign SinLUT[15] = 18'b0000000_0010111011;
                            assign SinLUT[16] = 18'b0000000_0011000111;
                            assign SinLUT[17] = 18'b0000000_0011010100;
                            assign SinLUT[18] = 18'b0000000_0011100000;
                            assign SinLUT[19] = 18'b0000000_0011101100;
                            assign SinLUT[20] = 18'b0000000_0011111000;
                            assign SinLUT[21] = 18'b0000000_0100000100;
                            assign SinLUT[22] = 18'b0000000_0100010001;
                            assign SinLUT[23] = 18'b0000000_0100011101;
                            assign SinLUT[24] = 18'b0000000_0100101001;
                            assign SinLUT[25] = 18'b0000000_0100110101;
                            assign SinLUT[26] = 18'b0000000_0101000001;
                            assign SinLUT[27] = 18'b0000000_0101001101;
                            assign SinLUT[28] = 18'b0000000_0101011000;
                            assign SinLUT[29] = 18'b0000000_0101100100;
                            assign SinLUT[30] = 18'b0000000_0101110000;
                            assign SinLUT[31] = 18'b0000000_0101111100;
                            assign SinLUT[32] = 18'b0000000_0110000111;
                            assign SinLUT[33] = 18'b0000000_0110010011;
                            assign SinLUT[34] = 18'b0000000_0110011110;
                            assign SinLUT[35] = 18'b0000000_0110101010;
                            assign SinLUT[36] = 18'b0000000_0110110101;
                            assign SinLUT[37] = 18'b0000000_0111000001;
                            assign SinLUT[38] = 18'b0000000_0111001100;
                            assign SinLUT[39] = 18'b0000000_0111010111;
                            assign SinLUT[40] = 18'b0000000_0111100010;
                            assign SinLUT[41] = 18'b0000000_0111101101;
                            assign SinLUT[42] = 18'b0000000_0111111000;
                            assign SinLUT[43] = 18'b0000000_1000000011;
                            assign SinLUT[44] = 18'b0000000_1000001110;
                            assign SinLUT[45] = 18'b0000000_1000011001;
                            assign SinLUT[46] = 18'b0000000_1000100011;
                            assign SinLUT[47] = 18'b0000000_1000101110;
                            assign SinLUT[48] = 18'b0000000_1000111000;
                            assign SinLUT[49] = 18'b0000000_1001000011;
                            assign SinLUT[50] = 18'b0000000_1001001101;
                            assign SinLUT[51] = 18'b0000000_1001010111;
                            assign SinLUT[52] = 18'b0000000_1001100001;
                            assign SinLUT[53] = 18'b0000000_1001101100;
                            assign SinLUT[54] = 18'b0000000_1001110101;
                            assign SinLUT[55] = 18'b0000000_1001111111;
                            assign SinLUT[56] = 18'b0000000_1010001001;
                            assign SinLUT[57] = 18'b0000000_1010010011;
                            assign SinLUT[58] = 18'b0000000_1010011100;
                            assign SinLUT[59] = 18'b0000000_1010100110;
                            assign SinLUT[60] = 18'b0000000_1010101111;
                            assign SinLUT[61] = 18'b0000000_1010111000;
                            assign SinLUT[62] = 18'b0000000_1011000010;
                            assign SinLUT[63] = 18'b0000000_1011001011;
                            assign SinLUT[64] = 18'b0000000_1011010100;
                            assign SinLUT[65] = 18'b0000000_1011011100;
                            assign SinLUT[66] = 18'b0000000_1011100101;
                            assign SinLUT[67] = 18'b0000000_1011101110;
                            assign SinLUT[68] = 18'b0000000_1011110110;
                            assign SinLUT[69] = 18'b0000000_1011111111;
                            assign SinLUT[70] = 18'b0000000_1100000111;
                            assign SinLUT[71] = 18'b0000000_1100001111;
                            assign SinLUT[72] = 18'b0000000_1100010111;
                            assign SinLUT[73] = 18'b0000000_1100011111;
                            assign SinLUT[74] = 18'b0000000_1100100111;
                            assign SinLUT[75] = 18'b0000000_1100101110;
                            assign SinLUT[76] = 18'b0000000_1100110110;
                            assign SinLUT[77] = 18'b0000000_1100111101;
                            assign SinLUT[78] = 18'b0000000_1101000101;
                            assign SinLUT[79] = 18'b0000000_1101001100;
                            assign SinLUT[80] = 18'b0000000_1101010011;
                            assign SinLUT[81] = 18'b0000000_1101011010;
                            assign SinLUT[82] = 18'b0000000_1101100001;
                            assign SinLUT[83] = 18'b0000000_1101100111;
                            assign SinLUT[84] = 18'b0000000_1101101110;
                            assign SinLUT[85] = 18'b0000000_1101110100;
                            assign SinLUT[86] = 18'b0000000_1101111010;
                            assign SinLUT[87] = 18'b0000000_1110000001;
                            assign SinLUT[88] = 18'b0000000_1110000111;
                            assign SinLUT[89] = 18'b0000000_1110001100;
                            assign SinLUT[90] = 18'b0000000_1110010010;
                            assign SinLUT[91] = 18'b0000000_1110011000;
                            assign SinLUT[92] = 18'b0000000_1110011101;
                            assign SinLUT[93] = 18'b0000000_1110100010;
                            assign SinLUT[94] = 18'b0000000_1110101000;
                            assign SinLUT[95] = 18'b0000000_1110101101;
                            assign SinLUT[96] = 18'b0000000_1110110010;
                            assign SinLUT[97] = 18'b0000000_1110110110;
                            assign SinLUT[98] = 18'b0000000_1110111011;
                            assign SinLUT[99] = 18'b0000000_1110111111;
                            assign SinLUT[100] = 18'b0000000_1111000100;
                            assign SinLUT[101] = 18'b0000000_1111001000;
                            assign SinLUT[102] = 18'b0000000_1111001100;
                            assign SinLUT[103] = 18'b0000000_1111010000;
                            assign SinLUT[104] = 18'b0000000_1111010011;
                            assign SinLUT[105] = 18'b0000000_1111010111;
                            assign SinLUT[106] = 18'b0000000_1111011010;
                            assign SinLUT[107] = 18'b0000000_1111011110;
                            assign SinLUT[108] = 18'b0000000_1111100001;
                            assign SinLUT[109] = 18'b0000000_1111100100;
                            assign SinLUT[110] = 18'b0000000_1111100111;
                            assign SinLUT[111] = 18'b0000000_1111101001;
                            assign SinLUT[112] = 18'b0000000_1111101100;
                            assign SinLUT[113] = 18'b0000000_1111101110;
                            assign SinLUT[114] = 18'b0000000_1111110000;
                            assign SinLUT[115] = 18'b0000000_1111110010;
                            assign SinLUT[116] = 18'b0000000_1111110100;
                            assign SinLUT[117] = 18'b0000000_1111110110;
                            assign SinLUT[118] = 18'b0000000_1111111000;
                            assign SinLUT[119] = 18'b0000000_1111111001;
                            assign SinLUT[120] = 18'b0000000_1111111011;
                            assign SinLUT[121] = 18'b0000000_1111111100;
                            assign SinLUT[122] = 18'b0000000_1111111101;
                            assign SinLUT[123] = 18'b0000000_1111111110;
                            assign SinLUT[124] = 18'b0000000_1111111110;
                            assign SinLUT[125] = 18'b0000000_1111111111;
                            assign SinLUT[126] = 18'b0000000_1111111111;
                            assign SinLUT[127] = 18'b0000000_1111111111;
                            assign SinLUT[128] = 18'b0000001_0000000000;
                            assign SinLUT[129] = 18'b0000000_1111111111;
                            assign SinLUT[130] = 18'b0000000_1111111111;
                            assign SinLUT[131] = 18'b0000000_1111111111;
                            assign SinLUT[132] = 18'b0000000_1111111110;
                            assign SinLUT[133] = 18'b0000000_1111111110;
                            assign SinLUT[134] = 18'b0000000_1111111101;
                            assign SinLUT[135] = 18'b0000000_1111111100;
                            assign SinLUT[136] = 18'b0000000_1111111011;
                            assign SinLUT[137] = 18'b0000000_1111111001;
                            assign SinLUT[138] = 18'b0000000_1111111000;
                            assign SinLUT[139] = 18'b0000000_1111110110;
                            assign SinLUT[140] = 18'b0000000_1111110100;
                            assign SinLUT[141] = 18'b0000000_1111110010;
                            assign SinLUT[142] = 18'b0000000_1111110000;
                            assign SinLUT[143] = 18'b0000000_1111101110;
                            assign SinLUT[144] = 18'b0000000_1111101100;
                            assign SinLUT[145] = 18'b0000000_1111101001;
                            assign SinLUT[146] = 18'b0000000_1111100111;
                            assign SinLUT[147] = 18'b0000000_1111100100;
                            assign SinLUT[148] = 18'b0000000_1111100001;
                            assign SinLUT[149] = 18'b0000000_1111011110;
                            assign SinLUT[150] = 18'b0000000_1111011010;
                            assign SinLUT[151] = 18'b0000000_1111010111;
                            assign SinLUT[152] = 18'b0000000_1111010011;
                            assign SinLUT[153] = 18'b0000000_1111010000;
                            assign SinLUT[154] = 18'b0000000_1111001100;
                            assign SinLUT[155] = 18'b0000000_1111001000;
                            assign SinLUT[156] = 18'b0000000_1111000100;
                            assign SinLUT[157] = 18'b0000000_1110111111;
                            assign SinLUT[158] = 18'b0000000_1110111011;
                            assign SinLUT[159] = 18'b0000000_1110110110;
                            assign SinLUT[160] = 18'b0000000_1110110010;
                            assign SinLUT[161] = 18'b0000000_1110101101;
                            assign SinLUT[162] = 18'b0000000_1110101000;
                            assign SinLUT[163] = 18'b0000000_1110100010;
                            assign SinLUT[164] = 18'b0000000_1110011101;
                            assign SinLUT[165] = 18'b0000000_1110011000;
                            assign SinLUT[166] = 18'b0000000_1110010010;
                            assign SinLUT[167] = 18'b0000000_1110001100;
                            assign SinLUT[168] = 18'b0000000_1110000111;
                            assign SinLUT[169] = 18'b0000000_1110000001;
                            assign SinLUT[170] = 18'b0000000_1101111010;
                            assign SinLUT[171] = 18'b0000000_1101110100;
                            assign SinLUT[172] = 18'b0000000_1101101110;
                            assign SinLUT[173] = 18'b0000000_1101100111;
                            assign SinLUT[174] = 18'b0000000_1101100001;
                            assign SinLUT[175] = 18'b0000000_1101011010;
                            assign SinLUT[176] = 18'b0000000_1101010011;
                            assign SinLUT[177] = 18'b0000000_1101001100;
                            assign SinLUT[178] = 18'b0000000_1101000101;
                            assign SinLUT[179] = 18'b0000000_1100111101;
                            assign SinLUT[180] = 18'b0000000_1100110110;
                            assign SinLUT[181] = 18'b0000000_1100101110;
                            assign SinLUT[182] = 18'b0000000_1100100111;
                            assign SinLUT[183] = 18'b0000000_1100011111;
                            assign SinLUT[184] = 18'b0000000_1100010111;
                            assign SinLUT[185] = 18'b0000000_1100001111;
                            assign SinLUT[186] = 18'b0000000_1100000111;
                            assign SinLUT[187] = 18'b0000000_1011111111;
                            assign SinLUT[188] = 18'b0000000_1011110110;
                            assign SinLUT[189] = 18'b0000000_1011101110;
                            assign SinLUT[190] = 18'b0000000_1011100101;
                            assign SinLUT[191] = 18'b0000000_1011011100;
                            assign SinLUT[192] = 18'b0000000_1011010100;
                            assign SinLUT[193] = 18'b0000000_1011001011;
                            assign SinLUT[194] = 18'b0000000_1011000010;
                            assign SinLUT[195] = 18'b0000000_1010111000;
                            assign SinLUT[196] = 18'b0000000_1010101111;
                            assign SinLUT[197] = 18'b0000000_1010100110;
                            assign SinLUT[198] = 18'b0000000_1010011100;
                            assign SinLUT[199] = 18'b0000000_1010010011;
                            assign SinLUT[200] = 18'b0000000_1010001001;
                            assign SinLUT[201] = 18'b0000000_1001111111;
                            assign SinLUT[202] = 18'b0000000_1001110101;
                            assign SinLUT[203] = 18'b0000000_1001101100;
                            assign SinLUT[204] = 18'b0000000_1001100001;
                            assign SinLUT[205] = 18'b0000000_1001010111;
                            assign SinLUT[206] = 18'b0000000_1001001101;
                            assign SinLUT[207] = 18'b0000000_1001000011;
                            assign SinLUT[208] = 18'b0000000_1000111000;
                            assign SinLUT[209] = 18'b0000000_1000101110;
                            assign SinLUT[210] = 18'b0000000_1000100011;
                            assign SinLUT[211] = 18'b0000000_1000011001;
                            assign SinLUT[212] = 18'b0000000_1000001110;
                            assign SinLUT[213] = 18'b0000000_1000000011;
                            assign SinLUT[214] = 18'b0000000_0111111000;
                            assign SinLUT[215] = 18'b0000000_0111101101;
                            assign SinLUT[216] = 18'b0000000_0111100010;
                            assign SinLUT[217] = 18'b0000000_0111010111;
                            assign SinLUT[218] = 18'b0000000_0111001100;
                            assign SinLUT[219] = 18'b0000000_0111000001;
                            assign SinLUT[220] = 18'b0000000_0110110101;
                            assign SinLUT[221] = 18'b0000000_0110101010;
                            assign SinLUT[222] = 18'b0000000_0110011110;
                            assign SinLUT[223] = 18'b0000000_0110010011;
                            assign SinLUT[224] = 18'b0000000_0110000111;
                            assign SinLUT[225] = 18'b0000000_0101111100;
                            assign SinLUT[226] = 18'b0000000_0101110000;
                            assign SinLUT[227] = 18'b0000000_0101100100;
                            assign SinLUT[228] = 18'b0000000_0101011000;
                            assign SinLUT[229] = 18'b0000000_0101001101;
                            assign SinLUT[230] = 18'b0000000_0101000001;
                            assign SinLUT[231] = 18'b0000000_0100110101;
                            assign SinLUT[232] = 18'b0000000_0100101001;
                            assign SinLUT[233] = 18'b0000000_0100011101;
                            assign SinLUT[234] = 18'b0000000_0100010001;
                            assign SinLUT[235] = 18'b0000000_0100000100;
                            assign SinLUT[236] = 18'b0000000_0011111000;
                            assign SinLUT[237] = 18'b0000000_0011101100;
                            assign SinLUT[238] = 18'b0000000_0011100000;
                            assign SinLUT[239] = 18'b0000000_0011010100;
                            assign SinLUT[240] = 18'b0000000_0011000111;
                            assign SinLUT[241] = 18'b0000000_0010111011;
                            assign SinLUT[242] = 18'b0000000_0010101111;
                            assign SinLUT[243] = 18'b0000000_0010100010;
                            assign SinLUT[244] = 18'b0000000_0010010110;
                            assign SinLUT[245] = 18'b0000000_0010001001;
                            assign SinLUT[246] = 18'b0000000_0001111101;
                            assign SinLUT[247] = 18'b0000000_0001110000;
                            assign SinLUT[248] = 18'b0000000_0001100100;
                            assign SinLUT[249] = 18'b0000000_0001010111;
                            assign SinLUT[250] = 18'b0000000_0001001011;
                            assign SinLUT[251] = 18'b0000000_0000111110;
                            assign SinLUT[252] = 18'b0000000_0000110010;
                            assign SinLUT[253] = 18'b0000000_0000100101;
                            assign SinLUT[254] = 18'b0000000_0000011001;
                            assign SinLUT[255] = 18'b0000000_0000001100;

                            //\\\\\\\\\\\\\\\\\\\//
                            // Cosine Computer I //
                            //\\\\\\\\\\\\\\\\\\\//

                            reg [8:0] NcoIAngle;
                            wire [8:0] NcoIShiftAngle = NcoIAngle + NcoPhase;

                            // Q7.10
                            wire signed [17:0] NcoI = (NcoIShiftAngle <= 255) ? SinLUT[NcoIShiftAngle] :
                                                                                -SinLUT[255 - (511 - NcoIShiftAngle)];

                            always @ (posedge AdcClk or negedge Reset_n)
                            begin
                                //
                                // This block computes the cosine value for the I signal.
                                //

                                if (!Reset_n)
                                begin
                                    //
                                    // A reset has been issued. Clear the current LUT index.
                                    //

                                    NcoIAngle <= 128;
                                end
                                else
                                begin
                                    //
                                    // Increment the NCO I angle by 1/10-th of a full cycle (1/10*360). We do this because
                                    // the carrier frequency is 1/10-th of the ADC sampling clock frequency.
                                    //
                                    // Delta = 512 / (AdcFreq / CarrierFreq)
                                    //

                                    NcoIAngle <= NcoIAngle + 51;
                                end
                            end

                            //\\\\\\\\\\\\\\\\\//
                            // Sine Computer Q //
                            //\\\\\\\\\\\\\\\\\//

                            reg [8:0] NcoQAngle;
                            wire [8:0] NcoQShiftAngle = NcoQAngle + NcoPhase;

                            // Q7.10
                            wire signed [17:0] NcoQ = (NcoQShiftAngle <= 255) ? -SinLUT[NcoQShiftAngle] :
                                                                                SinLUT[255 - (511 - NcoQShiftAngle)];

                            always @ (posedge AdcClk or negedge Reset_n)
                            begin
                                //
                                // This block computes the sine value for the Q signal.
                                //

                                if (!Reset_n)
                                begin
                                    //
                                    // A reset has been issued. Clear the current LUT index.
                                    //

                                    NcoQAngle <= 0;
                                end
                                else
                                begin
                                    //
                                    // Increment the NCO Q angle by 1/10-th of a full cycle (1/10*360). We do this because
                                    // the carrier frequency is 1/10-th of the ADC sampling clock frequency.
                                    //
                                    // Delta = 512 / (AdcFreq / CarrierFreq)
                                    //

                                    NcoQAngle <= NcoQAngle + 51;
                                end
                            end

                            //\\\\\\\\\//
                            // Mixer I //
                            //\\\\\\\\\//

                            wire signed [27:0] MixICur = mSig * NcoI; // Q17.10
                            reg signed [27:0] MixI[0:9]; // Q17.10

                            always @ (posedge AdcClk or negedge Reset_n)
                            begin
                                if (!Reset_n)
                                begin
                                    //
                                    // A reset has been issued. Initialise the mixer value array.
                                    //

                                    for (i = 0; i < 10; i = i + 1) begin
                                        MixI[i] <= 0;
                                    end
                                end
                                else
                                begin
                                    //
                                    // Concatenate the current mixer value to the mixer value array.
                                    //
                                    // NOTE: The following statement requires SystemVerilog for proper synthesis.
                                    //

                                    //MixI[0:19] <= { MixICur, MixI[0:18] };

                                    MixI[0]  <= MixICur;  MixI[1]  <= MixI[0];  MixI[2]  <= MixI[1];  MixI[3]  <= MixI[2];
                                    MixI[4]  <= MixI[3];  MixI[5]  <= MixI[4];  MixI[6]  <= MixI[5];  MixI[7]  <= MixI[6];
                                    MixI[8]  <= MixI[7];  MixI[9]  <= MixI[8];
                                end
                            end

                            //\\\\\\\\\//
                            // Mixer Q //
                            //\\\\\\\\\//

                            wire signed [27:0] MixQCur = mSig * NcoQ; // Q17.10
                            reg signed [27:0] MixQ[0:9]; // Q17.10

                            always @ (posedge AdcClk or negedge Reset_n)
                            begin
                                if (!Reset_n)
                                begin
                                    //
                                    // A reset has been issued. Initialise the mixer value array.
                                    //

                                    for (i = 0; i < 10; i = i + 1) begin
                                        MixQ[i] <= 0;
                                    end
                                end
                                else
                                begin
                                    //
                                    // Concatenate the current mixer value to the mixer value array.
                                    //
                                    // NOTE: The following statement requires SystemVerilog for proper synthesis.
                                    //

                                    //MixQ[0:19] <= { MixQCur, MixQ[0:18] };

                                    MixQ[0]  <= MixQCur;  MixQ[1]  <= MixQ[0];  MixQ[2]  <= MixQ[1];  MixQ[3]  <= MixQ[2];
                                    MixQ[4]  <= MixQ[3];  MixQ[5]  <= MixQ[4];  MixQ[6]  <= MixQ[5];  MixQ[7]  <= MixQ[6];
                                    MixQ[8]  <= MixQ[7];  MixQ[9]  <= MixQ[8];
                                end
                            end

                            //\\\\\\\\\\\\\\\\\\\//
                            // Low-pass Filter I //
                            //\\\\\\\\\\\\\\\\\\\//

                            reg signed [27:0] LpfI; // Q17.10

                            always @ (posedge AdcClk or negedge Reset_n)
                            begin
                                if (!Reset_n)
                                begin
                                    //
                                    // A reset has been issued. Initialise the low-pass filter value.
                                    //

                                    LpfI <= 0;
                                end
                                else
                                begin
                                    //
                                    // Integrate the mixer values.
                                    //

                                    LpfI <= MixI[0]  + MixI[1]  + MixI[2]  + MixI[3]  + MixI[4]  +
                                            MixI[5]  + MixI[6]  + MixI[7]  + MixI[8]  + MixI[9];
                                end
                            end

                            //\\\\\\\\\\\\\\\\\\\//
                            // Low-pass Filter Q //
                            //\\\\\\\\\\\\\\\\\\\//

                            reg signed [27:0] LpfQ; // Q17.10

                            always @ (posedge AdcClk or negedge Reset_n)
                            begin
                                if (!Reset_n)
                                begin
                                    //
                                    // A reset has been issued. Initialise the low-pass filter value.
                                    //

                                    LpfQ <= 0;
                                end
                                else
                                begin
                                    //
                                    // Integrate the mixer values.
                                    //

                                    LpfQ <= MixQ[0]  + MixQ[1]  + MixQ[2]  + MixQ[3]  + MixQ[4]  +
                                            MixQ[5]  + MixQ[6]  + MixQ[7]  + MixQ[8]  + MixQ[9];
                                end
                            end

                            //\\\\\\\\\\//
                            // Mixer FB //
                            //\\\\\\\\\\//

                            wire signed [17:0] LpfIReduced = LpfI >>> 10; // Q17.0
                            wire signed [17:0] LpfQReduced = LpfQ >>> 10; // Q17.0

                            wire signed [35:0] MixFB = LpfIReduced * LpfQReduced; // Q35.0

                            //\\\\\\\\\\\\\\\\\\\\\//
                            // Feedback Controller //
                            //\\\\\\\\\\\\\\\\\\\\\//

                            always @ (posedge AdcClk or negedge Reset_n)
                            begin
                                if (!Reset_n)
                                begin
                                    //
                                    // A reset has been issued. Reset the NCO phase.
                                    //

                                    NcoPhase <= 0;
                                end
                                else
                                begin
                                    //
                                    // Increment or decrement NCO phase based on the feedback mixer sign.
                                    //

                                    if (MixFB[35] == 0) // Positive Feedback
                                        NcoPhase <= NcoPhase + 1;
                                    else // Negative Feedback
                                        NcoPhase <= NcoPhase - 1;
                                end
                            end

                            //\\\\\\\\\\\\\\\\\\\\//
                            // Data Clock Divider //
                            //\\\\\\\\\\\\\\\\\\\\//

                            reg RxDataClk;
                            reg [4:0] RxDataClkDivCnt;

                            always @ (posedge AdcClk or negedge Reset_n)
                            begin
                                if (!Reset_n)
                                begin
                                    //
                                    // A reset has been issued. Clear the data clock divider counter.
                                    //

                                    RxDataClk <= 0;
                                    RxDataClkDivCnt <= 0;
                                end
                                else
                                begin
                                    if (RxDataClkDivCnt == 9)
                                    begin
                                        //
                                        // If the counter reached the threshold, tick the data clock and reset the counter.
                                        //

                                        RxDataClk = ~RxDataClk;
                                        RxDataClkDivCnt <= 0;
                                    end
                                    else
                                    begin
                                        //
                                        // Increment the data clock divider counter.
                                        //

                                        RxDataClkDivCnt <= RxDataClkDivCnt + 1;
                                    end
                                end
                            end

                            //\\\\\\\\\\\\//
                            // Data Latch //
                            //\\\\\\\\\\\\//

                            reg RxDataBit;
                            reg RxInverted;

                            always @ (posedge RxDataClk or negedge Reset_n)
                            begin
                                if (!Reset_n)
                                begin
                                    //
                                    // A reset has been issued. Clear the data bit.
                                    //

                                    RxDataBit <= 0;
                                end
                                else
                                begin
                                    //
                                    // Digitise the analog data from the LPF-I output. The value of the data bit depends
                                    // on the sign bit (27-th) of the LpfI value.
                                    //

                                    RxDataBit <= (RxInverted == 0) ? ~LpfI[27] : LpfI[27];
                                end
                            end

                            //\\\\\\\\\\\\\\\\\\\\//
                            // Receive Controller //
                            //\\\\\\\\\\\\\\\\\\\\//
                            
                            `define RXSTATE_WAITMAGIC       0
                            `define RXSTATE_RECVDATA        1
                            `define RXSTATE_RECVXSUM        2
                            `define RXSTATE_VERIFYXSUM      3

                            reg [1:0] RxState;
                            reg [63:0] RxMagicTemp;
                            reg [31:0] RxXsumTemp;
                            reg [31:0] RxXsumExpected;
                            reg [10:0] RxBitIndex;
                            reg [31:0] RxData [0:15] /* synthesis ramstyle = "M9K" */;
                            reg RxInt;

                            always @ (negedge RxDataClk or negedge Reset_n)
                            begin
                                if (!Reset_n)
                                begin
                                    //
                                    // A reset has been issued. Clear the receive data buffer and set the current receive
                                    // state to "wait magic".
                                    //

                                    RxState <= `RXSTATE_WAITMAGIC;
                                    RxInverted <= 0;
                                    RxMagicTemp <= 0;
                                    RxXsumTemp <= 0;
                                    RxXsumExpected <= 0;
                                    RxData[0] <= 0; // FIXME: Init all.
                                    RxBitIndex <= 0;
                                    RxInt <= 0;
                                end
                                else
                                begin
                                    //
                                    // Reset interrupt request if set.
                                    //

                                    if (RxInt == 1)
                                    begin
                                        RxInt <= 0;
                                    end

                                    //
                                    // Process based on the receive state.
                                    //

                                    if (RxState == `RXSTATE_WAITMAGIC)
                                    begin
                                        //
                                        // The current receive controller state is "wait magic."
                                        //
                                        // Detect the magic packet consisting of the following bit sequence:
                                        //  1011_0101_1010_0110_1111_1111_1111_1111_  (B5 A6 FF FF) 
                                        //  1001_1011_1110_0011_0111_1100_0011_1001   (9B E3 7C 39)
                                        //

                                        RxMagicTemp = (RxMagicTemp << 1) | RxDataBit;

                                        if (RxMagicTemp == 64'hB5A6FFFF9BE37C39) // Non-inverted Bit Sequence
                                        begin
                                            //
                                            // A non-inverted bit sequence has been received. Switch to receive data state
                                            // without data inversion.
                                            //

                                            RxState <= `RXSTATE_RECVDATA;
                                            RxInverted <= 0;
                                            RxBitIndex <= 0;
                                        end
                                        else if (RxMagicTemp == ~(64'hB5A6FFFF9BE37C39)) // Inverted Bit Sequence
                                        begin
                                            //
                                            // An inverting bit sequence has been received. Switch to receive data state
                                            // with data inversion.
                                            //

                                            RxState <= `RXSTATE_RECVDATA;
                                            RxInverted <= 1;
                                            RxBitIndex <= 0;
                                        end
                                    end
                                    else if (RxState == `RXSTATE_RECVDATA)
                                    begin
                                        //
                                        // A data bit has been received. Latch the received data bit.
                                        //

                                        RxData[RxBitIndex >> 5] <= (RxData[RxBitIndex >> 5] << 1) | RxDataBit;

                                        if (RxBitIndex == 511)
                                        begin
                                            //
                                            // Received the last bit. Reset the bit index for reuse during the receive
                                            // checksum stage.
                                            //

                                            RxBitIndex <= 0;

                                            //
                                            // Transition to receive checksum state.
                                            //

                                            RxState <= `RXSTATE_RECVXSUM;
                                        end
                                        else
                                        begin
                                            //
                                            // Increment the data bit index.
                                            //

                                            RxBitIndex <= RxBitIndex + 1;
                                        end
                                    end
                                    else if (RxState == `RXSTATE_RECVXSUM)
                                    begin
                                        //
                                        // Latch in the checksum bits.
                                        //

                                        RxXsumTemp[31 - RxBitIndex] <= RxDataBit;

                                        if (RxBitIndex == 31)
                                        begin
                                            //
                                            // Compute the checksum from the received data.
                                            //

                                            RxXsumExpected <=
                                                RxData[0]  ^ RxData[1]  ^ RxData[2]  ^ RxData[3]  ^
                                                RxData[4]  ^ RxData[5]  ^ RxData[6]  ^ RxData[7]  ^
                                                RxData[8]  ^ RxData[9]  ^ RxData[10] ^ RxData[11] ^
                                                RxData[12] ^ RxData[13] ^ RxData[14] ^ RxData[15];

                                            //
                                            // Received the last checksum bit. Transition to the verify checksum stage.
                                            //

                                            RxState <= `RXSTATE_VERIFYXSUM;
                                        end
                                        else
                                        begin
                                            //
                                            // Increment the data bit index.
                                            //

                                            RxBitIndex <= RxBitIndex + 1;
                                        end
                                    end
                                    else if (RxState == `RXSTATE_VERIFYXSUM)
                                    begin
                                        //
                                        // Reset the bit index and bit inversion state.
                                        //

                                        RxInverted <= 0;
                                        RxBitIndex <= 0;

                                        if (RxXsumTemp == RxXsumExpected)
                                        begin
                                            //
                                            // Raise the data receive interrupt only when the received checksum is valid.
                                            //

                                            RxInt <= 1;
                                        end

                                        //
                                        // Return to the "wait magic" state.
                                        //

                                        RxState <= `RXSTATE_WAITMAGIC;
                                    end
                                end
                            end

                            //\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\//
                            // Receive Interrupt Edge Detector Block //
                            //\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\//

                            reg [1:0] RIDetect;

                            always @ (posedge Clk or negedge Reset_n)
                            begin
                                //
                                // This block detects the receive interrupt by storing last three bits and comparing their
                                // values to the latest values.
                                //

                                if (!Reset_n)
                                begin
                                    //
                                    // A reset has been issued. Clear all edge detection buffer bits.
                                    //

                                    RIDetect <= 0;
                                end
                                else
                                begin
                                    //
                                    // Shift the detector buffer left and insert the latest RX bit.
                                    //

                                    RIDetect <= (RIDetect << 1) | RxInt;
                                end
                            end

                            //
                            // Detect the rising edge on the receive interrupt line.
                            //

                            wire RIRisingEdge = !RIDetect[1] & RIDetect[0];

                            //
                            // Synchronise the transmit interrupt rising edge signal to sequencer clock.
                            //

                            reg [7:0] RIDetectedSyncCnt;
                            reg RIDetected;

                            reg [31:0] DataDrv [0:15] /* synthesis ramstyle = "M9K" */;
                            assign Data = DataDrv;

                            always @ (posedge Clk or negedge Reset_n)
                            begin
                                if (!Reset_n)
                                begin
                                    //
                                    // Initialise sync counter and TIDetected signal.
                                    //

                                    RIDetectedSyncCnt <= 0;
                                    RIDetected <= 0;
                                end
                                else
                                begin
                                    if (RIRisingEdge && (RIDetectedSyncCnt == 0))
                                    begin
                                        //
                                        // If a rising edge is detected and the counter is not started, assert RIDetected
                                        // and begin synchronisation.
                                        //

                                        RIDetected <= 1;
                                        RIDetectedSyncCnt <= 1;

                                        //
                                        // Latch data bits only when Ack is high (i.e. interrupt is acknowledged by the
                                        // processor, pending = 0).
                                        //

                                        if (Ack)
                                        begin
                                            //
                                            // A depulicate copy is required in order to prevent processor excess contention.
                                            //

                                            DataDrv[0] <= RxData[0];
                                            DataDrv[1] <= RxData[1];
                                            DataDrv[2] <= RxData[2];
                                            DataDrv[3] <= RxData[3];
                                            DataDrv[4] <= RxData[4];
                                            DataDrv[5] <= RxData[5];
                                            DataDrv[6] <= RxData[6];
                                            DataDrv[7] <= RxData[7];
                                            DataDrv[8] <= RxData[8];
                                            DataDrv[9] <= RxData[9];
                                            DataDrv[10] <= RxData[10];
                                            DataDrv[11] <= RxData[11];
                                            DataDrv[12] <= RxData[12];
                                            DataDrv[13] <= RxData[13];
                                            DataDrv[14] <= RxData[14];
                                            DataDrv[15] <= RxData[15];
                                            /*DataDrv[16] <= RxData[16];
                                            DataDrv[17] <= RxData[17];
                                            DataDrv[18] <= RxData[18];
                                            DataDrv[19] <= RxData[19];
                                            DataDrv[20] <= RxData[20];
                                            DataDrv[21] <= RxData[21];
                                            DataDrv[22] <= RxData[22];
                                            DataDrv[23] <= RxData[23];
                                            DataDrv[24] <= RxData[24];
                                            DataDrv[25] <= RxData[25];
                                            DataDrv[26] <= RxData[26];
                                            DataDrv[27] <= RxData[27];
                                            DataDrv[28] <= RxData[28];
                                            DataDrv[29] <= RxData[29];
                                            DataDrv[30] <= RxData[30];
                                            DataDrv[31] <= RxData[31];*/
                                        end
                                    end
                                    else if (RIDetectedSyncCnt != 0)
                                    begin
                                        //
                                        // Wait for the ModemClk-BusClk division ratio cycles in ModemClk domain.
                                        //

                                        if (RIDetectedSyncCnt == ModemBusClkDiv)
                                        begin
                                            RIDetected <= 0;
                                            RIDetectedSyncCnt <= 0;
                                        end
                                        else
                                        begin
                                            RIDetectedSyncCnt <= RIDetectedSyncCnt + 1;
                                        end
                                    end
                                end
                            end

                            //
                            // Connect RIDetected to Int output.
                            //

                            assign Int = RIDetected;

                        endmodule
                        

/*++

                            RELEASED FOR ACADEMIC AND NON-COMMERCIAL USE ONLY

                            Module Name:

                               BPSK.v

                            Abstract:

                               This module implements a Binary Phase Shift Keying (BPSK) modem.

                            Author:

                               Stephanos Ioannidis (root@stephanos.io)  22-Aug-2016

                            Revision History:

                           --*/

                           module BpskModem(
                               // Base System
                               input               Clk,
                               input               Reset_n,

                               // Modulator Signals
                               input   [2:0]       ModOutDiv,
                               input               ModInt,
                               input   [31:0]      ModData [0:15],
                               output              ModDone,
                               output  [7:0]       ModOut,

                               // Demodulator Signals
                               input               DemodAdcClk,
                               input   [9:0]       DemodAdcIn,
                               output              DemodInt,
                               output  [31:0]      DemodData [0:15],
                               input               DemodAck
                               );

                               //
                               // Modulator Block
                               //

                               BpskMod modulator(
                                   .Reset_n(Reset_n),
                                   .Clk(Clk),

                                   .OutDiv(ModOutDiv),
                                   .Data(ModData),
                                   .Int(ModInt),
                                   .Done(ModDone),

                                   .Out(ModOut)
                               );

                               //
                               // Demodulator Block
                               //

                               BpskDemod demodulator(
                                   .Reset_n(Reset_n),
                                   .Clk(Clk),

                                   .AdcClk(DemodAdcClk),
                                   .AdcIn(DemodAdcIn),

                                   .Int(DemodInt),
                                   .Data(DemodData),
                                   .Ack(DemodAck)
                               );

                           endmodule
                           

/*++

                               RELEASED FOR ACADEMIC AND NON-COMMERCIAL USE ONLY

                               Module Name:

                                  Pga.v

                               Abstract:

                                  This module implements control logic for MCP6S91 Programmable Gain Amplifier.

                               Author:

                                  Stephanos Ioannidis (root@stephanos.io)  12-Aug-2016

                               Revision History:
                               
                                  Stephanos Ioannidis (root@stephanos.io)  10-Oct-2016
                                      Ported this module for use with the PLC Phase 2 development boards.
                                  
                                  Stephanos Ioannidis (root@stephanos.io)  13-Mar-2017
                                      Ported this module for use with prototype boards.

                              --*/

                              module Pga(
                                  // Base System
                                  input           Reset_n,
                                  input           Clk,

                                  // Module Control Interface
                                  input           Int,
                                  input   [2:0]   Gain,
                                  output          Done,

                                  // SPI Control Interface
                                  output          SPI_nCS,
                                  output          SPI_SO,
                                  output          SPI_SCK
                                  );

                                  //
                                  // Module Output
                                  //

                                  reg DoneDrv;
                                  reg SPI_nCSDrv;
                                  reg SPI_SODrv;
                                  reg SPI_SCKDrv;

                                  assign Done = DoneDrv;
                                  assign SPI_nCS = SPI_nCSDrv;
                                  assign SPI_SO = SPI_SODrv;
                                  assign SPI_SCK = SPI_SCKDrv;

                                  //
                                  // Transmit Clock Generator Block
                                  //

                                  parameter ClkDiv = 50;

                                  //
                                  // NOTE: Clock division ratio = Clk / 2 / CounterCriterion
                                  //       Given that the input Clk is 200MHz, the TxClk is 2MHz.
                                  //       TxClk is twice the frequency of the actual SPI serial clock.
                                  //

                                  reg TxClk;
                                  reg [6:0] TxClkDivCnt;

                                  always @ (posedge Clk or negedge Reset_n)
                                  begin
                                      if (!Reset_n)
                                      begin
                                          TxClk <= 0;
                                          TxClkDivCnt <= 0;
                                      end
                                      else if (TxClkDivCnt == ClkDiv)
                                      begin
                                          TxClk <= ~TxClk;
                                          TxClkDivCnt <= 0;
                                      end
                                      else
                                      begin
                                          TxClkDivCnt <= TxClkDivCnt + 1;
                                      end
                                  end

                                  //
                                  // Set Gain Interrupt Detector Block
                                  //
                                  // NOTE: This block detects a positive edge on the interrupt line.
                                  //

                                  reg IntPrev;

                                  always @ (posedge Clk or negedge Reset_n)
                                  begin
                                      if (!Reset_n)
                                      begin
                                          IntPrev <= 0;
                                      end
                                      else
                                      begin
                                          IntPrev <= Int;
                                      end
                                  end

                                  wire IntDetected = !IntPrev & Int;

                                  //
                                  // SPI Transmission Control Block
                                  //

                                  reg TxEnabled;
                                  reg [0:15] TxBits;
                                  reg TxDone;
                                  reg TxDonePrev;

                                  always @ (posedge Clk or negedge Reset_n)
                                  begin
                                      if (!Reset_n)
                                      begin
                                          //
                                          // A reset has been issued. Disable transmission cycle.
                                          //

                                          TxEnabled <= 0;
                                          TxBits <= 0;
                                          TxDonePrev <= 0;
                                          DoneDrv <= 0;
                                      end
                                      else
                                      begin
                                          if (IntDetected)
                                          begin
                                              //
                                              // A transmit interrupt has been detected. Initiate a transmission cycle.
                                              //

                                              TxEnabled <= 1;

                                              // Instruction Register [7:0]
                                              TxBits[0:2]   <= 3'b010;  // [7:5] Command (Write to Register)
                                              TxBits[3:6]   <= 0;       // [4:1] Reserved
                                              TxBits[7]     <= 0;       // [0]   Address (Gain)

                                              // Gain Register [7:0]
                                              TxBits[8:12]  <= 0;       // [7:3] Reserved
                                              TxBits[13:15] <= Gain;    // [2:0] Gain
                                          end
                                          else if (!TxDonePrev && TxDone)
                                          begin
                                              //
                                              // If the previously initiated transmission cycle is completed, drive Done output
                                              // for one cycle and synchronise to the TxClk clock domain.
                                              //

                                              DoneDrv <= 1;
                                          end
                                          else if (DoneDrv)
                                          begin
                                              //
                                              // Deactivate Done output one clock cycle after it is activated.
                                              //

                                              DoneDrv <= 0;
                                          end
                                          else if (TxDonePrev & !TxDone)
                                          begin
                                              //
                                              // A falling edge on TxDone has been detected. Deactivate TxEnabled.
                                              //

                                              TxEnabled <= 0;
                                          end

                                          //
                                          // Latch TxDone value for edge detection.
                                          //

                                          TxDonePrev <= TxDone;
                                      end
                                  end

                                  //
                                  // SPI Command Transmit Block
                                  //

                                  reg [5:0] TxIndex;

                                  always @ (posedge TxClk or negedge Reset_n)
                                  begin
                                      if (!Reset_n)
                                      begin
                                          //
                                          // A reset has been issued. Reset the internal register values.
                                          //

                                          TxIndex <= 0;
                                          TxDone <= 0;

                                          //
                                          // Reset SPI outputs.
                                          //

                                          SPI_nCSDrv <= 1;
                                          SPI_SODrv <= 0;
                                          SPI_SCKDrv <= 0;
                                      end
                                      else
                                      begin
                                          if (TxEnabled)
                                          begin
                                              //
                                              // Drive CS to LOW when a transmission cycle begins.
                                              //

                                              if (TxIndex == 0)
                                              begin
                                                  //
                                                  // Enable CS (active low).
                                                  //

                                                  SPI_nCSDrv <= 0;
                                              end

                                              //
                                              // Toggle clock and drive data output.
                                              //

                                              if (TxIndex <= 31)
                                              begin
                                                  if (TxIndex & 1)
                                                  begin
                                                      //
                                                      // If the transmission index is an odd number, drive clock to HIGH.
                                                      //

                                                      SPI_SCKDrv <= 1;
                                                  end
                                                  else
                                                  begin
                                                      //
                                                      // If the transmission index is an even number, drive clock to LOW and
                                                      // drive output to corresponding bit.
                                                      //

                                                      SPI_SCKDrv <= 0;
                                                      SPI_SODrv <= TxBits[TxIndex >> 1];
                                                  end
                                              end
                                              else if (TxIndex == 32)
                                              begin
                                                  //
                                                  // End of transmission cycle. Drive clock and data output to LOW.
                                                  //

                                                  SPI_SCKDrv <= 0;
                                                  SPI_SODrv <= 0;
                                              end
                                              else if (TxIndex == 33)
                                              begin
                                                  //
                                                  // Disable CS and set TxDone.
                                                  //

                                                  SPI_nCSDrv <= 1;
                                                  TxDone <= 1;
                                              end
                                              else if (TxIndex == 34)
                                              begin
                                                  //
                                                  // Disable TxDone and reset transmission index.
                                                  //

                                                  TxDone <= 0;
                                                  TxIndex <= 0;
                                              end

                                              //
                                              // Increment transmission index.
                                              //

                                              if (TxIndex < 34)
                                              begin
                                                  TxIndex <= TxIndex + 1;
                                              end
                                          end
                                      end
                                  end

                              endmodule
                              

/*++

                                  RELEASED FOR ACADEMIC AND NON-COMMERCIAL USE ONLY

                                  Module Name:

                                     Plc.sv

                                  Abstract:

                                     This module is the top level module of Power Line Communication controller logic.

                                  Author:

                                     Stephanos Ioannidis (root@stephanos.io)  06-Mar-2017

                                  Revision History:

                                 --*/

                                 module Plc(
                                     //
                                     // Bus Interface Signals
                                     //

                                     input           BusClk,
                                     input           BusReset_n,
                                     input   [5:0]   BusAddress,
                                     input   [3:0]   BusByteEnable,
                                     input   [31:0]  BusWriteData,
                                     output  [31:0]  BusReadData,
                                     input           BusWrite,
                                     input           BusRead,

                                     //
                                     // Modem Clock
                                     //

                                     input           ModemClk,

                                     //
                                     // Board Power-Line Communication Control Signals
                                     //

                                     output          RX_VGA_CS,
                                     output          RX_VGA_SCK,
                                     output          RX_VGA_SI,

                                     output          RX_ADC_OE,
                                     output          RX_ADC_CLK,
                                     input   [7:0]   RX_ADC_DATA,

                                     output          TX_DRV
                                     );

                                     //
                                     // NOTE: Only modem is driven by a higher clock frequency and the rest of the logic is driven
                                     //       by the lower bus clock frequency to reduce power consumption.
                                     //

                                     //
                                     // Bus Interface Internal Registers
                                     //

                                     reg             CtlTxDo;
                                     wire            CtlTxDone;
                                     reg     [2:0]   CtlTxDiv;

                                     reg             CtlRxPending;
                                     reg     [2:0]   CtlRxGain;

                                     reg     [31:0]  CtlTxData [0:15] /* synthesis ramstyle = "M9K" */;
                                     wire    [31:0]  CtlRxData [0:15];

                                     //
                                     // Instantiate BPSK Modem.
                                     //

                                     wire TxInt;
                                     wire TxDone;
                                     wire [31:0] TxData [0:15];
                                     wire [7:0] TxOut;

                                     wire RxAdcClk;
                                     wire [7:0] RxAdcIn;
                                     wire RxInt;
                                     wire [31:0] RxData [0:15];

                                     BpskModem modem(
                                         .Clk(ModemClk),
                                         .Reset_n(BusReset_n),

                                         .ModOutDiv(CtlTxDiv),
                                         .ModInt(TxInt),
                                         .ModData(TxData),
                                         .ModDone(TxDone),
                                         .ModOut(TxOut),

                                         .DemodAdcClk(RxAdcClk),
                                         .DemodAdcIn(RxAdcIn),
                                         .DemodInt(RxInt),
                                         .DemodData(RxData),
                                         .DemodAck(~CtlRxPending)
                                         );

                                     assign TxInt = CtlTxDo;
                                     assign CtlTxDone = TxDone;
                                     assign TxData = CtlTxData;

                                     assign CtlRxData = RxData;

                                     //
                                     // Instantiate Delta Sigma Modulator.
                                     //

                                     DeltaSigmaMod dsm(
                                         .Reset_n(BusReset_n),
                                         .Clk(BusClk),

                                         .In(TxOut),
                                         .Out(TX_DRV)
                                         );

                                     //
                                     // Instantiate Programmable Gain Amplifier Controller.
                                     //

                                     reg RxPgaGainUpdateInt;
                                     wire RxPgaGainUpdateDone;

                                     Pga pga(
                                         .Reset_n(BusReset_n),
                                         .Clk(BusClk),

                                         .Int(RxPgaGainUpdateInt),
                                         .Gain(CtlRxGain),
                                         .Done(RxPgaGainUpdateDone),

                                         .SPI_nCS(RX_VGA_CS),
                                         .SPI_SO(RX_VGA_SI),
                                         .SPI_SCK(RX_VGA_SCK)
                                         );

                                     //
                                     // Instantiate Analog-to-Digital Converter Controller.
                                     //
                                     // NOTE: ModemClk is used for ADC Controller because it is impossible to generate 10MHz ADC
                                     //       clock from 50MHz input.
                                     //

                                     wire [7:0] AdcData;

                                     Adc adc(
                                         .Reset_n(BusReset_n),
                                         .Clk(ModemClk),

                                         .Data(RX_ADC_DATA),

                                         .nOE(RX_ADC_OE),
                                         .ClkOut(RxAdcClk),

                                         .DataOut(RxAdcIn)
                                         );

                                     assign RX_ADC_CLK = RxAdcClk;

                                     //
                                     // Programmable Gain Amplifier Gain Update Loop
                                     //

                                     reg     [31:0]  RxPgaWaitCnt;

                                     always @ (posedge BusClk or negedge BusReset_n)
                                     begin
                                         if (!BusReset_n)
                                         begin
                                             RxPgaWaitCnt <= 0;
                                         end
                                         else
                                         begin
                                             if (RxPgaWaitCnt == 50000000)
                                             begin
                                                 //
                                                 // Transmit a gain setting packet by issuing an interrupt.
                                                 //

                                                 RxPgaGainUpdateInt <= 1;
                                                 RxPgaWaitCnt <= RxPgaWaitCnt + 1;
                                             end
                                             else if (RxPgaWaitCnt == 50000001)
                                             begin
                                                 //
                                                 // Deactivate the interrupt after one primary clock cycle.
                                                 //

                                                 RxPgaGainUpdateInt <= 0;
                                                 RxPgaWaitCnt <= 0;
                                             end
                                             else
                                             begin
                                                 RxPgaWaitCnt <= RxPgaWaitCnt + 1;
                                             end
                                         end
                                     end

                                     //
                                     // Bus Interface Register File
                                     //

                                     wire    [31:0]  RegFile [0:64];

                                     // Transmit Control Register (TXCON)
                                     assign RegFile[0][0] = CtlTxDo;
                                     assign RegFile[0][1] = CtlTxDone;
                                     assign RegFile[0][4:2] = CtlTxDiv;

                                     // Receive Control Register (RXCON)
                                     assign RegFile[0][8] = CtlRxPending;
                                     assign RegFile[0][12:10] = CtlRxGain;

                                     // Transmit Data Register
                                     /*assign RegFile[1] = CtlTxData[0];
                                     assign RegFile[2] = CtlTxData[1];
                                     assign RegFile[3] = CtlTxData[2];
                                     assign RegFile[4] = CtlTxData[3];
                                     assign RegFile[5] = CtlTxData[4];
                                     assign RegFile[6] = CtlTxData[5];
                                     assign RegFile[7] = CtlTxData[6];
                                     assign RegFile[8] = CtlTxData[7];
                                     assign RegFile[9] = CtlTxData[8];
                                     assign RegFile[10] = CtlTxData[9];
                                     assign RegFile[11] = CtlTxData[10];
                                     assign RegFile[12] = CtlTxData[11];
                                     assign RegFile[13] = CtlTxData[12];
                                     assign RegFile[14] = CtlTxData[13];
                                     assign RegFile[15] = CtlTxData[14];
                                     assign RegFile[16] = CtlTxData[15];
                                     assign RegFile[17] = CtlTxData[16];
                                     assign RegFile[18] = CtlTxData[17];
                                     assign RegFile[19] = CtlTxData[18];
                                     assign RegFile[20] = CtlTxData[19];
                                     assign RegFile[21] = CtlTxData[20];
                                     assign RegFile[22] = CtlTxData[21];
                                     assign RegFile[23] = CtlTxData[22];
                                     assign RegFile[24] = CtlTxData[23];
                                     assign RegFile[25] = CtlTxData[24];
                                     assign RegFile[26] = CtlTxData[25];
                                     assign RegFile[27] = CtlTxData[26];
                                     assign RegFile[28] = CtlTxData[27];
                                     assign RegFile[29] = CtlTxData[28];
                                     assign RegFile[30] = CtlTxData[29];
                                     assign RegFile[31] = CtlTxData[30];
                                     assign RegFile[32] = CtlTxData[31];*/

                                     // Receive Data Register
                                     assign RegFile[17] = CtlRxData[0];
                                     assign RegFile[18] = CtlRxData[1];
                                     assign RegFile[19] = CtlRxData[2];
                                     assign RegFile[20] = CtlRxData[3];
                                     assign RegFile[21] = CtlRxData[4];
                                     assign RegFile[22] = CtlRxData[5];
                                     assign RegFile[23] = CtlRxData[6];
                                     assign RegFile[24] = CtlRxData[7];
                                     assign RegFile[25] = CtlRxData[8];
                                     assign RegFile[26] = CtlRxData[9];
                                     assign RegFile[27] = CtlRxData[10];
                                     assign RegFile[28] = CtlRxData[11];
                                     assign RegFile[29] = CtlRxData[12];
                                     assign RegFile[30] = CtlRxData[13];
                                     assign RegFile[31] = CtlRxData[14];
                                     assign RegFile[32] = CtlRxData[15];
                                     /*assign RegFile[49] = CtlRxData[16];
                                     assign RegFile[50] = CtlRxData[17];
                                     assign RegFile[51] = CtlRxData[18];
                                     assign RegFile[52] = CtlRxData[19];
                                     assign RegFile[53] = CtlRxData[20];
                                     assign RegFile[54] = CtlRxData[21];
                                     assign RegFile[55] = CtlRxData[22];
                                     assign RegFile[56] = CtlRxData[23];
                                     assign RegFile[57] = CtlRxData[24];
                                     assign RegFile[58] = CtlRxData[25];
                                     assign RegFile[59] = CtlRxData[26];
                                     assign RegFile[60] = CtlRxData[27];
                                     assign RegFile[61] = CtlRxData[28];
                                     assign RegFile[62] = CtlRxData[29];
                                     assign RegFile[63] = CtlRxData[30];
                                     assign RegFile[64] = CtlRxData[31];*/

                                     //
                                     // Bus Interface Controller
                                     //

                                     assign BusReadData = BusRead ? RegFile[BusAddress] : { 32{ 1'bz } };

                                     always @ (posedge BusClk or negedge BusReset_n)
                                     begin
                                         if (!BusReset_n)
                                         begin
                                             CtlTxDo <= 0;
                                             CtlTxData[0] <= 0;
                                         end
                                         else if (BusWrite)
                                         begin
                                             if (BusAddress == 0)
                                             begin
                                                 //
                                                 // TxCon Register
                                                 //

                                                 if (BusByteEnable[0])
                                                 begin
                                                     CtlTxDo <= BusWriteData[0];
                                                     CtlTxDiv <= BusWriteData[4:2];
                                                 end

                                                 //
                                                 // RxCon Register
                                                 //

                                                 if (BusByteEnable[1])
                                                 begin
                                                     //
                                                     // TODO: RxCon register structure to be determined.
                                                     //
                                                 end
                                             end
                                             else
                                             begin
                                                 //
                                                 // Process Transmit Data Registers Write
                                                 //

                                                 case (BusAddress)
                                                     1:  CtlTxData[0] <= BusWriteData;
                                                     2:  CtlTxData[1] <= BusWriteData;
                                                     3:  CtlTxData[2] <= BusWriteData;
                                                     4:  CtlTxData[3] <= BusWriteData;
                                                     5:  CtlTxData[4] <= BusWriteData;
                                                     6:  CtlTxData[5] <= BusWriteData;
                                                     7:  CtlTxData[6] <= BusWriteData;
                                                     8:  CtlTxData[7] <= BusWriteData;
                                                     9:  CtlTxData[8] <= BusWriteData;
                                                     10: CtlTxData[9] <= BusWriteData;
                                                     11: CtlTxData[10] <= BusWriteData;
                                                     12: CtlTxData[11] <= BusWriteData;
                                                     13: CtlTxData[12] <= BusWriteData;
                                                     14: CtlTxData[13] <= BusWriteData;
                                                     15: CtlTxData[14] <= BusWriteData;
                                                     16: CtlTxData[15] <= BusWriteData;
                                                     /*17: CtlTxData[16] <= BusWriteData;
                                                     18: CtlTxData[17] <= BusWriteData;
                                                     19: CtlTxData[18] <= BusWriteData;
                                                     20: CtlTxData[19] <= BusWriteData;
                                                     21: CtlTxData[20] <= BusWriteData;
                                                     22: CtlTxData[21] <= BusWriteData;
                                                     23: CtlTxData[22] <= BusWriteData;
                                                     24: CtlTxData[23] <= BusWriteData;
                                                     25: CtlTxData[24] <= BusWriteData;
                                                     26: CtlTxData[25] <= BusWriteData;
                                                     27: CtlTxData[26] <= BusWriteData;
                                                     28: CtlTxData[27] <= BusWriteData;
                                                     29: CtlTxData[28] <= BusWriteData;
                                                     30: CtlTxData[29] <= BusWriteData;
                                                     31: CtlTxData[30] <= BusWriteData;
                                                     32: CtlTxData[31] <= BusWriteData;*/
                                                 endcase
                                             end
                                         end
                                     end

                                     //
                                     // Receive State Controller
                                     //

                                     always @ (posedge BusClk or negedge BusReset_n)
                                     begin
                                         if (!BusReset_n)
                                         begin
                                             CtlRxPending <= 0;
                                         end
                                         else if (RxInt)
                                         begin
                                             //
                                             // RxPending is set when a receive interrupt is generated by the modem. 
                                             //

                                             CtlRxPending <= 1;
                                         end
                                         else if (BusWrite && (BusAddress == 0) && BusByteEnable[1] && BusWriteData[9])
                                         begin
                                             //
                                             // RxPending is reset when ACK bit is written in TXCON register.
                                             //

                                             CtlRxPending <= 0;
                                         end
                                     end


                                 endmodule
                                 





John Doe
04:50:18am On 2024.05.02
Our premium databases for XRumer and GSA Search Engine Ranker are just what you need! What do our databases include? • Active links: Get access to constantly updated lists of active links from profiles, posts, forums, guestbooks, blogs, and more. No.
John Doe
10:36:04am On 2024.05.16
Want to improve your SEO rankings and save time? Our premium databases for XRumer and GSA Search Engine Ranker are just what you need! What do our databases include? • Active links: Get access to constantly updated lists of active links from profile.