module at_boot_clk_config ( input clk, input clk_valid, input pll_refclk, output [3:0] leds_red, output reg [3:0] leds_green, input [2:0] cm_switch, output uart_tx, input iic_eeprom_scl_I, output iic_eeprom_scl_O, output iic_eeprom_scl_T, input iic_eeprom_sda_I, output iic_eeprom_sda_T, output iic_eeprom_sda_O, output reg samp_spi_sclk, output reg samp_spi_mosi, output reg samp_spi_cs_n = 1, output reg rfref_spi_sclk, output reg rfref_spi_mosi, output reg rfref_spi_cs_n = 1, output reg cm_spi_sclk, output reg cm_spi_mosi, output reg cm_spi_cs_n = 1, input cm_pll_status, output reg clk_config_done = 0 ); wire [11:0] pb_address; wire [17:0] pb_instruction; wire pb_bram_enable; wire [7:0] pb_io_port_id; wire [7:0] pb_out_port; reg [7:0] pb_in_port; wire pb_out_write_en; wire pb_k_write_strobe; wire pb_in_read_en; wire pb_sleep; wire pb_reset; wire pb_bram_rdl; wire [7:0] pb_uart_tx_byte; wire pb_uart_tx_wr_en; wire pb_uart_tx_data_rdy; wire pb_uart_tx_half_full; wire pb_uart_tx_full; reg pb_uart_tx_reset; reg pb_iic_scl_drive_low; reg pb_iic_sda_drive_low; reg [6:0] pb_uart_clk16_cnt; reg pb_uart_clk16_en; reg cm_pll_status_d; reg [2:0] cm_switch_d; reg serial_data_mosi; wire pll_refclk_valid;//TODO reg pll_refclk_mon_en; reg [7:0] pb_uart_tx_byte_d1; reg pb_uart_tx_wr_en_d1; //Register inputs always @(posedge clk) begin cm_pll_status_d <= cm_pll_status; cm_switch_d <= cm_switch; end // PicoBlaze CPU kcpsm6 #( .interrupt_vector (12'h3FF), .scratch_pad_memory_size(128), .hwbuild (8'h00) ) picoblaze_cpu ( .address (pb_address), .instruction (pb_instruction), .bram_enable (pb_bram_enable), .port_id (pb_io_port_id), .write_strobe (pb_out_write_en), .k_write_strobe (pb_k_write_strobe), .out_port (pb_out_port), .read_strobe (pb_in_read_en), .in_port (pb_in_port), .interrupt (1'b0), .interrupt_ack (), .reset (pb_reset), .sleep (pb_sleep), .clk (clk) ); // Picoblaze program ROM //leds_only #( prog_clk_config_boot #( .C_FAMILY ("V6"), //Family 'S6' or 'V6' .C_RAM_SIZE_KWORDS (2), //Program size '1', '2' or '4' .C_JTAG_LOADER_ENABLE (0) //Include JTAG Loader when set to 1'b1 ) program_rom ( //Name to match your PSM file .rdl (pb_bram_rdl), .enable (pb_bram_enable), .address (pb_address), .instruction (pb_instruction), .clk (clk) ); //Hold PicoBlaze in reset until clk is valid // clk_valid tied to MMCM.locked in XPS design assign pb_reset = pb_bram_rdl || (~clk_valid); //PicoBlaze UART Tx module uart_tx6 pb_uart_tx ( .data_in(pb_uart_tx_byte_d1), .en_16_x_baud(pb_uart_clk16_en), .serial_out(uart_tx), .buffer_write(pb_uart_tx_wr_en_d1), .buffer_data_present(pb_uart_tx_data_rdy), .buffer_half_full(pb_uart_tx_half_full), .buffer_full(pb_uart_tx_full), .buffer_reset(pb_uart_tx_reset), .clk(clk) ); // Mux for PicoBlaze input port // Port 0: Tx UART Status // P0[2]: pb_uart_tx_full // P0[1]: pb_uart_tx_half_full // P0[0]: pb_uart_tx_data_rdy // Port 1: SPI Inputs // P1[2]: Clock module PLL MISO // P1[1]: RF ref clk buffer MISO // P1[0]: Samp clk buffer MISO // Port 2: Clock module config/status // P2[4]: Ref clock valid // P2[3]: PLL locked // P2[2]: CM switch[2] (CM-PLL) or 1'b1 (CM-MMCX) // P2[1]: CM switch[1] // P2[0]: CM switch[0] // Port 3: I2C inputs // P3[0]: IIC SCL input (.O of IOBUFT for SCL in/out) // P3[1]: IIC SDA input (.O of IOBUFT for SDA in/out) always @ (posedge clk) begin case (pb_io_port_id[1:0]) 2'b00 : pb_in_port <= { 5'b0, pb_uart_tx_full, pb_uart_tx_half_full, pb_uart_tx_data_rdy}; 2'b01 : pb_in_port <= { 8'b0 }; 2'b10 : pb_in_port <= { 3'b0, pll_refclk_valid, cm_pll_status_d, cm_switch_d[2:0]}; 2'b11 : pb_in_port <= { 6'b0, iic_eeprom_sda_I, iic_eeprom_scl_I}; default : pb_in_port <= 8'bXXXXXXXX ; endcase end /* Decode for PicoBlaze output port Some output writes use OUTPUTK instruction. HDL must monitor k_write_strobe and write_en SPI slave devices must honor their chip selects to ignore clock/data assertions when not selected. SPI chip select signals from PicoBlaze are active high (1=chip selected). HDL must invert for active-low outputs. PicoBlaze only asserts "drive low" signal for IIC clock/data. IOBUFT.I must be tied to net_gnd. Port 0: UART Tx P0[7:0]: Byte to transmit Port 1: SPI clocks P1[0]: Samp clk buffer SPI clk P1[1]: RF ref clk buffer SPI clk P1[2]: Clock mod PLL SPI clk Port 2: SPI serial data out P2[7]: SPI MOSI - should be shared by all slaves Port 3: SPI chip selects P3[0]: Samp clk buffer SPI chip select (active high) P3[1]: RF ref clk buffer SPI chip select (active high) P3[2]: Clock mod PLL SPI chip select (active high) Port 4: IIC clock/data P4[0]: Drive IIC SCL output low P4[1]: Drive IIC SDA output low Port 5: LEDs P4[3:0]: Green LEDs P4[7:4]: Red LEDs Port 6: Status/control P5[0]: Program done - allow MMCMs to start and MicroBlazes to boot P5[1]: Enable PLL ref clock monitor P5[2]: Reset UART Tx core */ // Decode output port 0 for UART Tx; add pipeline reg before UART core for better timing assign pb_uart_tx_byte = pb_out_port; assign pb_uart_tx_wr_en = ((pb_k_write_strobe == 1'b1) || (pb_out_write_en == 1'b1)) & (pb_io_port_id[2:0] == 3'd0); always @(posedge clk) begin pb_uart_tx_byte_d1 <= pb_uart_tx_byte; pb_uart_tx_wr_en_d1 <= pb_uart_tx_wr_en; end // Decode other ports always @ (posedge clk) begin if ( (pb_k_write_strobe == 1'b1) || (pb_out_write_en == 1'b1) ) begin if (pb_io_port_id[2:0] == 3'd1) begin samp_spi_sclk <= pb_out_port[0]; rfref_spi_sclk <= pb_out_port[1]; cm_spi_sclk <= pb_out_port[2]; end else if(pb_io_port_id[2:0] == 3'd2) begin serial_data_mosi <= pb_out_port[7]; end else if(pb_io_port_id[2:0] == 3'd3) begin samp_spi_cs_n <= ~pb_out_port[0]; //AD9512 chip select is active low rfref_spi_cs_n <= ~pb_out_port[1]; //AD9512 chip select is active low cm_spi_cs_n <= ~pb_out_port[2]; //AD9511 chip select is active low end else if (pb_io_port_id[2:0] == 3'd4) begin pb_iic_scl_drive_low <= pb_out_port[0]; pb_iic_sda_drive_low <= pb_out_port[1]; end else if (pb_io_port_id[2:0] == 3'd5) begin leds_green[3:0] <= pb_out_port[3:0]; //leds_red[3:0] <= pb_out_port[7:4]; end else if (pb_io_port_id[2:0] == 3'd6) begin clk_config_done <= pb_out_port[0]; pll_refclk_mon_en <= pb_out_port[1]; pb_uart_tx_reset <= pb_out_port[2]; end end end //Duplicate common SPI MOSI signal to all outputs always @(posedge clk) begin samp_spi_mosi <= serial_data_mosi; rfref_spi_mosi <= serial_data_mosi; cm_spi_mosi <= serial_data_mosi; end //Perma-sleep PicoBlaze when its program completes // This register will stay asserted until the FPGA is re-configured reg clk_config_done_d1 = 0; assign pb_sleep = clk_config_done_d1; always @(posedge clk) clk_config_done_d1 <= clk_config_done; //Generate UART clock (~16x serial port data rate) // pb_uart_clk16_cnt == 108 for 200MHz clk, UART @ 115200 always @ (posedge clk) begin if (pb_uart_clk16_cnt >= 108) //200MHz/108/16 ~ 115k begin pb_uart_clk16_cnt <= 0; pb_uart_clk16_en <= 1'b1; end else begin pb_uart_clk16_cnt <= pb_uart_clk16_cnt + 1; pb_uart_clk16_en <= 1'b0; end end //IOBUFT signals for I2C pins; actual IOBUFT are implemented above // this module to allow muxing with other IIC controller in XPS design assign iic_eeprom_scl_T = pb_iic_scl_drive_low; assign iic_eeprom_scl_O = 1'b0; assign iic_eeprom_sda_T = pb_iic_sda_drive_low; assign iic_eeprom_sda_O = 1'b0; //PLL ref clock monitor reg [11:0] pll_refclk_mon_cnt = 0; reg [7:0] pll_refclk_mon_timeout_cnt = 0; reg pll_refclk_mon_timeout_reset; wire pll_refclk_mon_timeout; always @(posedge clk) begin if(pll_refclk_mon_timeout_reset || pll_refclk_valid || ~pll_refclk_mon_en) pll_refclk_mon_timeout_cnt <= 8'h00; else if(clk_valid) pll_refclk_mon_timeout_cnt <= pll_refclk_mon_timeout_cnt + 1; end assign pll_refclk_mon_timeout = (pll_refclk_mon_timeout_cnt == 8'hFF); wire pll_refclk_mon_reset; assign pll_refclk_mon_reset = (~pll_refclk_mon_en || pll_refclk_mon_timeout); always @(posedge pll_refclk or posedge pll_refclk_mon_reset) begin if(pll_refclk_mon_reset) begin pll_refclk_mon_cnt <= 12'h000; pll_refclk_mon_timeout_reset <= 1'b0; end else if(pll_refclk_mon_cnt < 12'hFFF) begin pll_refclk_mon_cnt <= pll_refclk_mon_cnt + 1; pll_refclk_mon_timeout_reset <= 1'b1; end else begin pll_refclk_mon_cnt <= pll_refclk_mon_cnt; pll_refclk_mon_timeout_reset <= 1'b0; end end assign leds_red = pll_refclk_mon_cnt[3:0]; assign pll_refclk_valid = (pll_refclk_mon_cnt == 12'hFFF); endmodule