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