updated wiki url
[debian/gnuradio] / usrp2 / fpga / control_lib / ram_loader.v
1
2 // Adapted from VHDL code in spi_boot by Arnim Legauer
3 //  Added a full wishbone master interface (32-bit)
4
5 module ram_loader #(parameter AWIDTH=16, RAM_SIZE=16384)
6   (input clk_i, input rst_i,
7    // CPLD Interface
8    input cfg_clk_i, input cfg_data_i,
9    output start_o, output mode_o, output done_o,
10    input detached_i,
11    // Wishbone interface
12    output wire [31:0] wb_dat_o,
13    output reg [AWIDTH-1:0] wb_adr_o,
14    output wb_stb_o,
15    output wb_cyc_o,
16    output reg [3:0] wb_sel_o,
17    output reg wb_we_o,
18    input wb_ack_i,
19    output ram_loader_done_o);
20    
21    //  FSM to control start signal, clocked on main clock
22    localparam FSM1_WAIT_DETACH = 2'b00;
23    localparam FSM1_CHECK_NO_DONE = 2'b01;
24    localparam FSM1_WAIT_DONE = 2'b10;
25    
26    reg [1:0]  start_fsm_q, start_fsm_s;
27    reg        start_q, enable_q, start_s, enable_s;
28    reg        done_q, done_s;
29    
30    always @(posedge clk_i or posedge rst_i)
31      if(rst_i)
32        begin
33           start_fsm_q <= FSM1_WAIT_DETACH;
34           start_q <= 1'b0;
35           enable_q <= 1'b0;
36        end
37      else
38        begin
39           start_fsm_q <= start_fsm_s;
40           enable_q <= enable_s;
41           start_q <= start_s;
42        end // else: !if(rst_i)
43    
44    always @*
45      case(start_fsm_q)
46        FSM1_WAIT_DETACH:
47          if(detached_i == 1'b1)
48            begin
49               start_fsm_s <= FSM1_CHECK_NO_DONE;
50               enable_s <= 1'b1;
51               start_s <= 1'b1;
52            end
53          else
54            begin
55               start_fsm_s <= FSM1_WAIT_DETACH;
56               enable_s <= enable_q;
57               start_s <= start_q;
58            end // else: !if(detached_i == 1'b1)
59        FSM1_CHECK_NO_DONE:
60          if(~done_q)
61            begin
62               start_fsm_s  <= FSM1_WAIT_DONE;
63               enable_s <= enable_q;
64               start_s <= start_q;
65            end
66          else
67            begin
68               start_fsm_s  <= FSM1_CHECK_NO_DONE;
69               enable_s <= enable_q;
70               start_s <= start_q;
71            end // else: !if(~done_q)
72        FSM1_WAIT_DONE:
73          if(done_q)
74            begin
75               start_fsm_s  <= FSM1_WAIT_DETACH;
76               enable_s <= 1'b0;
77               start_s <= 1'b0;
78            end
79          else
80            begin
81               start_fsm_s  <= FSM1_WAIT_DONE;
82               enable_s <= enable_q;
83               start_s <= start_q;
84            end // else: !if(done_q)
85        default:
86          begin
87             start_fsm_s  <= FSM1_WAIT_DETACH;
88             enable_s <= enable_q;
89             start_s <= start_q;
90          end // else: !if(done_q)
91      endcase // case(start_fsm_q)
92    
93    //  FSM running on data clock
94
95    localparam FSM2_IDLE = 3'b000;
96    localparam FSM2_WE_ON = 3'b001;
97    localparam FSM2_WE_OFF = 3'b010;
98    localparam FSM2_INC_ADDR1 = 3'b011;
99    localparam FSM2_INC_ADDR2 = 3'b100;
100    localparam FSM2_FINISHED = 3'b101;
101    
102    reg [AWIDTH-1:0] addr_q;
103    reg [7:0]        shift_dat_q, ser_dat_q;
104    reg [2:0]        bit_q, fsm_q, fsm_s;
105    reg              bit_ovfl_q, ram_we_s, ram_we_q, mode_q, mode_s, inc_addr_s;
106    
107    always @(posedge cfg_clk_i or posedge rst_i)
108      if(rst_i)
109        begin
110           addr_q <= 0;
111           shift_dat_q <= 8'd0;
112           ser_dat_q <= 8'd0;
113           bit_q <= 3'd0;
114           bit_ovfl_q <= 1'b0;
115           fsm_q <= FSM2_IDLE;
116           ram_we_q <= 1'b0;
117           done_q <= 1'b0;
118           mode_q <= 1'b0;
119        end
120      else
121        begin
122           if(inc_addr_s)
123             addr_q <= addr_q + 1;
124           if(enable_q)
125             begin
126                bit_q <= bit_q + 1;
127                bit_ovfl_q <= (bit_q == 3'd7);
128                shift_dat_q[0] <= cfg_data_i;
129                shift_dat_q[7:1] <= shift_dat_q[6:0];
130             end
131           if(bit_ovfl_q)
132             ser_dat_q <= shift_dat_q;
133
134           fsm_q <= fsm_s;
135
136           ram_we_q <= ram_we_s;
137
138           if(done_s)
139             done_q <= 1'b1;
140           mode_q <= mode_s;
141        end // else: !if(rst_i)
142
143    always @*
144      begin
145         inc_addr_s <= 1'b0;
146         ram_we_s <= 1'b0;
147         done_s <= 1'b0;
148         fsm_s <= FSM2_IDLE;
149         mode_s <= 1'b0;
150
151         case(fsm_q)
152           FSM2_IDLE :
153             if(start_q)
154               if(bit_ovfl_q)
155                 fsm_s <= FSM2_WE_ON;
156           FSM2_WE_ON:
157             begin
158                ram_we_s <= 1'b1;
159                fsm_s <= FSM2_WE_OFF;
160             end
161           FSM2_WE_OFF:
162             begin
163                ram_we_s <= 1'b1;
164                fsm_s <= FSM2_INC_ADDR1;
165             end
166           FSM2_INC_ADDR1:
167             fsm_s <= FSM2_INC_ADDR2;
168           FSM2_INC_ADDR2:
169             if(addr_q == (RAM_SIZE-1))
170             //if(&addr_q)
171               begin
172                  fsm_s <= FSM2_FINISHED;
173                  done_s <= 1'b1;
174                  mode_s <= 1'b1;
175               end
176             else
177               begin
178                  inc_addr_s <= 1'b1;
179                  fsm_s <= FSM2_IDLE;
180               end // else: !if(&addr_q)
181           FSM2_FINISHED:
182             begin
183                fsm_s <= FSM2_FINISHED;
184                mode_s <= 1'b1;
185             end
186         endcase // case(fsm_q)
187      end // always @ *
188    
189    assign start_o = start_q;
190    assign mode_o = mode_q;
191    assign done_o = start_q ? done_q : 1'b1;
192    wire [AWIDTH-1:0] ram_addr = addr_q;
193    wire [7:0] ram_data = ser_dat_q;
194    assign ram_loader_done_o = (fsm_q == FSM2_FINISHED);
195    
196    // wishbone master, only writes
197    reg [7:0] dat_holder;
198    assign    wb_dat_o = {4{dat_holder}};
199    assign    wb_stb_o = wb_we_o;
200    assign    wb_cyc_o = wb_we_o;
201    
202    always @(posedge clk_i or posedge rst_i)
203      if(rst_i)
204        begin
205           dat_holder <= 8'd0;
206           wb_adr_o <= 0;
207           wb_sel_o <= 4'b0000;
208           wb_we_o <= 1'b0;
209        end
210      else if(ram_we_q)
211        begin
212           dat_holder <= ram_data;
213           wb_adr_o <= ram_addr;
214           wb_we_o <= 1'b1;
215           case(ram_addr[1:0])   // Big Endian
216             2'b00 : wb_sel_o <= 4'b1000;
217             2'b01 : wb_sel_o <= 4'b0100;
218             2'b10 : wb_sel_o <= 4'b0010;
219             2'b11 : wb_sel_o <= 4'b0001;
220           endcase // case(ram_addr[1:0])
221        end // if (ram_we_q)
222      else if(wb_ack_i)
223        wb_we_o <= 1'b0;
224       
225 endmodule // ram_loader