/*
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃                                                                                                 ┃
┃          Program Name: Antennenkoppler.v                                                        ┃
┃                Author: Michael Krämer                                                           ┃
┃                 Email: Michael@dk8pp.de                                                         ┃
┃                  Date: 07.01.2026                                                               ┃
┃                  Tool: Gowin FPGA Designer V1.9.11.01 Education                                 ┃
┃                Device: GW5A-LV25MG121 Typ A                                                     ┃
┃               Version: 0.9                                                                      ┃
┃        Program status: still testing                                                            ┃
┃                                                                                                 ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃                                                                                                 ┃
┃  Purpose: Antenna coupler signal processing including:                                          ┃
┃           - measurement of phase difference between forward and reflected signal                ┃
┃           - measurement of forward and reflected signal frequency                               ┃
┃           - measurement of forward and reflected signal quality (i.e. percentage of high time)  ┃
┃           - measurement of forward and reflected signal level by external ADC connected via SPI ┃
┃           - asynchronous serial transmitter to send data                                        ┃
┃           - interval timer to generate regular interrupt requests                               ┃
┃           - instantiation of picoRV32 RISC CPU                                                  ┃
┃           - instantiation of PLL to generate sampling clock and CPU clock                       ┃
┃           - reset generation                                                                    ┃
┃                                                                                                 ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃                                                                                                 ┃
┃  © Copyright 2025-2026 Michael Krämer, DK8PP                                                    ┃
┃                                                                                                 ┃
┃  This program is free software: you can redistribute it and/or modify it under the terms of     ┃
┃  the GNU Lesser General Public License as published by the Free Software Foundation, either     ┃
┃  version 3 of the License, or (at your option) any later version.                               ┃
┃                                                                                                 ┃
┃  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;      ┃
┃  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.      ┃
┃  See the GNU Lesser General Public License for more details.                                    ┃
┃                                                                                                 ┃
┃  You should have received a copy of the GNU Lesser General Public License along with this       ┃
┃  program.   If not, see <http://www.gnu.org/licenses/>.                                         ┃
┃                                                                                                 ┃
┃  ============================================================================================   ┃
┃                                                                                                 ┃
┃  Dieses Programm ist Freie Software: Sie können es unter den Bedingungen der GNU Lesser         ┃
┃  General Public License, wie von der Free Software Foundation, Version 3 der Lizenz oder        ┃
┃  (nach Ihrer Wahl) jeder neueren veröffentlichten Version, weiter verteilen und/oder            ┃
┃  modifizieren.                                                                                  ┃
┃                                                                                                 ┃
┃  Dieses Programm wird in der Hoffnung bereitgestellt, dass es nützlich sein wird, jedoch OHNE   ┃
┃  JEDE GEWÄHR,; sogar ohne die implizite Gewähr der MARKTFÄHIGKEIT oder EIGNUNG FÜR EINEN        ┃
┃  BESTIMMTEN ZWECK. Siehe die GNU Lesser General Public License für weitere Einzelheiten.        ┃
┃                                                                                                 ┃
┃  Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit diesem Programm      ┃
┃  erhalten haben. Wenn nicht, siehe <https://www.gnu.org/licenses/>.                             ┃
┃                                                                                                 ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
*/
module antennenkoppler
               (input  wire xosc,               /* oscillator, system clock, 50 MHz */
                input  wire reset_in_dock,      /* reset input button from dock board, active high */
                input  wire sig_forward_in,     /* forward signal from coupler */
                input  wire sig_reflected_in,   /* reflected signal from coupler */

/* test signals */
                output wire [5:1] ta,           /* Test port A */
                output wire [5:1] tb,           /* Test port B */
                input  wire [4:1] dsw,          /* DIP switches (pin header) */
                input  wire [2:1] pb,           /* push buttons */
                output wire [4:1] led,          /* LED */
                output wire [2:1] to,           /* test outputs to coax connectors */

/* UARTS */
                input  wire usb_txd,            /* USB transmit data, RxD on this side */
                output wire usb_rxd,            /* USB receive data, TxD on this side */
//                output wire wbuart_tx,          /* WB UART transmit data */
//                input  wire wbuart_rx,          /* WB UART receive data */
                input  wire bt_txd,             /* Bluetooth transmit data, RxD on this side */
                output wire bt_rxd,             /* Bluetooth receive data, TxD on this side */
                output wire bt_mode,            /* Bluetooth mode, 0=communication mode, 1=AT mode */
                input  wire bt_pair,            /* Bluetooth pair status, 0=not paired, 1=paired */
                output wire txd0,               /* RS485 transmit data */
                output wire dren,               /* RS485 driver enable, active high */
                input  wire rxd0,               /* RS485 receive data */

/* ADC */
                output wire adc_sclk,           /* ADC serial clock */
                output wire adc_din,            /* ADC serial data input */
                output wire adc_csn,            /* ADC chip select, active low */
                input  wire adc_dout,           /* ADC serial data output combined with data ready; active low */

/* LogAmp */
                output wire logamp_ena          /* enable logarithmic amplifiers, active high */

                ) ;

