[4287] | 1 | module at_boot_clk_config ( |
---|
| 2 | |
---|
| 3 | input clk, |
---|
[4288] | 4 | input clk_valid, |
---|
[4287] | 5 | input pll_refclk, |
---|
| 6 | |
---|
[4295] | 7 | output [3:0] leds_red, |
---|
[4287] | 8 | output reg [3:0] leds_green, |
---|
| 9 | |
---|
| 10 | input [2:0] cm_switch, |
---|
| 11 | |
---|
| 12 | output uart_tx, |
---|
| 13 | |
---|
[4294] | 14 | input iic_eeprom_scl_I, |
---|
| 15 | output iic_eeprom_scl_O, |
---|
| 16 | output iic_eeprom_scl_T, |
---|
| 17 | |
---|
| 18 | input iic_eeprom_sda_I, |
---|
| 19 | output iic_eeprom_sda_T, |
---|
| 20 | output iic_eeprom_sda_O, |
---|
[4287] | 21 | |
---|
| 22 | output reg samp_spi_sclk, |
---|
| 23 | output reg samp_spi_mosi, |
---|
| 24 | output reg samp_spi_cs_n = 1, |
---|
| 25 | |
---|
| 26 | output reg rfref_spi_sclk, |
---|
| 27 | output reg rfref_spi_mosi, |
---|
| 28 | output reg rfref_spi_cs_n = 1, |
---|
| 29 | |
---|
| 30 | output reg cm_spi_sclk, |
---|
| 31 | output reg cm_spi_mosi, |
---|
| 32 | output reg cm_spi_cs_n = 1, |
---|
| 33 | |
---|
| 34 | input cm_pll_status, |
---|
| 35 | |
---|
| 36 | output reg clk_config_done = 0 |
---|
| 37 | ); |
---|
| 38 | |
---|
| 39 | wire [11:0] pb_address; |
---|
| 40 | wire [17:0] pb_instruction; |
---|
| 41 | wire pb_bram_enable; |
---|
| 42 | wire [7:0] pb_io_port_id; |
---|
| 43 | wire [7:0] pb_out_port; |
---|
| 44 | reg [7:0] pb_in_port; |
---|
| 45 | wire pb_out_write_en; |
---|
| 46 | wire pb_k_write_strobe; |
---|
| 47 | wire pb_in_read_en; |
---|
| 48 | wire pb_sleep; |
---|
| 49 | wire pb_reset; |
---|
| 50 | wire pb_bram_rdl; |
---|
| 51 | |
---|
| 52 | wire [7:0] pb_uart_tx_byte; |
---|
| 53 | wire pb_uart_tx_wr_en; |
---|
| 54 | wire pb_uart_tx_data_rdy; |
---|
| 55 | wire pb_uart_tx_half_full; |
---|
| 56 | wire pb_uart_tx_full; |
---|
| 57 | reg pb_uart_tx_reset; |
---|
| 58 | |
---|
[4294] | 59 | reg pb_iic_scl_drive_low; |
---|
| 60 | reg pb_iic_sda_drive_low; |
---|
| 61 | |
---|
[4287] | 62 | reg [6:0] pb_uart_clk16_cnt; |
---|
| 63 | reg pb_uart_clk16_en; |
---|
| 64 | |
---|
| 65 | reg cm_pll_status_d; |
---|
| 66 | reg [2:0] cm_switch_d; |
---|
| 67 | |
---|
[4294] | 68 | reg serial_data_mosi; |
---|
| 69 | |
---|
[4287] | 70 | wire pll_refclk_valid;//TODO |
---|
| 71 | reg pll_refclk_mon_en; |
---|
| 72 | |
---|
[4303] | 73 | reg [7:0] pb_uart_tx_byte_d1; |
---|
| 74 | reg pb_uart_tx_wr_en_d1; |
---|
| 75 | |
---|
| 76 | |
---|
[4287] | 77 | //Register inputs |
---|
| 78 | always @(posedge clk) |
---|
| 79 | begin |
---|
| 80 | cm_pll_status_d <= cm_pll_status; |
---|
| 81 | cm_switch_d <= cm_switch; |
---|
| 82 | end |
---|
| 83 | |
---|
[4295] | 84 | // PicoBlaze CPU |
---|
[4287] | 85 | kcpsm6 #( |
---|
| 86 | .interrupt_vector (12'h3FF), |
---|
[4294] | 87 | .scratch_pad_memory_size(128), |
---|
[4287] | 88 | .hwbuild (8'h00) |
---|
| 89 | ) picoblaze_cpu ( |
---|
| 90 | .address (pb_address), |
---|
| 91 | .instruction (pb_instruction), |
---|
| 92 | .bram_enable (pb_bram_enable), |
---|
| 93 | .port_id (pb_io_port_id), |
---|
| 94 | .write_strobe (pb_out_write_en), |
---|
| 95 | .k_write_strobe (pb_k_write_strobe), |
---|
| 96 | .out_port (pb_out_port), |
---|
| 97 | .read_strobe (pb_in_read_en), |
---|
| 98 | .in_port (pb_in_port), |
---|
| 99 | .interrupt (1'b0), |
---|
| 100 | .interrupt_ack (), |
---|
| 101 | .reset (pb_reset), |
---|
| 102 | .sleep (pb_sleep), |
---|
| 103 | .clk (clk) |
---|
| 104 | ); |
---|
| 105 | |
---|
| 106 | // Picoblaze program ROM |
---|
[4294] | 107 | //leds_only #( |
---|
[4287] | 108 | prog_clk_config_boot #( |
---|
| 109 | .C_FAMILY ("V6"), //Family 'S6' or 'V6' |
---|
| 110 | .C_RAM_SIZE_KWORDS (2), //Program size '1', '2' or '4' |
---|
[4295] | 111 | .C_JTAG_LOADER_ENABLE (0) //Include JTAG Loader when set to 1'b1 |
---|
[4287] | 112 | ) program_rom ( //Name to match your PSM file |
---|
| 113 | .rdl (pb_bram_rdl), |
---|
| 114 | .enable (pb_bram_enable), |
---|
| 115 | .address (pb_address), |
---|
| 116 | .instruction (pb_instruction), |
---|
| 117 | .clk (clk) |
---|
| 118 | ); |
---|
| 119 | |
---|
[4295] | 120 | //Hold PicoBlaze in reset until clk is valid |
---|
| 121 | // clk_valid tied to MMCM.locked in XPS design |
---|
[4288] | 122 | assign pb_reset = pb_bram_rdl || (~clk_valid); |
---|
[4287] | 123 | |
---|
[4295] | 124 | //PicoBlaze UART Tx module |
---|
[4287] | 125 | uart_tx6 pb_uart_tx ( |
---|
[4303] | 126 | .data_in(pb_uart_tx_byte_d1), |
---|
[4287] | 127 | .en_16_x_baud(pb_uart_clk16_en), |
---|
| 128 | .serial_out(uart_tx), |
---|
[4303] | 129 | .buffer_write(pb_uart_tx_wr_en_d1), |
---|
[4287] | 130 | .buffer_data_present(pb_uart_tx_data_rdy), |
---|
| 131 | .buffer_half_full(pb_uart_tx_half_full), |
---|
| 132 | .buffer_full(pb_uart_tx_full), |
---|
| 133 | .buffer_reset(pb_uart_tx_reset), |
---|
| 134 | .clk(clk) |
---|
| 135 | ); |
---|
| 136 | |
---|
| 137 | // Mux for PicoBlaze input port |
---|
| 138 | // Port 0: Tx UART Status |
---|
| 139 | // P0[2]: pb_uart_tx_full |
---|
| 140 | // P0[1]: pb_uart_tx_half_full |
---|
| 141 | // P0[0]: pb_uart_tx_data_rdy |
---|
| 142 | // Port 1: SPI Inputs |
---|
| 143 | // P1[2]: Clock module PLL MISO |
---|
| 144 | // P1[1]: RF ref clk buffer MISO |
---|
| 145 | // P1[0]: Samp clk buffer MISO |
---|
| 146 | // Port 2: Clock module config/status |
---|
| 147 | // P2[4]: Ref clock valid |
---|
| 148 | // P2[3]: PLL locked |
---|
| 149 | // P2[2]: CM switch[2] (CM-PLL) or 1'b1 (CM-MMCX) |
---|
| 150 | // P2[1]: CM switch[1] |
---|
| 151 | // P2[0]: CM switch[0] |
---|
[4294] | 152 | // Port 3: I2C inputs |
---|
| 153 | // P3[0]: IIC SCL input (.O of IOBUFT for SCL in/out) |
---|
| 154 | // P3[1]: IIC SDA input (.O of IOBUFT for SDA in/out) |
---|
[4287] | 155 | always @ (posedge clk) |
---|
| 156 | begin |
---|
| 157 | case (pb_io_port_id[1:0]) |
---|
| 158 | 2'b00 : pb_in_port <= { 5'b0, pb_uart_tx_full, pb_uart_tx_half_full, pb_uart_tx_data_rdy}; |
---|
| 159 | 2'b01 : pb_in_port <= { 8'b0 }; |
---|
[4295] | 160 | 2'b10 : pb_in_port <= { 3'b0, pll_refclk_valid, cm_pll_status_d, cm_switch_d[2:0]}; |
---|
[4294] | 161 | 2'b11 : pb_in_port <= { 6'b0, iic_eeprom_sda_I, iic_eeprom_scl_I}; |
---|
[4287] | 162 | default : pb_in_port <= 8'bXXXXXXXX ; |
---|
| 163 | endcase |
---|
| 164 | end |
---|
| 165 | |
---|
| 166 | /* |
---|
| 167 | Decode for PicoBlaze output port |
---|
[4295] | 168 | Some output writes use OUTPUTK instruction. HDL must monitor k_write_strobe and write_en |
---|
| 169 | SPI slave devices must honor their chip selects to ignore clock/data assertions when not selected. |
---|
| 170 | SPI chip select signals from PicoBlaze are active high (1=chip selected). HDL must invert for active-low outputs. |
---|
| 171 | PicoBlaze only asserts "drive low" signal for IIC clock/data. IOBUFT.I must be tied to net_gnd. |
---|
[4287] | 172 | |
---|
| 173 | Port 0: UART Tx |
---|
| 174 | P0[7:0]: Byte to transmit |
---|
| 175 | |
---|
[4294] | 176 | Port 1: SPI clocks |
---|
[4287] | 177 | P1[0]: Samp clk buffer SPI clk |
---|
| 178 | P1[1]: RF ref clk buffer SPI clk |
---|
| 179 | P1[2]: Clock mod PLL SPI clk |
---|
| 180 | |
---|
[4294] | 181 | Port 2: SPI serial data out |
---|
[4287] | 182 | P2[7]: SPI MOSI - should be shared by all slaves |
---|
| 183 | |
---|
[4294] | 184 | Port 3: SPI chip selects |
---|
[4287] | 185 | P3[0]: Samp clk buffer SPI chip select (active high) |
---|
| 186 | P3[1]: RF ref clk buffer SPI chip select (active high) |
---|
| 187 | P3[2]: Clock mod PLL SPI chip select (active high) |
---|
| 188 | |
---|
[4294] | 189 | Port 4: IIC clock/data |
---|
| 190 | P4[0]: Drive IIC SCL output low |
---|
| 191 | P4[1]: Drive IIC SDA output low |
---|
| 192 | |
---|
| 193 | Port 5: LEDs |
---|
[4287] | 194 | P4[3:0]: Green LEDs |
---|
| 195 | P4[7:4]: Red LEDs |
---|
| 196 | |
---|
[4294] | 197 | Port 6: Status/control |
---|
[4287] | 198 | P5[0]: Program done - allow MMCMs to start and MicroBlazes to boot |
---|
| 199 | P5[1]: Enable PLL ref clock monitor |
---|
| 200 | P5[2]: Reset UART Tx core |
---|
| 201 | */ |
---|
| 202 | |
---|
[4303] | 203 | // Decode output port 0 for UART Tx; add pipeline reg before UART core for better timing |
---|
[4287] | 204 | assign pb_uart_tx_byte = pb_out_port; |
---|
| 205 | 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); |
---|
| 206 | |
---|
[4303] | 207 | always @(posedge clk) |
---|
| 208 | begin |
---|
| 209 | pb_uart_tx_byte_d1 <= pb_uart_tx_byte; |
---|
| 210 | pb_uart_tx_wr_en_d1 <= pb_uart_tx_wr_en; |
---|
| 211 | end |
---|
| 212 | |
---|
[4295] | 213 | // Decode other ports |
---|
[4287] | 214 | always @ (posedge clk) |
---|
| 215 | begin |
---|
| 216 | if ( (pb_k_write_strobe == 1'b1) || (pb_out_write_en == 1'b1) ) |
---|
| 217 | begin |
---|
| 218 | if (pb_io_port_id[2:0] == 3'd1) |
---|
| 219 | begin |
---|
| 220 | samp_spi_sclk <= pb_out_port[0]; |
---|
| 221 | rfref_spi_sclk <= pb_out_port[1]; |
---|
| 222 | cm_spi_sclk <= pb_out_port[2]; |
---|
| 223 | end |
---|
| 224 | else if(pb_io_port_id[2:0] == 3'd2) |
---|
| 225 | begin |
---|
| 226 | serial_data_mosi <= pb_out_port[7]; |
---|
| 227 | end |
---|
| 228 | else if(pb_io_port_id[2:0] == 3'd3) |
---|
| 229 | begin |
---|
| 230 | samp_spi_cs_n <= ~pb_out_port[0]; //AD9512 chip select is active low |
---|
| 231 | rfref_spi_cs_n <= ~pb_out_port[1]; //AD9512 chip select is active low |
---|
| 232 | cm_spi_cs_n <= ~pb_out_port[2]; //AD9511 chip select is active low |
---|
| 233 | end |
---|
| 234 | else if (pb_io_port_id[2:0] == 3'd4) |
---|
| 235 | begin |
---|
[4294] | 236 | pb_iic_scl_drive_low <= pb_out_port[0]; |
---|
| 237 | pb_iic_sda_drive_low <= pb_out_port[1]; |
---|
| 238 | end |
---|
| 239 | else if (pb_io_port_id[2:0] == 3'd5) |
---|
| 240 | begin |
---|
[4287] | 241 | leds_green[3:0] <= pb_out_port[3:0]; |
---|
[4295] | 242 | //leds_red[3:0] <= pb_out_port[7:4]; |
---|
[4287] | 243 | end |
---|
[4294] | 244 | else if (pb_io_port_id[2:0] == 3'd6) |
---|
[4287] | 245 | begin |
---|
| 246 | clk_config_done <= pb_out_port[0]; |
---|
| 247 | pll_refclk_mon_en <= pb_out_port[1]; |
---|
| 248 | pb_uart_tx_reset <= pb_out_port[2]; |
---|
| 249 | end |
---|
| 250 | end |
---|
| 251 | end |
---|
| 252 | |
---|
[4295] | 253 | //Duplicate common SPI MOSI signal to all outputs |
---|
[4287] | 254 | always @(posedge clk) |
---|
| 255 | begin |
---|
| 256 | samp_spi_mosi <= serial_data_mosi; |
---|
| 257 | rfref_spi_mosi <= serial_data_mosi; |
---|
| 258 | cm_spi_mosi <= serial_data_mosi; |
---|
| 259 | end |
---|
| 260 | |
---|
| 261 | //Perma-sleep PicoBlaze when its program completes |
---|
| 262 | // This register will stay asserted until the FPGA is re-configured |
---|
[4295] | 263 | reg clk_config_done_d1 = 0; |
---|
[4287] | 264 | assign pb_sleep = clk_config_done_d1; |
---|
| 265 | always @(posedge clk) |
---|
| 266 | clk_config_done_d1 <= clk_config_done; |
---|
| 267 | |
---|
| 268 | //Generate UART clock (~16x serial port data rate) |
---|
| 269 | // pb_uart_clk16_cnt == 108 for 200MHz clk, UART @ 115200 |
---|
| 270 | always @ (posedge clk) |
---|
| 271 | begin |
---|
| 272 | if (pb_uart_clk16_cnt >= 108) //200MHz/108/16 ~ 115k |
---|
| 273 | begin |
---|
| 274 | pb_uart_clk16_cnt <= 0; |
---|
| 275 | pb_uart_clk16_en <= 1'b1; |
---|
| 276 | end |
---|
| 277 | else |
---|
| 278 | begin |
---|
| 279 | pb_uart_clk16_cnt <= pb_uart_clk16_cnt + 1; |
---|
| 280 | pb_uart_clk16_en <= 1'b0; |
---|
| 281 | end |
---|
| 282 | end |
---|
| 283 | |
---|
[4294] | 284 | //IOBUFT signals for I2C pins; actual IOBUFT are implemented above |
---|
| 285 | // this module to allow muxing with other IIC controller in XPS design |
---|
| 286 | assign iic_eeprom_scl_T = pb_iic_scl_drive_low; |
---|
| 287 | assign iic_eeprom_scl_O = 1'b0; |
---|
[4287] | 288 | |
---|
[4294] | 289 | assign iic_eeprom_sda_T = pb_iic_sda_drive_low; |
---|
| 290 | assign iic_eeprom_sda_O = 1'b0; |
---|
| 291 | |
---|
[4295] | 292 | |
---|
| 293 | //PLL ref clock monitor |
---|
| 294 | reg [11:0] pll_refclk_mon_cnt = 0; |
---|
| 295 | reg [7:0] pll_refclk_mon_timeout_cnt = 0; |
---|
| 296 | reg pll_refclk_mon_timeout_reset; |
---|
| 297 | wire pll_refclk_mon_timeout; |
---|
| 298 | |
---|
| 299 | always @(posedge clk) |
---|
| 300 | begin |
---|
| 301 | if(pll_refclk_mon_timeout_reset || pll_refclk_valid || ~pll_refclk_mon_en) |
---|
| 302 | pll_refclk_mon_timeout_cnt <= 8'h00; |
---|
| 303 | else if(clk_valid) |
---|
| 304 | pll_refclk_mon_timeout_cnt <= pll_refclk_mon_timeout_cnt + 1; |
---|
| 305 | end |
---|
| 306 | |
---|
| 307 | assign pll_refclk_mon_timeout = (pll_refclk_mon_timeout_cnt == 8'hFF); |
---|
| 308 | |
---|
| 309 | wire pll_refclk_mon_reset; |
---|
| 310 | assign pll_refclk_mon_reset = (~pll_refclk_mon_en || pll_refclk_mon_timeout); |
---|
| 311 | |
---|
| 312 | always @(posedge pll_refclk or posedge pll_refclk_mon_reset) |
---|
| 313 | begin |
---|
| 314 | if(pll_refclk_mon_reset) |
---|
| 315 | begin |
---|
| 316 | pll_refclk_mon_cnt <= 12'h000; |
---|
| 317 | pll_refclk_mon_timeout_reset <= 1'b0; |
---|
| 318 | end |
---|
| 319 | else if(pll_refclk_mon_cnt < 12'hFFF) |
---|
| 320 | begin |
---|
| 321 | pll_refclk_mon_cnt <= pll_refclk_mon_cnt + 1; |
---|
| 322 | pll_refclk_mon_timeout_reset <= 1'b1; |
---|
| 323 | end |
---|
| 324 | else |
---|
| 325 | begin |
---|
| 326 | pll_refclk_mon_cnt <= pll_refclk_mon_cnt; |
---|
| 327 | pll_refclk_mon_timeout_reset <= 1'b0; |
---|
| 328 | end |
---|
| 329 | end |
---|
| 330 | assign leds_red = pll_refclk_mon_cnt[3:0]; |
---|
| 331 | |
---|
| 332 | assign pll_refclk_valid = (pll_refclk_mon_cnt == 12'hFFF); |
---|
| 333 | |
---|
[4287] | 334 | endmodule |
---|