replace defined_parameters with instance_defines
[shakti-peripherals.git] / src / peripherals / dma / DMA.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 //TODO
15 //1. change CPAR, CMAR and CNDTR registers to conditionalWrite registers so that a write to these registers is possible only when the DMA channel is disabled.
16 // DMA ISR register cannot be written by the software in any case. It can be reset by the software by writing into to DMA_IFCR.
17 //--DONE-- 2. Implement functionality of DMA_IFCR
18 //--DONE-- 3. Optimization. Remove the 1+ from 1 + (2*chanNum) for id because we are anyways checking for read and write responses in different FIFOs
19 //--DONE-- 4. What to do if the DMA channel needs to be disabled in between? How to clear the FIFOs, and what to do about the pending on going transaction?
20 //5. Opt. Try to remove currentReadRs and currentWriteRs and use !destAddrFs.notEmpty instead to detect transfer complete and generate exception. Is generateTransferDoneRules even needed then?
21 //6. Parameterize the number of channels and peripherals completely.
22 //7. Write an assertion if currentReadRs[chan]==currentWriteRs[chan] then destAddrFs and responseDataFs are both empty. Prove this formally?
23 //8. Implement burst mode readConfig and writeConfig registers
24 //9. While joining generateTransferDoneRules, try using rJoinConflictFree instead of rJoinDescendingUrgency and check if they are formally equivalent. The conflict is between finishWrite and this rule. But the condition currentReadRs==currentWriteRs will not be true untill finishWrite fires. So, these two rules will never actually fire together.
25
26 package DMA;
27
28 import FIFO :: * ;
29 import FIFOF :: * ;
30 import Vector :: * ;
31 import FShow::*;
32 import GetPut::*;
33 import DefaultValue ::*;
34 import AXI4_Types :: *;
35 import AXI4_Fabric :: *;
36 import Semi_FIFOF :: *;
37 import ConcatReg :: *;
38 import ConfigReg :: *;
39
40 `define Burst_length_bits 8
41 `include "instance_defines.bsv"
42 `define verbose
43 // ================================================================
44 // DMA requests and responses parameters
45
46
47 function Bit#(1) fn_aligned_addr(Bit#(3) addr, Bit#(3) awsize);
48 bit out = 0;
49 case(awsize)
50 'd3: begin
51 if(addr == 0) out = 1;
52 end
53 'd2: begin
54 if(addr[1:0] == 0) out = 1;
55 end
56 'd1: begin
57 if(addr[0] == 0) out = 1;
58 end
59 'd0: begin
60 out = 1;
61 end
62 default: out = 0;
63 endcase
64 return out;
65 endfunction
66
67
68
69
70 typedef Bit#(`USERSPACE) Req_Info;
71 typedef Bit#(`PADDR) Req_Addr;
72 typedef Bit#(`Reg_width) Req_Data;
73 //The Req and Resp are of the same width in the current design
74 //typedef Bit#(10) RespInfo;
75 //typedef Bit#(1) RespAddr;
76 //typedef Bit#(32) RespData;
77
78 // ----------------------------------------------------------------
79 // At times it is best to consider registers as completely homogeneous,
80 // so that they can be accessed as a bit pattern with no internal
81 // structure. These functions convert reg interfaces based on a
82 // structured type to reg interfaces based on a bit pattern of at
83 // least the same width.
84
85 function Reg#(Bit#(n)) regAToRegBitN( Reg#(a_type) rin )
86 provisos ( Bits#( a_type, asize),
87 Add#(asize,xxx,n) ) ;
88
89 return
90 interface Reg
91 method Bit#(n) _read ();
92 a_type tmp = rin._read() ;
93 return zeroExtend (pack( tmp )) ;
94 endmethod
95 method Action _write( Bit#(n) din );
96 rin._write( unpack( truncate(din) )) ;
97 endmethod
98 endinterface ;
99 endfunction
100
101 // This function converts a Vector of 7 Registers to a single Register
102 function Reg#(Bit#(TMul#(7,q))) vector7ToRegN(Vector#(7,Reg#(Bit#(q))) inpV);
103 return concatReg7(inpV[6], inpV[5], inpV[4], inpV[3], inpV[2], inpV[1], inpV[0]);
104 //return asReg(zeroExtend(pack(inpV)));
105 endfunction
106
107 // ================================================================
108 // The DMA interface has two sub-interfaces
109 // A AXI4 Slave interface for config
110 // A AXI4 Master interface for data transfers
111
112 interface DmaC #(numeric type numChannels, numeric type numPeripherals);
113 interface AXI4_Master_IFC#(`PADDR,`Reg_width,`USERSPACE) mmu;
114 interface AXI4_Slave_IFC#(`PADDR,`Reg_width,`USERSPACE) cfg;
115 method Action interrupt_from_peripherals(Bit#(numPeripherals) pint);
116 method Bit#(numChannels) interrupt_to_processor();
117 endinterface
118
119
120 typedef UInt#(16) DMACounts ;
121 // The number of channels is a parameter.
122 // typedef 2 NumChannels;
123
124
125 // Several configuration registers are included, and connected to the
126 // config socket/fifo.
127
128 // Along with the destination address, if we are writing into a peripheral, we need to pass the peripheral id
129 // of the peripheral to check if the corresponding interrupt line is still high.
130 // Also, we need to send the destination transfer size for all the transactions.
131 typedef struct{
132 Req_Addr addr;
133 Bool is_dest_periph;
134 Bit#(TLog#(numPeriphs)) periph_id;
135 } DestAddrFs_type#(numeric type numPeriphs) deriving (Bits,Eq);
136
137 typedef struct{
138 Bit#(TLog#(numChannels)) chanNum;
139 Bit#(4) id;
140 } Disable_channel_type#(numeric type numChannels) deriving (Bits, Eq);
141
142 instance DefaultValue#(Disable_channel_type#(numChannels));
143 defaultValue= Disable_channel_type { chanNum: 'd-1,
144 id: 'd-1 };
145 endinstance
146
147 (* descending_urgency = "writeConfig, handle_interrupts" *)
148 (* descending_urgency = "writeConfig, rl_finishRead" *)
149 (* descending_urgency = "writeConfig, rl_startWrite" *)
150 module mkDMA( DmaC #(numChannels, numPeripherals) )
151 provisos ( Add#(numChannels, 0, 7),
152 Add#(a__, TLog#(numPeripherals), 4));
153
154 // The DMA contains one master interface, and one slave interface. The processor sends
155 // request through the slave interface to set the config registers.
156 // The DMA's master initiates a request to one of the peripherals through one of the
157 // channels. The response is taken (through response sub-interface of DMA's Master interface
158 // and returned to the processor (through response sub-interface of the DMA's Slave interface
159 AXI4_Slave_Xactor_IFC #(`PADDR,`Reg_width,`USERSPACE) s_xactor <- mkAXI4_Slave_Xactor;
160 AXI4_Master_Xactor_IFC #(`PADDR,`Reg_width,`USERSPACE) m_xactor <- mkAXI4_Master_Xactor;
161
162
163 ////////////////////////////////////////////////////////////////
164 //////////////////////// DMA Registers /////////////////////////
165 ////////////////////////////////////////////////////////////////
166 Vector#(numChannels,Reg#(Bit#(4))) dma_isr <- replicateM(mkReg(0)); //Interrupt Status Register
167 Vector#(numChannels,Reg#(Bit#(4))) dma_ifcr <- replicateM(mkReg(0)); //Interrupt Flag Clear Register
168 Vector#(numChannels,Reg#(Bit#(32))) dma_ccr <- replicateM(mkConfigReg(0)); //Channel Configuration Register
169 Vector#(numChannels,Reg#(Bit#(16))) dma_cndtr <- replicateM(mkConfigReg(0)); //Channel Number of Data Transfer Register
170 Vector#(numChannels,Reg#(Req_Addr)) dma_cpar <- replicateM(mkReg(0)); //Channel Peripheral Address Register
171 Vector#(numChannels,Reg#(Req_Addr)) dma_cmar <- replicateM(mkReg(0)); //Channel Memory Address Register
172 Vector#(numChannels,Reg#(Bit#(4))) dma1_cselr <- replicateM(mkReg(0)); //Channel SELection Register
173 //We do not have dma2_cselr because there is only one DMA, and not 2 in this architecture
174
175 //Registers to keep track if all the data read is wrtten
176 //Vector#(numChannels, Array#(Reg#(DMACounts))) currentReadRs[2] <- replicateM(mkCReg(2,0));
177 //Vector#(numChannels, Array#(Reg#(DMACounts))) currentWriteRs[2] <- replicateM(mkCReg(2,0));
178 Reg#(DMACounts) currentReadRs[valueOf(numChannels)][2];
179 Reg#(DMACounts) currentWriteRs[valueOf(numChannels)][2];
180 Reg#(Bool) rg_is_cndtr_zero[valueOf(numChannels)][2];
181 Reg#(Bit#(8)) rg_write_strobe <- mkReg(0);
182 Reg#(Bit#(2)) rg_tsize <- mkReg(0);
183 for(Integer i=0 ; i<valueOf(numChannels) ; i=i+1) begin
184 currentReadRs[i] <- mkCReg(2,0);
185 currentWriteRs[i] <- mkCReg(2,0);
186 rg_is_cndtr_zero[i] <- mkCReg(2,True);
187 end
188
189 // Use a FIFO to pass the read response to the write "side",
190 // thus allowing pending transations and concurrency.
191 // FIFOs can be replicated as well.
192 Vector#(numChannels,FIFOF#(Req_Data))
193 responseDataFs <- replicateM(mkSizedFIFOF(2)) ;
194
195 //Wire to pass the interrupt from peripheral to DMA
196 Wire#(Vector#(numPeripherals,Bit#(1))) wr_peripheral_interrupt <- mkDWire(replicate(0));
197
198 //Wire to set the TEIF
199 Wire#(Maybe#(Bit#(4))) wr_bus_err <- mkDWire(tagged Invalid);
200
201 // We also want to pass the destination address for each read over
202 // to the write "side", along with some other metadata.
203 // The depth of this fifo limits the number of outstanding reads
204 // which may be pending before the write. The maximum outstanding
205 // reads depends on the overall latency of the read requests.
206 Vector#(numChannels,FIFOF#(DestAddrFs_type#(numPeripherals)))
207 destAddrFs <- replicateM( mkSizedFIFOF(2)) ;
208
209 // This register stores the initial value of the CNDTR. It is used to restore the value back
210 // when operating in circular mode.
211 Vector#(numChannels,Reg#(Bit#(16))) rg_cndtr <- replicateM(mkReg(0));
212
213 // The spec specifies that the CPAR and CMAR values when read in middle of a transaction should
214 // still hold the original programmed value, and not the address of the current transaction.
215 // Therefore, we have a copy of these registers which indicate the address of the current
216 // ongoing transaction on that channel.
217 Vector#(numChannels,Reg#(Req_Addr)) rg_cpa <- replicateM(mkConfigReg(0)); // Local Channel Peripheral Address Register
218 Vector#(numChannels,Reg#(Req_Addr)) rg_cma <- replicateM(mkConfigReg(0)); // Local Channel Memory Address Register
219
220 Reg#(Bit#(`Burst_length_bits)) rg_burst_count <- mkReg(0);
221 Reg#(Bit#(TLog#(numChannels))) rg_current_trans_chan_id <- mkReg(0);
222 Reg#(Tuple3#(Bool, Bit#(TLog#(numChannels)), Bit#(4))) rg_disable_channel <- mkReg(tuple3(False, ?, 'd-1));
223 Reg#(Tuple2#(Bit#(TLog#(numChannels)), Bit#(32))) rg_writeConfig_ccr <- mkReg(tuple2(0,0));
224 Reg#(Bool) rg_finish_write[valueOf(numChannels)][2];
225 Reg#(Bool) rg_finish_read[valueOf(numChannels)][2];
226 for(Integer i=0 ; i<valueOf(numChannels) ; i=i+1) begin
227 rg_finish_write[i]<- mkCReg(2,True);
228 rg_finish_read[i]<- mkCReg(2,True);
229 end
230
231 // This function returns the id of the peripheral for which this channel is configured
232 function Bit#(TLog#(numPeripherals)) fn_map_channel_to_periph(Integer chanNum);
233 return truncate(dma1_cselr[chanNum]);
234 endfunction
235
236 // This function tells the maximum priority number amongst all the active peripherals
237 // which want to initiate a transaction. If one of the peripherals want to initiate a transaction
238 // i.e. it's interrupt line in high, we check if any other peripheral, whose interrupt line is high,
239 // has a higher priority (bits 13:12 in dma_ccrX). If so, we set the max_priority_num to
240 // the value of the highest interrupt.
241 // Note that even after this there might be multiple peripheral which have the same priority level as
242 // max_priority_num. Amongst them, the one with the lower channel number is given priority.
243 function Tuple2#(Bit#(TLog#(numChannels)),Bit#(TLog#(numPeripherals))) fn_dma_priority_encoder();
244 Bit#(2) max_priority_num= 0;
245 //stores id of the periph whose channel has been granted to generate req in this cycle.
246 Bit#(TLog#(numChannels)) grant_chan_id= 'd-1;
247 Bit#(TLog#(numPeripherals)) grant_periph_id= 'd-1;
248 for(Integer i=valueOf(numChannels)-1; i>=0; i=i-1) begin //for every channel
249 let periph_connected_to_channel_i=fn_map_channel_to_periph(i); //identify the peripheral connected to this channel
250 if(dma_ccr[i][0]==1 && dma_isr[i][1]==0 && //if the DMA channel is enabled
251 (wr_peripheral_interrupt[periph_connected_to_channel_i]==1 //if the peripheral has raised an interrupt
252 || dma_ccr[i][14]==1 //if M2M transfer, need not check for interrupt
253 //|| (dma_ccr[4]==1 && !rg_burst) //if not burst mode, the interrupt of periph needn't be high when reading from memory
254 //if in burst mode, its better if the peripheral is ready, and then we fetch the word from memory? TODO
255 )) begin
256 //check if its priority is greater than any of the other peripherals' priority
257 //here we check for equality also as the channels with lower number have higher priority.
258 //therefore if two requests have same "high" software priority, the channel whose channel number
259 //is lower will be chosen
260 if(dma_ccr[i][13:12]>=max_priority_num) begin
261 max_priority_num= dma_ccr[i][13:12]; //if so, then set the current priority level to be that of peripheral[i]
262 grant_chan_id= fromInteger(i);
263 grant_periph_id= periph_connected_to_channel_i;
264 end
265 end
266 end
267 return tuple2(grant_chan_id,grant_periph_id);
268 endfunction
269
270 function Bit#(16) fn_decr_cndtr(Bit#(16) cndtr, Bit#(2) tsize, Bit#(`Burst_length_bits) bsize);
271 Bit#(17) lv_to_sub= (zeroExtend(bsize)+1) << tsize;
272 Bit#(17) lv_result= {1'b0,cndtr}-lv_to_sub;
273 if(lv_result[16]==1) //underflow. Can happen in burst mode when the bytes to be transferred is not an exact multiple of the burst length x burst size.
274 return 0;
275 else
276 return lv_result[15:0];
277 endfunction
278
279 // This function increments the source or destination address depending on
280 // the size of the transfer.
281 // Note that though STM's DMA defines tsize=2'b11 as reserved, we use it to
282 // perform a 64-bit data transfer.
283 function Req_Addr fn_incr_address(Req_Addr addr, Bit#(2) tsize, Bit#(`Burst_length_bits) bsize) provisos(Bits#(Req_Addr,sz_Req_Addr), Add#(sz_Req_Addr,1, a));
284 Bit#(a) lv_to_add= (zeroExtend(bsize)+1) << tsize;
285 Bit#(a) lv_result= {1'b0,addr}+lv_to_add;
286 return truncate(lv_result);
287 endfunction
288
289 //This function performs the data alignment for 64 bit data
290 function Bit#(64) fn_data_alignment64 (Bit#(64) data, Bit#(2) source_sz, Bit#(2) dest_sz);
291 Bit#(64) outp;
292 case (source_sz) matches
293 2'd0: begin
294 outp= zeroExtend(data[7:0]);
295 end
296 2'd1: begin
297 if(dest_sz==2'd0)
298 outp= zeroExtend(data[7:0]);
299 else
300 outp= zeroExtend(data[15:0]);
301 end
302 2'd2: begin
303 if(dest_sz==2'd0)
304 outp= zeroExtend(data[7:0]);
305 else if(dest_sz==2'd1)
306 outp= zeroExtend(data[15:0]);
307 else
308 outp= zeroExtend(data[31:0]);
309 end
310 2'd3: begin
311 if(dest_sz==2'd0)
312 outp= zeroExtend(data[7:0]);
313 else if(dest_sz==2'd1)
314 outp= zeroExtend(data[15:0]);
315 else if(dest_sz== 2'd2)
316 outp= zeroExtend(data[31:0]);
317 else
318 outp= data;
319 end
320 endcase
321 return outp;
322 endfunction
323
324 // DMA rules //////////////////////////////////////////////////
325 // We define a function inside the module so it can access some
326 // of the registers without passing too many arguments.
327 // The function takes as arguments the conditions and fifos
328 // (interfaces)
329 // And returns a set a rules.
330 // The rule are identical to the set used in the one mmu port case.
331 function Rules generatePortDMARules (AXI4_Master_Xactor_IFC#(`PADDR,`Reg_width,`USERSPACE) xactor, Integer chanNum);
332 return
333 rules
334
335 /*rule display_stat(dma_ccr[chanNum][0]==1 || tpl_1(rg_disable_channel));
336 Bit#(2) max_priority_num= 0;
337 //stores id of the periph whose channel has been granted to generate req in this cycle.
338 Bit#(TLog#(numChannels)) grant_chan_id= 'd-1;
339 Bit#(TLog#(numPeripherals)) grant_periph_id= 'd-1;
340 for(Integer i=valueOf(numChannels)-1; i>=0; i=i-1) begin //for every channel
341 let periph_connected_to_channel_i=fn_map_channel_to_periph(i); //identify the peripheral connected to this channel
342 //$display("\nChan %d interrupt: %b cndtr: 'h%h prio: %d", i, dma_isr[i][1], wr_peripheral_interrupt[periph_connected_to_channel_i], dma_cndtr[chanNum],tpl_1(fn_dma_priority_encoder()));
343 if(dma_ccr[i][0]==1 && dma_isr[i][1]==0 && //if the DMA channel is enabled
344 (wr_peripheral_interrupt[periph_connected_to_channel_i]==1 //if the peripheral has raised an interrupt
345 || dma_ccr[i][14]==1 //if M2M transfer, need not check for interrupt
346 //|| (dma_ccr[4]==1 && !rg_burst)
347 )) begin //if not burst mode, the interrupt of periph needn't be high when reading from memory
348 //check if its priority is greater than any of the other peripherals' priority
349 //here we check for equality also as the channels with lower number have higher priority.
350 //therefore if two requests have same "high" software priority, the channel whose channel number
351 //is lower will be chosen
352 if(dma_ccr[i][13:12]>=max_priority_num) begin
353 max_priority_num= dma_ccr[i][13:12]; //if so, then set the current priority level to be that of peripheral[i]
354 grant_chan_id= fromInteger(i);
355 grant_periph_id= periph_connected_to_channel_i;
356 //$display("########## grant chan: %d grant periph_id: %d", grant_chan_id, grant_periph_id);
357 end
358 //$display("dma_ccr[%d][13:12]: %b max_prio: %b",i,dma_ccr[i][13:12],max_priority_num);
359 end
360 end
361 if(pack(wr_peripheral_interrupt)!=0 || dma_ccr[chanNum][14]==1) begin
362 Reg#(Bit#(64)) lv_dma_ifcr= regAToRegBitN( vector7ToRegN( dma_ifcr ));
363 $display($time,"Chan%d: cndtr: %h dma_isr: %h dma_ifcr: %h", chanNum, dma_cndtr[chanNum], dma_isr[chanNum], lv_dma_ifcr );
364 end
365 //$display($time,"grant chan_id: %d periph_id: %d",grant_chan_id,grant_periph_id);
366 //$display("Channel no. %d user_id: %d", chanNum, xactor.o_rd_data.first.ruser);
367 endrule*/
368
369 // To start a read, following conditions need to be met
370 // 1. There is data to be transferred
371 // 2. The dma is enabled (dma_ccr[chanNum][0]=1)
372 // 3. The channel has the highest priority
373 // 4. If multiple channels have same high priority, choose the one whose channel number is lowest
374 // 5. A channel is disabled before the complete transfer is finished, do not initiate any more requests
375 // The 2nd, 3rd and 4th conditions are handled by fn_dma_priority_encoder
376 (* descending_urgency = "rl_startWrite, rl_startRead" *)
377 //(* preempts = "rl_finishRead, rl_can_change_channel" *)
378 //(* preempts = "rl_startWrite, rl_can_change_channel" *)
379 //(* preempts = "rl_send_burst_write_data, rl_can_change_channel" *)
380 rule rl_startRead ( !rg_is_cndtr_zero[chanNum][0] && //no of bytes remaining to transfer is not 0
381 fromInteger(chanNum) == tpl_1(fn_dma_priority_encoder()) && //if the this channel has the highest priority
382 (!tpl_1(rg_disable_channel) || tpl_2(rg_disable_channel)!=fromInteger(chanNum))
383 && rg_finish_read[chanNum][1]); //if the channel is not being disabled by the processor
384 Req_Addr lv_araddr;
385 Bit#(2) lv_arsize;
386 bit lv_burst_type;
387 let lv_dma_ccr= dma_ccr[chanNum];
388 Bit#(`Burst_length_bits) lv_burst= lv_dma_ccr[`Burst_length_bits+15:16]; //Upper bits of CCR supports configurable bursts !! Added, not part of STMicro
389 let lv_periph_id= tpl_2(fn_dma_priority_encoder());
390
391 if(lv_dma_ccr[6]==1) //peripheral increment mode is on
392 rg_cpa[chanNum]<= fn_incr_address(rg_cpa[chanNum], lv_dma_ccr[9:8], dma_ccr[chanNum][`Burst_length_bits+15:16]);
393 if(lv_dma_ccr[7]==1) //memory increment mode is on
394 rg_cma[chanNum]<= fn_incr_address(rg_cma[chanNum], lv_dma_ccr[11:10], dma_ccr[chanNum][`Burst_length_bits+15:16]);
395
396 if(lv_dma_ccr[4]==0) begin //read from peripheral
397 lv_araddr= rg_cpa[chanNum]; //set the address to read from
398 lv_arsize= lv_dma_ccr[9:8]; //set the transfer size
399 lv_burst_type= lv_dma_ccr[6]; //0: Fixed, 1: INCR which is consistent with that of AXI4
400 `ifdef verbose $display($time,"\tDMA: chan[%0d] starting read from peripheral address %h",chanNum, lv_araddr); `endif
401 // Since the destination is memory, the write request needn't wait for any interrupt line to be high
402 // Therefore, we send the first argument as Invalid
403 destAddrFs[chanNum].enq( DestAddrFs_type { addr: rg_cma[chanNum], // Enqueue the Write destination address
404 is_dest_periph: False,
405 periph_id: lv_periph_id});
406 end
407 else begin //read from memory
408 lv_araddr= rg_cma[chanNum]; //set the address to read from
409 lv_arsize= lv_dma_ccr[11:10]; //set the transfer size
410 lv_burst_type= lv_dma_ccr[7]; //0: Fixed, 1: INCR which is consistent with that of AXI4
411 `ifdef verbose $display($time,"\tDMA: chan[%0d] starting read from memory address %h",chanNum, lv_araddr); `endif
412 // Since the destination address is that of a peripheral, the write request can be issued only when
413 // the corresponding peripheral's interrupt line is high. Therefore, we send the periph_id too.
414 Bool lv_is_dest_periph;
415 if(lv_dma_ccr[14]==0)
416 lv_is_dest_periph= True;
417 else
418 lv_is_dest_periph= False;
419 `ifdef verbose $display("dest_is_periph: %h",lv_is_dest_periph); `endif
420 destAddrFs[chanNum].enq( DestAddrFs_type { addr: rg_cpa[chanNum], // Enqueue the Write destination address
421 is_dest_periph: lv_is_dest_periph,
422 periph_id: lv_periph_id});
423
424 end
425
426 // Create a read request, and enqueue it
427 // Since there can be multiple pending requests, either read or
428 // writes, we use the `Req_Info field to mark these.
429 let read_request = AXI4_Rd_Addr {araddr: lv_araddr,
430 arid: {1'b1,fromInteger(chanNum)}, arlen: lv_burst,
431 arsize: zeroExtend(lv_arsize), arburst: zeroExtend(lv_burst_type), //arburst: 00-FIXED 01-INCR 10-WRAP
432 aruser: 0 };
433
434 xactor.i_rd_addr.enq(read_request);
435 `ifdef verbose $display("Sending a read request with araddr: %h arid: %h arlen: %h arsize: %h arburst: %h",lv_araddr,fromInteger(chanNum),lv_burst,lv_arsize,lv_burst_type); `endif
436
437 //housekeeping. To be done when the transaction is complete.
438 currentReadRs[chanNum][0]<= currentReadRs[chanNum][0] + 1;
439 dma_cndtr[chanNum]<= fn_decr_cndtr(dma_cndtr[chanNum], lv_arsize, dma_ccr[chanNum][`Burst_length_bits+15:16]);
440 rg_current_trans_chan_id<= fromInteger(chanNum);
441 rg_finish_read[chanNum][1]<= False;
442 endrule
443
444 // We finish the read when we see the correct respInfo on the mmu response fifo
445 rule rl_finishRead (xactor.o_rd_data.first.rid == {1'b1,fromInteger(chanNum)} && xactor.o_rd_data.first.rresp==AXI4_OKAY);
446 // update cndtr register to keep track of remaining transactions
447 let lv_dma_ccr= dma_ccr[chanNum];
448 Bit#(2) lv_tsize;
449 Bit#(2) lv_source_size;
450
451 if(dma_ccr[chanNum][4]==0) begin //if the source is peripheral
452 lv_tsize= dma_ccr[chanNum][11:10]; //destination's tsize will be that of memory
453 lv_source_size= dma_ccr[chanNum][9:8];
454 end
455 else begin
456 lv_tsize= dma_ccr[chanNum][9:8]; //destination's tsize will be that of peripheral
457 lv_source_size= dma_ccr[chanNum][11:10];
458 end
459
460 // grab the data from the mmu reponse fifo
461 let resp <- pop_o(xactor.o_rd_data);
462 `ifdef verbose $display("DMA: chan[%d] finish read. Got data: %h",chanNum, resp.rdata); `endif
463
464 // Pass the read data to the write "side" of the dma
465 responseDataFs[chanNum].enq( resp.rdata );
466 rg_finish_read[chanNum][0]<= True;
467 endrule
468
469 //rule to handle circ mode
470 rule rl_handle_circ_mode(dma_ccr[chanNum][5]==1 && rg_is_cndtr_zero[chanNum][1]); //if circular mode is enabled
471 dma_cndtr[chanNum]<= rg_cndtr[chanNum];
472 endrule
473
474 // This rule start the write process
475 // Note that this rule conflicts with rule startRead, so we make
476 // this rule be more urgent. i.e., finish writing before you start
477 // reading more.
478 /*rule rl_startWrite111;
479 $display("helloo.. intrpt: %b burst_count: %h finish_write: %b", wr_peripheral_interrupt[ destAddrFs[chanNum].first.periph_id ], rg_burst_count, rg_finish_write[chanNum][1]);
480 endrule*/
481
482 rule rl_startWrite( (destAddrFs[chanNum].first.is_dest_periph==False //if the dest is memory
483 || wr_peripheral_interrupt[ destAddrFs[chanNum].first.periph_id ]==1) //if dest is not memory, then check if the peripheral's interrupt line is active
484 && rg_burst_count==0 && rg_finish_write[chanNum][1]==True);
485 let lv_data= destAddrFs[chanNum].first;
486
487 Bit#(2) lv_tsize;
488 bit lv_burst_type;
489 let lv_dma_ccr= dma_ccr[chanNum];
490 if(lv_dma_ccr[4]==0) begin //if the source is peripheral
491 lv_tsize= lv_dma_ccr[11:10]; //destination's tsize will be that of memory
492 lv_burst_type= lv_dma_ccr[7]; //destination's burst type will be that of memory
493 end
494 else begin
495 lv_tsize= lv_dma_ccr[9:8]; //destination's tsize will be that of peripheral
496 lv_burst_type= lv_dma_ccr[6]; //destination's burst type will be that of peripheral
497 end
498
499 Bit#(`Reg_width) actual_data= responseDataFs[chanNum].first;
500 Bit#(`Burst_length_bits) lv_burst_len= lv_dma_ccr[`Burst_length_bits+15:16];
501 // Bit#(6) x = {3'b0,lv_data.addr[2:0]}<<3;
502 Bit#(8) write_strobe=lv_tsize==0?8'b1:lv_tsize==1?8'b11:lv_tsize==2?8'hf:8'hff;
503 if(lv_tsize!=3)begin // 8-bit write;
504 //actual_data=actual_data<<(x);
505 write_strobe=write_strobe<<(lv_data.addr[`byte_offset:0]);
506 end
507 //lv_data.addr[2:0]=0; // also make the address 64-bit aligned
508 `ifdef verbose $display("Start Write"); `endif
509
510
511 Bool lv_last= True;
512 if(lv_burst_len>0) begin // only enable the next rule when doing a write in burst mode.
513 rg_burst_count<=rg_burst_count+1;
514 lv_last= False;
515 `ifdef verbose $display("Starting burst mode write...."); `endif
516 end
517 `ifdef verbose
518 else begin
519 $display("Performing a single write...");
520 end
521 `endif
522
523 rg_write_strobe <= write_strobe; //Write strobe needs to be rotated so that burst writes are sent correctly, storing write_strobe in a register. ~Vinod
524 rg_tsize <= lv_tsize; //Storing rg_tsize in a register. ~Vinod
525 // Generate a Write
526 let write_data = AXI4_Wr_Data { wdata: actual_data , wstrb: write_strobe, wlast: lv_last, wid: {1'b1,fromInteger(chanNum)}};
527 let write_addr = AXI4_Wr_Addr { awaddr: lv_data.addr, awuser: 0,
528 awlen: lv_burst_len, awsize: zeroExtend(lv_tsize), awburst: zeroExtend(lv_burst_type),
529 awid: {1'b1,fromInteger(chanNum)} };
530
531 // enqueue the request.
532 xactor.i_wr_data.enq(write_data);
533 xactor.i_wr_addr.enq(write_addr);
534 rg_finish_write[chanNum][1]<= False;
535
536 // Some other house keeping - removing the data from the fifos
537 responseDataFs[chanNum].deq;
538 destAddrFs[chanNum].deq; //dequeing this FIFO will cause startRead to fire.
539 `ifdef verbose $display ($time,"\tDMA[%0d] startWrite addr: %h data: %h", chanNum,lv_data.addr,responseDataFs[chanNum].first); `endif
540 endrule
541
542 //This rule is used to send burst write data. The explicit condition ensures that we
543 //send burst length number of data i.e. rg_burst_count>1. When rg_burst_count = the burst
544 //length specified in dma_ccr, rg_burst_count becomes 0. Since rg_burst_count!=0 infers
545 //lesser hardware compared to rg_burst_count>1, we write that as the explicit condition.
546 rule rl_send_burst_write_data(rg_burst_count!=0);// && dma_ccr[chanNum][`Burst_length_bits+15:16]!='d0);
547 Bool lv_last= rg_burst_count==dma_ccr[chanNum][`Burst_length_bits+15:16];
548 /*== Since this is going to always be a line write request in burst mode No need of shifting data and address=== */
549 let write_strobe = rotateBitsBy(rg_write_strobe,1<<rg_tsize); //~Vinod Rotating write_strobe by awsize
550 let w = AXI4_Wr_Data {wdata: responseDataFs[chanNum].first, wstrb: write_strobe , wlast: lv_last, wid: {1'b1, fromInteger(chanNum)} };
551 xactor.i_wr_data.enq(w);
552 `ifdef verbose $display ($time,"\tDMA[%0d] startWrite Burst data: %h rg_burst_count: %d dma_ccr[23:16]: %d", chanNum,responseDataFs[chanNum].first, rg_burst_count, dma_ccr[chanNum][23:16]); `endif
553 if(lv_last)begin
554 `ifdef verbose $display("Last data received..."); `endif
555 rg_burst_count<=0;
556 end
557 else begin
558 rg_burst_count<=rg_burst_count+1;
559 end
560 responseDataFs[chanNum].deq;
561 rg_write_strobe <= write_strobe;
562 endrule
563
564
565 // This rule waits for the write to finish
566 rule rl_finishWrite( (xactor.o_wr_resp.first.bid == {1'b1, fromInteger(chanNum)}) &&
567 (xactor.o_wr_resp.first.bresp==AXI4_OKAY) );
568 let x<- pop_o(xactor.o_wr_resp) ; // take the response data and finish
569 currentWriteRs[chanNum][0]<= currentWriteRs[chanNum][0] + 1;
570 `ifdef verbose $display ("DMA[%0d]: finishWrite", chanNum); `endif
571 rg_finish_write[chanNum][0]<= True;
572 endrule
573
574 rule rl_cndtr_is_zero;
575 rg_is_cndtr_zero[chanNum][0]<= (dma_cndtr[chanNum]==0);
576 endrule
577
578 endrules;
579 endfunction
580
581 function Rules generateTransferDoneRules( Integer chanNum );
582 return
583 rules
584 // Conditions to mark when transfer is done.
585 // This rule will not fire for when circular mode because dma_cndtr[chanNum] is updated
586 // in the next cycle, which is before currentWriteRs can possibly get updated.
587 rule markTransferDone ( dma_ccr[chanNum][0]==1 && //if the channel is enabled
588 rg_is_cndtr_zero[chanNum][0] && //if the remaining data to transfer is 0
589 currentWriteRs[chanNum][0]== currentReadRs[chanNum][0]) ; //the final write has finished
590 //dmaEnabledRs[chanNum]._write (False) ;
591 currentWriteRs[chanNum][0] <= 0 ;
592 currentReadRs[chanNum][0] <= 0 ;
593 $display ("DMA[%0d]: transfer done", chanNum);
594 endrule
595 endrules ;
596 endfunction
597
598 // Generate the rules, place them in priority order
599 //
600 Rules ruleset = emptyRules;
601
602 for (Integer ch = 0; ch < valueof (numChannels); ch = ch + 1)
603 ruleset = rJoinDescendingUrgency (ruleset,
604 generatePortDMARules( m_xactor, ch));
605
606 //
607 for (Integer ch = 0; ch < valueof (numChannels); ch = ch + 1)
608 ruleset = rJoinDescendingUrgency (ruleset,
609 generateTransferDoneRules(ch));
610
611
612
613 (* descending_urgency = "rl_write_response_error, rl_read_response_error" *)
614 rule rl_write_response_error(m_xactor.o_wr_resp.first.bresp == AXI4_SLVERR || m_xactor.o_wr_resp.first.bresp == AXI4_DECERR);
615 wr_bus_err<= tagged Valid m_xactor.o_wr_resp.first.bid;
616 endrule
617
618 rule rl_read_response_error(m_xactor.o_rd_data.first.rresp == AXI4_SLVERR || m_xactor.o_rd_data.first.rresp == AXI4_DECERR);
619 wr_bus_err<= tagged Valid m_xactor.o_rd_data.first.rid;
620 endrule
621
622 rule handle_interrupts; //interrupts will be raised only when channel is enabled
623 for (Integer chanNum = 0; chanNum < valueOf (numChannels); chanNum = chanNum + 1) begin
624 Bit#(4) chan_isr= 'd0; //TEIF, HTIF, TCIF, GIF
625 Bit#(32) lv_dma_ccr= dma_ccr[chanNum];
626 //$display("*** chan: %d en: %d dma_cndtr: %h rg_cndtr: %h",chanNum, dma_ccr[chanNum][0], dma_cndtr[chanNum], rg_cndtr[chanNum]);
627 if(wr_bus_err matches tagged Valid .chan_num &&& fromInteger(chanNum)=={1'b1, chan_num[2:0]}) begin
628 chan_isr[3]=1;
629 $display("Bus error on channel %d",chanNum);
630 end
631 if(lv_dma_ccr[0]==1) begin
632 if(currentWriteRs[chanNum][1]==currentReadRs[chanNum][1]) begin //once the read and write transactions are over
633 if(rg_is_cndtr_zero[chanNum][0]) //TODO check what happens if you read from port 1 here
634 chan_isr[1]= 1;
635 end
636 //The Half Transfer Complete will be set when half transfer is complete.
637 //Since dma_cndtr is modified by startRead rule, though it would've become half,
638 //the transaction wouldn't be complete till the write is over. Also, by the time write is over,
639 //another read request could've been issued. Therefore, we have the below condition.
640 if(dma_cndtr[chanNum]<=(rg_cndtr[chanNum]>>1) && rg_finish_write[chanNum][1]) begin
641 chan_isr[2]= 1;
642 end
643 end
644 chan_isr[0]= chan_isr[3] | chan_isr[2] | chan_isr[1]; //Setting the GIF
645 chan_isr= dma_isr[chanNum][3:0] | chan_isr; //Sticky nature of interrupts. Should be cleared by software using ifcr.
646
647 //The bits in IFCR represent the interrupts that need to be cleared
648 chan_isr= chan_isr & ~(dma_ifcr[chanNum]);
649 dma_isr[chanNum]<= chan_isr;
650 // $display("chan_isr %b dma_cndtr[%d] :%h",chan_isr,chanNum,dma_cndtr[chanNum]);
651 end
652 endrule
653
654
655 // Rules and other code to interface config port /////////////
656
657 // Add a zero-size register as a default for invalid addresses
658 Reg#(Bit#(0)) nullReg <- mkReg( ? ) ;
659
660 // For ease of development we want all registers to look like 64
661 // bit resister-- the data size of the config socket.
662 // Create function to map from address to specific registers
663 function Tuple2#(Reg#(Req_Data), Bool) selectReg( Req_Addr addr );
664 Bit#(8) taddr = truncate( addr ) ;
665 return
666 case ( taddr )
667 8'h00 : return tuple2(regAToRegBitN( vector7ToRegN( dma_isr )), True);
668 8'h04 : return tuple2(regAToRegBitN( vector7ToRegN( dma_ifcr )), True);
669 8'hB0 : return tuple2(regAToRegBitN( vector7ToRegN( dma1_cselr )), True);
670
671 8'h08 : return tuple2(regAToRegBitN( dma_ccr[0] ), True); //32-bit
672 8'h0c : return tuple2(regAToRegBitN( dma_cndtr[0] ), True); //16-bit -- 32-bit Addr
673 8'h10 : return tuple2(regAToRegBitN( dma_cpar[0] ), True); //64-bit
674 8'h18 : return tuple2(regAToRegBitN( dma_cmar[0] ), True); //64-bit
675
676 8'h20 : return tuple2(regAToRegBitN( dma_ccr[1] ), True);
677 8'h24 : return tuple2(regAToRegBitN( dma_cndtr[1] ), True);
678 8'h28 : return tuple2(regAToRegBitN( dma_cpar[1] ), True);
679 8'h30 : return tuple2(regAToRegBitN( dma_cmar[1] ), True);
680
681 8'h38 : return tuple2(regAToRegBitN( dma_ccr[2] ), True);
682 8'h3C : return tuple2(regAToRegBitN( dma_cndtr[2] ), True);
683 8'h40 : return tuple2(regAToRegBitN( dma_cpar[2] ), True);
684 8'h48 : return tuple2(regAToRegBitN( dma_cmar[2] ), True);
685
686 8'h50 : return tuple2(regAToRegBitN( dma_ccr[3] ), True);
687 8'h54 : return tuple2(regAToRegBitN( dma_cndtr[3] ), True);
688 8'h58 : return tuple2(regAToRegBitN( dma_cpar[3] ), True);
689 8'h60 : return tuple2(regAToRegBitN( dma_cmar[3] ), True);
690
691 8'h68 : return tuple2(regAToRegBitN( dma_ccr[4] ), True);
692 8'h6C : return tuple2(regAToRegBitN( dma_cndtr[4] ), True);
693 8'h70 : return tuple2(regAToRegBitN( dma_cpar[4] ), True);
694 8'h78 : return tuple2(regAToRegBitN( dma_cmar[4] ), True);
695
696 8'h80 : return tuple2(regAToRegBitN( dma_ccr[5] ), True);
697 8'h84 : return tuple2(regAToRegBitN( dma_cndtr[5] ), True);
698 8'h88 : return tuple2(regAToRegBitN( dma_cpar[5] ), True);
699 8'h90 : return tuple2(regAToRegBitN( dma_cmar[5] ), True);
700
701 8'h98 : return tuple2(regAToRegBitN( dma_ccr[6] ), True);
702 8'h9C : return tuple2(regAToRegBitN( dma_cndtr[6] ), True);
703 8'hA0 : return tuple2(regAToRegBitN( dma_cpar[6] ), True);
704 8'hA8 : return tuple2(regAToRegBitN( dma_cmar[6] ), True);
705
706 default: return tuple2(regAToRegBitN( nullReg ), False);
707 endcase ;
708 endfunction
709
710 function Bit#(3) ccr_channel_number (Req_Addr addr);
711 Bit#(8) taddr= truncate(addr);
712 return
713 case ( taddr )
714 8'h08 : return 0;
715 8'h20 : return 1;
716 8'h38 : return 2;
717 8'h50 : return 3;
718 8'h68 : return 4;
719 8'h80 : return 5;
720 8'h98 : return 6;
721 default: 'd7;
722 endcase;
723 endfunction
724
725 Rules writeConfig = (rules
726 rule writeConfig;
727 let write_addr <- pop_o(s_xactor.o_wr_addr);
728 let write_data <- pop_o(s_xactor.o_wr_data);
729 Req_Data lv_data= 0;
730 Req_Addr lv_addr= 0;
731 AXI4_Resp lv_bresp= AXI4_OKAY;
732 Bool lv_send_response= True;
733
734 if(write_data.wstrb=='hF0) begin
735 lv_data= zeroExtend(write_data.wdata[63:32]);
736 lv_addr= {truncateLSB(write_addr.awaddr),3'b100};
737 end
738 else if(write_data.wstrb=='h0F) begin
739 lv_data= zeroExtend(write_data.wdata[31:0]);
740 lv_addr= {truncateLSB(write_addr.awaddr),3'b000};
741 end
742 else if(write_data.wstrb=='hFF) begin
743 lv_data= write_data.wdata;
744 lv_addr= write_addr.awaddr;
745 end
746 else begin //The write request is not 64-bits, and therefore return a bus error
747 lv_bresp= AXI4_SLVERR;
748 $display($time,"\tDMA: KAT GAYA");
749 end
750
751 `ifdef verbose $display ($time,"\tDMA writeConfig addr: %0h data: %0h", lv_addr, lv_data); `endif
752 // Select and write the register
753 let lv1= selectReg(lv_addr);
754 let thisReg = tpl_1(lv1);
755 if(!tpl_2(lv1)) begin //if no register mapping exists for the given address
756 lv_bresp= AXI4_SLVERR;
757 $display($time,"\tDMA: Wapas KAT GAYA");
758 end
759 //else is not needed as the selectReg function handles it
760
761 let lv_ccr_channel_number= ccr_channel_number(lv_addr);
762 `ifdef verbose $display("ccr_channel_number %h lv_addr %h",lv_ccr_channel_number, lv_addr); `endif
763 if( lv_ccr_channel_number!='d-1 && tpl_2(lv1)) begin //if the current write is happening to one of the channel's CCR.
764 if(lv_data[0]==1 ) begin //if the channel is being enabled
765 rg_cpa[lv_ccr_channel_number] <= dma_cpar[lv_ccr_channel_number]; //peripheral address is copied
766 rg_cma[lv_ccr_channel_number] <= dma_cmar[lv_ccr_channel_number]; //memory address is copied
767 rg_cndtr[lv_ccr_channel_number]<= dma_cndtr[lv_ccr_channel_number]; //the cndtr value is saved
768 rg_disable_channel<= tuple3(False,?,?);
769 $display("----------------------- ENABLING DMA CHANNEL %d", lv_ccr_channel_number," -----------------------");
770
771 Bit#(3) cmar_align = dma_cmar[lv_ccr_channel_number][2:0]; //Vinod
772 Bit#(3) cpar_align = dma_cpar[lv_ccr_channel_number][2:0]; //Vinod
773
774 //lv_data[9:8] and lv_data[11:10] gives transfer size supposedly. Using K-Maps --Possibility of a bug?
775 bit cmar_is_aligned = fn_aligned_addr(write_addr.awaddr[2:0], write_addr.awsize);
776 bit cpar_is_aligned = fn_aligned_addr(write_addr.awaddr[2:0], write_addr.awsize);
777
778 if((cmar_is_aligned&cpar_is_aligned)==0) begin
779 lv_bresp = AXI4_DECERR; //DECERR for Unaligned addresses
780 $display("\tAXI4_DECERR\n");
781 end
782
783 $display("cmar_is_aligned: %b cpar_is_aligned: %b",cmar_is_aligned,cpar_is_aligned);
784
785
786 if(lv_data[4]==0) begin
787 $display("SOURCE: Peripheral Addr: 'h%0h Transfer size: 'b%b Incr: %b",dma_cpar[lv_ccr_channel_number], lv_data[9:8], lv_data[6]);
788 $display("DEST : Memory Addr: 'h%0h Transfer size: 'b%b Incr: %b",dma_cmar[lv_ccr_channel_number], lv_data[11:10], lv_data[7]);
789 end
790 else if(lv_data[14]==0) begin
791 $display("SOURCE: Memory Addr: 'h%0h Transfer size: 'b%b Incr: %b",dma_cmar[lv_ccr_channel_number], lv_data[11:10], lv_data[7]);
792 $display("DEST : Peripheral Addr: 'h%0h Transfer size: 'b%b Incr: %b",dma_cpar[lv_ccr_channel_number], lv_data[9:8], lv_data[6]);
793 end
794 else begin
795 $display("SOURCE: Memory Addr: 'h%0h Transfer size: 'b%b Incr: %b",dma_cmar[lv_ccr_channel_number], lv_data[11:10], lv_data[7]);
796 $display("DEST : Memory Addr: 'h%0h Transfer size: 'b%b Incr: %b",dma_cpar[lv_ccr_channel_number], lv_data[9:8], lv_data[6]);
797 end
798 $display("Priority level: 'b%b Circular mode: %b CNDTR: 'h%h", lv_data[13:12], lv_data[5], dma_cndtr[lv_ccr_channel_number]);
799 end
800 else begin //the channel is being disabled
801 //TODO since it is a CReg, what if we check in port [1]?
802 if(currentReadRs[lv_ccr_channel_number][0]!=currentWriteRs[lv_ccr_channel_number][0]) begin //there is an on going transaction
803 rg_disable_channel<= tuple3(True, lv_ccr_channel_number, write_addr.awid);
804 lv_send_response= False;
805 rg_writeConfig_ccr<= tuple2(lv_ccr_channel_number, truncate(lv_data));
806 end
807 else begin // no pending transaction
808 //clear the local registers
809 rg_is_cndtr_zero[lv_ccr_channel_number][0]<= True;
810 end
811 end
812 end
813
814 // Now generate the response and enqueue
815 if(lv_send_response) begin
816 thisReg <= lv_data;
817 let resp = AXI4_Wr_Resp { bresp: lv_bresp, buser: 0, bid: write_addr.awid };
818 s_xactor.i_wr_resp.enq(resp);
819 end
820 endrule
821 endrules);
822
823 //Rule to send response to processor that the dma channel has been disabled after the on going transactions are over
824 Rules rl_send_chan_disabled_to_proc = (rules
825 rule rl_send_chan_disabled_to_proc(tpl_1(rg_disable_channel) && currentReadRs[tpl_2(rg_disable_channel)][1]==currentWriteRs[tpl_2(rg_disable_channel)][1]);
826 rg_disable_channel<= tuple2(False,?);
827 dma_ccr[tpl_1(rg_writeConfig_ccr)]<= tpl_2(rg_writeConfig_ccr);
828 let resp = AXI4_Wr_Resp { bresp: AXI4_OKAY, buser: 0, bid: tpl_3(rg_disable_channel) };
829 s_xactor.i_wr_resp.enq(resp);
830 endrule
831 endrules);
832
833 //writeConfig gets highest priority since we do not want the core to stall
834 ruleset= rJoinDescendingUrgency(writeConfig,ruleset);
835
836 //writeConfig if more urgent than rl_send_chan_disabled_to_proc
837 ruleset= rJoinDescendingUrgency(ruleset, rl_send_chan_disabled_to_proc);
838
839 // A rule for reading a configuration register
840 //TODO need to add preempts with writeConfig? or mutually_exclusive? Because both these rules will never fire together.
841 // If we do not put any attributes, won't two instances of selectReg get synthesized?
842 rule readConfig;
843 AXI4_Resp lv_rresp;
844 let read_addr <- pop_o(s_xactor.o_rd_addr);
845 // Select the register
846 let lv1= selectReg(read_addr.araddr);
847 let thisReg = tpl_1(lv1);
848
849 //If read happens to a non defined register,
850 //or if read size is not 32-bits return SLVERR.
851 if(!tpl_2(lv1))
852 lv_rresp= AXI4_SLVERR;
853 else
854 lv_rresp= AXI4_OKAY;
855
856 Req_Data lv_data;
857 if(read_addr.arsize=='b0)
858 lv_data={thisReg[7:0], thisReg[7:0], thisReg[7:0], thisReg[7:0], thisReg[7:0], thisReg[7:0], thisReg[7:0], thisReg[7:0]};
859 else if(read_addr.arsize=='b01)
860 lv_data={thisReg[15:0], thisReg[15:0], thisReg[15:0], thisReg[15:0]};
861 else if(read_addr.arsize=='b10)
862 lv_data={thisReg[31:0], thisReg[31:0]};
863 else
864 lv_data= thisReg;
865 // Now generate the response and enqueue
866 let resp = AXI4_Rd_Data {rresp: lv_rresp, rdata: thisReg, rlast: True,
867 ruser: 0, rid: read_addr.arid};
868 s_xactor.i_rd_data.enq(resp);
869 endrule
870
871
872 // Add the rules to this module
873 addRules (ruleset);
874
875 //Note that unknownConfig rule is not needed here because all the FIFOs will
876 //be empty and hence neither writeConfig nor readConfig will fire.
877
878 ////////////////////////////////////////////////////////////////
879 ////////////////////////////////////////////////////////////////
880 //
881 // Create the interfaces by connecting the axi side interfaces
882 // of the transactors to it.
883
884 interface cfg= s_xactor.axi_side;
885 interface mmu= m_xactor.axi_side;
886
887 //This method receives various interrupts from the peripheral devices and gives it to the DMA
888 method Action interrupt_from_peripherals(Bit#(numPeripherals) pint);
889 wr_peripheral_interrupt<= unpack(pint);
890 endmethod
891
892 //TODO should the interrupt be sent in the next cycle (as is implemented) or in the same cycle as generated (using Wires instead)?
893 //This method returns the interrupt generated by the DMA corresponding to every channel
894 //Raise the interrupt of a particular channel if any of the interrupts are active (in ISR) and are not masked(in CCR)
895 method Bit#(numChannels) interrupt_to_processor();
896 Bit#(numChannels) lv_interrupt_to_processor;
897 for(Integer chanNum= 0; chanNum < valueof(numChannels); chanNum= chanNum + 1) begin
898 let lv_dma_ccr= dma_ccr[chanNum];
899 //The bits in CCR represent the interrupts that are enabled, whereas the ones in IFCR represent which need to be cleared
900 let lv_intr_TE_HT_TC_enable= lv_dma_ccr[3:1];
901
902 //The bits in ISR represent which interrupts are active right now
903 Bit#(3) active_interrupts= {lv_intr_TE_HT_TC_enable} & dma_isr[chanNum][3:1];
904 lv_interrupt_to_processor[chanNum]= |(active_interrupts);
905 end
906 return lv_interrupt_to_processor;
907 endmethod
908 endmodule
909
910 endpackage