localparam CPU_FREQ =       32'd20_000_000 ;    /* CPU frequency in Hz, must be an integral multiple of 1000 */
localparam SAMPLING_FREQ =  32'd200_000_000 ;   /* sampling frequency in Hz, must be an integral multiple of 1000 */
localparam SAMPLE_COUNT =   32'd2_000_000 ;     /* default sample count per interval, must be an integral multiple of 1000 */
localparam CNTR_BITSIZE =   26 ;                /* number of counter bits,
                                                   must be wide enough to hold SAMPLE_COUNT
                                                   also note that SAMPLE_COUNT may be set by software */

    reg  [7:0] reset_counter ;              /* reset delay counter */
    reg  cpu_master_reset ;                 /* master reset for CPU clock domain */

/* T1 Interval Timer */
    wire t1_intrq ;                         /* t1 interrupt request */

/* ATx signals */
    wire txd_out ;                          /* transmit data serial output */
    wire txbe_intrq ;                       /* transmit buffer empty interrupt request */
    wire tx_active ;                        /* transmission is active */
    wire txbuffer_valid ;                   /* valid data in transmission buffer */
    wire at_intack ;                        /* interrupt acknowledge */

/* SPI Master */
    wire wbspi_master_miso ;                /* input wbspi_master_miso        */
    wire wbspi_master_mosi ;                /* output wbspi_master_mosi       */
    wire wbspi_master_ssn ;                 /* output [0:0] wbspi_master_ssn  */
    wire wbspi_master_sclk ;                /* output wbspi_master_sclk       */

/* PLL */
    wire pll_lock ;
    wire pll_clkout0 ;
    wire pll_clkout1 ;

    wire pll_clkin = xosc ;
    wire rm_clkin  = pll_clkout0 ;          /* sampling clock for reflection measurement */
    wire cpu_clkin = pll_clkout1 ;          /* CPU und wishbone bus clock */

    wire wbuart_tx ;
    wire wbuart_rx ;

    wire [11:0] irq_in ;

    wire reset_pb ;                         /* active high reset button */

    wire [6:0] testsig ;

