overhaul of interpreter, update ships to match; "make test" works now
[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
9 data  out:   out
10
11 == TeX ==============================================================
12
13 The {\tt Memory} ship represents an interface to a storage space,
14 which can be used to read from it or write to it.  This storage space
15 might be a fast on-chip cache, off chip DRAM, or perhaps even a disk
16 drive.
17
18 Generally, distinct {\tt Memory} ships do not access the same backing
19 storage, although this is not strictly prohibited.
20
21 Each {\tt Memory} ship may have multiple {\it interfaces}, numbered
22 starting with {\tt 0}.  Each interface may have any subset of the
23 following docks: {\tt inCBD}, {\tt inAddrRead}, {\tt inAddrWrite},
24 {\tt inDataWrite}, and {\tt out}.  If {\tt inCBD} or {\tt inAddrRead}
25 is present on an interface, then {\tt out} must be present as well.
26 If {\tt inAddrWrite} is present then {\tt inDataWrite} must be present
27 as well.
28
29 Each interface serializes the operations presented to it; this means
30 that an interface with both read and write capabilities will not be
31 able to read and write concurrently.  Instead, a {\tt Memory} ship
32 with the ability to read and write concurrently should have two
33 interfaces, one which is read-only and one which is write-only.
34
35 There may be multiple {\tt Memory} ships which interface to the same
36 physical storage space.  An implementation of Fleet must provide
37 additional documentation to the programmer indicating which {\tt
38 Memory} ships correspond to which storage spaces.  A single {\tt
39 Memory} ship may also access a ``virtual storage space'' formed by
40 concatenating multiple physical storage spaces.
41
42 \subsection*{Code Bag Fetch}
43
44 When a word appears at the {\tt inCBD} port, it is treated as a {\it
45 code bag descriptor}, as shown below:
46
47 \begin{center}
48 \setlength{\bitwidth}{3mm}
49 {\tt
50 \begin{bytefield}{37}
51   \bitheader[b]{36,6,5,0}\\
52   \bitbox{31}{Address} 
53   \bitbox{6}{size} 
54 \end{bytefield}
55 }
56 \end{center}
57
58 When a word arrives at the {\tt inCBD} port, it is treated as a memory
59 read with {\tt inAddrRead=Address}, {\tt inStride=1}, and {\tt
60 inCount=size}.
61
62 \subsection*{Reading}
63
64 When a word is delivered to {\tt inAddrRead}, the word residing in
65 memory at that address is provided at {\tt out}.  The {\tt c-flag} at
66 the {\tt out} port is set to zero.
67
68 \subsection*{Writing}
69
70 When a word is delivered to {\tt inAddrWrite} and {\tt inDataWrite},
71 the word at {\tt inDataWrite} is written to the address specified by
72 {\tt inAddrWrite}.  Once the word is successfully committed to memory,
73 the value {\tt inAddr+inStride} is provided at {\tt out} (that is, the
74 address of the next word to be written).  The {\tt c-flag} at
75 the {\tt out} port is set to one.
76
77 \subsection*{To Do}
78
79 Stride and count are not implemented.
80
81 We need a way to do an ``unordered fetch'' -- a way to tell the memory
82 unit to retrieve some block of words in any order it likes.  This can
83 considerably accelerate fetches when the first word of the region is
84 not cached, but other parts are cached.  This can also be used for
85 dispatching codebags efficiently -- but how will we make sure that
86 instructions destined for a given pump are dispatched in the correct
87 order (source sequence guarantee)?
88
89 A more advanced form would be ``unordered fetch of ordered records''
90 -- the ability to specify a record size (in words), the offset of the
91 first record, and the number of records to be fetched.  The memory
92 unit would then fetch the records in any order it likes, but would be
93 sure to return the words comprising a record in the order in which
94 they appear in memory.  This feature could be used to solve the source
95 sequence guarantee problem mentioned in the previous paragraph.
96
97 == Fleeterpreter ====================================================
98     private long[] mem = new long[0];
99     public long readMem(int addr) { return addr >= mem.length ? 0 : mem[addr]; }
100     public void writeMem(int addr, long val) {
101         if (addr >= mem.length) {
102             long[] newmem = new long[addr * 2 + 1];
103             System.arraycopy(mem, 0, newmem, 0, mem.length);
104             mem = newmem;
105         }
106         mem[addr] = val;
107     }
108     private Queue<Long> toDispatch = new LinkedList<Long>();
109     public void reset() {
110       super.reset();
111       mem = new long[0];
112       toDispatch.clear();
113     }
114     public void service() {
115         if (toDispatch.size() > 0) {
116             if (!box_out.readyForDataFromShip()) return;
117             box_out.addDataFromShip(toDispatch.remove());
118         }
119         if (box_inCBD.dataReadyForShip()) {
120             long val = box_inCBD.removeDataForShip();
121             long addr = ((Interpreter)getFleet()).CBD_OFFSET.getval(val);
122             long size = ((Interpreter)getFleet()).CBD_SIZE.getval(val);
123             for(int i=0; i<size; i++)
124               toDispatch.add(readMem((int)(addr+i)));
125         } else if (box_inAddrWrite.dataReadyForShip() && box_inDataWrite.dataReadyForShip() && box_out.readyForDataFromShip()) {
126             writeMem((int)box_inAddrWrite.removeDataForShip(), box_inDataWrite.removeDataForShip());
127             box_out.addDataFromShip(0,true);
128         } else if (box_inAddrRead.dataReadyForShip() && box_out.readyForDataFromShip()) {
129             box_out.addDataFromShip(readMem((int)box_inAddrRead.removeDataForShip()),false);
130         }
131     }
132
133 == FleetSim ==============================================================
134
135 == FPGA ==============================================================
136
137   `define BRAM_ADDR_WIDTH 14
138   `define BRAM_SIZE (1<<(`BRAM_ADDR_WIDTH))
139
140   reg    [(`WORDWIDTH-1):0]       ram [((`BRAM_SIZE)-1):0];
141   reg    [(`BRAM_ADDR_WIDTH-1):0] addr1;
142   reg    [(`BRAM_ADDR_WIDTH-1):0] addr2;
143   reg    [(`WORDWIDTH-1):0]       out1;
144   reg    [(`WORDWIDTH-1):0]       out2;
145
146   reg                             out_w;
147   reg                             write_flag;
148   reg [(`BRAM_ADDR_WIDTH-1):0]    cursor;
149   reg [(`CODEBAG_SIZE_BITS-1):0]  counter;
150
151   assign out_d_ = { out_w, out1 };
152
153   // I use "blocking assignment" here in order to facilitate BRAM inferencea
154   always @(posedge clk) begin
155     write_flag = 0;
156
157     if (!rst) begin
158       `reset
159       cursor      = 0;
160       counter     = 0;
161     end else begin
162       `flush
163       `cleanup
164
165       if (counter!=0) begin
166         if (`out_empty) begin
167           `fill_out
168           out_w    = 0;
169           addr1    = cursor;
170           cursor   = cursor  + 1;
171           counter  = counter - 1;
172         end
173
174       end else if (`inCBD_full) begin
175         cursor    = inCBD_d[(`WORDWIDTH-1):(`CODEBAG_SIZE_BITS)];
176         counter   = inCBD_d[(`CODEBAG_SIZE_BITS-1):0];
177         addr1     = cursor;
178         `drain_inCBD
179
180       end else if (`out_empty && `inAddrRead_full) begin
181         addr1     = inAddrRead_d[(`WORDWIDTH-1):0];
182         `drain_inAddrRead
183         `fill_out
184         out_w     = 0;
185
186       end else if (`out_empty && `inAddrWrite_full && `inDataWrite_full) begin
187         write_flag = 1;
188         `drain_inAddrWrite
189         `drain_inDataWrite
190         `fill_out
191         addr2     = inAddrWrite_d[(`WORDWIDTH-1):0];
192         out_w     = 1;
193
194       end
195     end
196
197     // this must appear at the end of the block, outside of any if..then's
198     if (write_flag) 
199       ram[addr2] <= inDataWrite_d; 
200     out1 <= ram[addr1];
201     out2 <= ram[addr2]; 
202   end
203     
204
205
206
207 == Test ==============================================================
208 // Note: this only tests the read/write interfaces, not the inCBD interface
209 // FIXME: test c-flag at out dock
210
211 // expected output
212 #expect 10
213
214 // ships required in order to run this code
215 #ship debug          : Debug
216 #ship memory         : Memory
217
218 memory.inAddrWrite:
219   set word=3;
220   deliver;
221   deliver;
222
223 memory.inDataWrite:
224   set word=4;
225   deliver;
226   set word=10;
227   deliver;
228
229 memory.inAddrRead:
230   recv token;
231   set word=3;
232   deliver;
233
234 memory.out:
235   collect;
236   collect;
237   send token to memory.inAddrRead;
238   collect;
239   send to debug.in;
240
241 debug.in:
242   set ilc=*;
243   recv, deliver;
244
245
246 == Constants ========================================================
247
248 == Contributors =========================================================
249 Adam Megacz <megacz@cs.berkeley.edu>