more reset code
[fleet.git] / ships / Memory.ship
1 ship: Memory
2
3 == Ports ===========================================================
4 data  in:    inCBD
5 data  in:    inAddrRead
6 data  in:    inAddrWrite
7 data  in:    inDataWrite
8 data  in:    inStride
9 data  in:    inCount
10
11 data  out:   out
12
13 == TeX ==============================================================
14
15 The {\tt Memory} ship represents an interface to a storage space,
16 which can be used to read from it or write to it.  This storage space
17 might be a fast on-chip cache, off chip DRAM, or perhaps even a disk drive.
18
19 There may be multiple {\tt Memory} ships which interface to the same
20 physical storage space.  An implementation of Fleet must provide
21 additional documentation to the programmer indicating which {\tt
22 Memory} ships correspond to which storage spaces.  A single {\tt
23 Memory} ship may also access a ``virtual storage space'' formed by
24 concatenating multiple physical storage spaces.
25
26 \subsection*{Code Bag Fetch}
27
28 When a word appears at the {\tt inCBD} port, it is treated as a {\it
29 code bag descriptor}, as shown below:
30
31 \begin{center}
32 \setlength{\bitwidth}{3mm}
33 {\tt
34 \begin{bytefield}{37}
35   \bitheader[b]{36,6,5,0}\\
36   \bitbox{31}{Address} 
37   \bitbox{6}{size} 
38 \end{bytefield}
39 }
40 \end{center}
41
42 When a word arrives at the {\tt inCBD} port, it is treated as a memory
43 read with {\tt inAddrRead=Address}, {\tt inStride=1}, and {\tt
44 inCount=size}.
45
46 \subsection*{Reading}
47
48 When a word is delivered to {\tt inAddrRead}, the word residing in
49 memory at that address is provided at {\tt out}.
50
51 \subsection*{Writing}
52
53 When a word is delivered to {\tt inAddrWrite} and {\tt inDataWrite},
54 the word at {\tt inDataWrite} is written to the address specified by
55 {\tt inAddrWrite}.  Once the word is successfully committed to memory,
56 the value {\tt inAddr+inStride} is provided at {\tt out} (that is, the
57 address of the next word to be written).
58
59 \subsection*{To Do}
60
61 Stride and count are not implemented.
62
63 We need a way to do an ``unordered fetch'' -- a way to tell the memory
64 unit to retrieve some block of words in any order it likes.  This can
65 considerably accelerate fetches when the first word of the region is
66 not cached, but other parts are cached.  This can also be used for
67 dispatching codebags efficiently -- but how will we make sure that
68 instructions destined for a given pump are dispatched in the correct
69 order (source sequence guarantee)?
70
71 A more advanced form would be ``unordered fetch of ordered records''
72 -- the ability to specify a record size (in words), the offset of the
73 first record, and the number of records to be fetched.  The memory
74 unit would then fetch the records in any order it likes, but would be
75 sure to return the words comprising a record in the order in which
76 they appear in memory.  This feature could be used to solve the source
77 sequence guarantee problem mentioned in the previous paragraph.
78
79 == Fleeterpreter ====================================================
80     private long[] mem = new long[0];
81     public long readMem(int addr) { return mem[addr]; }
82     public void writeMem(int addr, long val) {
83         if (addr >= mem.length) {
84             long[] newmem = new long[addr * 2 + 1];
85             System.arraycopy(mem, 0, newmem, 0, mem.length);
86             mem = newmem;
87         }
88         mem[addr] = val;
89     }
90
91     public void dispatch(int addr, int size) {
92         for(int i=addr; i<addr+size; i++) {
93             Instruction instr = ((Interpreter)getFleet()).readInstruction(readMem(i));
94             ((Interpreter)getFleet()).dispatch(instr, i);
95         }
96     }
97
98     public void boot(byte[] instructions) {
99         Interpreter fleet = (Interpreter)getFleet();
100         // load the iscratch and take note of the 0-address INCBD
101         long launch = 0;
102         for(int i=0; i<instructions.length; i+=6) {
103             long word = 0;
104             for(int j=0; j<6; j++)
105                 word = (word << 8) | (instructions[i+j] & 0xff);
106             writeMem(i/6, word);
107             if (i==0) launch = word;
108         }
109
110         // dispatch the 0-address INCBD
111         int base = (int)(launch >> 6);
112         base = base & ~(0xffffffff << 18);
113         int size = (int)launch;
114         size = size & ~(0xffffffff <<  6);
115         dispatch(base, size);
116     }
117
118     private long stride = 0;
119     private long count = 0;
120     private long addr = 0;
121     private boolean writing = false;
122
123     public void service() {
124         if (box_inCBD.dataReadyForShip()) {
125             long val = box_inCBD.removeDataForShip();
126             long addr = val >> 6;
127             long size = val & 0x3f;
128             dispatch((int)addr, (int)size);
129         }
130         if (count > 0) {
131             if (writing) {
132               if (box_inDataWrite.dataReadyForShip() && box_out.readyForDataFromShip()) {
133                  writeMem((int)addr, box_inDataWrite.removeDataForShip());
134                  box_out.addDataFromShip(0);
135                  count--;
136                  addr += stride;
137               }
138             } else {
139               if (box_out.readyForDataFromShip()) {
140                  box_out.addDataFromShip(readMem((int)addr));
141                  count--;
142                  addr += stride;
143               }
144             }
145
146         } else if (box_inAddrRead.dataReadyForShip()) {
147             addr = box_inAddrRead.removeDataForShip();
148             stride = 0;
149             count = 1;
150             writing = false;
151
152         } else if (box_inAddrWrite.dataReadyForShip()) {
153             addr = box_inAddrWrite.peekPacketForShip().value;
154             box_inAddrWrite.removeDataForShip();
155             stride = 0;
156             count = 1;
157             writing = true;
158         }
159     }
160
161 == FleetSim ==============================================================
162
163 == FPGA ==============================================================
164 `include "macros.v"
165 `define BRAM_ADDR_WIDTH 14
166 `define BRAM_DATA_WIDTH `INSTRUCTION_WIDTH
167 `define BRAM_NAME some_bram
168
169 /* bram.inc */
170 module `BRAM_NAME(clk, rst, we, a, dpra, di, spo, dpo); 
171     input  clk; 
172     input  rst; 
173     input  we; 
174     input  [(`BRAM_ADDR_WIDTH-1):0] a; 
175     input  [(`BRAM_ADDR_WIDTH-1):0] dpra; 
176     input  [(`BRAM_DATA_WIDTH-1):0] di; 
177     output [(`BRAM_DATA_WIDTH-1):0] spo; 
178     output [(`BRAM_DATA_WIDTH-1):0] dpo; 
179     reg    [(`BRAM_DATA_WIDTH-1):0] ram [((1<<(`BRAM_ADDR_WIDTH))-1):0];
180     reg    [(`BRAM_ADDR_WIDTH-1):0] read_a; 
181     reg    [(`BRAM_ADDR_WIDTH-1):0] read_dpra; 
182     always @(posedge clk) begin 
183         if (we) 
184             ram[a] <= di; 
185         read_a <= a; 
186         read_dpra <= dpra; 
187     end
188     assign spo = ram[read_a]; 
189     assign dpo = ram[read_dpra]; 
190 endmodule 
191 /* bram.inc */
192
193 module memory (clk, rst,
194                cbd_r,          cbd_a_,         cbd_d,
195                in_addr_r,      in_addr_a_,     in_addr_d,
196                write_addr_r,   write_addr_a_,  write_addr_d,
197                write_data_r,   write_data_a_,  write_data_d,
198                stride_r,       stride_a_,      stride_d,
199                count_r,        count_a_,       count_d,
200                out_r_,         out_a,          out_d_,
201                preload_r,      preload_a_,     preload_d,
202                ihorn_r_,       ihorn_a,        ihorn_d_,
203                dhorn_r_,       dhorn_a,        dhorn_d_
204               );
205
206   input  clk;
207   input  rst;
208   `input(in_addr_r,      in_addr_a,     in_addr_a_,     [(2+`DATAWIDTH-1):0],       in_addr_d)
209   `input(write_addr_r,   write_addr_a,  write_addr_a_,  [(2+`DATAWIDTH-1):0],       write_addr_d)
210   `input(write_data_r,   write_data_a,  write_data_a_,  [(`DATAWIDTH-1):0],         write_data_d)
211   `input(stride_r,       stride_a,      stride_a_,      [(`DATAWIDTH-1):0],         stride_d)
212   `input(count_r,        count_a,       count_a_,       [(`DATAWIDTH-1):0],         count_d)
213   `output(out_r,         out_r_,        out_a,          [(`DATAWIDTH-1):0],         out_d_)
214   `input(preload_r,      preload_a,     preload_a_,     [(`DATAWIDTH-1):0],         preload_d)
215   `input(cbd_r,          cbd_a,         cbd_a_,         [(`DATAWIDTH-1):0],         cbd_d)
216   `output(ihorn_r,       ihorn_r_,      ihorn_a,        [(`PACKET_WIDTH-1):0], ihorn_d_)
217   `defreg(ihorn_d_,                                     [(`PACKET_WIDTH-1):0], ihorn_d)
218   `output(dhorn_r,       dhorn_r_,      dhorn_a,        [(`PACKET_WIDTH-1):0],      dhorn_d_)
219   `defreg(dhorn_d_,                                     [(`PACKET_WIDTH-1):0],      dhorn_d)
220
221   reg ihorn_full;
222   initial ihorn_full = 0;
223   reg dhorn_full;
224   initial dhorn_full = 0;
225   reg command_valid;
226   initial command_valid = 0;
227
228   reg [(`BRAM_ADDR_WIDTH-1):0]    preload_pos;
229   reg [(`BRAM_ADDR_WIDTH-1):0]    preload_size;
230   initial preload_size = 0;
231
232   reg [(`BRAM_ADDR_WIDTH-1):0]    current_instruction_read_from;
233   reg [(`BRAM_ADDR_WIDTH-1):0]    temp_base;
234   reg [(`CODEBAG_SIZE_BITS-1):0]  temp_size;
235   reg [(`BRAM_ADDR_WIDTH-1):0]    cbd_base;
236   reg [(`CODEBAG_SIZE_BITS-1):0]  cbd_size;
237   reg [(`CODEBAG_SIZE_BITS-1):0]  cbd_pos;
238   reg [(`INSTRUCTION_WIDTH-1):0]  command;
239   reg [(`BRAM_DATA_WIDTH-1):0]    ram [((1<<(`BRAM_ADDR_WIDTH))-1):0];
240   reg                             send_done;
241   reg                             send_read;
242
243   reg [(`INSTRUCTION_WIDTH-(2+`DESTINATION_ADDRESS_BITS)):0] temp;
244   reg [(`DATAWIDTH-1):0]                                     data;
245
246   reg                             write_flag;
247   reg [(`BRAM_ADDR_WIDTH-1):0]    in_addr;
248   reg [(`BRAM_DATA_WIDTH-1):0]    write_data;
249
250   wire [(`BRAM_DATA_WIDTH-1):0]   ramread;
251
252   reg command_valid_read;
253   initial command_valid_read = 0;
254
255   reg launched;
256   initial launched = 0;
257
258   some_bram mybram(clk, rst, write_flag, in_addr, current_instruction_read_from, write_data, not_connected, ramread);
259   assign out_d_ = ramread;
260
261   always @(posedge clk /*or negedge rst*/) begin
262
263     if (!rst) begin
264
265 /*
266       in_addr_a = 1;
267       write_addr_a = 1;
268       write_data_a = 1;
269       stride_a <= 1;
270       count_a <= 1;
271       preload_a <= 1;
272       cbd_a <= 1;
273 */
274       out_r <= 0;
275       ihorn_r <= 0;
276       dhorn_r <= 0;
277
278       ihorn_full <= 0;
279       dhorn_full <= 0;
280       command_valid <= 0;
281
282       // uncommenting either of these causes headaches
283       preload_size <= 0;
284       preload_pos <= 0;
285       temp_base = 0;
286       temp_size = 0;
287
288       launched <= 0;
289       command_valid_read <= 0;
290       write_flag <= 0;
291
292       dhorn_r <= 0;
293       ihorn_r <= 0;
294       out_r <= 0;
295     end else begin
296
297     write_flag <= 0;
298
299     if (!in_addr_r && in_addr_a) in_addr_a = 0;
300     if (!write_data_r && write_data_a) write_data_a = 0;
301     if (!write_addr_r && write_addr_a) write_addr_a = 0;
302
303     if (command_valid_read) begin
304       command_valid_read  <= 0;
305       command_valid       <= 1;
306
307     end else  if (send_done) begin
308       `onwrite(out_r, out_a)
309         send_done <= 0;
310       end
311
312     end else  if (send_read) begin
313       `onwrite(out_r, out_a)
314         send_read <= 0;
315       end
316
317     end else if (in_addr_r) begin
318       in_addr_a                        = 1;
319       send_read                       <= 1;
320       current_instruction_read_from   <= in_addr_d[(`DATAWIDTH-1):0];
321
322     end else if (write_addr_r && write_data_r) begin
323       write_addr_a       = 1;
324       write_data_a       = 1;
325       send_done         <= 1;
326       write_flag        <= 1;
327       in_addr           <= write_addr_d[(`DATAWIDTH-1):0];
328       write_data        <= write_data_d;
329
330     end else if (ihorn_full && launched) begin
331       `onwrite(ihorn_r, ihorn_a)
332         ihorn_full <= 0;
333       end
334
335     end else if (dhorn_full) begin
336       `onwrite(dhorn_r, dhorn_a)
337         dhorn_full <= 0;
338       end
339
340     end else if (command_valid) begin
341       command_valid <= 0;
342       command = ramread;
343       ihorn_full  <= 1;
344       `packet_data(ihorn_d) <= `instruction_data(command);
345       `packet_dest(ihorn_d) <= `instruction_dest(command);
346
347     end else if (cbd_pos < cbd_size) begin
348       current_instruction_read_from <= cbd_base+cbd_pos;
349       command_valid_read            <= 1;
350       cbd_pos                       <= cbd_pos + 1;
351
352     end else begin
353       `onread(cbd_r, cbd_a)
354         cbd_pos       <= 0;
355         cbd_size      <= cbd_d[(`CODEBAG_SIZE_BITS-1):0];
356         cbd_base      <= cbd_d[(`INSTRUCTION_WIDTH-1):(`CODEBAG_SIZE_BITS)];
357
358       end else begin
359         `onread(preload_r, preload_a)
360           if (preload_size == 0) begin
361             preload_size     <= preload_d;
362             preload_pos      <= 0;
363           end else if (!launched) begin
364             write_flag <= 1;
365             write_data <= preload_d;
366             in_addr <= preload_pos;
367             if (preload_pos == 0) begin
368               temp_base = preload_d[(`INSTRUCTION_WIDTH-(3+`DESTINATION_ADDRESS_BITS)):(`CODEBAG_SIZE_BITS)];
369               temp_size = preload_d[(`CODEBAG_SIZE_BITS-1):0];
370             end
371             if ((preload_pos+1) == preload_size) begin
372               cbd_pos  <= 0;
373               cbd_base <= temp_base;
374               cbd_size <= temp_size;
375               launched <= 1;
376             end
377             preload_pos      <= preload_pos + 1;
378           end
379         end
380       end
381
382     end
383
384     end
385   end
386 endmodule
387
388   
389
390
391
392 == Test ==============================================================
393 // expected output
394 #expect 12
395 #expect 13
396 #expect 14
397
398 // ships required in order to run this code
399 #ship debug          : Debug
400 #ship memory         : Memory
401
402 // instructions not in any codebag are part of the "root codebag"
403 // which is dispatched when the code is loaded
404
405 memory.inCBD:
406   literal BOB;
407   deliver;
408
409 BOB: {
410   debug.in:
411     literal 12; deliver;
412     literal 13; deliver;
413     literal 14; deliver;
414 }
415
416
417 == Constants ========================================================
418
419 == Contributors =========================================================
420 Adam Megacz <megacz@cs.berkeley.edu>