update ships for 1.0 overhaul
[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 data  out:   outIhorn
13
14 == TeX ==============================================================
15
16 The {\tt Memory} ship represents an interface to a storage space,
17 which can be used to read from it or write to it.  This storage space
18 might be a fast on-chip cache, off chip DRAM, or perhaps even a disk drive.
19
20 There may be multiple {\tt Memory} ships which interface to the same
21 physical storage space.  An implementation of Fleet must provide
22 additional documentation to the programmer indicating which {\tt
23 Memory} ships correspond to which storage spaces.  A single {\tt
24 Memory} ship may also access a ``virtual storage space'' formed by
25 concatenating multiple physical storage spaces.
26
27 \subsection*{Code Bag Fetch}
28
29 When a word appears at the {\tt inCBD} port, it is treated as a {\it
30 code bag descriptor}, as shown below:
31
32 \begin{center}
33 \setlength{\bitwidth}{3mm}
34 {\tt
35 \begin{bytefield}{37}
36   \bitheader[b]{36,6,5,0}\\
37   \bitbox{31}{Address} 
38   \bitbox{6}{size} 
39 \end{bytefield}
40 }
41 \end{center}
42
43 When a word arrives at the {\tt inCBD} port, it is treated as a memory
44 read with {\tt inAddrRead=Address}, {\tt inStride=1}, and {\tt
45 inCount=size}.
46
47 \subsection*{Reading}
48
49 When a word is delivered to {\tt inAddrRead}, the word residing in
50 memory at that address is provided at {\tt out}.
51
52 \subsection*{Writing}
53
54 When a word is delivered to {\tt inAddrWrite} and {\tt inDataWrite},
55 the word at {\tt inDataWrite} is written to the address specified by
56 {\tt inAddrWrite}.  Once the word is successfully committed to memory,
57 the value {\tt inAddr+inStride} is provided at {\tt out} (that is, the
58 address of the next word to be written).
59
60 \subsection*{To Do}
61
62 Stride and count are not implemented.
63
64 We need a way to do an ``unordered fetch'' -- a way to tell the memory
65 unit to retrieve some block of words in any order it likes.  This can
66 considerably accelerate fetches when the first word of the region is
67 not cached, but other parts are cached.  This can also be used for
68 dispatching codebags efficiently -- but how will we make sure that
69 instructions destined for a given pump are dispatched in the correct
70 order (source sequence guarantee)?
71
72 A more advanced form would be ``unordered fetch of ordered records''
73 -- the ability to specify a record size (in words), the offset of the
74 first record, and the number of records to be fetched.  The memory
75 unit would then fetch the records in any order it likes, but would be
76 sure to return the words comprising a record in the order in which
77 they appear in memory.  This feature could be used to solve the source
78 sequence guarantee problem mentioned in the previous paragraph.
79
80 == Fleeterpreter ====================================================
81     private long[] mem = new long[0];
82     public long readMem(int addr) { return addr >= mem.length ? 0 : mem[addr]; }
83     public void writeMem(int addr, long val) {
84         if (addr >= mem.length) {
85             long[] newmem = new long[addr * 2 + 1];
86             System.arraycopy(mem, 0, newmem, 0, mem.length);
87             mem = newmem;
88         }
89         mem[addr] = val;
90     }
91 /*
92     public void dispatch(int addr, int size) {
93         for(int i=addr; i<addr+size; i++) {
94             Instruction instr = ((Interpreter)getFleet()).readInstruction(getFleet().getUniversalSource(), readMem(i));
95             ((Interpreter)getFleet()).dispatch(instr, i);
96         }
97     }
98
99     public void boot(byte[] instructions) {
100         Interpreter fleet = (Interpreter)getFleet();
101         // load the iscratch and take note of the 0-address INCBD
102         long launch = 0;
103         for(int i=0; i<instructions.length; i+=6) {
104             long word = 0;
105             for(int j=0; j<6; j++)
106                 word = (word << 8) | (instructions[i+j] & 0xff);
107             writeMem(i/6, word);
108             if (i==0) launch = word;
109         }
110
111         // dispatch the 0-address INCBD
112         int base = (int)(launch >> 6);
113         base = base & ~(0xffffffff << 18);
114         int size = (int)launch;
115         size = size & ~(0xffffffff <<  6);
116         dispatch(base, size);
117     }
118 */
119     private long stride = 0;
120     private long count = 0;
121     private long addr = 0;
122     private boolean writing = false;
123
124     public void service() {
125 /*
126         if (box_inCBD.dataReadyForShip()) {
127             long val = box_inCBD.removeDataForShip();
128             long addr = val >> 6;
129             long size = val & 0x3f;
130             dispatch((int)addr, (int)size);
131         }
132 */
133         if (count > 0) {
134             if (writing) {
135               if (box_inDataWrite.dataReadyForShip() && box_out.readyForDataFromShip()) {
136                  writeMem((int)addr, box_inDataWrite.removeDataForShip());
137                  box_out.addDataFromShip(0);
138                  count--;
139                  addr += stride;
140               }
141             } else {
142               if (box_out.readyForDataFromShip()) {
143                  box_out.addDataFromShip(readMem((int)addr));
144                  count--;
145                  addr += stride;
146               }
147             }
148
149         } else if (box_inAddrRead.dataReadyForShip()) {
150             addr = box_inAddrRead.removeDataForShip();
151             stride = 0;
152             count = 1;
153             writing = false;
154
155         } else if (box_inAddrWrite.dataReadyForShip()) {
156             addr = box_inAddrWrite.peekPacketForShip().value;
157             box_inAddrWrite.removeDataForShip();
158             stride = 0;
159             count = 1;
160             writing = true;
161         }
162     }
163
164 == FleetSim ==============================================================
165
166 == FPGA ==============================================================
167
168   reg [(`CODEBAG_SIZE_BITS-1):0]  cursor;
169   reg                             write_flag;
170
171   wire [(`BRAM_ADDR_WIDTH-1):0]   addr1;
172   wire [(`BRAM_ADDR_WIDTH-1):0]   addr2;
173   wire [(`BRAM_DATA_WIDTH-1):0]   val2;
174   assign addr1 = write_flag ? inAddrWrite_d[(`DATAWIDTH-1):0] : inAddrRead_d[(`DATAWIDTH-1):0];
175   assign addr2 = (inCBD_d[(`INSTRUCTION_WIDTH-1):(`CODEBAG_SIZE_BITS)])+cursor;
176
177   bram14 mybram(clk, rst, write_flag, addr1, addr2, inDataWrite_d, out_d_, val2);
178
179   always @(posedge clk) begin
180
181     write_flag <= 0;
182
183     if (!rst) begin
184       `reset
185       cursor <= 0;
186     end else begin
187       write_flag <= 0;
188
189       if (!inAddrRead_r  && inAddrRead_a)  inAddrRead_a    <= 0;
190       if (!inDataWrite_r && inDataWrite_a) inDataWrite_a <= 0;
191       if (!inAddrWrite_r && inAddrWrite_a) inAddrWrite_a <= 0;
192
193       if ( out_r && !out_a) begin
194       end else if ( out_r &&  out_a) begin out_r <= 0;
195       end else if (!out_r && !out_a && inAddrRead_r && !inAddrRead_a) begin
196         inAddrRead_a    <= 1;
197         out_r           <= 1;
198   
199       end else if (!out_r && !out_a && inAddrWrite_r && inDataWrite_r) begin
200         // timing note: it's okay to set the *_a flags here because *_d will still
201         // be valid on the *next* cycle, which is all we care about
202         inAddrWrite_a   <= 1;
203         inDataWrite_a   <= 1;
204         out_r           <= 1;
205         write_flag      <= 1;
206   
207       end else if ( outIhorn_r &&  outIhorn_a)                       begin outIhorn_r         <= 0;
208       end else if (!inCBD_r &&  inCBD_a) begin inCBD_a <= 0;
209       end else if ( inCBD_r && !inCBD_a && !outIhorn_r && !outIhorn_a) begin
210         if (cursor < inCBD_d[(`CODEBAG_SIZE_BITS-1):0]) begin
211           outIhorn_d    <= val2;
212           outIhorn_r    <= 1;
213           cursor        <= cursor + 1;
214         end else begin
215           inCBD_a       <= 1;
216           cursor        <= 0;
217         end
218       end
219     end
220   end
221     
222
223
224
225 == Test ==============================================================
226 // expected output
227 #expect 12
228 #expect 13
229 #expect 14
230
231 // ships required in order to run this code
232 #ship debug          : Debug
233 #ship memory         : Memory
234
235 // instructions not in any codebag are part of the "root codebag"
236 // which is dispatched when the code is loaded
237
238 memory.inCBD:
239   literal BOB;
240   deliver;
241
242 BOB: {
243   debug.in:
244     literal 12; deliver;
245     literal 13; deliver;
246     literal 14; deliver;
247 }
248
249
250 == Constants ========================================================
251
252 == Contributors =========================================================
253 Adam Megacz <megacz@cs.berkeley.edu>