1 | module at_boot_clk_config ( |
---|
2 | |
---|
3 | input clk, |
---|
4 | input clk_valid, |
---|
5 | input pll_refclk, |
---|
6 | |
---|
7 | output [3:0] leds_red, |
---|
8 | output reg [3:0] leds_green, |
---|
9 | |
---|
10 | input [2:0] cm_switch, |
---|
11 | |
---|
12 | output uart_tx, |
---|
13 | |
---|
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, |
---|
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 | |
---|
59 | reg pb_iic_scl_drive_low; |
---|
60 | reg pb_iic_sda_drive_low; |
---|
61 | |
---|
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 | |
---|
68 | reg serial_data_mosi; |
---|
69 | |
---|
70 | wire pll_refclk_valid;//TODO |
---|
71 | reg pll_refclk_mon_en; |
---|
72 | |
---|
73 | reg [7:0] pb_uart_tx_byte_d1; |
---|
74 | reg pb_uart_tx_wr_en_d1; |
---|
75 | |
---|
76 | |
---|
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 | |
---|
84 | // PicoBlaze CPU |
---|
85 | kcpsm6 #( |
---|
86 | .interrupt_vector (12'h3FF), |
---|
87 | .scratch_pad_memory_size(128), |
---|
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 |
---|
107 | //leds_only #( |
---|
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' |
---|
111 | .C_JTAG_LOADER_ENABLE (0) //Include JTAG Loader when set to 1'b1 |
---|
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 | |
---|
120 | //Hold PicoBlaze in reset until clk is valid |
---|
121 | // clk_valid tied to MMCM.locked in XPS design |
---|
122 | assign pb_reset = pb_bram_rdl || (~clk_valid); |
---|
123 | |
---|
124 | //PicoBlaze UART Tx module |
---|
125 | uart_tx6 pb_uart_tx ( |
---|
126 | .data_in(pb_uart_tx_byte_d1), |
---|
127 | .en_16_x_baud(pb_uart_clk16_en), |
---|
128 | .serial_out(uart_tx), |
---|
129 | .buffer_write(pb_uart_tx_wr_en_d1), |
---|
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] |
---|
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) |
---|
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 }; |
---|
160 | 2'b10 : pb_in_port <= { 3'b0, pll_refclk_valid, cm_pll_status_d, cm_switch_d[2:0]}; |
---|
161 | 2'b11 : pb_in_port <= { 6'b0, iic_eeprom_sda_I, iic_eeprom_scl_I}; |
---|
162 | default : pb_in_port <= 8'bXXXXXXXX ; |
---|
163 | endcase |
---|
164 | end |
---|
165 | |
---|
166 | /* |
---|
167 | Decode for PicoBlaze output port |
---|
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. |
---|
172 | |
---|
173 | Port 0: UART Tx |
---|
174 | P0[7:0]: Byte to transmit |
---|
175 | |
---|
176 | Port 1: SPI clocks |
---|
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 | |
---|
181 | Port 2: SPI serial data out |
---|
182 | P2[7]: SPI MOSI - should be shared by all slaves |
---|
183 | |
---|
184 | Port 3: SPI chip selects |
---|
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 | |
---|
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 |
---|
194 | P4[3:0]: Green LEDs |
---|
195 | P4[7:4]: Red LEDs |
---|
196 | |
---|
197 | Port 6: Status/control |
---|
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 | |
---|
203 | // Decode output port 0 for UART Tx; add pipeline reg before UART core for better timing |
---|
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 | |
---|
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 | |
---|
213 | // Decode other ports |
---|
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 |
---|
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 |
---|
241 | leds_green[3:0] <= pb_out_port[3:0]; |
---|
242 | //leds_red[3:0] <= pb_out_port[7:4]; |
---|
243 | end |
---|
244 | else if (pb_io_port_id[2:0] == 3'd6) |
---|
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 | |
---|
253 | //Duplicate common SPI MOSI signal to all outputs |
---|
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 |
---|
263 | reg clk_config_done_d1 = 0; |
---|
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 | |
---|
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; |
---|
288 | |
---|
289 | assign iic_eeprom_sda_T = pb_iic_sda_drive_low; |
---|
290 | assign iic_eeprom_sda_O = 1'b0; |
---|
291 | |
---|
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 | |
---|
334 | endmodule |
---|