/*++ 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