module multiboot ( input wire clk, input wire clk_icap, // WARNING: this clock must not be greater than 20MHz (50ns period) input wire rst_n, input wire [7:0] zxuno_addr, input wire zxuno_regwr, input wire [7:0] din ); parameter ADDR_COREADDR = 8'hFC, ADDR_COREBOOT = 8'hFD; reg [23:0] spi_addr = 24'h0AC000; // default: SPI address of second core as defined by the SPI memory map reg writting_to_spi_addr = 1'b0; reg writting_to_bootcore = 1'b0; reg boot_core = 1'b0; always @(posedge clk) begin if (rst_n == 1'b0) begin writting_to_spi_addr <= 1'b0; writting_to_bootcore <= 1'b0; boot_core <= 1'b0; end else begin if (zxuno_addr == ADDR_COREADDR) begin if (zxuno_regwr == 1'b1 && writting_to_spi_addr == 1'b0) begin spi_addr <= {spi_addr[15:0], din}; writting_to_spi_addr <= 1'b1; end if (zxuno_regwr == 1'b0) begin writting_to_spi_addr <= 1'b0; end end else begin writting_to_spi_addr <= 1'b0; end if (zxuno_addr == ADDR_COREBOOT) begin if (zxuno_regwr == 1'b1 && din[0] == 1'b1 && writting_to_bootcore == 1'b0) begin boot_core <= 1'b1; writting_to_bootcore <= 1'b1; end if (writting_to_bootcore == 1'b1) begin boot_core <= 1'b0; end if (zxuno_regwr == 1'b0) begin writting_to_bootcore <= 1'b0; end end else begin boot_core <= 1'b0; writting_to_bootcore <= 1'b0; end end end reg [4:0] q = 5'b00000; reg reboot_ff = 1'b0; always @(posedge clk_icap) begin q[0] <= boot_core; q[1] <= q[0]; q[2] <= q[1]; q[3] <= q[2]; q[4] <= q[3]; reboot_ff <= (q[4] && (!q[3]) && (!q[2]) && (!q[1]) ); end multiboot_spartan6 hacer_multiboot ( .CLK(clk_icap), .MBT_RESET(1'b0), .MBT_REBOOT(reboot_ff), .spi_addr(spi_addr) ); endmodule module multiboot_spartan6 ( input wire CLK, input wire MBT_RESET, input wire MBT_REBOOT, input wire [23:0] spi_addr ); reg [15:0] icap_din; reg icap_ce; reg icap_wr; reg [15:0] ff_icap_din_reversed; reg ff_icap_ce; reg ff_icap_wr; ICAP_SPARTAN6 ICAP_SPARTAN6_inst ( .CE (ff_icap_ce), // Clock enable input .CLK (CLK), // Clock input .I (ff_icap_din_reversed), // 16-bit data input .WRITE (ff_icap_wr) // Write input ); // ------------------------------------------------- // -- State Machine for ICAP_SPARTAN6 MultiBoot -- // ------------------------------------------------- parameter IDLE = 0, SYNC_H = 1, SYNC_L = 2, CWD_H = 3, CWD_L = 4, GEN1_H = 5, GEN1_L = 6, GEN2_H = 7, GEN2_L = 8, GEN3_H = 9, GEN3_L = 10, GEN4_H = 11, GEN4_L = 12, GEN5_H = 13, GEN5_L = 14, NUL_H = 15, NUL_L = 16, MOD_H = 17, MOD_L = 18, HCO_H = 19, HCO_L = 20, RBT_H = 21, RBT_L = 22, NOOP_0 = 23, NOOP_1 = 24, NOOP_2 = 25, NOOP_3 = 26; reg [4:0] state; reg [4:0] next_state; always @* begin: COMB case (state) IDLE: begin if (MBT_REBOOT) begin next_state = SYNC_H; icap_ce = 0; icap_wr = 0; icap_din = 16'hAA99; // Sync word 1 end else begin next_state = IDLE; icap_ce = 1; icap_wr = 1; icap_din = 16'hFFFF; // Null end end SYNC_H: begin next_state = SYNC_L; icap_ce = 0; icap_wr = 0; icap_din = 16'h5566; // Sync word 2 end SYNC_L: begin next_state = NUL_H; icap_ce = 0; icap_wr = 0; icap_din = 16'h30A1; // Write to Command Register.... end NUL_H: begin // next_state = NUL_L; next_state = GEN1_H; icap_ce = 0; icap_wr = 0; icap_din = 16'h0000; // Null Command issued.... value = 0x0000 end //Q GEN1_H: begin next_state = GEN1_L; icap_ce = 0; icap_wr = 0; icap_din = 16'h3261; // Escritura a reg GENERAL_1 (bit boot en caliente) end GEN1_L: begin next_state = GEN2_H; icap_ce = 0; icap_wr = 0; icap_din = spi_addr[15:0]; //16'hC000; // dreccion SPI BAJA end GEN2_H: begin next_state = GEN2_L; icap_ce = 0; icap_wr = 0; icap_din = 16'h3281; // Escritura a reg GENERAL_2 end GEN2_L: begin next_state = MOD_H; icap_ce = 0; icap_wr = 0; icap_din = {8'h6B, spi_addr[23:16]}; // 16'h030A; // 03 lectura SPI opcode + direccion SPI ALTA (03 = 1x, 6B = 4x) end /////// Registro MODE (para carga a 4x tras reboot) MOD_H: begin next_state = MOD_L; icap_ce = 0; icap_wr = 0; icap_din = 16'h3301; // Escritura a reg MODE end MOD_L: begin next_state = NUL_L; icap_ce = 0; icap_wr = 0; icap_din = 16'h3100; // Activamos bit de lectura a modo 4x en el proceso de Config end ///// NUL_L: begin next_state = RBT_H; icap_ce = 0; icap_wr = 0; icap_din = 16'h30A1; // Write to Command Register.... end RBT_H: begin next_state = RBT_L; icap_ce = 0; icap_wr = 0; icap_din = 16'h000E; // REBOOT Command 0x000E end //-------------------- RBT_L: begin next_state = NOOP_0; icap_ce = 0; icap_wr = 0; icap_din = 16'h2000; // NOOP end NOOP_0: begin next_state = NOOP_1; icap_ce = 0; icap_wr = 0; icap_din = 16'h2000; // NOOP end NOOP_1: begin next_state = NOOP_2; icap_ce = 0; icap_wr = 0; icap_din = 16'h2000; // NOOP end NOOP_2: begin next_state = NOOP_3; icap_ce = 0; icap_wr = 0; icap_din = 16'h2000; // NOOP end //-------------------- NOOP_3: begin next_state = IDLE; icap_ce = 1; icap_wr = 1; icap_din = 16'h1111; // NULL value end default: begin next_state = IDLE; icap_ce = 1; icap_wr = 1; icap_din = 16'h1111; // 16'h1111" end endcase end always @(posedge CLK) begin: SEQ if (MBT_RESET) state <= IDLE; else state <= next_state; end always @(posedge CLK) begin: ICAP_FF ff_icap_din_reversed[0] <= icap_din[7]; //need to reverse bits to ICAP module since D0 bit is read first ff_icap_din_reversed[1] <= icap_din[6]; ff_icap_din_reversed[2] <= icap_din[5]; ff_icap_din_reversed[3] <= icap_din[4]; ff_icap_din_reversed[4] <= icap_din[3]; ff_icap_din_reversed[5] <= icap_din[2]; ff_icap_din_reversed[6] <= icap_din[1]; ff_icap_din_reversed[7] <= icap_din[0]; ff_icap_din_reversed[8] <= icap_din[15]; ff_icap_din_reversed[9] <= icap_din[14]; ff_icap_din_reversed[10] <= icap_din[13]; ff_icap_din_reversed[11] <= icap_din[12]; ff_icap_din_reversed[12] <= icap_din[11]; ff_icap_din_reversed[13] <= icap_din[10]; ff_icap_din_reversed[14] <= icap_din[9]; ff_icap_din_reversed[15] <= icap_din[8]; ff_icap_ce <= icap_ce; ff_icap_wr <= icap_wr; end endmodule