finish overhaul of interpreter
[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     private long stride = 0;
93     private long count = 0;
94     private long addr = 0;
95     private boolean writing = false;
96
97     private Queue<Long> toDispatch = new LinkedList<Long>();
98     public void service() {
99
100         if (toDispatch.size() > 0) {
101             //if (!box_out.readyForDataFromShip()) return;
102             //box_out.addDataFromShip(toDispatch.remove());
103             getInterpreter().dispatch(getInterpreter().readInstruction(toDispatch.remove(), getDock("out")));
104         }
105
106         if (box_inCBD.dataReadyForShip() && box_out.readyForDataFromShip()) {
107             long val = box_inCBD.removeDataForShip();
108             long addr = val >> 6;
109             long size = val & 0x3f;
110             for(int i=0; i<size; i++)
111               toDispatch.add(readMem((int)(addr+i)));
112         }
113         if (count > 0) {
114             if (writing) {
115               if (box_inDataWrite.dataReadyForShip() && box_out.readyForDataFromShip()) {
116                  writeMem((int)addr, box_inDataWrite.removeDataForShip());
117                  box_out.addDataFromShip(0);
118                  count--;
119                  addr += stride;
120               }
121             } else {
122               if (box_out.readyForDataFromShip()) {
123                  box_out.addDataFromShip(readMem((int)addr));
124                  count--;
125                  addr += stride;
126               }
127             }
128
129         } else if (box_inAddrRead.dataReadyForShip()) {
130             addr = box_inAddrRead.removeDataForShip();
131             stride = 0;
132             count = 1;
133             writing = false;
134
135         } else if (box_inAddrWrite.dataReadyForShip()) {
136             addr = box_inAddrWrite.removeDataForShip();
137             stride = 0;
138             count = 1;
139             writing = true;
140         }
141     }
142
143 == FleetSim ==============================================================
144
145 == FPGA ==============================================================
146
147   reg [(`CODEBAG_SIZE_BITS-1):0]  cursor;
148   reg                             write_flag;
149
150   wire [(`BRAM_ADDR_WIDTH-1):0]   addr1;
151   wire [(`BRAM_ADDR_WIDTH-1):0]   addr2;
152   wire [(`BRAM_DATA_WIDTH-1):0]   val2;
153   assign addr1 = write_flag ? inAddrWrite_d[(`DATAWIDTH-1):0] : inAddrRead_d[(`DATAWIDTH-1):0];
154   assign addr2 = (inCBD_d[(`INSTRUCTION_WIDTH-1):(`CODEBAG_SIZE_BITS)])+cursor;
155
156   bram14 mybram(clk, rst, write_flag, addr1, addr2, inDataWrite_d, out_d_, val2);
157
158   always @(posedge clk) begin
159
160     write_flag <= 0;
161
162     if (!rst) begin
163       `reset
164       cursor <= 0;
165     end else begin
166       write_flag <= 0;
167
168       if (!inAddrRead_r  && inAddrRead_a)  inAddrRead_a    <= 0;
169       if (!inDataWrite_r && inDataWrite_a) inDataWrite_a <= 0;
170       if (!inAddrWrite_r && inAddrWrite_a) inAddrWrite_a <= 0;
171
172       if ( out_r && !out_a) begin
173       end else if ( out_r &&  out_a) begin out_r <= 0;
174       end else if (!out_r && !out_a && inAddrRead_r && !inAddrRead_a) begin
175         inAddrRead_a    <= 1;
176         out_r           <= 1;
177   
178       end else if (!out_r && !out_a && inAddrWrite_r && inDataWrite_r) begin
179         // timing note: it's okay to set the *_a flags here because *_d will still
180         // be valid on the *next* cycle, which is all we care about
181         inAddrWrite_a   <= 1;
182         inDataWrite_a   <= 1;
183         out_r           <= 1;
184         write_flag      <= 1;
185   
186       end else if ( outIhorn_r &&  outIhorn_a)                       begin outIhorn_r         <= 0;
187       end else if (!inCBD_r &&  inCBD_a) begin inCBD_a <= 0;
188       end else if ( inCBD_r && !inCBD_a && !outIhorn_r && !outIhorn_a) begin
189         if (cursor < inCBD_d[(`CODEBAG_SIZE_BITS-1):0]) begin
190           outIhorn_d    <= val2;
191           outIhorn_r    <= 1;
192           cursor        <= cursor + 1;
193         end else begin
194           inCBD_a       <= 1;
195           cursor        <= 0;
196         end
197       end
198     end
199   end
200     
201
202
203
204 == Test ==============================================================
205 // expected output
206 #expect 12
207 #expect 13
208 #expect 14
209
210 // ships required in order to run this code
211 #ship debug          : Debug
212 #ship memory         : Memory
213
214 // instructions not in any codebag are part of the "root codebag"
215 // which is dispatched when the code is loaded
216
217 memory.inCBD:
218   literal BOB;
219   deliver;
220
221 BOB: {
222   debug.in:
223     literal 12; deliver;
224     literal 13; deliver;
225     literal 14; deliver;
226 }
227
228
229 == Constants ========================================================
230
231 == Contributors =========================================================
232 Adam Megacz <megacz@cs.berkeley.edu>