// Adapted from VHDL code in spi_boot by Arnim Legauer // Added a full wishbone master interface (32-bit) module ram_loader #(parameter AWIDTH=16, RAM_SIZE=16384) (input clk_i, input rst_i, // CPLD Interface input cfg_clk_i, input cfg_data_i, output start_o, output mode_o, output done_o, input detached_i, // Wishbone interface output wire [31:0] wb_dat_o, output reg [AWIDTH-1:0] wb_adr_o, output wb_stb_o, output wb_cyc_o, output reg [3:0] wb_sel_o, output reg wb_we_o, input wb_ack_i, output ram_loader_done_o); // FSM to control start signal, clocked on main clock localparam FSM1_WAIT_DETACH = 2'b00; localparam FSM1_CHECK_NO_DONE = 2'b01; localparam FSM1_WAIT_DONE = 2'b10; reg [1:0] start_fsm_q, start_fsm_s; reg start_q, enable_q, start_s, enable_s; reg done_q, done_s; always @(posedge clk_i or posedge rst_i) if(rst_i) begin start_fsm_q <= FSM1_WAIT_DETACH; start_q <= 1'b0; enable_q <= 1'b0; end else begin start_fsm_q <= start_fsm_s; enable_q <= enable_s; start_q <= start_s; end // else: !if(rst_i) always @* case(start_fsm_q) FSM1_WAIT_DETACH: if(detached_i == 1'b1) begin start_fsm_s <= FSM1_CHECK_NO_DONE; enable_s <= 1'b1; start_s <= 1'b1; end else begin start_fsm_s <= FSM1_WAIT_DETACH; enable_s <= enable_q; start_s <= start_q; end // else: !if(detached_i == 1'b1) FSM1_CHECK_NO_DONE: if(~done_q) begin start_fsm_s <= FSM1_WAIT_DONE; enable_s <= enable_q; start_s <= start_q; end else begin start_fsm_s <= FSM1_CHECK_NO_DONE; enable_s <= enable_q; start_s <= start_q; end // else: !if(~done_q) FSM1_WAIT_DONE: if(done_q) begin start_fsm_s <= FSM1_WAIT_DETACH; enable_s <= 1'b0; start_s <= 1'b0; end else begin start_fsm_s <= FSM1_WAIT_DONE; enable_s <= enable_q; start_s <= start_q; end // else: !if(done_q) default: begin start_fsm_s <= FSM1_WAIT_DETACH; enable_s <= enable_q; start_s <= start_q; end // else: !if(done_q) endcase // case(start_fsm_q) // FSM running on data clock localparam FSM2_IDLE = 3'b000; localparam FSM2_WE_ON = 3'b001; localparam FSM2_WE_OFF = 3'b010; localparam FSM2_INC_ADDR1 = 3'b011; localparam FSM2_INC_ADDR2 = 3'b100; localparam FSM2_FINISHED = 3'b101; reg [AWIDTH-1:0] addr_q; reg [7:0] shift_dat_q, ser_dat_q; reg [2:0] bit_q, fsm_q, fsm_s; reg bit_ovfl_q, ram_we_s, ram_we_q, mode_q, mode_s, inc_addr_s; always @(posedge cfg_clk_i or posedge rst_i) if(rst_i) begin addr_q <= 0; shift_dat_q <= 8'd0; ser_dat_q <= 8'd0; bit_q <= 3'd0; bit_ovfl_q <= 1'b0; fsm_q <= FSM2_IDLE; ram_we_q <= 1'b0; done_q <= 1'b0; mode_q <= 1'b0; end else begin if(inc_addr_s) addr_q <= addr_q + 1; if(enable_q) begin bit_q <= bit_q + 1; bit_ovfl_q <= (bit_q == 3'd7); shift_dat_q[0] <= cfg_data_i; shift_dat_q[7:1] <= shift_dat_q[6:0]; end if(bit_ovfl_q) ser_dat_q <= shift_dat_q; fsm_q <= fsm_s; ram_we_q <= ram_we_s; if(done_s) done_q <= 1'b1; mode_q <= mode_s; end // else: !if(rst_i) always @* begin inc_addr_s <= 1'b0; ram_we_s <= 1'b0; done_s <= 1'b0; fsm_s <= FSM2_IDLE; mode_s <= 1'b0; case(fsm_q) FSM2_IDLE : if(start_q) if(bit_ovfl_q) fsm_s <= FSM2_WE_ON; FSM2_WE_ON: begin ram_we_s <= 1'b1; fsm_s <= FSM2_WE_OFF; end FSM2_WE_OFF: begin ram_we_s <= 1'b1; fsm_s <= FSM2_INC_ADDR1; end FSM2_INC_ADDR1: fsm_s <= FSM2_INC_ADDR2; FSM2_INC_ADDR2: if(addr_q == (RAM_SIZE-1)) //if(&addr_q) begin fsm_s <= FSM2_FINISHED; done_s <= 1'b1; mode_s <= 1'b1; end else begin inc_addr_s <= 1'b1; fsm_s <= FSM2_IDLE; end // else: !if(&addr_q) FSM2_FINISHED: begin fsm_s <= FSM2_FINISHED; mode_s <= 1'b1; end endcase // case(fsm_q) end // always @ * assign start_o = start_q; assign mode_o = mode_q; assign done_o = start_q ? done_q : 1'b1; wire [AWIDTH-1:0] ram_addr = addr_q; wire [7:0] ram_data = ser_dat_q; assign ram_loader_done_o = (fsm_q == FSM2_FINISHED); // wishbone master, only writes reg [7:0] dat_holder; assign wb_dat_o = {4{dat_holder}}; assign wb_stb_o = wb_we_o; assign wb_cyc_o = wb_we_o; always @(posedge clk_i or posedge rst_i) if(rst_i) begin dat_holder <= 8'd0; wb_adr_o <= 0; wb_sel_o <= 4'b0000; wb_we_o <= 1'b0; end else if(ram_we_q) begin dat_holder <= ram_data; wb_adr_o <= ram_addr; wb_we_o <= 1'b1; case(ram_addr[1:0]) // Big Endian 2'b00 : wb_sel_o <= 4'b1000; 2'b01 : wb_sel_o <= 4'b0100; 2'b10 : wb_sel_o <= 4'b0010; 2'b11 : wb_sel_o <= 4'b0001; endcase // case(ram_addr[1:0]) end // if (ram_we_q) else if(wb_ack_i) wb_we_o <= 1'b0; endmodule // ram_loader