/* selectors */
    wire sel_usb = (dsw[2:1] == 2'b11) ;    /* no jumper: serial port is USB */
    wire sel_485 = (dsw[2:1] == 2'b10) ;    /* jumper 1: serial port is RS485 */
    wire sel_bt  = (dsw[2]   == 1'b0)  ;    /* jumper 2: serial port is bluetooth */

/* JTAG */
    wire jtag_TDI = 0 ;                     /* input jtag_TDI */
    wire jtag_TCK = 0 ;                     /* input jtag_TCK */
    wire jtag_TMS = 0 ;                     /* input jtag_TMS */
    wire jtag_TDO ;                         /* output jtag_TDO */

/* assign test signals */
assign led[1] = ~txd_out ;
assign led[2] = ~wbuart_rx ;
assign led[3] = ~pb[1] ;
assign led[4] = ~(bt_pair) ;    /* to avoid "unused input" warning */

assign reset_pb = ~pb[2] ;      /* active high reset button on Koppler */

assign to[1] = 0 ;              /* use with care, connected to dedicated I2C pin */
assign to[2] = 0 ;

/* select serial communication port */
//assign usb_rxd = sel_usb ? wbuart_tx : 0 ;
assign usb_rxd = sel_usb ? txd_out : 0 ;
assign bt_rxd  = sel_bt  ? wbuart_tx : 0 ;
assign txd0    = sel_485 ? wbuart_tx : 0 ;
assign wbuart_rx = sel_usb ? usb_txd : (sel_485 ? rxd0 : (sel_bt ? bt_txd : 0)) ;
assign dren = 0 ;               /* RS485 driver enable, active high */
assign bt_mode = 0 ;            /* Bluetooth mode, 0=communication mode, 1=AT mode */
assign logamp_ena = 1 ;         /* enable logarithmic amplifiers, active high */

/* ADC */
assign adc_sclk = wbspi_master_sclk ;       /* ADC serial clock */
assign adc_din = wbspi_master_mosi ;        /* ADC serial data input */
//assign adc_csn = wbspi_master_ssn ;         /* ADC chip select, active low */
assign adc_csn = 0 ;         /* ADC chip select, active low */
assign wbspi_master_miso = adc_dout ;       /* ADC serial data output */

    wire tp_active = 1'b1 ;     /* activate test port */

/* assign test signals */
//assign tb[1] = tp_active & adc_sclk ;
//assign tb[2] = tp_active & adc_din ;
//assign tb[3] = tp_active & adc_csn ;
//assign tb[4] = tp_active & adc_dout ;
//assign tb[5] = tp_active & t1_intrq ;
assign ta[1] = tp_active & trigger5 ;
assign ta[2] = tp_active & trigger4 ;
assign ta[3] = tp_active & t1_intrq ;
assign ta[4] = tp_active & at_intack ;
assign ta[5] = tp_active & txbe_intrq ;
assign tb[1] = tp_active & cpu_master_reset ;
assign tb[2] = tp_active & cpu_clkin ;
assign tb[3] = tp_active & txd_out ;
assign tb[4] = tp_active & tx_active ;
assign tb[5] = tp_active & txbuffer_valid ;

//assign tb[1] = tp_active & testsig[6] ;
//assign tb[2] = tp_active & testsig[5] ;
//assign tb[3] = tp_active & testsig[4] ;
//assign tb[4] = tp_active & testsig[3] ;
//assign tb[5] = tp_active & testsig[2] ;
//assign ta[1] = 0 ;
//assign ta[2] = 0 ;
//assign ta[3] = 0 ;
//assign ta[4] = tp_active & testsig[0] ;
//assign ta[5] = tp_active & testsig[1] ;

assign irq_in[11:0] = {10'b0, t1_intrq, txbe_intrq} ;

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       Address mapping                                                                           │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯

Reflection Measurement (RM), Interval Timer (T1) and Asynchronous Transmitter (ATx) registers are
 implemented in the respective modules, System Information registers are implemented here.

System Information SI:
+SI_CPUFREQ_OFFSET: CPUFREQ (R)
    This register holds the CPU frequency in Hz.

+SI_SAMPLINGFREQ_OFFSET: SAMPLINGFREQ (R)
    This register holds the sampling frequency in Hz.

*/
localparam ADSIZE =       8 ;    /* Bitsize of address decoder */

localparam RM_BASE =                32'h00 ;    /* Base address of Reflection Measurement RM */
localparam T1_BASE =                32'h40 ;    /* Base address of Timer1 T1 */
localparam AT_BASE =                32'h50 ;    /* Base address of Asynchronous Transmitter ATx */
localparam SI_BASE =                32'h60 ;    /* Base address of system information */

localparam SI_CPUFREQ_OFFSET =      32'h00 ;    /* CPU frequency offset to system information register base */
localparam SI_SAMPLINGFREQ_OFFSET = 32'h04 ;    /* Sampling frequency offset to system information register base */
localparam SI_TRIGGER_LA_OFFSET =   32'h0C ;    /* write to trigger signal for LA */

/* Reflection Measurement RM */
localparam RM_ADSIZE = 6 ;    /* LSB bit count for address space for RM */
wire rm_select = wb_stb_o & (wb_adr_o[ADSIZE-1:RM_ADSIZE] == RM_BASE[ADSIZE-1:RM_ADSIZE]) ;
wire rm_read = rm_select & ~wb_we_o ;
wire [31:0] rm_rdat ;

/* Interval timer 1 */
localparam T1_ADSIZE = 4 ;    /* LSB bit count for address space for T1 */
wire t1_select = wb_stb_o & (wb_adr_o[ADSIZE-1:T1_ADSIZE] == T1_BASE[ADSIZE-1:T1_ADSIZE]) ;
wire t1_read = t1_select & ~wb_we_o ;
wire [31:0] t1_rdat ;

/* Asynchronous Transmitter ATx */
localparam AT_ADSIZE = 4 ;    /* LSB bit count for address space for AT */
wire at_select = wb_stb_o & (wb_adr_o[ADSIZE-1:AT_ADSIZE] == AT_BASE[ADSIZE-1:AT_ADSIZE]) ;
wire at_read = at_select & ~wb_we_o ;
wire [31:0] at_rdat ;

/* System Information, read only */
wire [ADSIZE-1:0] cpufreq_addr = SI_BASE + SI_CPUFREQ_OFFSET ;
wire [ADSIZE-1:0] samplingfreq_addr = SI_BASE + SI_SAMPLINGFREQ_OFFSET ;
wire cpufreq_read = ~wb_we_o & wb_stb_o & (wb_adr_o[ADSIZE-1:0] == cpufreq_addr) ;
wire samplingfreq_read = ~wb_we_o & wb_stb_o & (wb_adr_o[ADSIZE-1:0] == samplingfreq_addr) ;

/* Generate a trigger signal for logic analyzer or scope */
wire [ADSIZE-1:0] trigger_addr = SI_BASE + SI_TRIGGER_LA_OFFSET ;
wire write_trigger = wb_we_o & wb_stb_o & (wb_adr_o[ADSIZE-1:0] == trigger_addr) ;

wire trigger0 = write_trigger & wb_dat_o[0] ;
wire trigger1 = write_trigger & wb_dat_o[1] ;
wire trigger2 = write_trigger & wb_dat_o[2] ;
wire trigger3 = write_trigger & wb_dat_o[3] ;
wire trigger4 = write_trigger & wb_dat_o[4] ;
wire trigger5 = write_trigger & wb_dat_o[5] ;
wire trigger6 = write_trigger & wb_dat_o[6] ;
wire trigger7 = write_trigger & wb_dat_o[7] ;

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       Wishbone register access                                                                  │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/

/* Open Wishbone bus, naming conventions as in Wishbone document but with leading "wb_"
   input (*_i) and output (*_o) direction as seen from the CPU
   => _o-signals are input and _i-signals are output here */

    wire wb_stb_o ;
    wire wb_we_o ;
    wire wb_cyc_o ;
    wire wb_ack_i ;
    wire [31:0] wb_adr_o ;
    wire [31:0] wb_dat_o ;
    wire [31:0] wb_dat_i ;
    wire [ 3:0] wb_sel_o ;

    reg         bus_ack ;   /* bus transfer acknowledge */

assign wb_ack_i = bus_ack ;
assign wb_dat_i = t1_read ? t1_rdat :
                  at_read ? at_rdat :
                  cpufreq_read ? CPU_FREQ :
                  samplingfreq_read ? SAMPLING_FREQ :
                  rm_read ? rm_rdat :
                  32'h00 ;

/* CPU read access */
always @(posedge cpu_clkin)
begin
    if (!cpu_master_reset)
    begin
/* generate bus transfer acknowledge output signal,
   immediate acknowledge, no wait states */
        bus_ack <= wb_cyc_o & wb_stb_o & ~bus_ack ;
    end
end

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       reset generator                                                                           │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
cpu_master_reset active high while
- PLL is not locked (!pll_lock) or
- button is pressed (reset_in_dock) or
- button is pressed (reset_pb) or
- startup delay not expired (reset_counter != 0)
*/
always @(posedge cpu_clkin)
begin
   if (!pll_lock || reset_in_dock || reset_pb)
   begin
      reset_counter <= 8'd255 ;
      cpu_master_reset <= 1 ;
   end
   else
   begin
      if (reset_counter != 0) reset_counter <= reset_counter - 8'd1 ;
      else cpu_master_reset <= 0 ;
   end
end

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       Reflection_Measurement instantiation                                                      │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
Reflection_Measurement #(.CNTR_BITSIZE(CNTR_BITSIZE),
                         .ADSIZE(RM_ADSIZE),
                         .SAMPLE_COUNT(SAMPLE_COUNT))
    ref_measurement(
        .cpuclk(cpu_clkin),                     /* cpu clock */
        .reset(cpu_master_reset),               /* reset input, active high */
        .addr_in(wb_adr_o[RM_ADSIZE-1:0]),      /* address input */
        .data_in(wb_dat_o),                     /* write data */
        .data_out(rm_rdat),                     /* read data output */
        .mod_sel(rm_select),                    /* select module */
        .cpu_write(wb_we_o),                    /* CPU write cycle */
        .testsig(testsig),

        .sclk_in(rm_clkin),                     /* sampling clock */
        .sig_forward_in(sig_forward_in),        /* forward signal from coupler */
        .sig_reflected_in(sig_reflected_in)     /* reflected signal from coupler */
    ) ;

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       ATx instantiation                                                                         │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
ATx #(.BRG_BITSIZE(10), .BRG_RELOAD(347), .ADSIZE(AT_ADSIZE))
    tx(
        .cpuclk(cpu_clkin),                     /* cpu clock */
        .reset(cpu_master_reset),               /* reset input, active high */
        .addr_in(wb_adr_o[AT_ADSIZE-1:0]),      /* address input */
        .data_in(wb_dat_o),                     /* write data */
        .data_out(at_rdat),                     /* read data output */
        .mod_sel(at_select),                    /* select module */
        .cpu_write(wb_we_o),                    /* CPU write cycle */
        .txd_out(txd_out),                      /* transmit data serial output */
        .tx_active_out(tx_active),              /* transmission is active */
        .txbuffer_valid_out(txbuffer_valid),    /* valid data in transmission buffer */
        .wr_intack_out(at_intack),              /* valid data in transmission buffer */
        .intrq(txbe_intrq)                      /* transmit buffer empty interrupt request */
    ) ;

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       Timer1 instantiation                                                                      │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
IntervalTimer #(.REG_BITSIZE(32), .RELOAD(32'd399_999), .ADSIZE(T1_ADSIZE))
    t1(
        .cpuclk(cpu_clkin),                 /* cpu clock */
        .reset(cpu_master_reset),           /* reset input, active high */
        .addr_in(wb_adr_o[T1_ADSIZE-1:0]),  /* address input */
        .data_in(wb_dat_o),                 /* data input */
        .data_out(t1_rdat),                 /* read data output */
        .mod_sel(t1_select),                /* select module */
        .cpu_write(wb_we_o),                /* CPU write cycle */
        .intrq(t1_intrq)                    /* interrupt request */
    ) ;

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       PLL instantiation                                                                         │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
    Gowin_PLL pll(
        .lock(pll_lock),                    /* PLL locked */
        .clkout0(pll_clkout0),              /* PLL output clk 0, sampling clock */
        .clkout1(pll_clkout1),              /* PLL output clk 1, CPU clock */
        .clkin(pll_clkin)                   /* PLL input clk */
    ) ;

/*
╭─────────────────────────────────────────────────────────────────────────────────────────────────╮
│       CPU instantiation                                                                         │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
*/
    Gowin_PicoRV32_Top PicoRV32(
        .wbuart_tx(wbuart_tx),              /* output wbuart_tx */
        .wbuart_rx(wbuart_rx),              /* input wbuart_rx */

        .wbspi_master_miso(wbspi_master_miso), //input wbspi_master_miso
        .wbspi_master_mosi(wbspi_master_mosi), //output wbspi_master_mosi
        .wbspi_master_ssn(wbspi_master_ssn), //output [0:0] wbspi_master_ssn
        .wbspi_master_sclk(wbspi_master_sclk), //output wbspi_master_sclk

        .slv_ext_stb_o(wb_stb_o),           /* output STB_O */
        .slv_ext_we_o(wb_we_o),             /* output WE_O */
        .slv_ext_cyc_o(wb_cyc_o),           /* output CYC_O */
        .slv_ext_ack_i(wb_ack_i),           /* input ACK_I */
        .slv_ext_adr_o(wb_adr_o),           /* output [31:0] ADR_O */
        .slv_ext_wdata_o(wb_dat_o),         /* output [31:0] DAT_O */
        .slv_ext_rdata_i(wb_dat_i),         /* input [31:0] DAT_I */
        .slv_ext_sel_o(wb_sel_o),           /* output [3:0] SEL_O */
        .irq_in(irq_in),                    /* input [31:20] irq_in */
        .jtag_TDI(jtag_TDI),                /* input jtag_TDI */
        .jtag_TDO(jtag_TDO),                /* output jtag_TDO */
        .jtag_TCK(jtag_TCK),                /* input jtag_TCK */
        .jtag_TMS(jtag_TMS),                /* input jtag_TMS */
        .clk_in(cpu_clkin),                 /* input clk_in */
        .resetn_in(~cpu_master_reset)       /* input resetn_in */
    ) ;

endmodule

