// Top level LLRF module // Larry Doolittle, LBNL, January 2003 // Includes conditional compilation: // Old vs. New board support (only New board mode currently works) // Feedback vs. test pattern at 40 MS/s // Feedforward table or not // Formatted as narrow as I can manage and keep readability; // try tab stops of 6 or 8, screen widths at least 84. `timescale 1ns / 1ns `define PRODUCT_ID 16'h7702 `define PRODUCT_REV 16'h0013 `define GEN2_BOARD // as opposed to the first generation board; // only GEN2_BOARD is tested at this point. `define FEEDBACK `define FEEDFORWARD // can't define TEST_BUFFERS and FEEDFORWARD on an XC2S150 `ifdef GEN2_BOARD `define DAC902 `endif // formal parameters are the pins of the XC2S150 module adctest( DA, DAOV, DB, DBOV, DC, DCOV, DD, DDOV, // ADC Inputs CLK, // 40 MHz input clock P_Down, // Output pin to power down the bank of ADCs RF_ON, RF_KILL, PD, // 16-bit bi-directional data bus ALE_host, WE_host, RD_host, CS0_host, CK_host, RDY_host, INT_host, `ifdef DAC902 CLK80X, DE, SLEEP, // 80 MS/s DAC `else DE, OCLK, OSEL, SLEEP, // dual 20 MS/s DAC `endif `ifdef GEN2_BOARD IL_STAT, SCLK, SDIN, DOUT1202, SDA75, CS1202, CS5742, DS2401, PLL_CLK, PLL_DATA, PLL_LE, PLL_MUXOUT, PLL_CE, LED2, LED3, LED4, DIO1, DIO2, DIO3, DIO4, DIO6 `else SP_DOUT, SP_DIN, SP_SCLK, SP_CS1, SP_CS2, SP_CS3, SP_CS4, TEST_1, TEST_2, TEST_3, TEST_4 `endif ); // 4 x ADS808 inputs at 40 MS/s input [11:0] DA; input DAOV; // from Forward ADC input [11:0] DB; input DBOV; // from Reflected ADC input [11:0] DC; input DCOV; // from Cavity ADC input [11:0] DD; input DDOV; // from Spare ADC `ifdef DAC902 // DAC902, use at 80 MS/s, rated to 165 MS/s input CLK80X; `else // AD9765, interleaved update of two outputs at 40 MS/s, rated to 125 MS/s output OCLK, OSEL; `endif output [11:0] DE; output SLEEP; wire SLEEP = 1'b0; // Miscellaneous inputs input RF_ON; // external RF gate pulse input CLK; input IL_STAT; // external interlock status // Miscellaneous outputs output P_Down; output RF_KILL; // we can disable the RF from here reg RF_KILL; // host interface inout[15:0] PD; input CK_host, ALE_host, WE_host, RD_host, CS0_host; output RDY_host, INT_host; wire RDY_host = 1'b1; `ifdef GEN2_BOARD // front panel LEDs and expansion DIO output LED2, LED3, LED4, DIO1, DIO2, DIO3, DIO4, DIO6; // Housekeeping devices output SCLK, SDIN, CS1202, CS5742; inout SDA75, DS2401; input DOUT1202; // ADF4001 output PLL_CLK, PLL_DATA, PLL_LE, PLL_CE; input PLL_MUXOUT; `else // Synchronous serial ports input SP_DOUT; // to FPGA sport from ADC/DAC output SP_DIN; // from FPGA sport to ADC/DAC output SP_SCLK; output SP_CS1; // CS1 on schematic output SP_CS2; // CS2 on schematic output SP_CS3; // CS3 on schematic output SP_CS4; // CS4 on schematic wire SP_DOUT, SP_DIN, SP_SCLK; wire SP_CS1, SP_CS2, SP_CS3, SP_CS4; // Test points output TEST_1, TEST_2, TEST_3, TEST_4; `endif // ====================end of I/O pin definitions reg [11:0] dal, dbl, dcl, ddl; // Latched input from ADCs wire [11:0] dals, dbls, dcls, ddls; // Latched and converted to signed binary reg [15:0] load_data; wire [15:0] ds_read_bus, pll_read_bus, sport_read_bus; reg [13:0] ADDR_reg; reg [11:0] trace_data; wire [14:0] dcnt_at_pulse_end, ucnt_at_pulse_end; wire [15:0] history_dout; reg trig, last_trig; reg error_clear_cmd; wire adc_power, rf_gate, ext_trigger_skipped; // output from rf_timer reg ext_trigger_skipped_latch; wire [15:0] status; wire [15:0] errors; wire trace_enable; reg host_timer_write; reg RF_ON_sync, quad_sync; reg clk40_missing, clk40_missing_pulse, pll_unlocked, handshake_error; reg handshake_token; reg we; wire [20:0] dkcm_bus; reg [1:0] gray_40MHz; wire trace_run, feedback_run, integrate_run; // output of timer // registers simply set by the host reg [15:0] SET_I; // otherwise unused bits used in register self-test reg [13:0] SET_Q; reg [15:0] dhistory_config, uhistory_config; reg [14:0] dstop_count, ustop_count; // configured by host with writes to 0x0028 reg trace_select; reg ignore_rf_off; reg self_retrigger; reg dds_passthru; `ifdef FEEDBACK reg feedback_select; reg integrate_select; reg continuous_feedforward; `endif reg halt; reg test1, test2, test3, test4; `ifdef SIMULATE // reasonable defaults for simple simulations initial trace_select = 1'b1; initial ignore_rf_off = 1'b0; initial self_retrigger = 1'b0; initial dds_passthru = 1'b0; initial halt = 1'b0; `endif // allow check of the actually synthesized configuration `ifdef FEEDBACK wire feedback_config = 1'b1; `else wire feedback_config = 1'b0; `endif `ifdef GEN2_BOARD wire gen2_board_config = 1'b1; `else wire gen2_board_config = 1'b0; `endif `ifdef FEEDFORWARD wire feedforward_config = 1'b1; `else wire feedforward_config = 1'b0; `endif wire test_buffers_config; // set by history module wire dds_unadjustable_config; // set by dds module // pass signal from the timing subsystem to the output pin: wire P_Down = ~adc_power; // buffer the clocks wire CLK_host, CLK_hack; IBUF u4( CLK_hack, CK_host); // since CK_host is not a dedicated clock pad BUFG u3( CLK_host, CLK_hack); // should turn into BUFG wire CLK_40MHz; buf u1( CLK_40MHz, CLK); wire [11:0] output40; wire [1:0] sync_count={gray_40MHz[1], gray_40MHz[1]^gray_40MHz[0]}; // barely workable hack wire [7:0] feedforward_host_dout; `ifdef FEEDBACK wire [7:0] feedforward_rf_dout; wire feedforward_start; `ifdef FEEDFORWARD feedforward feedforward( .clk(CLK_40MHz), .start(feedforward_start), .data_out(feedforward_rf_dout), .host_clk(CLK_host), .host_we(we & ADDR_reg[13:10] == 4'b0011), // 0x3000-0x3ffc .host_addr(ADDR_reg[8:0]), .host_data(load_data[7:0]), .host_dout(feedforward_host_dout), .continuous_feedforward(continuous_feedforward) ); `else assign feedforward_host_dout = 8'd0; assign feedforward_rf_dout = 8'd0; `endif wire [13:0] set_wave; reg [15:0] dds_freq_set; dds dds(CLK_40MHz, set_wave, SET_I[15:2], SET_Q, (adc_power|dds_passthru), dds_freq_set, dds_unadjustable_config); wire feedback_enable = feedback_run & feedback_select; wire integrate_enable = integrate_run & integrate_select; wire [11:0] output40m; fdbk_loop fdbk( .M(dcls), .set_wave(set_wave), .dkcm_bus(dkcm_bus), .dkcm_clk(CLK_host), .t_mod_4(sync_count[1:0] ), .feedback_enable(feedback_enable), .integrate_enable(integrate_enable), .feedforward_data(feedforward_rf_dout), .CLK(CLK_40MHz), .fdbk_err_out(output40m)); assign output40 = dds_passthru ? set_wave[13:2] : output40m; `else dac_testpattern pattern(.clk80(CLK_40MHz), .dac_out(output40), .load_data(load_data), .clk_host(CLK_host), .we(we&(ADDR_reg == 14'b00000000000110))); // 0x0018 assign feedforward_host_dout = 8'h00; `endif `ifdef DAC902 wire CLK_80MHz; buf u5( CLK_80MHz, CLK80X); wire [11:0] ab_out; afterburner ab(CLK_40MHz, output40, CLK_80MHz, ab_out, CLK_host, dkcm_bus); // convert from signed to straight binary for DAC902 assign DE = {~ab_out[11], ab_out[10:0]}; `else // convert from signed to straight binary for AD9765 assign DE = {~output40[11], output40[10:0]; `endif reg [11:0] KCM_load_data; reg [2:0] KCM_load_addr; wire KCM_load_busy; dkcm_controller kcm_stuff(.clk(CLK_host), .dkcm_bus(dkcm_bus), .konstant(KCM_load_data), .load(we&(ADDR_reg[13:3] == 11'b00000000010)), // 0x0040-0x005c .addr(KCM_load_addr), .busy(KCM_load_busy)); history2e history(.clk40(CLK_40MHz), .rstn(1'b1), .dals(dals), .dbls(dbls), .dcls(dcls), .ddls(ddls), .outm(output40), .trace_enable(trace_enable), .dcnt_at_pulse_end(dcnt_at_pulse_end), .ucnt_at_pulse_end(ucnt_at_pulse_end), .dstop_count(dstop_count), .ustop_count(ustop_count), .dhistory_config(dhistory_config), .uhistory_config(uhistory_config), .test_buffers_config(test_buffers_config), .clk_host(CLK_host), .host_dout(history_dout), .host_addr(ADDR_reg), .we(we)); ds2401 serial( CLK_host, DS2401, we & (ADDR_reg == 14'b00000000000111), // 0x001c load_data[3:0], ds_read_bus); `ifdef LARRY_SERIAL sportx sportx( CLK_host, ADDR_reg[0], we & (ADDR_reg[13:3] == 11'b00000000011), // 0x0060 load_data, sport_read_bus, SCLK, SDIN, DOUT1202, SDA75, CS1202, CS5742, PLL_CLK, PLL_DATA, PLL_LE, PLL_MUXOUT, PLL_CE); `else wire altsport_reset = we & (ADDR_reg == 14'b00000000000001); // 0x0004 (firmware version) altsport altsport( CLK_host, ADDR_reg[2:0], we & (ADDR_reg[13:3] == 11'b00000000011), // 0x0060 load_data, sport_read_bus, SCLK, SDIN, DOUT1202, SDA75, CS1202, CS5742, PLL_CLK, PLL_DATA, PLL_LE, PLL_MUXOUT, PLL_CE, altsport_reset); `endif // TIMING CONTROL LOGIC assign trace_enable = trace_run & trace_select; wire [15:0] host_timer_odata; rf_timer rf_timer1( .ck(CLK_40MHz), .rstn(1'b1), .quad_enable(quad_sync), .halt(halt), .rf(RF_ON_sync), .self_retrigger(self_retrigger), .ignore_rf_off(ignore_rf_off), .write_pulse(host_timer_write), .host_address(ADDR_reg[2:0] ), .host_data(load_data), .host_read(host_timer_odata), `ifdef FEEDBACK .feedback_run(feedback_run), .integrate_run(integrate_run), .feedforward_start(feedforward_start), `endif .trace_enable(trace_run), .adc_power(adc_power), .host_interrupt(INT_host), .rf_gate(rf_gate), // XXX unused .trigger_skipped(ext_trigger_skipped)); // das blinkenlights flasher flasher1(.clk(CLK_host), .err(clk40_missing_pulse), .lampo(LED2)); reg daov_latch, dbov_latch, dcov_latch, ddov_latch; `ifdef SIMULATE initial begin daov_latch=1'b0; dbov_latch=1'b0; dcov_latch=1'b0; ddov_latch=1'b0; end `endif always @(posedge CLK_40MHz) begin // The following 48 latches should be absorbed into IOBs: dal <= DA; dbl <= DB; dcl <= DC; ddl <= DD; if (trace_enable & DAOV | error_clear_cmd) daov_latch <= trace_enable & DAOV; if (trace_enable & DBOV | error_clear_cmd) dbov_latch <= trace_enable & DBOV; if (trace_enable & DCOV | error_clear_cmd) dcov_latch <= trace_enable & DCOV; if (trace_enable & DDOV | error_clear_cmd) ddov_latch <= trace_enable & DDOV; `ifdef GEN2_BOARD RF_ON_sync <= ~RF_ON; `else RF_ON_sync <= RF_ON; `endif end assign dals = {~dal[11], dal[10:0]}; assign dbls = {~dbl[11], dbl[10:0]}; assign dcls = {~dcl[11], dcl[10:0]}; assign ddls = {~ddl[11], ddl[10:0]}; // these two processes provide a "clock detect" feature. // If the 40 MHz goes away, or is even erratic, an error bit is raised. // If the 25 MHz CPU clock goes away, there's nobody to tell :-( // Strategy for crossing the clock domain: use a 2-bit Gray code // counter clocked at 40 MHz, which can be sampled at 25 MHz. // The counter will always have advanced one or two 25 ns cycles // between 40 ns clocks. `ifdef SIMULATE initial gray_40MHz = 2'b0; `endif always @(posedge CLK_40MHz) gray_40MHz <= {gray_40MHz[0], ~gray_40MHz[1]}; reg [1:0] gray_sample, gray_previous; always @(posedge CLK_host) begin gray_sample <= gray_40MHz; // cross clock domains *here* gray_previous <= gray_sample; clk40_missing_pulse <= (gray_previous == gray_sample); if(clk40_missing_pulse | error_clear_cmd) clk40_missing <= clk40_missing_pulse; end // quad_sync is now entirely local, no means of phasing the hardware // from an external source. Relative phase is determined in software // by digitizing the analog 50 MHz phase reference. always @(posedge CLK_40MHz) quad_sync <= gray_40MHz == 2'b00; wire host_write_cycle = (~WE_host) & (~CS0_host); wire host_read_cycle = (~RD_host) & (~CS0_host); always @(posedge CLK_host) begin if (ALE_host & ~CS0_host) ADDR_reg <= PD[15:2] ; trig <= host_write_cycle; last_trig <= trig; we <= trig & ~last_trig; // single (25 MHz) write pulse if (trig & ~last_trig) load_data <= PD; if (trig & ~last_trig & (ADDR_reg[13:3] == 11'b00000000010)) begin // latch these so we can do other things while it reloads KCM_load_addr <= ADDR_reg[2:0]; KCM_load_data <= PD[15:4]; end if (we & (ADDR_reg == 14'b00000000000110)) dds_freq_set <= load_data; // 0x0018 if (we & (ADDR_reg == 14'b00000000001000)) SET_I <= load_data; // 0x0020 if (we & (ADDR_reg == 14'b00000000001001)) SET_Q <= load_data[15:2]; // 0x0024 if (we & (ADDR_reg == 14'b00000000001010)) begin // 0x0028 trace_select <= load_data[0]; // phase_sense_adjust <= load_data[1]; // Rev. 1 only // rising_edge_decay <= load_data[2]; // moved to history_config ignore_rf_off <= load_data[4]; self_retrigger <= load_data[5]; halt <= load_data[6]; // trace_sel <= load_data[8:7]; // moved to history_config `ifdef FEEDBACK continuous_feedforward <= load_data[3]; feedback_select <= load_data[9] ; integrate_select <= load_data[10] ; `endif RF_KILL <= load_data[11]; // iq_hand_flip <= load_data[12]; // Rev. 1 only test1 <= load_data[12]; dds_passthru <= load_data[13]; test2 <= load_data[13]; test3 <= load_data[14]; test4 <= load_data[15]; end if (we & (ADDR_reg == 14'b00000000001100)) dhistory_config <= load_data; // 0x0030 if (we & (ADDR_reg == 14'b00000000001101)) dstop_count <= load_data; // 0x0034 if (we & (ADDR_reg == 14'b00000000001110)) uhistory_config <= load_data; // 0x0038 if (we & (ADDR_reg == 14'b00000000001111)) ustop_count <= load_data; // 0x003c // write-enable logic for the bank of timer registers. // This decoding matches 0x0080 through 0x00bc, of which the 8 words at // 0x0080 through 0x09c are actually used. host_timer_write <= we & (ADDR_reg[13:4] == 10'b0000000010); // Reading the error register (0x000c) causes its bits to clear. // This clear happens after the data is latched into PD_cr. // XXX There are about three cycles of dead time, where errors // can happen and will never be visible to the software. error_clear_cmd <= host_read_cycle & (ADDR_reg == 14'b00000000000011); // Latch PLL errors if (~PLL_MUXOUT | error_clear_cmd) pll_unlocked <= ~PLL_MUXOUT; // The software is expected to write to the error register (0x000c) // (the data is ignored) at the beginning of its xfer_from_fpga // routine, which is triggered by the interrupt. This puts the // handshake logic into "armed" mode, where handshake_token=1. // If an RF pulse comes along in this mode, the handshake_error // bit is set. The xfer_from_fpga routine will read from error // register as the last thing it does, which both finds out if // it acted fast enough to not get corrupted data, and sets // handshake_token back to 0, so the handshake logic won't // complain when the next RF pulse hits. if ((host_write_cycle | host_read_cycle) & (ADDR_reg == 14'b00000000000011)) handshake_token <= host_write_cycle; if ((trace_run & handshake_token) | error_clear_cmd) handshake_error <= trace_run & handshake_token; // ext_trigger_skipped comes from rf_timer module as a 100 ns pulse, // and is a simple register output ( glitchless), so // it is guaranteed to `stick' if we sample it at 25 MHz. if (ext_trigger_skipped | error_clear_cmd) ext_trigger_skipped_latch <= ext_trigger_skipped; end // decoding of ADDR_reg for read cycles // 0x0000 product code // 0x0004 revision number // 0x0008 status // 0x000c errors // 0x0014 address_at_pulse_end // 0x0018 not used (see dactest.v) // 0x001c ds2401 // 0x0020 SET_I // 0x0060 sport_read_bus // 0x0080-0x00bc timer // 0x2000-0x3ffc feedforward buffer, delegated to feedforward.v // 0x4000-0xfffc history buffers, delegated to history.v assign errors = {6'b000000, pll_unlocked, handshake_error, 2'b00, ext_trigger_skipped_latch, clk40_missing, daov_latch, dbov_latch, dcov_latch, ddov_latch}; assign status = {feedback_config, gen2_board_config, test_buffers_config, feedforward_config, dds_unadjustable_config, 1'b0, PLL_MUXOUT, IL_STAT, RF_ON_sync, 1'b0, KCM_load_busy, 1'b0, gray_sample, gray_previous}; wire [15:0] PD_a = ADDR_reg[1] ? (ADDR_reg[0] ? errors : status) : (ADDR_reg[0] ? `PRODUCT_REV : `PRODUCT_ID); wire [15:0] PD_b = ADDR_reg[1] ? ds_read_bus : (ADDR_reg[0] ? ucnt_at_pulse_end : dcnt_at_pulse_end); wire [15:0] PD_c = (ADDR_reg[4:3]!=0) ? (ADDR_reg[4] ? sport_read_bus : SET_I) : (ADDR_reg[2] ? PD_b : PD_a); // All the above decoding and reading is combinatorial based on // static state and ADDR_reg. Pipeline that in a register, // which lines it up with other virtual addresses, stored in RAM, // that need a cycle to "mature". reg [15:0] PD_cr; always @(posedge CLK_host) PD_cr <= PD_c; // Second pipeline stage wire [15:0] PDi = (ADDR_reg[13]|ADDR_reg[12]) ? history_dout : (ADDR_reg[11] ? feedforward_host_dout : (ADDR_reg[5] ? host_timer_odata : PD_cr)) ; // Three-state bus assign PD = host_read_cycle ? PDi : 16'b ZZZZZZZZZZZZZZZZ; // Test points // assign LED2 = host_write_cycle; assign LED3 = RF_ON; assign LED4 = halt; assign DIO1 = test1; assign DIO2 = test2; assign DIO3 = test3; assign DIO4 = test4; assign DIO6 = trig; endmodule