add dma peripheral
[shakti-peripherals.git] / src / peripherals / dma / DMA_try.bsv
1 /*
2 Copyright (c) 2013, IIT Madras
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
6
7 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
8 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
9 * Neither the name of IIT Madras nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
10
11 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
12 ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
13 */
14 package DMA ;
15
16 // ================================================================
17 // Copyright (c) Bluespec, Inc., 2007-2011 All Rights Reserved
18
19 import FIFO :: * ;
20 import FIFOF :: * ;
21 import Vector :: * ;
22 import GDefines::*;
23 import FShow::*;
24 import GetPut::*;
25 import DefaultValue ::*;
26
27 `include "ARM.defines"
28
29 // ================================================================
30 // DMA requests and responses
31
32 // ----------------
33 // Requests
34
35 typedef enum { NOP, WR, RD } ReqOp
36 deriving (Bits, Eq);
37
38 instance FShow #(ReqOp);
39 function Fmt fshow (ReqOp op);
40 case (op)
41 NOP : return fshow ("NOP");
42 WR : return fshow ("WR");
43 RD : return fshow ("RD");
44 endcase
45 endfunction
46 endinstance
47
48 typedef Bit#(10) ReqInfo;
49 typedef Bit#(32) ReqAddr;
50 typedef Bit#(32) ReqData;
51
52 typedef struct {
53 ReqOp reqOp;
54 ReqInfo reqInfo;
55 ReqAddr reqAddr;
56 ReqData reqData;
57 } Socket_Req
58 deriving (Bits);
59
60 instance FShow #(Socket_Req);
61 function Fmt fshow (Socket_Req req);
62 return (fshow ("Socket_Req{")
63 +
64 fshow (req.reqOp)
65 +
66 ( (req.reqOp() != NOP)
67 ? $format (", %h, %h, %h}", req.reqInfo(), req.reqAddr(), req.reqData())
68 : fshow (""))
69 +
70 fshow ("}"));
71 endfunction
72 endinstance
73
74 // ================================================================
75 // Responses
76
77 typedef enum { NOP, OK } RespOp
78 deriving (Bits, Eq);
79
80 instance FShow #(RespOp);
81 function Fmt fshow (RespOp op);
82 case (op)
83 NOP : return fshow ("NOP");
84 OK : return fshow ("OK");
85 endcase
86 endfunction
87 endinstance
88
89 typedef Bit#(10) RespInfo;
90 typedef Bit#(1) RespAddr;
91 typedef Bit#(32) RespData;
92
93 typedef struct {
94 ReqOp reqOp;
95 RespOp respOp;
96 RespInfo respInfo;
97 RespAddr respAddr;
98 RespData respData;
99 } Socket_Resp
100 deriving (Eq, Bits);
101
102 instance FShow #(Socket_Resp);
103 function Fmt fshow (Socket_Resp resp);
104 return (fshow ("Socket_Resp{")
105 +
106 fshow (resp.respOp())
107 +
108 ( (resp.respOp() != NOP)
109 ? $format (", %h, %h, %h", resp.respInfo(), resp.respAddr(), resp.respData())
110 : fshow (""))
111 +
112 fshow ("}"));
113 endfunction
114 endinstance
115
116 // ----------------------------------------------------------------
117 // At times it is best to consider registers as completely homogeneous,
118 // so that they can be accessed as a bit pattern with no internal
119 // structure. These functions convert reg interfaces based on a
120 // structured type to reg interfaces based on a bit pattern of at
121 // least the same width.
122
123 function Reg#(Bit#(n)) regAToRegBitN( Reg#(a_type) rin )
124 provisos ( Bits#( a_type, asize),
125 Add#(asize,xxx,n) ) ;
126
127 return
128 interface Reg
129 method Bit#(n) _read ();
130 a_type tmp = rin._read() ;
131 return zeroExtend (pack( tmp )) ;
132 endmethod
133 method Action _write( Bit#(n) din );
134 rin._write( unpack( truncate(din) )) ;
135 endmethod
136 endinterface ;
137
138 endfunction
139
140
141
142
143
144
145
146
147
148
149
150 // ================================================================
151 // The DMA interface has two sub-interfaces
152 // A TLM Receive interface (slave) for config
153 // A TLM Send interface (master) for data transfers
154
155 interface DmaC #(numeric type numChannels);
156 interface AXI4_Lite_Master_IFC#(`PADDR, `Reg_width, 0) cfg;
157 interface TLMRecvIFC#(`ARM_RR) cfg;
158 interface TLMSendIFC#(`ARM_RR) mmu;
159 endinterface
160
161
162 typedef UInt#(16) DMACounts ;
163 // The number of channels is a parameter.
164 // typedef 2 NumChannels;
165
166 // For the module, we add additional configuration registers to control
167 // which port the transfer reads from and writes to.
168 // The majority of the design remains the same, additional fifos, and
169 // interface must be added, as well as adding new rules to control
170 // which port is read or written.
171
172 // Several configuration registers are included, and connected to the
173 // config socket/fifo.
174
175
176 module mkDMA( DmaC #(numChannels) );
177
178 // For each socket, we will need 2 fifos, one for request, and 1
179 // for response. These fifos provide the interface for the
180 // interface sockets
181 ////////////////////////////////////////////////////////////////
182 // The fifos for the config port -- these are 1 element pipeline fifos.
183 (* doc = "a fifo to hold incoming configuration requests" *)
184 FIFOF#(Socket_Req) cnfReqF <- mkFIFOF ;
185 (* doc = "a fifo to hold outgoing configuration responses" *)
186 FIFOF#(Socket_Resp) cnfRespF <- mkFIFOF;
187
188
189 ////////////////////////////////////////////////////////////////
190 // The fifos for the MMU port
191 (* doc = "a fifo to hold outgoing requests towards the memory" *)
192 FIFOF#(Socket_Req) mmuReqF <- mkFIFOF;
193 (* doc = "a fifo to hold incoming responses from the memory" *)
194 FIFOF#(Socket_Resp) mmuRespF <- mkFIFOF;
195
196
197 ////////////////////////////////////////////////////////////////
198 // The fifos for the config port -- these are 1 element pipeline fifos.
199 // FIFOF#(Socket_Req) cnfReqF <- mkGSizedFIFOF(True, False, 2) ;
200 // FIFOF#(Socket_Resp) cnfRespF <- mkGSizedFIFOF(False, True, 2) ;
201
202 // // The fifos for the MMU
203 // FIFOF#(Socket_Req) mmuReqF <- mkGSizedFIFOF(False, True, 2);
204 // FIFOF#(Socket_Resp) mmuRespF <- mkGSizedFIFOF(True, False, 2);
205
206 // // The fifos for the MMU2
207 // FIFOF#(Socket_Req) mmu2ReqF <- mkGSizedFIFOF(False, True, 2);
208 // FIFOF#(Socket_Resp) mmu2RespF <- mkGSizedFIFOF(True, False, 2);
209
210 ////////////////////////////////////////////////////////////////
211 // We will need some registers to control the DMA transfer
212 // A Bit to signal if the transfer is enabled
213 Vector#(numChannels, Reg#(Bool)) dmaEnabledRs <- replicateM(mkReg(False));
214
215 // The read address and other stuff needed to generate a read
216 Vector#(numChannels, Reg#(ReqAddr)) readAddrRs <- replicateM(mkReg(0));
217 Vector#(numChannels, Reg#(DMACounts)) readCntrRs <- replicateM(mkReg(0));
218 Vector#(numChannels, Reg#(DMACounts)) currentReadRs <- replicateM(mkReg(0));
219 Vector#(numChannels, Reg#(DMACounts)) currentWriteRs <- replicateM(mkReg(0));
220
221 // To distinguish the ports for reads and writes, we need 2 bits
222 Vector#(numChannels,Reg#(Bit#(2))) portSrcDestRs <- replicateM( mkReg(0)) ;
223
224 // The destination address
225 Vector#(numChannels, Reg#(ReqAddr)) destAddrRs <- replicateM(mkReg(0));
226
227 // Use a FIFO to pass the read response to the write "side",
228 // thus allowing pending transations and concurrency.
229 // FIFOs can be replicated as well.
230 Vector#(numChannels,FIFO#(ReqData))
231 responseDataFs <- replicateM( mkSizedFIFO(2)) ;
232
233 // We also want to pass the destination address for each read over
234 // to the write "side"
235 // The depth of this fifo limits the number of outstanding reads
236 // which may be pending before the write. The maximum outstanding
237 // reads depends on the overall latency of the read requests.
238 Vector#(numChannels,FIFO#(ReqAddr))
239 destAddrFs <- replicateM( mkSizedFIFO( 4 )) ;
240
241 /// DMA rules //////////////////////////////////////////////////
242 // We define a function inside the module so it can access some
243 // of the registers without passing too many arguments.
244 // The function takes as arguments the conditions and fifos
245 // (interfaces)
246 // And returns a set a rules.
247 // The rule are identical to the set used in the one mmu port case.
248 function Rules generatePortDMARules (FIFOF#(Socket_Req) requestF,
249 FIFOF#(Socket_Resp) responseF,
250 Integer chanNum
251 );
252 return
253 rules
254
255 // To start a read, when the dma is enabled and there are data to
256 // move, and we are in the right state
257 rule startRead (dmaEnabledRs[chanNum]._read &&
258 readCntrRs[chanNum] > currentReadRs[chanNum] );
259 // Create a read request, and enqueue it
260 // Since there can be multiple pending requests, either read or
261 // writes, we use the reqInfo field to mark these.
262
263 //let wa= AXI4_Lite_Wr_Addr {awaddr: reqs.first.reqAddr, awprot:0, awuser:0, awlen: 0, awsize: 3, awburst: 'b01};
264 let req = Socket_Req {reqAddr : readAddrRs[chanNum]._read,
265 reqData : 0,
266 reqOp : RD,
267 reqInfo : fromInteger(0 + 2*chanNum)};
268 requestF.enq( req ) ;
269
270 // Enqueue the Write destination address
271 destAddrFs[chanNum].enq( destAddrRs[chanNum] ) ;
272
273 // Some house keeping -- increment the read address,
274 // decrement the counter.
275 readAddrRs[chanNum] <= readAddrRs[chanNum] + 4 ;
276 currentReadRs[chanNum] <= currentReadRs[chanNum] + 1 ;
277 destAddrRs[chanNum] <= destAddrRs[chanNum] + 4 ;
278 $display ("DMA[%0d] startRead", chanNum);
279 endrule
280
281
282 // We finish the read when we see the correct respInfo on the mmu response fifo
283 rule finishRead ( responseF.first.respInfo == fromInteger(0 + 2*chanNum) );
284 // grab the data from the mmu reponse fifo
285 Socket_Resp resp = responseF.first ;
286 responseF.deq ;
287
288 // Need to consider what to do if the response is an error or
289 // fail but we will keep it simple for now
290
291 // Pass the read data to the write "side" of the dma
292 responseDataFs[chanNum].enq( resp.respData ) ;
293 $display ("DMA[%0d]: finishRead", chanNum);
294 endrule
295
296 // This rule start the write process
297 // Note that this rule conflicts with rule startRead, so we make
298 // this rule be more urgent. I.e., finish writing before you start
299 // reading more.
300
301 rule startWrite ;
302 // Generate a Write
303 let wreq = Socket_Req {reqAddr : destAddrFs[chanNum].first,
304 reqData : responseDataFs[chanNum].first,
305 reqOp : WR,
306 reqInfo : fromInteger(1 + 2*chanNum) } ;
307
308 // enqueue the request.
309 requestF.enq( wreq ) ;
310
311 // Some other house keeping - removing the data from the fifos
312 destAddrFs[chanNum].deq;
313 responseDataFs[chanNum].deq;
314 $display ("DMA[%0d] startWrite", chanNum);
315 endrule
316
317 // This rule waits for the write to finish
318 rule finishWrite((responseF.first.respInfo == fromInteger(1 + 2*chanNum)) );
319 responseF.deq ; // take the response data and finish
320 currentWriteRs[chanNum]._write (currentWriteRs[chanNum] + 1);
321 $display ("DMA[%0d]: finishWrite", chanNum);
322 endrule
323
324
325 endrules;
326 endfunction
327
328 function Rules generateTransferDoneRules( Integer chanNum );
329 return
330 rules
331 // Conditions to mark when transfer is done
332 rule markTransferDone (dmaEnabledRs[chanNum]._read &&
333 (currentWriteRs[chanNum]._read == readCntrRs[chanNum]._read) &&
334 (currentReadRs[chanNum]._read == readCntrRs[chanNum]._read) ) ;
335 dmaEnabledRs[chanNum]._write (False) ;
336 currentWriteRs[chanNum] <= 0 ;
337 currentReadRs[chanNum] <= 0 ;
338 $display ("DMA[%0d]: transfer done", chanNum);
339 endrule
340 endrules ;
341 endfunction
342
343 // Generate the rules, place them in priority order
344 //
345 Rules ruleset = emptyRules;
346
347 for (Integer ch = 0; ch < valueof (numChannels); ch = ch + 1)
348 ruleset = rJoinDescendingUrgency (ruleset,
349 generatePortDMARules( mmuReqF, mmuRespF, ch));
350
351 for (Integer ch = 0; ch < valueof (numChannels); ch = ch + 1)
352 ruleset = rJoinDescendingUrgency (ruleset,
353 generateTransferDoneRules(ch));
354
355 // Add the rules to this module
356 //
357 addRules (ruleset);
358
359
360
361
362
363 // // Now we can generate the rules which can be manipulated further.
364 // Rules r01 = generatePortDMARules( portSrcDestRs[0]._read[0] == 0,
365 // portSrcDestRs[0]._read[1] == 0,
366 // mmu1ReqF, mmu1RespF, 0 ) ;
367 // Rules r02 = generatePortDMARules( portSrcDestRs[0]._read[0] == 1,
368 // portSrcDestRs[0]._read[1] == 1,
369 // mmu2ReqF, mmu2RespF, 0 ) ;
370 // Rules r11 = generatePortDMARules( portSrcDestRs[1]._read[0] == 0,
371 // portSrcDestRs[1]._read[1] == 0,
372 // mmu1ReqF, mmu1RespF, 1 ) ;
373 // Rules r12 = generatePortDMARules( portSrcDestRs[1]._read[0] == 1,
374 // portSrcDestRs[1]._read[1] == 1,
375 // mmu2ReqF, mmu2RespF, 1 ) ;
376 // Rules td0 = generateTransferDoneRules(0) ;
377 // Rules td1 = generateTransferDoneRules(1) ;
378
379 // // The set of rules above create a conflict because 2 startRead
380 // // conflict. To specify priority of the DMA channels, we relate
381 // // the urgency of the rules by joining the rules with following
382 // // rule functions.
383 // Rules r1 = rJoinDescendingUrgency( r01, r11) ;
384 // Rules r2 = rJoinDescendingUrgency( r02, r12) ;
385
386 // r2 = rJoinDescendingUrgency( r1, r2 ) ;
387 // r2 = rJoinDescendingUrgency( r2, td0 ) ;
388 // r2 = rJoinDescendingUrgency( r2, td1 ) ;
389
390 // addRules( r2 ) ;
391
392
393 /// Rules and other code to interface config port /////////////
394
395 // Add a zero-size register as a default for invalid addresses
396 Reg#(Bit#(0)) nullReg <- mkReg( ? ) ;
397
398 // For ease of development we want all registers to look like 32
399 // bit resister-- the data size of the config socket.
400 // Create function to map from address to specific registers
401 // For the multi channel DMA, split the 12 bit address into 2
402 // fields, 4 bits to select the channel, 8 for the register.
403
404 function Reg#(ReqData) selectReg( ReqAddr addr ) ;
405 Bit#(8) taddr = truncate( addr ) ;
406 Bit#(4) channelSel = truncate ( addr >> 8 ) ;
407 return
408 case ( taddr )
409 8'h00 : return regAToRegBitN( readAddrRs[channelSel] ) ;
410 8'h04 : return regAToRegBitN( readCntrRs[channelSel] ) ;
411 8'h08 : return regAToRegBitN( destAddrRs[channelSel] ) ;
412 8'h0C : return regAToRegBitN( dmaEnabledRs[channelSel] ) ;
413 8'h10 : return regAToRegBitN( portSrcDestRs[channelSel] ) ;
414 default: return regAToRegBitN( nullReg ) ;
415 endcase ;
416 endfunction
417
418
419 // A rule for writing to a registers
420 rule writeConfig ( cnfReqF.first.reqOp == WR ) ;
421 let req = cnfReqF.first ;
422 cnfReqF.deq ;
423
424 $display ("DMA[%0d] writeConfig: ", (req.reqAddr[11:8]), fshow (req));
425
426 // Select and write the register
427 let thisReg = selectReg( req.reqAddr ) ;
428 thisReg <= req.reqData ;
429
430 // Now generate the response and enqueue
431 let resp = Socket_Resp {respOp : OK,
432 reqOp : WR,
433 respAddr : 0,
434 respInfo : req.reqInfo,
435 respData : req.reqData } ;
436 cnfRespF.enq( resp ) ;
437 endrule
438
439 // A rule for reading a configuration register
440 rule readConfig ( cnfReqF.first.reqOp == RD ) ;
441 let req = cnfReqF.first ;
442 cnfReqF.deq ;
443
444 // Select the register
445 let thisReg = selectReg( req.reqAddr ) ;
446
447 // Now generate the response and enqueue
448 let resp = Socket_Resp {respOp : OK,
449 reqOp : RD,
450 respAddr : 0,
451 respInfo : req.reqInfo,
452 respData : thisReg } ;
453 cnfRespF.enq( resp ) ;
454 endrule
455
456 (* descending_urgency =
457 "writeConfig, readConfig, unknownConfig" *)
458 rule unknownConfig ( True ) ;
459 let req = cnfReqF.first ;
460 cnfReqF.deq ;
461
462 // Select the register
463 let thisReg = selectReg( req.reqAddr ) ;
464
465 // Now generate the response and enqueue
466 let resp = Socket_Resp {respOp : NOP,
467 reqOp : NOP,
468 respAddr : 0,
469 respInfo : req.reqInfo,
470 respData : thisReg } ;
471 cnfRespF.enq( resp ) ;
472 endrule
473
474 function AXI4_Lite_Master_Xactor_IFC#(wd_addr,wd_dara,wd_user)
475 fifos_to_AXI4_Lite_ifc (FIFOF#(Socket_Req) reqs,
476 FIFOF#(Socket_Resp) resps);
477 return
478 (interface AXI4_Lite_Master_Xactor_IFC#(wd_addr,wd_data,wd_user)
479 //interface AXI4_Lite_Master_IFC #(wd_addr, wd_data, wd_user) axi_side;
480 interface FIFOF_I #(AXI4_Lite_Wr_Addr #(wd_addr, wd_user))
481 i_wr_addr= fifos_to_AXI4_Lite_Wr_Addr(reqs);
482 interface FIFOF_I #(AXI4_Lite_Wr_Data #(wd_data))
483 i_wr_data= fifos_to_AXI4_Lite_Wr_Data(reqs);
484 interface FIFOF_O #(AXI4_Lite_Wr_Resp #(wd_user))
485 o_wr_resp= fifos_to_AXI4_Lite_Wr_Resp(resps);
486
487 interface FIFOF_I #(AXI4_Lite_Rd_Addr #(wd_addr, wd_user));
488 i_rd_addr= fifos_to_AXI4_Lite_Rd_Addr(reqs);
489 interface FIFOF_O #(AXI4_Lite_Rd_Data #(wd_data, wd_user))
490 o_rd_data= fifos_to_AXI4_Lite_Rd_Data(resps);
491 endinterface);
492 endfunction
493
494 function FIFO_I#(AXI4_Lite_Wr_Addr #(wd_addr, wd_user))
495 fifos_to_AXI4_Lite_Wr_Addr#(FIFOF#(Socket_Req) reqs);
496 return interface FIFO_I
497 method Action enq(din);
498 let x= Socket_Req {reqOp: defaultValue,
499 reqInfo: defaultValue,
500 reqAddr: din.awaddr,
501 reqData: defaultValue};
502
503 reqs.enq (x);
504 endmethod
505 method Bool notFull()= reqs.notFull;
506 endinterface
507 endfunction
508
509
510 ////////////////////////////////////////////////////////////////
511 ////////////////////////////////////////////////////////////////
512 //
513 // Create the interfaces by connecting the fifo interfaces to the
514 // the socket ports.
515
516 interface TLMRecvIFC cfg;
517 interface Get tx;
518 method ActionValue#(BusResponse) get;
519 cnfRespF.deq();
520 return socketRespToBusResp(cnfRespF.first());
521 endmethod
522 endinterface
523 interface Put rx;
524 method Action put(x) = cnfReqF.enq(busReqToSocketReq(x));
525 endinterface
526 endinterface
527
528
529
530
531 AXI4_Lite_Master_Xactor_IFC #(`PADDR,`Reg_width,0) m_xactor <- mkAXI4_Lite_Master_Xactor;
532 interface AXI4_Lite_Master_IFC#(`PADDR, `Reg_width, 0) cfg;
533
534
535
536 interface TLMSendIFC mmu;
537 interface Get tx;
538 method ActionValue#(BusRequest) get;
539 mmuReqF.deq();
540 return socketReqToBusReq(mmuReqF.first());
541 endmethod
542 endinterface
543 interface Put rx;
544 method Action put(x) = mmuRespF.enq(busRespToSocketResp(x));
545 endinterface
546 endinterface
547
548 endmodule
549
550 // ================================================================
551
552 function BusResponse socketRespToBusResp(Socket_Resp tmp);
553 BusResponse r = defaultValue;
554 r.error = !(tmp.respOp==OK);
555 r.data = tmp.respData;
556 r.write = (tmp.reqOp==WR);
557 r.id = unpack(truncate(tmp.respInfo));
558 return r;
559 endfunction
560
561 function BusRequest socketReqToBusReq(Socket_Req tmp);
562 BusRequest r = defaultValue;
563 r.byteen = '1;
564 r.address = tmp.reqAddr;
565 r.data = tmp.reqData;
566 r.write = (tmp.reqOp == WR);
567 r.id = unpack(truncate(tmp.reqInfo));
568 return r;
569 endfunction
570
571 function Socket_Req busReqToSocketReq(BusRequest x);
572 Socket_Req r = unpack(0);
573 r.reqOp = x.write ? WR : RD;
574 r.reqAddr = x.address;
575 r.reqData = x.data;
576 r.reqInfo = pack(extend(x.id));
577
578 return r;
579 endfunction
580
581 function Socket_Resp busRespToSocketResp(BusResponse x);
582 Socket_Resp r = unpack(0);
583 r.respOp = x.error ? NOP : OK;
584 r.respData = x.data;
585 r.reqOp = x.write ? WR : RD;
586 r.respInfo = pack(extend(x.id));
587 return r;
588 endfunction
589
590 endpackage
591
592
593