summaryrefslogtreecommitdiffstats
path: root/control_lib/ram_loader.v
diff options
context:
space:
mode:
Diffstat (limited to 'control_lib/ram_loader.v')
-rw-r--r--control_lib/ram_loader.v225
1 files changed, 225 insertions, 0 deletions
diff --git a/control_lib/ram_loader.v b/control_lib/ram_loader.v
new file mode 100644
index 000000000..cb67de739
--- /dev/null
+++ b/control_lib/ram_loader.v
@@ -0,0 +1,225 @@
+
+// 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