add dma peripheral
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Wed, 25 Jul 2018 03:57:53 +0000 (04:57 +0100)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Wed, 25 Jul 2018 03:57:53 +0000 (04:57 +0100)
src/peripherals/dma/DMA.bsv [new file with mode: 0644]
src/peripherals/dma/DMA.defines [new file with mode: 0644]
src/peripherals/dma/DMA_try.bsv [new file with mode: 0644]
src/peripherals/dma/DMAv2.bsv [new file with mode: 0644]
src/peripherals/dma/GDefines.bsv [new file with mode: 0644]
src/peripherals/dma/tb_DMA.bsv [new file with mode: 0644]
src/peripherals/dma/tb_DMA_AXI_Memory.bsv [new file with mode: 0644]

diff --git a/src/peripherals/dma/DMA.bsv b/src/peripherals/dma/DMA.bsv
new file mode 100644 (file)
index 0000000..ac51120
--- /dev/null
@@ -0,0 +1,910 @@
+/*
+Copyright (c) 2013, IIT Madras
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+*  Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+*  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.
+*  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.
+
+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. 
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+*/
+//TODO 
+//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.
+//   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.
+//--DONE-- 2. Implement functionality of DMA_IFCR
+//--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
+//--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?
+//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?
+//6. Parameterize the number of channels and peripherals completely.
+//7. Write an assertion if currentReadRs[chan]==currentWriteRs[chan] then destAddrFs and responseDataFs are both empty. Prove this formally?
+//8. Implement burst mode readConfig and writeConfig registers
+//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.
+
+package DMA;
+
+import FIFO :: * ;
+import FIFOF :: * ;
+import Vector :: * ;
+import FShow::*;
+import GetPut::*;
+import DefaultValue ::*;
+import AXI4_Types   :: *;
+import AXI4_Fabric  :: *;
+import Semi_FIFOF        :: *;
+import ConcatReg :: *;
+import ConfigReg :: *;
+
+`define Burst_length_bits 8
+`include "defined_parameters.bsv"
+`define verbose
+// ================================================================
+// DMA requests and responses parameters
+
+
+function Bit#(1) fn_aligned_addr(Bit#(3) addr, Bit#(3) awsize);
+   bit out = 0;
+    case(awsize)
+        'd3: begin
+            if(addr == 0) out = 1;
+        end
+        'd2: begin
+            if(addr[1:0] == 0) out = 1;
+        end
+        'd1: begin
+            if(addr[0] == 0) out = 1;
+        end
+        'd0: begin
+            out = 1;
+        end
+        default: out = 0;
+    endcase
+    return out;
+endfunction
+
+
+
+
+typedef Bit#(`USERSPACE) Req_Info; 
+typedef Bit#(`PADDR) Req_Addr; 
+typedef Bit#(`Reg_width) Req_Data; 
+//The Req and Resp are of the same width in the current design
+//typedef Bit#(10) RespInfo;
+//typedef Bit#(1) RespAddr;
+//typedef Bit#(32) RespData;
+
+// ----------------------------------------------------------------
+// At times it is best to consider registers as completely homogeneous,
+// so that they can be accessed as a bit pattern with no internal
+// structure.  These functions convert reg interfaces based on a
+// structured type to reg interfaces based on a bit pattern of at
+// least the same width.
+
+function Reg#(Bit#(n)) regAToRegBitN( Reg#(a_type) rin )
+       provisos ( Bits#( a_type, asize),
+                          Add#(asize,xxx,n) ) ;
+
+       return
+       interface Reg
+               method Bit#(n) _read ();
+                       a_type tmp =  rin._read()  ;
+                       return zeroExtend (pack( tmp )) ;
+               endmethod
+               method Action _write( Bit#(n) din );
+                       rin._write( unpack( truncate(din) )) ;
+               endmethod
+       endinterface ;
+endfunction
+
+// This function converts a Vector of 7 Registers to a single Register
+function Reg#(Bit#(TMul#(7,q))) vector7ToRegN(Vector#(7,Reg#(Bit#(q))) inpV);
+       return concatReg7(inpV[6], inpV[5], inpV[4], inpV[3], inpV[2], inpV[1], inpV[0]);
+       //return asReg(zeroExtend(pack(inpV)));
+endfunction
+
+// ================================================================
+// The DMA interface has two sub-interfaces
+//  A AXI4 Slave interface for config
+//  A AXI4 Master interface for data transfers
+
+interface DmaC #(numeric type numChannels, numeric type numPeripherals);
+       interface AXI4_Master_IFC#(`PADDR,`Reg_width,`USERSPACE) mmu;
+       interface AXI4_Slave_IFC#(`PADDR,`Reg_width,`USERSPACE) cfg;
+       method Action interrupt_from_peripherals(Bit#(numPeripherals) pint);
+       method Bit#(numChannels) interrupt_to_processor();
+endinterface
+
+
+typedef UInt#(16)  DMACounts ;
+// The number of channels is a parameter.
+// typedef 2 NumChannels;
+
+
+// Several configuration registers are included, and connected to the
+// config socket/fifo.
+
+// Along with the destination address, if we are writing into a peripheral, we need to pass the peripheral id 
+// of the peripheral to check if the corresponding interrupt line is still high.
+// Also, we need to send the destination transfer size for all the transactions.
+typedef struct{
+       Req_Addr addr;
+       Bool is_dest_periph;
+       Bit#(TLog#(numPeriphs)) periph_id;
+} DestAddrFs_type#(numeric type numPeriphs) deriving (Bits,Eq);
+
+typedef struct{
+       Bit#(TLog#(numChannels)) chanNum;
+       Bit#(4) id;
+} Disable_channel_type#(numeric type numChannels) deriving (Bits, Eq);
+
+instance DefaultValue#(Disable_channel_type#(numChannels));
+       defaultValue= Disable_channel_type { chanNum: 'd-1,
+                                                                                id: 'd-1 };
+endinstance
+
+(* descending_urgency = "writeConfig, handle_interrupts" *)
+(* descending_urgency = "writeConfig, rl_finishRead" *)
+(* descending_urgency = "writeConfig, rl_startWrite" *)
+module mkDMA( DmaC #(numChannels, numPeripherals) )
+       provisos ( Add#(numChannels, 0, 7),
+                          Add#(a__, TLog#(numPeripherals), 4)); 
+
+       // The DMA contains one master interface, and one slave interface. The processor sends
+       // request through the slave interface to set the config registers.
+       // The DMA's master initiates a request to one of the peripherals through one of the
+       // channels. The response is taken (through response sub-interface of DMA's Master interface
+       // and returned to the processor (through response sub-interface of the DMA's Slave interface 
+       AXI4_Slave_Xactor_IFC #(`PADDR,`Reg_width,`USERSPACE) s_xactor <- mkAXI4_Slave_Xactor;
+       AXI4_Master_Xactor_IFC #(`PADDR,`Reg_width,`USERSPACE) m_xactor <- mkAXI4_Master_Xactor;
+
+
+       ////////////////////////////////////////////////////////////////
+       //////////////////////// DMA Registers /////////////////////////
+       ////////////////////////////////////////////////////////////////
+       Vector#(numChannels,Reg#(Bit#(4))) dma_isr <- replicateM(mkReg(0));             //Interrupt Status Register
+       Vector#(numChannels,Reg#(Bit#(4))) dma_ifcr <- replicateM(mkReg(0));    //Interrupt Flag Clear Register
+       Vector#(numChannels,Reg#(Bit#(32))) dma_ccr <- replicateM(mkConfigReg(0));      //Channel Configuration Register
+       Vector#(numChannels,Reg#(Bit#(16))) dma_cndtr <- replicateM(mkConfigReg(0));    //Channel Number of Data Transfer Register
+       Vector#(numChannels,Reg#(Req_Addr)) dma_cpar <- replicateM(mkReg(0));   //Channel Peripheral Address Register
+       Vector#(numChannels,Reg#(Req_Addr)) dma_cmar <- replicateM(mkReg(0));   //Channel Memory Address Register
+       Vector#(numChannels,Reg#(Bit#(4))) dma1_cselr <- replicateM(mkReg(0));  //Channel SELection Register
+       //We do not have dma2_cselr because there is only one DMA, and not 2 in this architecture
+
+       //Registers to keep track if all the data read is wrtten
+       //Vector#(numChannels, Array#(Reg#(DMACounts))) currentReadRs[2]  <- replicateM(mkCReg(2,0));
+       //Vector#(numChannels, Array#(Reg#(DMACounts))) currentWriteRs[2] <- replicateM(mkCReg(2,0));
+       Reg#(DMACounts) currentReadRs[valueOf(numChannels)][2];
+       Reg#(DMACounts) currentWriteRs[valueOf(numChannels)][2];
+       Reg#(Bool)              rg_is_cndtr_zero[valueOf(numChannels)][2];
+    Reg#(Bit#(8)) rg_write_strobe <- mkReg(0);
+    Reg#(Bit#(2)) rg_tsize <- mkReg(0);
+       for(Integer i=0 ; i<valueOf(numChannels) ; i=i+1) begin
+               currentReadRs[i] <- mkCReg(2,0);
+               currentWriteRs[i] <- mkCReg(2,0);
+               rg_is_cndtr_zero[i] <- mkCReg(2,True);
+       end
+
+       // Use a FIFO to pass the read response to the write "side",
+       //  thus allowing pending transations and concurrency.
+       // FIFOs can be replicated as well.
+       Vector#(numChannels,FIFOF#(Req_Data))  
+                 responseDataFs <- replicateM(mkSizedFIFOF(2)) ;  
+
+       //Wire to pass the interrupt from peripheral to DMA
+       Wire#(Vector#(numPeripherals,Bit#(1))) wr_peripheral_interrupt <- mkDWire(replicate(0));
+
+       //Wire to set the TEIF
+       Wire#(Maybe#(Bit#(4))) wr_bus_err <- mkDWire(tagged Invalid);
+
+       // We also want to pass the destination address for each read over
+       // to the write "side", along with some other metadata.
+       // The depth of this fifo limits the number of outstanding reads
+       // which may be pending before the write.  The maximum outstanding
+       // reads depends on the overall latency of the read requests.
+       Vector#(numChannels,FIFOF#(DestAddrFs_type#(numPeripherals))) 
+               destAddrFs <- replicateM( mkSizedFIFOF(2)) ;
+       
+       // This register stores the initial value of the CNDTR. It is used to restore the value back
+       // when operating in circular mode.
+       Vector#(numChannels,Reg#(Bit#(16))) rg_cndtr <- replicateM(mkReg(0));
+
+       // The spec specifies that the CPAR and CMAR values when read in middle of a transaction should
+       // still hold the original programmed value, and not the address of the current transaction.
+       // Therefore, we have a copy of these registers which indicate the address of the current
+       // ongoing transaction on that channel.
+       Vector#(numChannels,Reg#(Req_Addr)) rg_cpa <- replicateM(mkConfigReg(0));       // Local Channel Peripheral Address Register
+       Vector#(numChannels,Reg#(Req_Addr)) rg_cma <- replicateM(mkConfigReg(0));       // Local Channel Memory Address Register
+
+       Reg#(Bit#(`Burst_length_bits)) rg_burst_count <- mkReg(0);
+       Reg#(Bit#(TLog#(numChannels))) rg_current_trans_chan_id <- mkReg(0);
+       Reg#(Tuple3#(Bool, Bit#(TLog#(numChannels)), Bit#(4))) rg_disable_channel <- mkReg(tuple3(False, ?, 'd-1));
+       Reg#(Tuple2#(Bit#(TLog#(numChannels)), Bit#(32))) rg_writeConfig_ccr <- mkReg(tuple2(0,0));
+       Reg#(Bool) rg_finish_write[valueOf(numChannels)][2];
+       Reg#(Bool) rg_finish_read[valueOf(numChannels)][2];
+       for(Integer i=0 ; i<valueOf(numChannels) ; i=i+1) begin
+               rg_finish_write[i]<- mkCReg(2,True);
+               rg_finish_read[i]<- mkCReg(2,True);
+       end
+
+       // This function returns the id of the peripheral for which this channel is configured
+       function Bit#(TLog#(numPeripherals)) fn_map_channel_to_periph(Integer chanNum);
+               return truncate(dma1_cselr[chanNum]);
+       endfunction
+
+       // This function tells the maximum priority number amongst all the active peripherals
+       // which want to initiate a transaction. If one of the peripherals want to initiate a transaction
+       // i.e. it's interrupt line in high, we check if any other peripheral, whose interrupt line is high,
+       // has a higher priority (bits 13:12 in dma_ccrX). If so, we set the max_priority_num to
+       // the value of the highest interrupt.
+       // Note that even after this there might be multiple peripheral which have the same priority level as
+       // max_priority_num. Amongst them, the one with the lower channel number is given priority.
+       function Tuple2#(Bit#(TLog#(numChannels)),Bit#(TLog#(numPeripherals))) fn_dma_priority_encoder();
+               Bit#(2) max_priority_num= 0;
+               //stores id of the periph whose channel has been granted to generate req in this cycle.
+               Bit#(TLog#(numChannels)) grant_chan_id= 'd-1;
+               Bit#(TLog#(numPeripherals)) grant_periph_id= 'd-1;
+               for(Integer i=valueOf(numChannels)-1; i>=0; i=i-1) begin                        //for every channel
+                       let periph_connected_to_channel_i=fn_map_channel_to_periph(i);  //identify the peripheral connected to this channel
+                       if(dma_ccr[i][0]==1 && dma_isr[i][1]==0 &&                                          //if the DMA channel is enabled
+                       (wr_peripheral_interrupt[periph_connected_to_channel_i]==1      //if the peripheral has raised an interrupt
+                       || dma_ccr[i][14]==1                                                                                    //if M2M transfer, need not check for interrupt
+                       //|| (dma_ccr[4]==1 && !rg_burst)       //if not burst mode, the interrupt of periph needn't be high when reading from memory
+                                                                                               //if in burst mode, its better if the peripheral is ready, and then we fetch the word from memory? TODO
+                       )) begin 
+                               //check if its priority is greater than any of the other peripherals' priority
+                               //here we check for equality also as the channels with lower number have higher priority.
+                               //therefore if two requests have same "high" software priority, the channel whose channel number
+                               //is lower will be chosen
+                               if(dma_ccr[i][13:12]>=max_priority_num) begin
+                                       max_priority_num= dma_ccr[i][13:12];    //if so, then set the current priority level to be that of peripheral[i]
+                                       grant_chan_id= fromInteger(i);
+                                       grant_periph_id= periph_connected_to_channel_i;
+                               end
+                       end
+               end
+               return tuple2(grant_chan_id,grant_periph_id);
+       endfunction
+
+       function Bit#(16) fn_decr_cndtr(Bit#(16) cndtr, Bit#(2) tsize, Bit#(`Burst_length_bits) bsize);
+               Bit#(17) lv_to_sub= (zeroExtend(bsize)+1) << tsize;
+               Bit#(17) lv_result= {1'b0,cndtr}-lv_to_sub;
+               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.
+                       return 0;
+        else
+                   return lv_result[15:0];
+    endfunction
+
+       // This function increments the source or destination address depending on
+       // the size of the transfer.
+       // Note that though STM's DMA defines tsize=2'b11 as reserved, we use it to
+       // perform a 64-bit data transfer.
+       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));
+               Bit#(a) lv_to_add= (zeroExtend(bsize)+1) << tsize;
+               Bit#(a) lv_result= {1'b0,addr}+lv_to_add;
+               return truncate(lv_result);
+       endfunction
+
+       //This function performs the data alignment for 64 bit data
+       function Bit#(64) fn_data_alignment64 (Bit#(64) data, Bit#(2) source_sz, Bit#(2) dest_sz);
+               Bit#(64) outp;
+               case (source_sz) matches
+                       2'd0: begin 
+                                       outp= zeroExtend(data[7:0]);
+                                 end
+                       2'd1: begin
+                                       if(dest_sz==2'd0)
+                                               outp= zeroExtend(data[7:0]);
+                                       else
+                                               outp= zeroExtend(data[15:0]);
+                                 end
+                       2'd2: begin
+                                       if(dest_sz==2'd0)
+                                               outp= zeroExtend(data[7:0]);
+                                       else if(dest_sz==2'd1)
+                                               outp= zeroExtend(data[15:0]);
+                                       else 
+                                               outp= zeroExtend(data[31:0]);
+                                 end
+                       2'd3: begin
+                                       if(dest_sz==2'd0)
+                                               outp= zeroExtend(data[7:0]);
+                                       else if(dest_sz==2'd1)
+                                               outp= zeroExtend(data[15:0]);
+                                       else if(dest_sz== 2'd2)
+                                               outp= zeroExtend(data[31:0]);
+                                       else
+                                               outp= data;
+                                 end
+               endcase
+               return outp;
+       endfunction
+
+       // DMA rules //////////////////////////////////////////////////
+       // We define a function inside the module so it can access some
+       // of the registers without passing too many arguments.  
+       // The function takes as arguments the conditions and fifos
+       // (interfaces)
+       // And returns a set a rules.
+       // The rule are identical to the set used in the one mmu port case.
+       function Rules generatePortDMARules (AXI4_Master_Xactor_IFC#(`PADDR,`Reg_width,`USERSPACE) xactor, Integer chanNum);
+               return
+               rules
+
+           /*rule display_stat(dma_ccr[chanNum][0]==1 || tpl_1(rg_disable_channel));
+                       Bit#(2) max_priority_num= 0;
+                       //stores id of the periph whose channel has been granted to generate req in this cycle.
+                       Bit#(TLog#(numChannels)) grant_chan_id= 'd-1;
+                       Bit#(TLog#(numPeripherals)) grant_periph_id= 'd-1;
+                       for(Integer i=valueOf(numChannels)-1; i>=0; i=i-1) begin                        //for every channel
+                               let periph_connected_to_channel_i=fn_map_channel_to_periph(i);  //identify the peripheral connected to this channel
+                               //$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()));
+                               if(dma_ccr[i][0]==1 && dma_isr[i][1]==0 &&                                          //if the DMA channel is enabled
+                                 (wr_peripheral_interrupt[periph_connected_to_channel_i]==1    //if the peripheral has raised an interrupt
+                                 || dma_ccr[i][14]==1                                                                                  //if M2M transfer, need not check for interrupt
+                                 //|| (dma_ccr[4]==1 && !rg_burst)
+                                 )) begin //if not burst mode, the interrupt of periph needn't be high when reading from memory
+                                       //check if its priority is greater than any of the other peripherals' priority
+                                       //here we check for equality also as the channels with lower number have higher priority.
+                                       //therefore if two requests have same "high" software priority, the channel whose channel number
+                                       //is lower will be chosen
+                                       if(dma_ccr[i][13:12]>=max_priority_num) begin
+                                               max_priority_num= dma_ccr[i][13:12];    //if so, then set the current priority level to be that of peripheral[i]
+                                               grant_chan_id= fromInteger(i);
+                                               grant_periph_id= periph_connected_to_channel_i;
+                                               //$display("########## grant chan: %d grant periph_id: %d", grant_chan_id, grant_periph_id);
+                                       end
+                               //$display("dma_ccr[%d][13:12]: %b max_prio: %b",i,dma_ccr[i][13:12],max_priority_num);
+                               end
+                       end
+                       if(pack(wr_peripheral_interrupt)!=0 || dma_ccr[chanNum][14]==1) begin
+                               Reg#(Bit#(64)) lv_dma_ifcr= regAToRegBitN( vector7ToRegN( dma_ifcr ));
+                               $display($time,"Chan%d: cndtr: %h dma_isr: %h dma_ifcr: %h", chanNum, dma_cndtr[chanNum], dma_isr[chanNum], lv_dma_ifcr );
+                       end
+                       //$display($time,"grant chan_id: %d periph_id: %d",grant_chan_id,grant_periph_id);
+                       //$display("Channel no. %d user_id: %d", chanNum, xactor.o_rd_data.first.ruser); 
+        endrule*/
+
+               // To start a read, following conditions need to be met
+               // 1. There is data to be transferred
+               // 2. The dma is enabled (dma_ccr[chanNum][0]=1)
+               // 3. The channel has the highest priority
+               // 4. If multiple channels have same high priority, choose the one whose channel number is lowest
+               // 5. A channel is disabled before the complete transfer is finished, do not initiate any more requests
+               // The 2nd, 3rd and 4th conditions are handled by fn_dma_priority_encoder
+               (* descending_urgency =  "rl_startWrite, rl_startRead" *)
+               //(* preempts = "rl_finishRead, rl_can_change_channel" *)
+               //(* preempts = "rl_startWrite, rl_can_change_channel" *)
+               //(* preempts = "rl_send_burst_write_data, rl_can_change_channel" *)
+               rule rl_startRead       ( !rg_is_cndtr_zero[chanNum][0] &&      //no of bytes remaining to transfer is not 0
+                                                         fromInteger(chanNum) == tpl_1(fn_dma_priority_encoder()) &&  //if the this channel has the highest priority
+                                                         (!tpl_1(rg_disable_channel) ||  tpl_2(rg_disable_channel)!=fromInteger(chanNum))
+                                                               && rg_finish_read[chanNum][1]); //if the channel is not being disabled by the processor
+                       Req_Addr lv_araddr;
+                       Bit#(2) lv_arsize;
+                       bit lv_burst_type;
+                       let lv_dma_ccr= dma_ccr[chanNum];
+                       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
+                       let lv_periph_id= tpl_2(fn_dma_priority_encoder());
+
+                       if(lv_dma_ccr[6]==1)    //peripheral increment mode is on
+                               rg_cpa[chanNum]<= fn_incr_address(rg_cpa[chanNum], lv_dma_ccr[9:8], dma_ccr[chanNum][`Burst_length_bits+15:16]);
+                       if(lv_dma_ccr[7]==1)    //memory increment mode is on
+                               rg_cma[chanNum]<= fn_incr_address(rg_cma[chanNum], lv_dma_ccr[11:10], dma_ccr[chanNum][`Burst_length_bits+15:16]);
+
+                       if(lv_dma_ccr[4]==0) begin              //read from peripheral
+                               lv_araddr= rg_cpa[chanNum];     //set the address to read from
+                               lv_arsize= lv_dma_ccr[9:8];     //set the transfer size
+                               lv_burst_type= lv_dma_ccr[6];   //0: Fixed, 1: INCR which is consistent with that of AXI4
+                               `ifdef verbose $display($time,"\tDMA: chan[%0d] starting read from peripheral address %h",chanNum, lv_araddr); `endif
+                               // Since the destination is memory, the write request needn't wait for any interrupt line to be high
+                               // Therefore, we send the first argument as Invalid
+                               destAddrFs[chanNum].enq( DestAddrFs_type {      addr: rg_cma[chanNum], // Enqueue the Write destination address
+                                                                                                                       is_dest_periph: False,
+                                                                                                                       periph_id: lv_periph_id});
+                       end
+                       else begin                                                      //read from memory
+                               lv_araddr= rg_cma[chanNum];             //set the address to read from
+                               lv_arsize= lv_dma_ccr[11:10];   //set the transfer size
+                               lv_burst_type= lv_dma_ccr[7];   //0: Fixed, 1: INCR which is consistent with that of AXI4
+                               `ifdef verbose $display($time,"\tDMA: chan[%0d] starting read from memory address %h",chanNum, lv_araddr); `endif
+                               // Since the destination address is that of a peripheral, the write request can be issued only when
+                               // the corresponding peripheral's interrupt line is high. Therefore, we send the periph_id too.
+                               Bool lv_is_dest_periph;
+                               if(lv_dma_ccr[14]==0)
+                                       lv_is_dest_periph= True;
+                               else
+                                       lv_is_dest_periph= False;
+                    `ifdef verbose $display("dest_is_periph: %h",lv_is_dest_periph); `endif
+                               destAddrFs[chanNum].enq( DestAddrFs_type {      addr: rg_cpa[chanNum], // Enqueue the Write destination address
+                                                                                                                       is_dest_periph: lv_is_dest_periph,
+                                                                                                                       periph_id: lv_periph_id});
+
+                       end
+
+                       // Create a read request, and enqueue it
+                       // Since there can be multiple pending requests, either read or
+                       // writes, we use the `Req_Info field to mark these.
+                       let read_request = AXI4_Rd_Addr {araddr: lv_araddr, 
+                                                                                        arid: {1'b1,fromInteger(chanNum)}, arlen: lv_burst,
+                                                                                        arsize: zeroExtend(lv_arsize), arburst: zeroExtend(lv_burst_type), //arburst: 00-FIXED 01-INCR 10-WRAP
+                                                                                        aruser: 0 };
+                               
+                       xactor.i_rd_addr.enq(read_request);
+            `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
+
+                       //housekeeping. To be done when the transaction is complete.
+                       currentReadRs[chanNum][0]<= currentReadRs[chanNum][0] + 1;
+            dma_cndtr[chanNum]<= fn_decr_cndtr(dma_cndtr[chanNum], lv_arsize, dma_ccr[chanNum][`Burst_length_bits+15:16]);
+            rg_current_trans_chan_id<= fromInteger(chanNum);
+                       rg_finish_read[chanNum][1]<= False;
+               endrule
+
+               // We finish the read when we see the correct respInfo on the mmu response fifo
+               rule rl_finishRead (xactor.o_rd_data.first.rid == {1'b1,fromInteger(chanNum)} && xactor.o_rd_data.first.rresp==AXI4_OKAY);
+                       // update cndtr register to keep track of remaining transactions
+                       let lv_dma_ccr= dma_ccr[chanNum];
+                       Bit#(2) lv_tsize;
+                       Bit#(2) lv_source_size;
+
+                       if(dma_ccr[chanNum][4]==0) begin                //if the source is peripheral
+                               lv_tsize= dma_ccr[chanNum][11:10];      //destination's tsize will be that of memory
+                               lv_source_size= dma_ccr[chanNum][9:8];
+                       end
+                       else begin
+                               lv_tsize= dma_ccr[chanNum][9:8];        //destination's tsize will be that of peripheral
+                               lv_source_size= dma_ccr[chanNum][11:10];
+                       end
+
+                       // grab the data from the mmu reponse fifo
+                       let resp <- pop_o(xactor.o_rd_data);
+                       `ifdef verbose $display("DMA: chan[%d] finish read. Got data: %h",chanNum, resp.rdata); `endif
+
+                       // Pass the read data to the write "side" of the dma
+                       responseDataFs[chanNum].enq( resp.rdata );
+                       rg_finish_read[chanNum][0]<= True;
+               endrule
+
+               //rule to handle circ mode
+               rule rl_handle_circ_mode(dma_ccr[chanNum][5]==1 && rg_is_cndtr_zero[chanNum][1]); //if circular mode is enabled
+                       dma_cndtr[chanNum]<= rg_cndtr[chanNum];
+               endrule
+
+               // This rule start the write process
+               // Note that this rule conflicts with rule startRead, so we make
+               // this rule be more urgent. i.e., finish writing before you start
+               // reading more.
+               /*rule rl_startWrite111;
+                       $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]);
+               endrule*/
+
+               rule rl_startWrite( (destAddrFs[chanNum].first.is_dest_periph==False            //if the dest is memory
+               || wr_peripheral_interrupt[ destAddrFs[chanNum].first.periph_id ]==1)   //if dest is not memory, then check if the peripheral's interrupt line is active
+               && rg_burst_count==0 && rg_finish_write[chanNum][1]==True);
+                       let lv_data= destAddrFs[chanNum].first;
+
+                       Bit#(2) lv_tsize;
+                       bit lv_burst_type;
+                       let lv_dma_ccr= dma_ccr[chanNum];
+                       if(lv_dma_ccr[4]==0) begin                      //if the source is peripheral
+                               lv_tsize= lv_dma_ccr[11:10];    //destination's tsize will be that of memory
+                               lv_burst_type= lv_dma_ccr[7];   //destination's burst type will be that of memory
+                       end
+                       else begin
+                               lv_tsize= lv_dma_ccr[9:8];              //destination's tsize will be that of peripheral
+                               lv_burst_type= lv_dma_ccr[6];   //destination's burst type will be that of peripheral
+                       end
+
+                       Bit#(`Reg_width) actual_data= responseDataFs[chanNum].first;
+                       Bit#(`Burst_length_bits) lv_burst_len= lv_dma_ccr[`Burst_length_bits+15:16];
+               //      Bit#(6) x = {3'b0,lv_data.addr[2:0]}<<3;
+                       Bit#(8) write_strobe=lv_tsize==0?8'b1:lv_tsize==1?8'b11:lv_tsize==2?8'hf:8'hff;
+                       if(lv_tsize!=3)begin                    // 8-bit write;
+                               //actual_data=actual_data<<(x);
+                               write_strobe=write_strobe<<(lv_data.addr[`byte_offset:0]);
+                       end
+                       //lv_data.addr[2:0]=0; // also make the address 64-bit aligned
+            `ifdef verbose $display("Start Write"); `endif
+
+                       
+                       Bool lv_last= True;
+                       if(lv_burst_len>0) begin // only enable the next rule when doing a write in burst mode.
+                               rg_burst_count<=rg_burst_count+1;
+                               lv_last= False;
+                               `ifdef verbose $display("Starting burst mode write...."); `endif
+                       end
+                       `ifdef verbose
+                       else begin
+                               $display("Performing a single write...");
+                       end 
+                       `endif
+
+            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
+            rg_tsize <= lv_tsize; //Storing rg_tsize in a register. ~Vinod
+                       // Generate a Write 
+                       let write_data = AXI4_Wr_Data { wdata: actual_data , wstrb: write_strobe, wlast: lv_last, wid: {1'b1,fromInteger(chanNum)}};
+                       let write_addr = AXI4_Wr_Addr { awaddr: lv_data.addr,  awuser: 0,
+                                                                                       awlen: lv_burst_len, awsize: zeroExtend(lv_tsize), awburst: zeroExtend(lv_burst_type),
+                                                                                       awid: {1'b1,fromInteger(chanNum)} };
+
+                       // enqueue the request.
+                       xactor.i_wr_data.enq(write_data);
+                       xactor.i_wr_addr.enq(write_addr);
+                       rg_finish_write[chanNum][1]<= False;
+
+                       // Some other house keeping - removing the data from the fifos
+                       responseDataFs[chanNum].deq;
+                       destAddrFs[chanNum].deq;        //dequeing this FIFO will cause startRead to fire.
+                       `ifdef verbose $display ($time,"\tDMA[%0d] startWrite addr: %h data: %h", chanNum,lv_data.addr,responseDataFs[chanNum].first); `endif
+               endrule
+
+               //This rule is used to send burst write data. The explicit condition ensures that we
+               //send burst length number of data i.e. rg_burst_count>1. When rg_burst_count = the burst
+               //length specified in dma_ccr, rg_burst_count becomes 0. Since rg_burst_count!=0 infers
+               //lesser hardware compared to rg_burst_count>1, we write that as the explicit condition.
+               rule rl_send_burst_write_data(rg_burst_count!=0);// && dma_ccr[chanNum][`Burst_length_bits+15:16]!='d0);
+                       Bool lv_last= rg_burst_count==dma_ccr[chanNum][`Burst_length_bits+15:16];
+                       /*==  Since this is going to always be a line write request in burst mode No need of shifting data and address=== */
+            let write_strobe = rotateBitsBy(rg_write_strobe,1<<rg_tsize); //~Vinod Rotating write_strobe by awsize
+                       let w  = AXI4_Wr_Data {wdata:  responseDataFs[chanNum].first, wstrb: write_strobe , wlast: lv_last, wid: {1'b1, fromInteger(chanNum)} };
+               xactor.i_wr_data.enq(w);
+                       `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
+                       if(lv_last)begin
+                               `ifdef verbose $display("Last data received..."); `endif
+                               rg_burst_count<=0;
+                       end
+                       else begin
+                               rg_burst_count<=rg_burst_count+1;
+                       end
+                       responseDataFs[chanNum].deq;
+            rg_write_strobe <= write_strobe;
+               endrule
+
+
+               // This rule waits for the write to finish
+               rule rl_finishWrite( (xactor.o_wr_resp.first.bid == {1'b1, fromInteger(chanNum)}) &&
+               (xactor.o_wr_resp.first.bresp==AXI4_OKAY) );
+                       let x<- pop_o(xactor.o_wr_resp) ;                        // take the response data and finish
+                       currentWriteRs[chanNum][0]<= currentWriteRs[chanNum][0] + 1;
+                       `ifdef verbose $display ("DMA[%0d]: finishWrite", chanNum); `endif
+                       rg_finish_write[chanNum][0]<= True;
+               endrule
+               
+               rule rl_cndtr_is_zero;
+                       rg_is_cndtr_zero[chanNum][0]<= (dma_cndtr[chanNum]==0);
+               endrule
+
+       endrules;
+       endfunction
+
+       function Rules generateTransferDoneRules( Integer chanNum );
+               return
+               rules
+                       // Conditions to mark when transfer is done.
+                       // This rule will not fire for when circular mode because dma_cndtr[chanNum] is updated 
+                       // in the next cycle, which is before currentWriteRs can possibly get updated.
+                       rule markTransferDone ( dma_ccr[chanNum][0]==1 &&       //if the channel is enabled
+                                                                       rg_is_cndtr_zero[chanNum][0] && //if the remaining data to transfer is 0
+                                                                       currentWriteRs[chanNum][0]== currentReadRs[chanNum][0]) ;       //the final write has finished
+                               //dmaEnabledRs[chanNum]._write (False) ; 
+                               currentWriteRs[chanNum][0] <= 0 ;
+                               currentReadRs[chanNum][0]  <= 0 ;
+                               $display ("DMA[%0d]: transfer done", chanNum);
+                       endrule
+               endrules ;
+       endfunction
+
+       // Generate the rules, place them in priority order
+       //
+       Rules ruleset = emptyRules;
+
+       for (Integer ch = 0; ch < valueof (numChannels); ch = ch + 1)
+               ruleset = rJoinDescendingUrgency (ruleset,
+                                       generatePortDMARules( m_xactor, ch));
+
+       //
+       for (Integer ch = 0; ch < valueof (numChannels); ch = ch + 1)
+               ruleset = rJoinDescendingUrgency (ruleset,
+                                       generateTransferDoneRules(ch));
+
+
+
+       (* descending_urgency = "rl_write_response_error, rl_read_response_error" *)
+       rule rl_write_response_error(m_xactor.o_wr_resp.first.bresp == AXI4_SLVERR || m_xactor.o_wr_resp.first.bresp == AXI4_DECERR);
+               wr_bus_err<= tagged Valid m_xactor.o_wr_resp.first.bid;
+       endrule
+
+       rule rl_read_response_error(m_xactor.o_rd_data.first.rresp == AXI4_SLVERR || m_xactor.o_rd_data.first.rresp == AXI4_DECERR);
+               wr_bus_err<= tagged Valid m_xactor.o_rd_data.first.rid;
+       endrule
+
+       rule handle_interrupts; //interrupts will be raised only when channel is enabled
+               for (Integer chanNum = 0; chanNum < valueOf (numChannels); chanNum = chanNum + 1) begin
+                       Bit#(4) chan_isr= 'd0;  //TEIF, HTIF, TCIF, GIF
+                       Bit#(32) lv_dma_ccr= dma_ccr[chanNum];
+                       //$display("*** chan: %d en: %d dma_cndtr: %h rg_cndtr: %h",chanNum, dma_ccr[chanNum][0], dma_cndtr[chanNum], rg_cndtr[chanNum]);
+                       if(wr_bus_err matches tagged Valid .chan_num &&& fromInteger(chanNum)=={1'b1, chan_num[2:0]}) begin
+                               chan_isr[3]=1;
+                               $display("Bus error on channel %d",chanNum);
+                       end
+                       if(lv_dma_ccr[0]==1) begin
+                               if(currentWriteRs[chanNum][1]==currentReadRs[chanNum][1]) begin //once the read and write transactions are over
+                                       if(rg_is_cndtr_zero[chanNum][0]) //TODO check what happens if you read from port 1 here
+                                               chan_isr[1]= 1;
+                               end
+                               //The Half Transfer Complete will be set when half transfer is complete.
+                               //Since dma_cndtr is modified by startRead rule, though it would've become half,
+                               //the transaction wouldn't be complete till the write is over. Also, by the time write is over, 
+                               //another read request could've been issued. Therefore, we have the below condition.
+                               if(dma_cndtr[chanNum]<=(rg_cndtr[chanNum]>>1) && rg_finish_write[chanNum][1]) begin
+                                       chan_isr[2]= 1;
+                               end
+                       end
+                       chan_isr[0]= chan_isr[3] | chan_isr[2] | chan_isr[1];   //Setting the GIF
+                       chan_isr= dma_isr[chanNum][3:0] | chan_isr; //Sticky nature of interrupts. Should be cleared by software using ifcr.
+                       
+                       //The bits in IFCR represent the interrupts that need to be cleared
+                       chan_isr= chan_isr & ~(dma_ifcr[chanNum]);
+                       dma_isr[chanNum]<= chan_isr;
+//            $display("chan_isr %b dma_cndtr[%d] :%h",chan_isr,chanNum,dma_cndtr[chanNum]);
+               end
+       endrule
+
+
+       // Rules and other code to interface config port /////////////
+
+       // Add a zero-size register as a default for invalid addresses
+       Reg#(Bit#(0)) nullReg <- mkReg( ? ) ;
+
+       // For ease of development we want all registers to look like 64
+       // bit resister-- the data size of the config socket.
+       // Create function to map from address to specific registers
+       function Tuple2#(Reg#(Req_Data), Bool) selectReg( Req_Addr addr );
+        Bit#(8) taddr = truncate( addr ) ;
+        return
+        case ( taddr )
+            8'h00 : return tuple2(regAToRegBitN( vector7ToRegN( dma_isr )), True);
+            8'h04 : return tuple2(regAToRegBitN( vector7ToRegN( dma_ifcr )), True);
+            8'hB0 : return tuple2(regAToRegBitN( vector7ToRegN( dma1_cselr )), True);
+            8'h08 : return tuple2(regAToRegBitN( dma_ccr[0] ), True);  //32-bit
+            8'h0c : return tuple2(regAToRegBitN( dma_cndtr[0] ), True); //16-bit -- 32-bit Addr 
+            8'h10 : return tuple2(regAToRegBitN( dma_cpar[0] ), True); //64-bit
+            8'h18 : return tuple2(regAToRegBitN( dma_cmar[0] ), True); //64-bit
+            8'h20 : return tuple2(regAToRegBitN( dma_ccr[1] ), True);
+            8'h24 : return tuple2(regAToRegBitN( dma_cndtr[1] ), True);
+            8'h28 : return tuple2(regAToRegBitN( dma_cpar[1] ), True);
+            8'h30 : return tuple2(regAToRegBitN( dma_cmar[1] ), True);
+            8'h38 : return tuple2(regAToRegBitN( dma_ccr[2] ), True);
+            8'h3C : return tuple2(regAToRegBitN( dma_cndtr[2] ), True);
+            8'h40 : return tuple2(regAToRegBitN( dma_cpar[2] ), True);
+            8'h48 : return tuple2(regAToRegBitN( dma_cmar[2] ), True);
+            8'h50 : return tuple2(regAToRegBitN( dma_ccr[3] ), True);
+            8'h54 : return tuple2(regAToRegBitN( dma_cndtr[3] ), True);
+            8'h58 : return tuple2(regAToRegBitN( dma_cpar[3] ), True);
+            8'h60 : return tuple2(regAToRegBitN( dma_cmar[3] ), True);
+            8'h68 : return tuple2(regAToRegBitN( dma_ccr[4] ), True);
+            8'h6C : return tuple2(regAToRegBitN( dma_cndtr[4] ), True);
+            8'h70 : return tuple2(regAToRegBitN( dma_cpar[4] ), True);
+            8'h78 : return tuple2(regAToRegBitN( dma_cmar[4] ), True);
+            8'h80 : return tuple2(regAToRegBitN( dma_ccr[5] ), True);
+            8'h84 : return tuple2(regAToRegBitN( dma_cndtr[5] ), True);
+            8'h88 : return tuple2(regAToRegBitN( dma_cpar[5] ), True);
+            8'h90 : return tuple2(regAToRegBitN( dma_cmar[5] ), True);
+            8'h98 : return tuple2(regAToRegBitN( dma_ccr[6] ), True);
+            8'h9C : return tuple2(regAToRegBitN( dma_cndtr[6] ), True);
+            8'hA0 : return tuple2(regAToRegBitN( dma_cpar[6] ), True);
+            8'hA8 : return tuple2(regAToRegBitN( dma_cmar[6] ), True);
+            default: return tuple2(regAToRegBitN( nullReg ), False);
+        endcase ;
+    endfunction
+
+       function Bit#(3) ccr_channel_number (Req_Addr addr);
+        Bit#(8) taddr= truncate(addr);
+        return
+        case ( taddr )
+            8'h08 : return 0;
+            8'h20 : return 1;
+            8'h38 : return 2;
+            8'h50 : return 3;
+            8'h68 : return 4;
+            8'h80 : return 5;
+            8'h98 : return 6;
+            default: 'd7;
+        endcase;
+    endfunction
+       
+       Rules writeConfig = (rules
+               rule writeConfig;
+                       let write_addr <- pop_o(s_xactor.o_wr_addr);
+                       let write_data <- pop_o(s_xactor.o_wr_data);
+                       Req_Data lv_data= 0;
+                       Req_Addr lv_addr= 0;
+                       AXI4_Resp lv_bresp= AXI4_OKAY;
+                       Bool lv_send_response= True;
+
+                       if(write_data.wstrb=='hF0) begin
+                               lv_data= zeroExtend(write_data.wdata[63:32]);
+                               lv_addr= {truncateLSB(write_addr.awaddr),3'b100};
+                       end
+                       else if(write_data.wstrb=='h0F) begin
+                               lv_data= zeroExtend(write_data.wdata[31:0]);
+                               lv_addr= {truncateLSB(write_addr.awaddr),3'b000};
+                       end
+                       else if(write_data.wstrb=='hFF) begin
+                               lv_data= write_data.wdata;
+                               lv_addr= write_addr.awaddr;
+                       end
+                       else begin      //The write request is not 64-bits, and therefore return a bus error
+                               lv_bresp= AXI4_SLVERR;
+                               $display($time,"\tDMA: KAT GAYA");
+                       end
+
+                               `ifdef verbose $display ($time,"\tDMA writeConfig addr: %0h data: %0h", lv_addr, lv_data); `endif
+                       // Select and write the register
+                       let lv1= selectReg(lv_addr);
+                       let thisReg = tpl_1(lv1);
+                       if(!tpl_2(lv1)) begin   //if no register mapping exists for the given address
+                               lv_bresp= AXI4_SLVERR;
+                               $display($time,"\tDMA: Wapas KAT GAYA");
+                       end
+                       //else is not needed as the selectReg function handles it
+
+                       let lv_ccr_channel_number= ccr_channel_number(lv_addr);
+            `ifdef verbose $display("ccr_channel_number %h lv_addr %h",lv_ccr_channel_number, lv_addr); `endif
+                       if( lv_ccr_channel_number!='d-1 && tpl_2(lv1)) begin    //if the current write is happening to one of the channel's CCR.
+                               if(lv_data[0]==1 ) begin                        //if the channel is being enabled
+                                       rg_cpa[lv_ccr_channel_number] <= dma_cpar[lv_ccr_channel_number];       //peripheral address is copied
+                                       rg_cma[lv_ccr_channel_number] <= dma_cmar[lv_ccr_channel_number];       //memory address is copied
+                                       rg_cndtr[lv_ccr_channel_number]<= dma_cndtr[lv_ccr_channel_number];     //the cndtr value is saved
+                                       rg_disable_channel<= tuple3(False,?,?);
+                                       $display("----------------------- ENABLING DMA CHANNEL %d", lv_ccr_channel_number," -----------------------");
+                    
+                    Bit#(3) cmar_align = dma_cmar[lv_ccr_channel_number][2:0]; //Vinod
+                    Bit#(3) cpar_align = dma_cpar[lv_ccr_channel_number][2:0]; //Vinod
+                    
+                    //lv_data[9:8] and lv_data[11:10] gives transfer size supposedly. Using K-Maps --Possibility of a bug?
+                bit cmar_is_aligned =  fn_aligned_addr(write_addr.awaddr[2:0], write_addr.awsize);
+                bit cpar_is_aligned =  fn_aligned_addr(write_addr.awaddr[2:0], write_addr.awsize); 
+
+                if((cmar_is_aligned&cpar_is_aligned)==0) begin
+                        lv_bresp = AXI4_DECERR; //DECERR for Unaligned addresses
+                        $display("\tAXI4_DECERR\n");
+                end
+
+                    $display("cmar_is_aligned: %b cpar_is_aligned: %b",cmar_is_aligned,cpar_is_aligned);
+                                       
+                    
+                    if(lv_data[4]==0) begin
+                                               $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]);
+                                               $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]);
+                                       end
+                                       else if(lv_data[14]==0) begin
+                                               $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]);
+                                               $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]);
+                                       end
+                                       else begin
+                                               $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]);
+                                               $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]);
+                                       end
+                                       $display("Priority level: 'b%b Circular mode: %b CNDTR: 'h%h", lv_data[13:12], lv_data[5], dma_cndtr[lv_ccr_channel_number]);
+                               end
+                               else begin //the channel is being disabled
+                                       //TODO since it is a CReg, what if we check in port [1]?
+                                       if(currentReadRs[lv_ccr_channel_number][0]!=currentWriteRs[lv_ccr_channel_number][0]) begin     //there is an on going transaction
+                                               rg_disable_channel<= tuple3(True, lv_ccr_channel_number, write_addr.awid);
+                                               lv_send_response= False;
+                                               rg_writeConfig_ccr<= tuple2(lv_ccr_channel_number, truncate(lv_data));
+                                       end
+                                       else begin      // no pending transaction
+                                               //clear the local registers
+                                               rg_is_cndtr_zero[lv_ccr_channel_number][0]<= True;
+                                       end
+                               end
+                       end
+
+                       // Now generate the response and enqueue
+                       if(lv_send_response) begin
+                               thisReg <= lv_data;
+                               let resp = AXI4_Wr_Resp { bresp: lv_bresp, buser: 0, bid: write_addr.awid };
+                               s_xactor.i_wr_resp.enq(resp);
+                       end
+               endrule
+       endrules);
+
+       //Rule to send response to processor that the dma channel has been disabled after the on going transactions are over
+       Rules rl_send_chan_disabled_to_proc = (rules
+               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]);
+                       rg_disable_channel<= tuple2(False,?);
+                       dma_ccr[tpl_1(rg_writeConfig_ccr)]<= tpl_2(rg_writeConfig_ccr);
+                       let resp = AXI4_Wr_Resp { bresp: AXI4_OKAY, buser: 0, bid: tpl_3(rg_disable_channel) };
+                       s_xactor.i_wr_resp.enq(resp);
+               endrule
+       endrules);
+
+       //writeConfig gets highest priority since we do not want the core to stall 
+       ruleset= rJoinDescendingUrgency(writeConfig,ruleset); 
+
+       //writeConfig if more urgent than rl_send_chan_disabled_to_proc
+       ruleset= rJoinDescendingUrgency(ruleset, rl_send_chan_disabled_to_proc); 
+
+       // A rule for reading a configuration register
+       //TODO need to add preempts with writeConfig? or mutually_exclusive? Because both these rules will never fire together.
+       // If we do not put any attributes, won't two instances of selectReg get synthesized?
+       rule readConfig;
+               AXI4_Resp lv_rresp;
+               let read_addr <- pop_o(s_xactor.o_rd_addr);
+               // Select the register
+               let lv1= selectReg(read_addr.araddr);
+               let thisReg = tpl_1(lv1);
+
+               //If read happens to a non defined register,
+               //or if read size is not 32-bits return SLVERR.
+               if(!tpl_2(lv1))
+                       lv_rresp= AXI4_SLVERR;
+               else
+                       lv_rresp= AXI4_OKAY;
+
+               Req_Data lv_data;
+               if(read_addr.arsize=='b0)
+                       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]};
+               else if(read_addr.arsize=='b01)
+                       lv_data={thisReg[15:0], thisReg[15:0], thisReg[15:0], thisReg[15:0]};
+               else if(read_addr.arsize=='b10)
+                       lv_data={thisReg[31:0], thisReg[31:0]};
+               else
+                       lv_data= thisReg;
+               // Now generate the response and enqueue
+               let resp = AXI4_Rd_Data {rresp: lv_rresp, rdata: thisReg, rlast: True,
+                                                                ruser: 0, rid: read_addr.arid};
+               s_xactor.i_rd_data.enq(resp);
+       endrule
+
+
+       // Add the rules to this module
+       addRules (ruleset);
+
+       //Note that unknownConfig rule is not needed here because all the FIFOs will
+       //be empty and hence neither writeConfig nor readConfig will fire.
+
+       ////////////////////////////////////////////////////////////////
+       ////////////////////////////////////////////////////////////////
+       //
+       // Create the interfaces by connecting the axi side interfaces
+       // of the transactors to it.
+
+       interface cfg= s_xactor.axi_side;
+       interface mmu= m_xactor.axi_side;
+       
+       //This method receives various interrupts from the peripheral devices and gives it to the DMA
+       method Action interrupt_from_peripherals(Bit#(numPeripherals) pint);
+               wr_peripheral_interrupt<= unpack(pint);
+       endmethod
+
+       //TODO should the interrupt be sent in the next cycle (as is implemented) or in the same cycle as generated (using Wires instead)?
+       //This method returns the interrupt generated by the DMA corresponding to every channel
+       //Raise the interrupt of a particular channel if any of the interrupts are active (in ISR) and are not masked(in CCR)
+       method Bit#(numChannels) interrupt_to_processor();
+               Bit#(numChannels) lv_interrupt_to_processor;
+               for(Integer chanNum= 0; chanNum < valueof(numChannels); chanNum= chanNum + 1) begin
+                       let lv_dma_ccr= dma_ccr[chanNum];
+                       //The bits in CCR represent the interrupts that are enabled, whereas the ones in IFCR represent which need to be cleared
+                       let lv_intr_TE_HT_TC_enable= lv_dma_ccr[3:1];
+
+                       //The bits in ISR represent which interrupts are active right now
+                       Bit#(3) active_interrupts= {lv_intr_TE_HT_TC_enable} & dma_isr[chanNum][3:1];
+                       lv_interrupt_to_processor[chanNum]= |(active_interrupts);
+               end
+               return lv_interrupt_to_processor;
+       endmethod
+endmodule
+
+endpackage
diff --git a/src/peripherals/dma/DMA.defines b/src/peripherals/dma/DMA.defines
new file mode 100644 (file)
index 0000000..f442371
--- /dev/null
@@ -0,0 +1,4 @@
+`define  Req_Info_sz 10
+`define  Req_Addr_sz 64
+`define  Req_Data_sz 64
+`define Burst_length_bits 8
diff --git a/src/peripherals/dma/DMA_try.bsv b/src/peripherals/dma/DMA_try.bsv
new file mode 100644 (file)
index 0000000..0e50821
--- /dev/null
@@ -0,0 +1,593 @@
+/*
+Copyright (c) 2013, IIT Madras
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+*  Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+*  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.
+*  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.
+
+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. 
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+*/
+package DMA ;
+
+// ================================================================
+// Copyright (c) Bluespec, Inc., 2007-2011 All Rights Reserved
+
+import FIFO :: * ;
+import FIFOF :: * ;
+import Vector :: * ;
+import GDefines::*;
+import FShow::*;
+import GetPut::*;
+import DefaultValue ::*;
+
+`include "ARM.defines"
+
+// ================================================================
+// DMA requests and responses
+
+// ----------------
+// Requests
+
+typedef enum { NOP, WR, RD } ReqOp
+                 deriving (Bits, Eq);
+
+instance FShow #(ReqOp);
+       function Fmt fshow (ReqOp op);
+               case (op)
+        NOP : return fshow ("NOP");
+        WR  : return fshow ("WR");
+        RD  : return fshow ("RD");
+               endcase
+       endfunction
+endinstance
+
+typedef Bit#(10)  ReqInfo;
+typedef Bit#(32)  ReqAddr;
+typedef Bit#(32)  ReqData;
+
+typedef struct {
+  ReqOp                                                reqOp;
+  ReqInfo                                      reqInfo;
+  ReqAddr                                      reqAddr;
+  ReqData                                      reqData;
+} Socket_Req
+  deriving (Bits);
+
+instance FShow #(Socket_Req);
+       function Fmt fshow (Socket_Req req);
+               return (fshow ("Socket_Req{")
+                       +
+                       fshow (req.reqOp)
+                       +
+                       (  (req.reqOp() != NOP)
+                        ? $format (", %h, %h, %h}", req.reqInfo(), req.reqAddr(), req.reqData())
+                        : fshow (""))
+                       +
+                       fshow ("}"));
+       endfunction
+endinstance
+
+// ================================================================
+// Responses
+
+typedef enum { NOP, OK } RespOp
+                 deriving (Bits, Eq);
+
+instance FShow #(RespOp);
+       function Fmt fshow (RespOp op);
+               case (op)
+        NOP  : return fshow ("NOP");
+        OK     : return fshow ("OK");
+               endcase
+       endfunction
+endinstance
+
+typedef Bit#(10)       RespInfo;
+typedef Bit#(1)         RespAddr;
+typedef Bit#(32)       RespData;
+
+typedef struct {
+  ReqOp                                                reqOp;
+  RespOp                                         respOp;
+  RespInfo                                     respInfo;
+  RespAddr                                     respAddr;
+  RespData                                     respData;
+} Socket_Resp
+  deriving (Eq, Bits);
+
+instance FShow #(Socket_Resp);
+       function Fmt fshow (Socket_Resp resp);
+               return (fshow ("Socket_Resp{")
+                       +
+                       fshow (resp.respOp())
+                       +
+                       (  (resp.respOp() != NOP)
+                        ? $format (", %h, %h, %h", resp.respInfo(), resp.respAddr(), resp.respData())
+                        : fshow (""))
+                       +
+                       fshow ("}"));
+       endfunction
+endinstance
+
+// ----------------------------------------------------------------
+// At times it is best to consider registers as completely homogeneous,
+// so that they can be accessed as a bit pattern with no internal
+// structure.  These functions convert reg interfaces based on a
+// structured type to reg interfaces based on a bit pattern of at
+// least the same width.
+
+function Reg#(Bit#(n)) regAToRegBitN( Reg#(a_type) rin )
+       provisos ( Bits#( a_type, asize),
+                                Add#(asize,xxx,n) ) ;
+
+       return
+       interface Reg
+               method Bit#(n) _read ();
+                       a_type tmp =  rin._read()  ;
+                       return zeroExtend (pack( tmp )) ;
+               endmethod
+               method Action _write( Bit#(n) din );
+                       rin._write( unpack( truncate(din) )) ;
+               endmethod
+       endinterface ;
+
+endfunction
+
+
+
+
+
+
+
+
+
+
+
+// ================================================================
+// The DMA interface has two sub-interfaces
+//       A TLM Receive interface (slave) for config
+//       A TLM Send     interface (master) for data transfers
+
+interface DmaC #(numeric type numChannels);
+       interface AXI4_Lite_Master_IFC#(`PADDR, `Reg_width, 0) cfg;
+       interface TLMRecvIFC#(`ARM_RR) cfg;
+       interface TLMSendIFC#(`ARM_RR) mmu;
+endinterface
+
+
+typedef UInt#(16)  DMACounts ;
+// The number of channels is a parameter.
+// typedef 2 NumChannels;
+
+// For the module, we add additional configuration registers to control
+// which port the transfer reads from and writes to.  
+// The majority of the design remains the same, additional fifos, and
+// interface must be added, as well as adding new rules to control
+// which port is read or written.
+
+// Several configuration registers are included, and connected to the
+// config socket/fifo.
+
+
+module mkDMA( DmaC #(numChannels) );    
+
+       // For each socket, we will need 2 fifos, one for request, and 1
+       // for response.  These fifos provide the interface for the
+       // interface sockets
+       ////////////////////////////////////////////////////////////////
+       // The fifos for the config port -- these are 1 element pipeline fifos.
+       (* doc = "a fifo to hold incoming configuration requests" *)
+       FIFOF#(Socket_Req)      cnfReqF  <- mkFIFOF ;
+       (* doc = "a fifo to hold outgoing configuration responses" *)
+       FIFOF#(Socket_Resp)  cnfRespF <- mkFIFOF;
+
+
+       ////////////////////////////////////////////////////////////////
+       // The fifos for the MMU port
+       (* doc = "a fifo to hold outgoing requests towards the memory" *)
+       FIFOF#(Socket_Req)  mmuReqF  <- mkFIFOF;
+       (* doc = "a fifo to hold incoming responses from the memory" *)
+       FIFOF#(Socket_Resp) mmuRespF <- mkFIFOF;
+
+
+       ////////////////////////////////////////////////////////////////        
+       // The fifos for the config port -- these are 1 element pipeline fifos.
+//      FIFOF#(Socket_Req)     cnfReqF  <- mkGSizedFIFOF(True, False, 2) ;
+//      FIFOF#(Socket_Resp)  cnfRespF <- mkGSizedFIFOF(False, True, 2)  ;
+
+//      // The fifos for the MMU
+//      FIFOF#(Socket_Req)  mmuReqF  <- mkGSizedFIFOF(False, True, 2);
+//      FIFOF#(Socket_Resp) mmuRespF <- mkGSizedFIFOF(True, False, 2);
+
+//      // The fifos for the MMU2
+//      FIFOF#(Socket_Req)  mmu2ReqF  <- mkGSizedFIFOF(False, True, 2);
+//      FIFOF#(Socket_Resp) mmu2RespF <- mkGSizedFIFOF(True, False, 2);
+
+       ////////////////////////////////////////////////////////////////        
+       // We will need some registers to control the DMA transfer
+       // A Bit to signal if the transfer is enabled   
+       Vector#(numChannels, Reg#(Bool))  dmaEnabledRs  <- replicateM(mkReg(False));
+
+       //  The read address and other stuff needed to generate a read
+       Vector#(numChannels, Reg#(ReqAddr))     readAddrRs      <- replicateM(mkReg(0));
+       Vector#(numChannels, Reg#(DMACounts)) readCntrRs  <- replicateM(mkReg(0));
+       Vector#(numChannels, Reg#(DMACounts)) currentReadRs  <- replicateM(mkReg(0));
+       Vector#(numChannels, Reg#(DMACounts)) currentWriteRs <- replicateM(mkReg(0));
+
+       // To distinguish the ports for reads and writes, we need 2 bits
+       Vector#(numChannels,Reg#(Bit#(2)))      portSrcDestRs <- replicateM( mkReg(0)) ;
+
+       // The destination address
+       Vector#(numChannels, Reg#(ReqAddr))  destAddrRs <- replicateM(mkReg(0));
+
+       // Use a FIFO to pass the read response to the write "side",
+       //  thus allowing pending transations and concurrency.
+       // FIFOs can be replicated as well.
+       Vector#(numChannels,FIFO#(ReqData))  
+                 responseDataFs <- replicateM( mkSizedFIFO(2)) ;  
+
+       // We also want to pass the destination address for each read over
+       // to the write "side"
+       // The depth of this fifo limits the number of outstanding reads
+       // which may be pending before the write.  The maximum outstanding
+       // reads depends on the overall latency of the read requests.
+       Vector#(numChannels,FIFO#(ReqAddr)) 
+               destAddrFs <- replicateM( mkSizedFIFO( 4 )) ;                     
+
+       ///  DMA rules //////////////////////////////////////////////////
+       // We define a function inside the module so it can access some
+       // of the registers without passing too many arguments.  
+       // The function takes as arguments the conditions and fifos
+       // (interfaces)
+       // And returns a set a rules.
+       // The rule are identical to the set used in the one mmu port case.
+       function Rules generatePortDMARules (FIFOF#(Socket_Req)  requestF,
+                                                                                                        FIFOF#(Socket_Resp) responseF,
+                                                                                                        Integer chanNum
+                                                                                                        );
+               return
+               rules
+
+               // To start a read, when the dma is enabled and there are data to
+               // move, and we are in the right state 
+               rule startRead (dmaEnabledRs[chanNum]._read && 
+                                                readCntrRs[chanNum] > currentReadRs[chanNum] );
+         // Create a read request, and enqueue it
+         // Since there can be multiple pending requests, either read or
+         // writes, we use the reqInfo field to mark these.            
+                       
+               //let wa= AXI4_Lite_Wr_Addr {awaddr: reqs.first.reqAddr, awprot:0, awuser:0, awlen: 0, awsize: 3, awburst: 'b01};
+                       let req = Socket_Req {reqAddr : readAddrRs[chanNum]._read,
+                                                                        reqData : 0,
+                                                                        reqOp  : RD,
+                                                                        reqInfo : fromInteger(0 + 2*chanNum)};
+                       requestF.enq( req ) ;
+
+                       // Enqueue the Write destination address
+                       destAddrFs[chanNum].enq( destAddrRs[chanNum] ) ;
+
+                       // Some house keeping -- increment the read address,
+                       // decrement the counter.
+                       readAddrRs[chanNum] <= readAddrRs[chanNum] + 4 ;
+                       currentReadRs[chanNum] <=  currentReadRs[chanNum] + 1  ;
+                       destAddrRs[chanNum] <=  destAddrRs[chanNum] + 4 ;
+                       $display ("DMA[%0d] startRead", chanNum);
+               endrule
+
+
+               // We finish the read when we see the correct respInfo on the mmu response fifo
+                       rule finishRead ( responseF.first.respInfo == fromInteger(0 + 2*chanNum) );
+                               // grab the data from the mmu reponse fifo
+                               Socket_Resp resp = responseF.first ;      
+                               responseF.deq ;
+
+                               // Need to consider what to do if the response is an error or
+                               // fail but we will keep it simple for now
+
+                               // Pass the read data to the write "side" of the dma
+                               responseDataFs[chanNum].enq( resp.respData ) ;
+                $display ("DMA[%0d]: finishRead", chanNum);
+                       endrule
+
+               // This rule start the write process
+               // Note that this rule conflicts with rule startRead, so we make
+               // this rule be more urgent. I.e., finish writing before you start
+               // reading more.                        
+                       
+               rule startWrite  ;
+                       // Generate a Write 
+                       let wreq = Socket_Req {reqAddr : destAddrFs[chanNum].first,
+                                                                         reqData : responseDataFs[chanNum].first,
+                                                                         reqOp : WR,
+                                                                         reqInfo : fromInteger(1 + 2*chanNum) } ;
+                                                                                 
+                       // enqueue the request.
+                       requestF.enq( wreq ) ;
+
+                       // Some other house keeping - removing the data from the fifos
+                       destAddrFs[chanNum].deq;
+                       responseDataFs[chanNum].deq;
+                       $display ("DMA[%0d] startWrite", chanNum);
+               endrule
+
+               // This rule waits for the write to finish
+               rule finishWrite((responseF.first.respInfo == fromInteger(1 + 2*chanNum)) );
+                       responseF.deq ;                  // take the response data and finish
+                       currentWriteRs[chanNum]._write (currentWriteRs[chanNum] + 1);
+                       $display ("DMA[%0d]: finishWrite", chanNum);
+               endrule
+                       
+                       
+        endrules;
+       endfunction
+
+       function Rules generateTransferDoneRules( Integer chanNum );
+               return
+               rules
+                       // Conditions to mark when transfer is done
+                       rule markTransferDone (dmaEnabledRs[chanNum]._read &&
+                                                                                (currentWriteRs[chanNum]._read == readCntrRs[chanNum]._read) &&
+                                                                                (currentReadRs[chanNum]._read  == readCntrRs[chanNum]._read) ) ;
+                               dmaEnabledRs[chanNum]._write (False) ; 
+                               currentWriteRs[chanNum] <= 0 ;
+                               currentReadRs[chanNum]  <= 0 ;
+                $display ("DMA[%0d]: transfer done", chanNum);
+                       endrule
+               endrules ;
+       endfunction
+       
+       // Generate the rules, place them in priority order
+       //
+       Rules ruleset = emptyRules;
+
+       for (Integer ch = 0; ch < valueof (numChannels); ch = ch + 1)
+               ruleset = rJoinDescendingUrgency (ruleset,
+                                       generatePortDMARules( mmuReqF, mmuRespF, ch));
+
+       for (Integer ch = 0; ch < valueof (numChannels); ch = ch + 1)
+               ruleset = rJoinDescendingUrgency (ruleset,
+                                       generateTransferDoneRules(ch));
+
+       // Add the rules to this module
+       //
+       addRules (ruleset);
+
+
+
+       
+       
+//      // Now we can generate the rules which can be manipulated further.
+//      Rules r01 = generatePortDMARules( portSrcDestRs[0]._read[0] == 0,
+//                                                                                               portSrcDestRs[0]._read[1] == 0,
+//                                                                                              mmu1ReqF, mmu1RespF, 0 ) ;
+//      Rules r02 = generatePortDMARules( portSrcDestRs[0]._read[0] == 1,
+//                                                                                               portSrcDestRs[0]._read[1] == 1,
+//                                                                                              mmu2ReqF, mmu2RespF, 0 ) ;
+//      Rules r11 = generatePortDMARules( portSrcDestRs[1]._read[0] == 0,
+//                                                                                               portSrcDestRs[1]._read[1] == 0,
+//                                                                                              mmu1ReqF, mmu1RespF, 1 ) ;
+//      Rules r12 = generatePortDMARules( portSrcDestRs[1]._read[0] == 1,
+//                                                                                               portSrcDestRs[1]._read[1] == 1,
+//                                                                                              mmu2ReqF, mmu2RespF, 1 ) ;
+//      Rules td0 = generateTransferDoneRules(0) ;
+//      Rules td1 = generateTransferDoneRules(1) ;
+       
+//      // The set of rules above create a conflict because 2 startRead
+//      // conflict.  To specify priority of the DMA channels, we relate
+//      // the urgency of the rules by joining the rules with following
+//      // rule functions.
+//      Rules r1 = rJoinDescendingUrgency( r01, r11) ;
+//      Rules r2 = rJoinDescendingUrgency( r02, r12) ;
+       
+//      r2 = rJoinDescendingUrgency( r1, r2 ) ;
+//      r2 = rJoinDescendingUrgency( r2, td0 ) ;
+//      r2 = rJoinDescendingUrgency( r2, td1 ) ;
+//      addRules( r2 ) ;  
+       
+       
+       ///  Rules and other code to interface config port /////////////
+
+       // Add a zero-size register as a default for invalid addresses
+       Reg#(Bit#(0)) nullReg <- mkReg( ? ) ;
+
+       // For ease of development we want all registers to look like 32
+       // bit resister-- the data size of the config socket.
+       // Create function to map from address to specific registers
+       // For the multi channel DMA, split the 12 bit address into 2
+       // fields, 4 bits to select the channel, 8 for the register.
+       
+       function Reg#(ReqData) selectReg( ReqAddr addr ) ;
+               Bit#(8) taddr = truncate( addr ) ;
+               Bit#(4) channelSel = truncate ( addr >> 8 ) ;
+               return
+               case ( taddr )
+                       8'h00 :  return regAToRegBitN( readAddrRs[channelSel] ) ;
+                       8'h04 :  return regAToRegBitN( readCntrRs[channelSel] ) ;
+                       8'h08 :  return regAToRegBitN( destAddrRs[channelSel] ) ;
+                       8'h0C :  return regAToRegBitN( dmaEnabledRs[channelSel] ) ;  
+                       8'h10 :  return regAToRegBitN( portSrcDestRs[channelSel] ) ;             
+                       default:  return regAToRegBitN( nullReg ) ;
+               endcase ;
+       endfunction
+
+
+       // A rule for writing to a registers
+       rule writeConfig ( cnfReqF.first.reqOp == WR ) ;
+               let req =  cnfReqF.first ;
+               cnfReqF.deq ;
+
+               $display ("DMA[%0d] writeConfig: ", (req.reqAddr[11:8]), fshow (req));
+
+               // Select and write the register 
+               let thisReg = selectReg( req.reqAddr ) ;
+               thisReg <= req.reqData ;
+
+               // Now generate the response and enqueue
+               let resp = Socket_Resp {respOp  : OK,
+                                                                               reqOp    : WR,
+                                                                               respAddr : 0,
+                                                                               respInfo : req.reqInfo,
+                                                                               respData : req.reqData } ;
+               cnfRespF.enq( resp ) ;
+       endrule
+
+       // A rule for reading a configuration register 
+       rule readConfig ( cnfReqF.first.reqOp == RD ) ;
+               let req =  cnfReqF.first ;
+               cnfReqF.deq ;
+
+               // Select the register 
+               let thisReg = selectReg( req.reqAddr ) ;
+
+               // Now generate the response and enqueue
+               let resp = Socket_Resp {respOp  : OK,
+                                                                               reqOp    : RD,
+                                                                               respAddr : 0,
+                                                                               respInfo : req.reqInfo,
+                                                                               respData : thisReg } ;
+               cnfRespF.enq( resp ) ;
+       endrule
+
+       (* descending_urgency = 
+        "writeConfig, readConfig, unknownConfig"  *)
+       rule unknownConfig ( True ) ;
+               let req =  cnfReqF.first ;
+               cnfReqF.deq ;
+
+               // Select the register 
+               let thisReg = selectReg( req.reqAddr ) ;
+
+               // Now generate the response and enqueue
+               let resp = Socket_Resp {respOp  : NOP,
+                                                                               reqOp    : NOP,
+                                                                               respAddr : 0,
+                                                                               respInfo : req.reqInfo,
+                                                                               respData : thisReg } ;
+               cnfRespF.enq( resp ) ;
+       endrule
+
+       function AXI4_Lite_Master_Xactor_IFC#(wd_addr,wd_dara,wd_user)
+               fifos_to_AXI4_Lite_ifc (FIFOF#(Socket_Req) reqs,
+                               FIFOF#(Socket_Resp) resps);
+               return
+               (interface AXI4_Lite_Master_Xactor_IFC#(wd_addr,wd_data,wd_user)
+                       //interface AXI4_Lite_Master_IFC #(wd_addr, wd_data, wd_user) axi_side;
+                       interface FIFOF_I #(AXI4_Lite_Wr_Addr #(wd_addr, wd_user))
+                               i_wr_addr= fifos_to_AXI4_Lite_Wr_Addr(reqs);
+                       interface FIFOF_I #(AXI4_Lite_Wr_Data #(wd_data))
+                               i_wr_data= fifos_to_AXI4_Lite_Wr_Data(reqs);
+                       interface FIFOF_O #(AXI4_Lite_Wr_Resp #(wd_user))
+                               o_wr_resp= fifos_to_AXI4_Lite_Wr_Resp(resps);
+
+                       interface FIFOF_I #(AXI4_Lite_Rd_Addr #(wd_addr, wd_user));
+                               i_rd_addr= fifos_to_AXI4_Lite_Rd_Addr(reqs);
+                       interface FIFOF_O #(AXI4_Lite_Rd_Data #(wd_data, wd_user))
+                               o_rd_data= fifos_to_AXI4_Lite_Rd_Data(resps);
+               endinterface);
+       endfunction
+
+       function FIFO_I#(AXI4_Lite_Wr_Addr #(wd_addr, wd_user))
+               fifos_to_AXI4_Lite_Wr_Addr#(FIFOF#(Socket_Req) reqs);
+               return interface FIFO_I
+                       method Action  enq(din);
+                               let x= Socket_Req {reqOp: defaultValue,
+                                   reqInfo: defaultValue,
+                                   reqAddr: din.awaddr,
+                                   reqData: defaultValue};
+
+                               reqs.enq (x);
+                       endmethod
+                       method Bool notFull()= reqs.notFull;
+               endinterface
+       endfunction
+
+
+       ////////////////////////////////////////////////////////////////
+       ////////////////////////////////////////////////////////////////
+       //
+       // Create the interfaces by connecting the fifo interfaces to the
+       //  the socket ports.
+
+       interface TLMRecvIFC cfg;
+               interface Get tx;
+                       method ActionValue#(BusResponse) get;
+                               cnfRespF.deq();
+                               return socketRespToBusResp(cnfRespF.first());
+                       endmethod
+               endinterface
+               interface Put rx;
+                       method Action put(x) = cnfReqF.enq(busReqToSocketReq(x));
+               endinterface
+       endinterface
+
+
+
+
+       AXI4_Lite_Master_Xactor_IFC #(`PADDR,`Reg_width,0) m_xactor <- mkAXI4_Lite_Master_Xactor;
+       interface AXI4_Lite_Master_IFC#(`PADDR, `Reg_width, 0) cfg;
+               
+
+
+       interface TLMSendIFC mmu;
+               interface Get tx;
+                       method ActionValue#(BusRequest) get;
+                               mmuReqF.deq();
+                               return socketReqToBusReq(mmuReqF.first());
+                       endmethod
+               endinterface
+               interface Put rx;
+                       method Action put(x) = mmuRespF.enq(busRespToSocketResp(x));
+               endinterface
+       endinterface
+
+endmodule
+
+// ================================================================
+
+function BusResponse socketRespToBusResp(Socket_Resp tmp);
+       BusResponse r = defaultValue;
+       r.error = !(tmp.respOp==OK);
+       r.data = tmp.respData;
+       r.write = (tmp.reqOp==WR);
+       r.id = unpack(truncate(tmp.respInfo));
+       return r;
+endfunction
+
+function BusRequest socketReqToBusReq(Socket_Req tmp);
+       BusRequest r = defaultValue;
+       r.byteen = '1;
+       r.address = tmp.reqAddr;
+       r.data = tmp.reqData;
+       r.write = (tmp.reqOp == WR);
+       r.id = unpack(truncate(tmp.reqInfo));
+       return r;
+endfunction
+
+function Socket_Req busReqToSocketReq(BusRequest x);
+        Socket_Req r = unpack(0);
+        r.reqOp = x.write ? WR : RD;
+        r.reqAddr = x.address;
+        r.reqData = x.data;
+        r.reqInfo = pack(extend(x.id));
+
+        return r;
+ endfunction
+
+ function Socket_Resp busRespToSocketResp(BusResponse x);
+        Socket_Resp r = unpack(0);
+        r.respOp = x.error ? NOP : OK;
+        r.respData = x.data;
+        r.reqOp = x.write ? WR : RD;
+        r.respInfo = pack(extend(x.id));
+        return r;
+ endfunction
+
+endpackage
+
+
+                       
diff --git a/src/peripherals/dma/DMAv2.bsv b/src/peripherals/dma/DMAv2.bsv
new file mode 100644 (file)
index 0000000..ac48ea0
--- /dev/null
@@ -0,0 +1,318 @@
+/*
+Copyright (c) 2013, IIT Madras
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+*  Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+*  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.
+*  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.
+
+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. 
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+*/
+package DMAv2;
+
+// ================================================================
+// Copyright (c) Bluespec, Inc., 2007-2011 All Rights Reserved
+
+import FIFO :: * ;
+import FIFOF :: * ;
+import Vector :: * ;
+import FShow::*;
+import GetPut::*;
+import DefaultValue ::*;
+import AXI4_Types   :: *;
+import AXI4_Fabric  :: *;
+import Semi_FIFOF        :: *;
+
+`include "ARM.defines"
+
+// ================================================================
+// DMA requests and responses parameters
+
+`define  Req_Info_sz 10
+`define  Req_Addr_sz 32
+`define  Req_Data_sz 32
+
+typedef Bit#(`Req_Info_sz) Req_Info; 
+typedef Bit#(`Req_Addr_sz) Req_Addr; 
+typedef Bit#(`Req_Data_sz) Req_Data; 
+//The Req and Resp are of the same width in the current design
+//typedef Bit#(10)     RespInfo;
+//typedef Bit#(1)      RespAddr;
+//typedef Bit#(32)     RespData;
+
+// ----------------------------------------------------------------
+// At times it is best to consider registers as completely homogeneous,
+// so that they can be accessed as a bit pattern with no internal
+// structure.  These functions convert reg interfaces based on a
+// structured type to reg interfaces based on a bit pattern of at
+// least the same width.
+
+function Reg#(Bit#(n)) regAToRegBitN( Reg#(a_type) rin )
+       provisos ( Bits#( a_type, asize),
+                                Add#(asize,xxx,n) ) ;
+
+       return
+       interface Reg
+               method Bit#(n) _read ();
+                       a_type tmp =  rin._read()  ;
+                       return zeroExtend (pack( tmp )) ;
+               endmethod
+               method Action _write( Bit#(n) din );
+                       rin._write( unpack( truncate(din) )) ;
+               endmethod
+       endinterface ;
+endfunction
+
+// ================================================================
+// The DMA interface has two sub-interfaces
+//       A AXI4 Slave interface for config
+//       A AXI4 Master interface for data transfers
+
+interface DmaC #(numeric type numChannels);
+       interface AXI4_Master_IFC#(`Req_Addr_sz,`Req_Data_sz,`Req_Info_sz) mmu;
+       interface AXI4_Slave_IFC#(`Req_Addr_sz,`Req_Data_sz,`Req_Info_sz) cfg;
+endinterface
+
+
+typedef UInt#(16)  DMACounts ;
+// The number of channels is a parameter.
+// typedef 2 NumChannels;
+
+// For the module, we add additional configuration registers to control
+// which port the transfer reads from and writes to.  
+// The majority of the design remains the same, additional fifos, and
+// interface must be added, as well as adding new rules to control
+// which port is read or written.
+
+// Several configuration registers are included, and connected to the
+// config socket/fifo.
+
+
+module mkDMA( DmaC #(numChannels) );    
+
+       // The DMA contains one master interface, and one slave interface. The processor sends
+       // request through the slave interface to set the config registers.
+       // The DMA's master initiates a request to one of the peripherals through one of the
+       // channels. The response is taken (through response sub-interface of DMA's Master interface
+       // and returned to the processor (through response sub-interface of the DMA's Slave interface 
+       AXI4_Slave_Xactor_IFC #(`Req_Addr_sz,`Req_Data_sz,`Req_Info_sz) s_xactor <- mkAXI4_Slave_Xactor;
+       AXI4_Master_Xactor_IFC #(`Req_Addr_sz,`Req_Data_sz,`Req_Info_sz) m_xactor <- mkAXI4_Master_Xactor;
+
+
+       ////////////////////////////////////////////////////////////////        
+       // We will need some registers to control the DMA transfer
+       // A Bit to signal if the transfer is enabled   
+       Vector#(numChannels, Reg#(Bool))  dmaEnabledRs  <- replicateM(mkReg(False));
+
+       //  The read address and other stuff needed to generate a read
+       Vector#(numChannels, Reg#(Req_Addr))    readAddrRs      <- replicateM(mkReg(0));
+       Vector#(numChannels, Reg#(DMACounts)) readCntrRs  <- replicateM(mkReg(0));
+       Vector#(numChannels, Reg#(DMACounts)) currentReadRs  <- replicateM(mkReg(0));
+       Vector#(numChannels, Reg#(DMACounts)) currentWriteRs <- replicateM(mkReg(0));
+
+       // To distinguish the ports for reads and writes, we need 2 bits
+       Vector#(numChannels,Reg#(Bit#(2)))      portSrcDestRs <- replicateM( mkReg(0)) ;
+
+       // The destination address
+       Vector#(numChannels, Reg#(Req_Addr))  destAddrRs        <- replicateM(mkReg(0));
+
+       // Use a FIFO to pass the read response to the write "side",
+       //  thus allowing pending transations and concurrency.
+       // FIFOs can be replicated as well.
+       Vector#(numChannels,FIFO#(Req_Data))  
+                 responseDataFs <- replicateM( mkSizedFIFO(2)) ;  
+
+       // We also want to pass the destination address for each read over
+       // to the write "side"
+       // The depth of this fifo limits the number of outstanding reads
+       // which may be pending before the write.  The maximum outstanding
+       // reads depends on the overall latency of the read requests.
+       Vector#(numChannels,FIFO#(Req_Addr)) 
+               destAddrFs <- replicateM( mkSizedFIFO( 4 )) ;                     
+
+       ///  DMA rules //////////////////////////////////////////////////
+       // We define a function inside the module so it can access some
+       // of the registers without passing too many arguments.  
+       // The function takes as arguments the conditions and fifos
+       // (interfaces)
+       // And returns a set a rules.
+       // The rule are identical to the set used in the one mmu port case.
+       function Rules generatePortDMARules (AXI4_Master_Xactor_IFC#(`Req_Addr_sz,`Req_Data_sz,`Req_Info_sz) xactor,
+                                                                                                        Integer chanNum
+                                                                                                        );
+               return
+               rules
+
+               // To start a read, when the dma is enabled and there are data to
+               // move, and we are in the right state 
+               rule startRead (dmaEnabledRs[chanNum]._read && 
+                                                readCntrRs[chanNum] > currentReadRs[chanNum] );
+         // Create a read request, and enqueue it
+         // Since there can be multiple pending requests, either read or
+         // writes, we use the `Req_Info field to mark these.          
+                       
+                       let read_request = AXI4_Rd_Addr {araddr: readAddrRs[chanNum]._read, arprot: 0,
+                       aruser: fromInteger(0 + 2*chanNum),     arlen: 0, arsize: 2, arburst: 'b0}; // arburst: 00-FIXED 01-INCR 10-WRAP
+                       xactor.i_rd_addr.enq(read_request);
+
+                       // Enqueue the Write destination address
+                       destAddrFs[chanNum].enq( destAddrRs[chanNum] ) ;
+
+                       // Some house keeping -- increment the read address,
+                       // decrement the counter.
+                       readAddrRs[chanNum] <= readAddrRs[chanNum] + 4 ;
+                       currentReadRs[chanNum] <=  currentReadRs[chanNum] + 1  ;
+                       destAddrRs[chanNum] <=  destAddrRs[chanNum] + 4 ;
+                       $display ("DMA[%0d] startRead", chanNum);
+               endrule
+
+
+               // We finish the read when we see the correct respInfo on the mmu response fifo
+               rule finishRead ( xactor.o_rd_data.first.ruser == fromInteger(0 + 2*chanNum) );
+                       // grab the data from the mmu reponse fifo
+                       let resp <- pop_o(xactor.o_rd_data) ;     
+
+                       // Need to consider what to do if the response is an error or
+                       // fail but we will keep it simple for now
+
+                       // Pass the read data to the write "side" of the dma
+                       responseDataFs[chanNum].enq( resp.rdata ) ;
+                       $display ("DMA[%0d]: finishRead", chanNum);
+               endrule
+
+
+               // This rule start the write process
+               // Note that this rule conflicts with rule startRead, so we make
+               // this rule be more urgent. I.e., finish writing before you start
+               // reading more.                        
+               rule startWrite;
+                       // Generate a Write 
+               let write_data = AXI4_Wr_Data {wdata: responseDataFs[chanNum].first, wstrb: 0, wlast:True};
+               let write_addr = AXI4_Wr_Addr {awaddr: destAddrFs[chanNum].first, awprot:0,
+                                                               awuser:fromInteger(1 + 2*chanNum), awlen: 0, awsize: 2, awburst: 0}; 
+
+                       // enqueue the request.
+                       xactor.i_wr_data.enq(write_data);
+                       xactor.i_wr_addr.enq(write_addr);
+
+                       // Some other house keeping - removing the data from the fifos
+                       destAddrFs[chanNum].deq;
+                       responseDataFs[chanNum].deq;
+                       $display ("DMA[%0d] startWrite", chanNum);
+               endrule
+
+               // This rule waits for the write to finish
+               rule finishWrite((xactor.o_wr_resp.first.buser == fromInteger(1 + 2*chanNum)) );
+                       xactor.o_wr_resp.deq ;                   // take the response data and finish
+                       currentWriteRs[chanNum]._write (currentWriteRs[chanNum] + 1);
+                       $display ("DMA[%0d]: finishWrite", chanNum);
+               endrule
+                       
+        endrules;
+       endfunction
+
+       function Rules generateTransferDoneRules( Integer chanNum );
+               return
+               rules
+                       // Conditions to mark when transfer is done
+                       rule markTransferDone (dmaEnabledRs[chanNum]._read &&
+                                                                                (currentWriteRs[chanNum]._read == readCntrRs[chanNum]._read) &&
+                                                                                (currentReadRs[chanNum]._read  == readCntrRs[chanNum]._read) ) ;
+                               dmaEnabledRs[chanNum]._write (False) ; 
+                               currentWriteRs[chanNum] <= 0 ;
+                               currentReadRs[chanNum]  <= 0 ;
+                $display ("DMA[%0d]: transfer done", chanNum);
+                       endrule
+               endrules ;
+       endfunction
+       
+       // Generate the rules, place them in priority order
+       //
+       Rules ruleset = emptyRules;
+
+       for (Integer ch = 0; ch < valueof (numChannels); ch = ch + 1)
+               ruleset = rJoinDescendingUrgency (ruleset,
+                                       generatePortDMARules( m_xactor, ch));
+
+       for (Integer ch = 0; ch < valueof (numChannels); ch = ch + 1)
+               ruleset = rJoinDescendingUrgency (ruleset,
+                                       generateTransferDoneRules(ch));
+
+       // Add the rules to this module
+       //
+       addRules (ruleset);
+
+
+       ///  Rules and other code to interface config port /////////////
+
+       // Add a zero-size register as a default for invalid addresses
+       Reg#(Bit#(0)) nullReg <- mkReg( ? ) ;
+
+       // For ease of development we want all registers to look like 32
+       // bit resister-- the data size of the config socket.
+       // Create function to map from address to specific registers
+       // For the multi channel DMA, split the 12 bit address into 2
+       // fields, 4 bits to select the channel, 8 for the register.
+       
+       function Reg#(Req_Data) selectReg( Req_Addr addr ) ;
+               Bit#(8) taddr = truncate( addr ) ;
+               Bit#(4) channelSel = truncate ( addr >> 8 ) ;
+               return
+               case ( taddr )
+                       8'h00 :  return regAToRegBitN( readAddrRs[channelSel] ) ;
+                       8'h04 :  return regAToRegBitN( readCntrRs[channelSel] ) ;
+                       8'h08 :  return regAToRegBitN( destAddrRs[channelSel] ) ;
+                       8'h0C :  return regAToRegBitN( dmaEnabledRs[channelSel] ) ;  
+                       8'h10 :  return regAToRegBitN( portSrcDestRs[channelSel] ) ;             
+                       default:  return regAToRegBitN( nullReg ) ;
+               endcase ;
+       endfunction
+
+
+       // A rule for writing into configuration registers
+       rule writeConfig;
+               let write_addr <- pop_o(s_xactor.o_wr_addr);
+               let write_data <- pop_o(s_xactor.o_wr_data);
+
+               $display ("DMA[%0d] writeConfig: ", (write_addr.awaddr[11:8]), fshow (write_addr));
+
+               // Select and write the register 
+               let thisReg = selectReg(write_addr.awaddr);
+               thisReg <= write_data.wdata;
+
+               // Now generate the response and enqueue
+               let resp = AXI4_Wr_Resp { bresp: AXI4_OKAY, buser: write_addr.awuser };
+               s_xactor.i_wr_resp.enq(resp);
+       endrule
+
+       // A rule for reading a configuration register 
+       rule readConfig;
+               let read_addr <- pop_o(s_xactor.o_rd_addr);
+               // Select the register 
+               let thisReg = selectReg(read_addr.araddr) ;
+               // Now generate the response and enqueue
+               let resp = AXI4_Rd_Data {rresp: AXI4_OKAY, rdata: thisReg,
+                                                                               rlast:True, ruser: read_addr.aruser};
+               s_xactor.i_rd_data.enq(resp);
+       endrule
+
+       //Note that unknownConfig rule is not needed here because all the FIFOs will
+       //be empty and hence neither writeConfig nor readConfig will fire.
+
+       ////////////////////////////////////////////////////////////////
+       ////////////////////////////////////////////////////////////////
+       //
+       // Create the interfaces by connecting the axi side interfaces
+       // of the transactors to it.
+
+       interface cfg= s_xactor.axi_side;
+       interface mmu= m_xactor.axi_side;
+endmodule
+
+endpackage
+
+
+                       
diff --git a/src/peripherals/dma/GDefines.bsv b/src/peripherals/dma/GDefines.bsv
new file mode 100644 (file)
index 0000000..036b37a
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+Copyright (c) 2013, IIT Madras
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+*  Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+*  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.
+*  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.
+
+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. 
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+*/
+////////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2010  Bluespec, Inc.   ALL RIGHTS RESERVED.
+////////////////////////////////////////////////////////////////////////////////
+//  Filename      : GDefines.bsv
+//  Description   : Global type definitions
+////////////////////////////////////////////////////////////////////////////////
+
+// Notes :
+
+////////////////////////////////////////////////////////////////////////////////
+/// Imports
+////////////////////////////////////////////////////////////////////////////////
+import Vector            ::*;
+import GetPut            ::*;
+import DefaultValue      ::*;
+import FShow             ::*;
+import FIFOF             ::*;
+import TLM2              ::*;
+import ClientServer      ::*;
+
+`include "ARM.defines"
+
+////////////////////////////////////////////////////////////////////////////////
+/// Types
+////////////////////////////////////////////////////////////////////////////////
+typedef TLMAddr#(`ARM_PRM)          MemAddr;
+typedef TLMData#(`ARM_PRM)          MemData;
+typedef TLMByteEn#(`ARM_PRM)        MemBen;
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+/// Bus Request type
+////////////////////////////////////////////////////////////////////////////////
+typedef struct {
+   Bool         first;
+   Bool         reduced;
+   Bool         inst;
+   Bool         write;
+   Bool         cop;
+   Bool         gdb;
+   Bool         c;
+   Bool         b;
+   Bool         usermode;
+   Bool         wrap;
+   UInt#(6)     id;
+   UInt#(10)    burst;
+   Bit#(4)      byteen;
+   Bit#(32)     address;
+   MemData      data;
+} BusRequest deriving (Bits, Eq);
+
+instance DefaultValue#(BusRequest);
+   defaultValue = BusRequest {
+      first:      True,
+      reduced:    False,
+      inst:       False,
+      write:      False,
+      cop:        False,
+      gdb:        False,
+      c:          False,
+      b:          False,
+      usermode:   False,
+      wrap:       False,
+      id:         0,
+      burst:      1,
+      byteen:     0,
+      address:    ?,
+      data:       ?
+      };
+endinstance
+
+////////////////////////////////////////////////////////////////////////////////
+/// Bus Response Type
+////////////////////////////////////////////////////////////////////////////////
+typedef struct {
+   Bool         error;
+   Bool         cop;
+   Bool         gdb;
+   Bool         write;
+   UInt#(6)     id;
+   MemData      data;
+} BusResponse deriving (Bits, Eq);
+
+instance DefaultValue#(BusResponse);
+   defaultValue = BusResponse {
+      error:    True,
+      cop:      False,
+      gdb:      False,
+      write:    False,
+      id:       0,
+      data:     0
+      };
+endinstance
+
+
+////////////////////////////////////////////////////////////////////////////////
+/// Overloading Function for TLM conversions
+////////////////////////////////////////////////////////////////////////////////
+instance TLMRequestTC#(BusRequest, `ARM_PRM);
+   function toTLMRequest(x);
+      if (x.first) begin
+        RequestDescriptor#(`ARM_PRM) request = createBasicRequestDescriptor;
+        request.custom[11]       = pack(x.reduced);
+        request.custom[10]       = pack(x.gdb);
+        request.custom[9]        = pack(x.cop);
+        request.custom[8]        = 0;
+        request.custom[7]        = 0;
+        request.custom[6]        = 0;
+        request.custom[5]        = pack(x.c);
+        request.custom[4]        = pack(x.c);
+        request.custom[3]        = pack(x.b);
+        request.custom[2]        = pack(x.inst);
+        request.custom[1]        = 1;
+        request.custom[0]        = pack(!x.usermode);
+        request.burst_mode       = (x.wrap) ? WRAP : INCR;
+        request.transaction_id   = pack(x.id);
+        request.burst_size       = truncate(pack(countOnesAlt(x.byteen) - 1));
+        request.burst_length     = x.burst;
+        request.byte_enable      = x.byteen;
+        request.command          = (x.write) ? WRITE : READ;
+        request.addr             = pack(x.address);
+        request.data             = x.data;
+        return (tagged Descriptor request);
+      end
+      else begin
+        RequestData#(`ARM_PRM) request = unpack(0);
+        request.custom[11]       = pack(x.reduced);
+        request.custom[10]       = pack(x.gdb);
+        request.custom[9]        = pack(x.cop);
+        request.custom[8]        = 0;
+        request.custom[7]        = 0;
+        request.custom[6]        = 0;
+        request.custom[5]        = pack(x.c);
+        request.custom[4]        = pack(x.c);
+        request.custom[3]        = pack(x.b);
+        request.custom[2]        = pack(x.inst);
+        request.custom[1]        = 1;
+        request.custom[0]        = pack(!x.usermode);
+        request.transaction_id   = pack(x.id);
+        request.data             = x.data;
+        return (tagged Data request);
+      end
+   endfunction
+
+   function fromTLMRequest(x);
+      case(x) matches
+        tagged Descriptor .d: begin
+           return BusRequest {
+              first:    True,
+              reduced:  unpack(d.custom[11]),
+              inst:     unpack(d.custom[2]),
+              write:    (d.command == WRITE),
+              cop:      unpack(d.custom[9]),
+              gdb:      unpack(d.custom[10]),
+              c:        unpack(d.custom[4]),
+              b:        unpack(d.custom[3]),
+              usermode: unpack(~d.custom[0]),
+              wrap:     d.burst_mode == WRAP,
+              id:       unpack(d.transaction_id),
+              burst:    d.burst_length,
+              byteen:   calculateByteEnables(d),
+              address:  unpack(d.addr),
+              data:     d.data
+              };
+        end
+        tagged Data       .d: begin
+           return BusRequest {
+              first:    False,
+              reduced:  unpack(d.custom[11]),
+              inst:     unpack(d.custom[2]),
+              write:    ?,
+              cop:      unpack(d.custom[9]),
+              gdb:      unpack(d.custom[10]),
+              c:        unpack(d.custom[4]),
+              b:        unpack(d.custom[3]),
+              usermode: unpack(~d.custom[0]),
+              wrap:     ?,
+              id:       unpack(d.transaction_id),
+              burst:    ?,
+              byteen:   '1,
+              address:  0,
+              data:     d.data
+              };
+        end
+      endcase
+   endfunction
+endinstance
+
+instance TLMResponseTC#(BusResponse, `ARM_PRM);
+   function toTLMResponse(x);
+      TLMResponse#(`ARM_PRM) response = unpack(0);
+      response.command        = (x.write) ? WRITE : READ;
+      response.data           = x.data;
+      response.status         = (x.error) ? ERROR : SUCCESS;
+      response.custom[10]     = pack(x.gdb);
+      response.custom[9]      = pack(x.cop);
+      response.transaction_id = pack(x.id);
+      return response;
+   endfunction
+   function fromTLMResponse(x);
+      return BusResponse {
+         error: (x.status != SUCCESS),
+        gdb:   unpack(x.custom[10]),
+        cop:   unpack(x.custom[9]),
+        write: (x.command == WRITE),
+        id:    unpack(x.transaction_id),
+        data:  x.data
+        };
+   endfunction
+endinstance
+
+////////////////////////////////////////////////////////////////////////////////
+///
+////////////////////////////////////////////////////////////////////////////////
+function Bit#(4) calculateByteEnables(RequestDescriptor#(`ARM_PRM) desc);
+   let offset_mask = 3 - desc.burst_size;
+   let offset      = desc.addr & zeroExtend(offset_mask);
+   let maskp1      = 1 << getTLMBurstSize(desc);
+   return  (maskp1-1) << offset;
+endfunction
diff --git a/src/peripherals/dma/tb_DMA.bsv b/src/peripherals/dma/tb_DMA.bsv
new file mode 100644 (file)
index 0000000..d0a085f
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+Copyright (c) 2013, IIT Madras
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+*  Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+*  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.
+*  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.
+
+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. 
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+*/
+package tb_DMA;
+       import DMA::*;
+       import Memory_AXI4      ::*;
+       import Semi_FIFOF :: *;
+       import AXI4_Types :: *;
+       import AXI4_Fabric :: *;
+       import Connectable :: *;
+       import ConfigReg :: *;
+       import RegFile::*;
+       import Clocks :: * ;
+       import DReg ::*;
+       import defined_types::*;
+       `include "defined_parameters.bsv"
+
+
+       `define Num_DMA_Channels 7
+       `define Num_Peripherals 12
+       `define Num_Masters 2
+       `define Num_Slaves TAdd#(`Num_Peripherals,2)
+
+       `define DMA_cfg_addr_start              64'h00000000
+       `define DMA_cfg_addr_end                64'h000000FF
+       `define Peripheral1_addr_start  64'h00001000
+       `define Peripheral1_addr_end    64'h00001FFF
+       `define Peripheral2_addr_start  64'h00002000
+       `define Peripheral2_addr_end    64'h00002FFF
+       `define Peripheral3_addr_start  64'h00003000
+       `define Peripheral3_addr_end    64'h00003FFF
+       `define MainMemory_addr_start   64'h80000000
+       `define MainMemory_addr_end     64'hFFFFFFFF
+
+       typedef enum{Send_req,Get_resp} Mem_state deriving(Bits,Eq);
+
+       /*function Tuple2#(t , Bit#(`Addr_space)) fn_slave_addr_range(Integer i) provisos(Literal#(t));
+               case (i) matches
+                       0: return tuple2(`DMA_cfg_addr_start, `DMA_cfg_addr_end);
+                       1: return tuple2(`MainMemory_addr_start, `MainMemory_addr_end);
+                       2: return tuple2(`Peripheral1_addr_start, `Peripheral1_addr_end);
+                       default: return tuple2(0,0);
+               endcase
+       endfunction*/
+
+       function Tuple2 #(Bool, Bit#(TLog#(`Num_Slaves))) fn_addr_to_slave_num (Bit #(`PADDR) addr);
+               if(addr>=`MainMemory_addr_start && addr<=`MainMemory_addr_end)
+                       return tuple2(True,1);  //Memory
+               else if(addr>=`Peripheral1_addr_start && addr<=`Peripheral1_addr_end)
+                       return tuple2(True,2);  //Peripherals
+               else if(addr>=`Peripheral2_addr_start && addr<=`Peripheral2_addr_end)
+                       return tuple2(True,3);  //Peripherals
+               else if(addr>=`Peripheral3_addr_start && addr<=`Peripheral3_addr_end)
+                       return tuple2(True,4);  //Peripherals
+               else if(addr>=`DMA_cfg_addr_start && addr<= `DMA_cfg_addr_end)
+                       return tuple2(True,0);  //DMA config registers
+               else
+                       return tuple2(False,0);
+       endfunction
+
+       (*synthesize*)
+       //(*mutually_exclusive= "get_read_response,get_write_response"*)
+       module mkTb_DMA(Empty);
+               DmaC#(`Num_DMA_Channels, `Num_Peripherals) dma <-mkDMA();//check parameter as DmaC-data type of mkDMA input takes two inputs
+               AXI4_Master_Xactor_IFC #(`PADDR,`Reg_width,`USERSPACE) processor <- mkAXI4_Master_Xactor();
+               Memory_IFC#(`MainMemory_addr_start,`Addr_space) main_memory <- mkMemory("MainMemory_MSB","MainMemory_LSB","MainMemory");
+
+               Memory_IFC#(`Peripheral1_addr_start,`Addr_space) peripheral1 <- mkMemory("Peripheral1_MSB", "Peripheral1_LSB", "Peripheral[1]");
+               Memory_IFC#(`Peripheral2_addr_start,`Addr_space) peripheral2 <- mkMemory("Peripheral2_MSB", "Peripheral2_LSB", "Peripheral[2]");
+               Memory_IFC#(`Peripheral3_addr_start,`Addr_space) peripheral3 <- mkMemory("Peripheral3_MSB", "Peripheral3_LSB", "Peripheral[2]");
+               /*for(Integer i=0; i<`Num_Peripherals; i=i+1) begin
+                       let lv_base_addr= fn_slave_addr_range(i).tpl_1;
+                       peripheral[i] <- mkMemory("Peripheral" +integerToString(i)+ "_MSB", "Peripheral" +integerToString(i)+ "_LSB", "Peripheral[" +integerToString(i)+ "]");
+               end*/
+
+               // Fabric
+               AXI4_Fabric_IFC #(`Num_Masters, `Num_Slaves, `PADDR, `Reg_width,`USERSPACE)
+               fabric <- mkAXI4_Fabric(fn_addr_to_slave_num());
+
+               //Connect the masters to fabric
+               mkConnection (processor.axi_side, fabric.v_from_masters [0]);   //MASTER0: Processor
+               mkConnection (dma.mmu, fabric.v_from_masters [1]);                              //MASTER1: DMA's MMU
+
+               mkConnection(fabric.v_to_slaves[0],dma.cfg);                                    //SLAVE1: Main Memory
+               mkConnection(fabric.v_to_slaves[1],main_memory.axi_slave);              //SLAVE1: Main Memory
+
+               mkConnection(fabric.v_to_slaves[2],peripheral1.axi_slave);              //SLAVE2: Peripheral1
+               mkConnection(fabric.v_to_slaves[3],peripheral2.axi_slave);              //SLAVE2: Peripheral1
+               mkConnection(fabric.v_to_slaves[4],peripheral3.axi_slave);              //SLAVE2: Peripheral1
+               /*for(Integer i=0; i<`Num_Peripherals; i=i+1)
+                       mkConnection(fabric.v_to_slaves[i+2],peripheral[i].axi_slave);          //SLAVE2 onwards: Various Peripherals*/
+
+               //Registers for reading instructions from Dummy processor
+               Reg#(Bit#(6)) index<-mkConfigReg(0); // states 0..7
+               Reg#(Bool) rg_read_flag<-mkConfigReg(False);
+               Reg#(Bool) rg_write_flag<-mkConfigReg(False);
+               RegFile#(Bit#(6),Bit#(136)) input_instructions <-mkRegFileFullLoad("trial.hex");
+               Reg#(Bit#(32)) rg_count <-mkReg(0);
+               Reg#(Bool) rg_done <-mkReg(False);
+
+               rule rl_inc_count;
+                       rg_count<= rg_count + 1;
+                       $display("\n");
+                       $display($time,"\tCount: %d",rg_count);
+                       if(rg_count==500)
+                               $finish(0);
+               endrule
+
+               rule proc_start_read(!rg_read_flag && !rg_done && input_instructions.sub(truncate(index))[65:64]==2'b00); //read operation
+                       let x = input_instructions.sub(truncate(index));
+                       let addr= x[31:0];
+                       let wdata= x[63:32];
+                       let stop= x[65];
+                       let size= 2'd2;
+                       $display($time,"\tTBMaster Processor: Sending Read Request to addr %h",addr);
+                       let read_request = AXI4_Rd_Addr {araddr: zeroExtend(addr), arprot: 0, aruser: 0, arsize: zeroExtend(size), arlen: 0 , arburst: 1, // arburst: 00-FIXED 01-INCR 10-WRAP
+                                                                                        arlock: 0, arcache: 0, arqos: 0,
+                                                                                        arregion: 0, arid: 0 };
+                       processor.i_rd_addr.enq(read_request);
+                       //x[15:0]=fn_decr_cndtr(x[15:0],2,x[50:48]);//CHECK correct this code USE FUNCTION
+                       rg_read_flag<= True;
+                       rg_done<= unpack(stop);
+               endrule
+
+               rule proc_start_write(!rg_write_flag && !rg_done && input_instructions.sub(truncate(index))[65:64]==2'b01); //write operation
+                       let x = input_instructions.sub(truncate(index));
+                       let addr= x[31:0];
+                       let wdata= x[63:32];
+                       let stop= x[65];
+                       let size= 2'd2;
+                       $display($time,"\tTBMaster Processor: Sending Write Request");
+                       let aw = AXI4_Wr_Addr { awaddr: zeroExtend(addr), awprot:0, awuser:0, awlen: 0, awsize: zeroExtend(size), awburst: 1, 
+                                                                       awlock: 0, awcache: 0, awqos: 0,
+                                                                       awregion: 0, awid: 0 };
+                       Bit#(8) lv_strb=0;
+                       Bit#(64) lv_wdata=0;
+                       if(addr[2:0]=='b000) begin
+                               lv_strb= 'h0F;
+                               lv_wdata= zeroExtend(wdata);
+                       end
+                       else if(addr[2:0]=='b100) begin
+                               lv_strb= 'hF0;
+                               lv_wdata= {wdata,32'd0};
+                       end
+                       else begin
+                               $display($time,"ERROR: Write to a wrong address");
+                       end
+                       let w  = AXI4_Wr_Data {wdata: lv_wdata, wstrb: lv_strb, wlast:True, wid: 0};    //TODO generate wstrb to be 2'b10 for all regs except cmar and cpar
+                       processor.i_wr_addr.enq(aw);
+                       processor.i_wr_data.enq(w);
+                       rg_write_flag<= True;
+                       rg_done<= unpack(stop);
+                       index<= index+1;
+               endrule
+
+               rule get_read_response1(rg_read_flag);
+                       let response <- pop_o (processor.o_rd_data);
+                       $display($time,"\tTBMaster Processor: Received read response with data %h",response.rdata);
+                       rg_read_flag<= False;
+               endrule
+
+               rule get_write_response1(rg_write_flag);
+                       let response <- pop_o (processor.o_wr_resp);
+                       $display($time,"\tTBMaster Processor: Received write response");
+                       rg_write_flag<= False;
+               endrule
+               
+               /////////////////////////        SEND INTERRUPT FROM PERIPHERAL        //////////////////////////////
+               rule rl_send_interrupt;
+                       dma.interrupt_from_peripherals('d-1);
+               endrule
+
+
+               rule rl_read_interrupt_status(rg_count>20 && rg_count<60);
+                       let size= 2'd2;
+                       $display($time,"\tTBMaster Processor: Sending Read Request to addr 0 to read interrupt status...");
+                       let read_request = AXI4_Rd_Addr {araddr: 0, arprot: 0, aruser: 0, arsize: zeroExtend(size), arlen: 0 , arburst: 1, // arburst: 00-FIXED 01-INCR 10-WRAP
+                                                                                        arlock: 0, arcache: 0, arqos: 0,
+                                                                                        arregion: 0, arid: 0 };
+                       processor.i_rd_addr.enq(read_request);
+                       //x[15:0]=fn_decr_cndtr(x[15:0],2,x[50:48]);//CHECK correct this code USE FUNCTION
+                       rg_read_flag<= True;
+
+               endrule
+       endmodule
+endpackage
diff --git a/src/peripherals/dma/tb_DMA_AXI_Memory.bsv b/src/peripherals/dma/tb_DMA_AXI_Memory.bsv
new file mode 100644 (file)
index 0000000..7c070ef
--- /dev/null
@@ -0,0 +1,361 @@
+/*
+Copyright (c) 2013, IIT Madras
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+*  Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+*  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.
+*  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.
+
+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. 
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+*/
+//TODO
+//1. Remove all userid and corresponding registers i.e. rg_memory_user and rg_peripheral_user.
+package tb_DMA_AXI_Memory;
+       import DMA::*;
+       import Semi_FIFOF :: *;
+       import AXI4_Types :: *;
+       import AXI4_Fabric :: *;
+       import Connectable :: *;
+       import ConfigReg :: *;
+       import RegFile::*;
+       import Clocks :: * ;
+       import DReg ::*;
+       `include "defined_parameters.bsv"
+       typedef 2 Num_Masters;
+       typedef 3 Num_Slaves;
+
+       `define Max_index 14
+       typedef enum{Send_req,Get_resp} Mem_state deriving(Bits,Eq);
+       //check with table in pdf
+       /*
+       function Bit#(8) write_strobe_generation(Bit#(3) transfer_size);
+               if(transfer_size==0)
+                       return 'b1;
+               else if(transfer_size==1)
+                       return 'b11;
+               else if(transfer_size==2)
+                       return 'b1111;
+               else
+                       return '1;
+       endfunction
+       */
+
+       function Tuple2 #(Bool, Bit#(TLog#(Num_Slaves))) fn_addr_to_slave_num (Bit #(`PADDR) addr);
+               if(addr<='h00000100)
+                       return tuple2(True,0);  //DMA config registers
+               else if(addr<='hFFFF)
+                       return tuple2(True,2);  //Peripherals
+               else 
+                       return tuple2(True,1);  //Memory
+       endfunction
+
+       (*synthesize*)
+       //(*mutually_exclusive="get_read_response,get_write_response"*)
+       module mkTb_DMA_AXI_Memory(Empty);
+               /*
+               
+               Clock curr_clk<-exposeCurrentClock;
+               Reset curr_reset<-exposeCurrentReset;
+               MakeResetIfc myrst1 <-mkReset(0,False,curr_clk);
+               Reset final_reset<-mkResetEither(myrst1.new_rst,curr_reset);
+
+               */
+               DmaC#(7,12) dma <-mkDMA();//check parameter as DmaC-data type of mkDMA input takes two inputs
+               AXI4_Master_Xactor_IFC #(`PADDR,`Reg_width,`USERSPACE) proc_xactor <- mkAXI4_Master_Xactor();
+               AXI4_Slave_Xactor_IFC #(`PADDR,`Reg_width,`USERSPACE) slave_memory_xactor <- mkAXI4_Slave_Xactor();
+               AXI4_Slave_Xactor_IFC #(`PADDR,`Reg_width,`USERSPACE) slave_peripheral_xactor <- mkAXI4_Slave_Xactor();
+               
+               //master testbench to slave dma connection
+               //mkConnection (m_xactor.axi_side, dma.cfg);
+               
+               //slave testbench to master dma connection
+               //mkConnection (dma.mmu,s_xactor.axi_side);
+               
+
+
+               // Fabric
+               AXI4_Fabric_IFC #(Num_Masters, Num_Slaves, `PADDR, `Reg_width,`USERSPACE)
+               fabric <- mkAXI4_Fabric(fn_addr_to_slave_num);
+
+               // Connect traffic generators to fabric
+               mkConnection (proc_xactor.axi_side, fabric.v_from_masters [0]);
+               mkConnection (dma.mmu, fabric.v_from_masters [1]);
+
+               // Connect fabric to memory slaves
+               mkConnection(fabric.v_to_slaves[0],dma.cfg);
+               mkConnection(fabric.v_to_slaves[1],slave_memory_xactor.axi_side);
+               mkConnection(fabric.v_to_slaves[2],slave_peripheral_xactor.axi_side);
+
+               Reg#(Bit#(6)) index<-mkConfigReg(0); // states 0..7
+               Reg#(Bool) rg_read_flag<-mkConfigReg(False);
+               Reg#(Bool) rg_write_flag<-mkConfigReg(False);
+               RegFile#(Bit#(6),Bit#(136)) input_instructions <-mkRegFileLoad("trial.hex",0,`Max_index);
+               Reg#(Bit#(32)) rg_count <-mkReg(0);
+               //Reg#(Maybe#(AXI4_Rd_Data#(`Reg_width, `USERSPACE))) rg_slave_read_response <- mkReg(tagged Invalid);
+               
+               Reg#(Mem_state)                 rg_memory_state <-mkDReg(Send_req);
+               Reg#(Bit#(8))                   rg_memory_readburst_counter<-mkReg(0);
+               Reg#(Bit#(8))                   rg_memory_readburst_value<-mkReg(0);
+               Reg#(Bit#(8))                   rg_memory_writeburst_counter<-mkReg(0);
+               Reg#(Bit#(`USERSPACE))  rg_memory_user<-mkReg(0);
+               Reg#(Bit#(4))                   rg_memory_id<-mkReg(0);
+               Reg#(Bit#(64))                  rg_memory_address<-mkReg(0);
+               Reg#(Bit#(3))                   rg_memory_transfer_size<-mkReg(0);
+               Reg#(Bit#(`Reg_width))  rg_memory_data <-mkReg(0);
+
+               Reg#(Mem_state)                 rg_peripheral_state <-mkDReg(Send_req);
+               Reg#(Bit#(8))                   rg_peripheral_readburst_counter<-mkReg(0);
+               Reg#(Bit#(8))                   rg_peripheral_readburst_value<-mkReg(0);
+               Reg#(Bit#(8))                   rg_peripheral_writeburst_counter<-mkReg(0);
+               Reg#(Bit#(`USERSPACE))  rg_peripheral_user<-mkReg(0);
+               Reg#(Bit#(4))                   rg_peripheral_id<-mkReg(0);
+               Reg#(Bit#(64))                  rg_peripheral_address<-mkReg(0);
+               Reg#(Bit#(3))                   rg_peripheral_transfer_size<-mkReg(0);
+               Reg#(Bit#(`Reg_width))  rg_peripheral_data <-mkReg(0);
+
+               rule rl_inc_count;
+                       rg_count<= rg_count + 1;
+                       $display("\n");
+                       $display($time,"\tCount: %d",rg_count);
+                       if(rg_count==400)
+                               $finish(0);
+               endrule
+
+               rule proc_start_read(!rg_read_flag && index<=`Max_index && input_instructions.sub(truncate(index))[64]==0); //read operation
+                       let x = input_instructions.sub(truncate(index));
+                       let addr= x[31:0];
+                       let wdata= x[63:32];
+                       let stop= x[65];
+                       let size= 2'd2;
+                       $display($time,"\tTBMaster_Processor: Sending Read Request to addr %h",addr);
+                       let read_request = AXI4_Rd_Addr {araddr: zeroExtend(addr), arprot: 0, aruser: 0, arsize: zeroExtend(size), arlen: 0 , arburst: 1, // arburst: 00-FIXED 01-INCR 10-WRAP
+                                                                                        arlock: 0, arcache: 0, arqos: 0,
+                                                                                        arregion: 0, arid: 0 };
+                       proc_xactor.i_rd_addr.enq(read_request);
+                       //x[15:0]=fn_decr_cndtr(x[15:0],2,x[50:48]);//CHECK correct this code USE FUNCTION
+                       rg_read_flag<= True;
+               endrule
+
+               rule proc_start_write(!rg_write_flag && index<=`Max_index && input_instructions.sub(truncate(index))[64]==1); //write operation
+                       let x = input_instructions.sub(truncate(index));
+                       let addr= x[31:0];
+                       let wdata= x[63:32];
+                       let stop= x[65];
+                       let size= 2'd2;
+                       $display($time,"\tTBMaster_Processor: Sending Write Request");
+                       let aw = AXI4_Wr_Addr { awaddr: zeroExtend(addr), awprot:0, awuser:0, awlen: 0, awsize: zeroExtend(size), awburst: 1, 
+                                                                       awlock: 0, awcache: 0, awqos: 0,
+                                                                       awregion: 0, awid: 0 };
+                       let w  = AXI4_Wr_Data {wdata: zeroExtend(wdata), wstrb: 0, wlast:True, wid: 0};
+                       proc_xactor.i_wr_addr.enq(aw);
+                       proc_xactor.i_wr_data.enq(w);
+                       rg_write_flag<= True;
+               endrule
+
+               rule get_read_response1(rg_read_flag);
+                       let response <- pop_o (proc_xactor.o_rd_data);
+                       $display($time,"\tTBMaster_Processor: Received read response with data %h",response.rdata);
+                       index<= index+1;
+                       rg_read_flag<= False;
+               endrule
+
+               rule get_write_response1(rg_write_flag);
+                       let response <- pop_o (proc_xactor.o_wr_resp);
+                       $display($time,"\tTBMaster_Processor: Received write response");
+                       index<= index+1;
+                       rg_write_flag<= False;
+               endrule
+       
+               ///////////////// ******************   SLAVE MEMORY **************//////////////////////
+               ///////      SLAVE MEMORY READ       ////////
+               rule rl_dummy_slave_memory_handle_read_request;
+                       let ar<- pop_o(slave_memory_xactor.o_rd_addr);
+                       Bit#(TSub#(mem_size,2)) index_address=(ar.araddr-fromInteger(valueOf(`Base_addr)))[valueOf(`Addr_space)-1:`byte_offset+1];
+                       rg_memory_address<=ar.araddr;
+                       rg_memory_transfer_size<=ar.arsize;
+                       rg_memory_readburst_value<=ar.arlen;
+                       rg_memory_user<=ar.aruser;
+                       rg_memory_id<= ar.arid;
+                       rg_memory_data<=zeroExtend({16'hbabe,rg_count[15:0]}); 
+                       rg_memory_state<=Get_resp;
+                       $display($time,"\tTbSlave_Memory: Recieved Read Request for Address: %h for id: %d",ar.araddr, ar.aruser);
+               endrule
+
+               rule rl_dummy_slave_memory_handle_read_response(rg_memory_state==Get_resp);
+                       /*`ifdef RV64
+                               Bit#(`Reg_width) data0 = {dmemMSB.a.read(),dmemLSB.a.read()};
+                       `else 
+                               Bit#(`Reg_width) data0 = dmemLSB.a.read();
+                       `endif*/
+                       Bit#(`Reg_width) data0= rg_memory_data;
+                       AXI4_Rd_Data#(`Reg_width,`USERSPACE) r = AXI4_Rd_Data { rresp: AXI4_OKAY, rdata: data0 ,
+                                                                                                                                       rlast: rg_memory_readburst_counter==rg_memory_readburst_value,
+                                                                                                                                       ruser: rg_memory_user, rid: rg_memory_id};
+                       if(rg_memory_transfer_size==2)begin // 32 bit
+                               if(rg_memory_address[`byte_offset:0]==0)
+                                       r.rdata={data0[31:0],data0[31:0]};
+                               else
+                                       r.rdata={data0[63:32],data0[63:32]};
+                       end
+                       else if (rg_memory_transfer_size=='d1)begin // half_word
+                               if(rg_memory_address[`byte_offset:0] ==0)
+                                       r.rdata = {data0[15:0],data0[15:0],data0[15:0],data0[15:0]};
+                               else if(rg_memory_address[`byte_offset:0] ==2)
+                                       r.rdata = {data0[31:16],data0[31:16],data0[31:16],data0[31:16]};
+                               `ifdef RV64
+                                       else if(rg_memory_address[`byte_offset:0] ==4)
+                                               r.rdata = {data0[47:32],data0[47:32],data0[47:32],data0[47:32]};
+                                       else if(rg_memory_address[`byte_offset:0] ==6)
+                                               r.rdata = {data0[63:48],data0[63:48],data0[63:48],data0[63:48]};
+                               `endif
+                       end
+                       else if (rg_memory_transfer_size=='d0) begin// one byte
+                               if(rg_memory_address[`byte_offset:0] ==0)
+                                       r.rdata = {data0[7:0],data0[7:0],data0[7:0],data0[7:0],data0[7:0],data0[7:0],data0[7:0],data0[7:0]};
+                               else if(rg_memory_address[`byte_offset:0] ==1)
+                                       r.rdata = {data0[15:8],data0[15:8],data0[15:8],data0[15:8],data0[15:8],data0[15:8],data0[15:8],data0[15:8]};
+                               else if(rg_memory_address[`byte_offset:0] ==2)
+                                       r.rdata = {data0[23:16],data0[23:16],data0[23:16],data0[23:16],data0[23:16],data0[23:16],data0[23:16],data0[23:16]};
+                               else if(rg_memory_address[`byte_offset:0] ==3)
+                                       r.rdata = {data0[31:24],data0[31:24],data0[31:24],data0[31:24],data0[31:24],data0[31:24],data0[31:24],data0[31:24]};
+                               `ifdef RV64
+                               else if(rg_memory_address[`byte_offset:0] ==4)
+                                       r.rdata = {data0[39:32],data0[39:32],data0[39:32],data0[39:32],data0[39:32],data0[39:32],data0[39:32],data0[39:32]};
+                               else if(rg_memory_address[`byte_offset:0] ==5)
+                               r.rdata = {data0[47:40],data0[47:40],data0[47:40],data0[47:40],data0[47:40],data0[47:40],data0[47:40],data0[47:40]};
+                               else if(rg_memory_address[`byte_offset:0] ==6)
+                               r.rdata = {data0[55:48],data0[55:48],data0[55:48],data0[55:48],data0[55:48],data0[55:48],data0[55:48],data0[55:48]};
+                               else if(rg_memory_address[`byte_offset:0] ==7)
+                                       r.rdata = {data0[63:56],data0[63:56],data0[63:56],data0[63:56],data0[63:56],data0[63:56],data0[63:56],data0[63:56]};
+                               `endif
+                       end
+                       slave_memory_xactor.i_rd_data.enq(r);
+                       if(rg_memory_readburst_counter==rg_memory_readburst_value)
+                               rg_memory_readburst_counter<=0;
+                       else
+                               rg_memory_readburst_counter<=rg_memory_readburst_counter+1;
+                       $display($time,"\tTBSlave: Responding Read Request with Data: %8h BurstCounter: %d BurstValue: %d for id: %d",r.rdata,rg_memory_readburst_counter,rg_memory_readburst_value,rg_memory_user);
+               endrule
+
+               ///////      SLAVE MEMORY WRITE       ////////
+               rule rl_wr_respond_memory;
+                       // Get the wr request
+                       let aw <- pop_o (slave_memory_xactor.o_wr_addr);
+                       let w  <- pop_o (slave_memory_xactor.o_wr_data);
+                       //Bit#(TSub#(mem_size,2)) index_address=(aw.awaddr-fromInteger(valueOf(base_address)))[valueOf(mem_size)-1:`byte_offset+1];
+                       //dmemLSB.b.put(w.wstrb[3:0],index_address,truncate(w.wdata));
+                       //`ifdef RV64 dmmMSB.b.put(w.wstrb[7:4],index_address,truncateLSB(w.wdata)); `endif
+                       let b = AXI4_Wr_Resp {bresp: AXI4_OKAY, buser: aw.awuser, bid:aw.awid};
+                       if(rg_memory_writeburst_counter==aw.awlen)begin
+                               rg_memory_writeburst_counter<=0;
+                       slave_memory_xactor.i_wr_resp.enq (b);
+                       end
+                       else
+                               rg_memory_writeburst_counter<=rg_memory_writeburst_counter+1;
+                       $display($time,"\tTBSlave_Memory: Recieved Write Request for Address: %h data: %h strb: %b awlen: %d rg_memory_writeburst_counter: %d",aw.awaddr,w.wdata,w.wstrb,aw.awlen,rg_memory_writeburst_counter);
+               endrule
+
+
+
+
+               ///////////////// ******************   SLAVE PERIPHERAL **************//////////////////////
+               ///////      SLAVE PERIPHERAL READ       ////////
+               rule rl_dummy_slave_peripheral_handle_read_request;
+                       //let ar<- pop_o(slave_peripheral_xactor.o_rd_addr);
+                       let ar<- pop_o(slave_peripheral_xactor.o_rd_addr);
+                       Bit#(TSub#(mem_size,2)) index_address=(ar.araddr-fromInteger(valueOf(`Base_addr)))[valueOf(`Addr_space)-1:`byte_offset+1];
+                       rg_peripheral_address<=ar.araddr;
+                       rg_peripheral_transfer_size<=ar.arsize;
+                       rg_peripheral_readburst_value<=ar.arlen;
+                       rg_peripheral_user<=ar.aruser;
+                       rg_peripheral_id<= ar.arid;
+                       rg_peripheral_data<=zeroExtend({16'hbabe,rg_count[15:0]}); 
+                       rg_peripheral_state<=Get_resp;
+                       $display($time,"\tTbSlave_peripheral: Recieved Read Request for Address: %h for id: %d",ar.araddr, ar.aruser);
+               endrule
+
+               rule rl_dummy_slave_peripheral_handle_read_response(rg_peripheral_state==Get_resp);
+                       /*`ifdef RV64
+                               Bit#(`Reg_width) data0 = {dmemMSB.a.read(),dmemLSB.a.read()};
+                       `else 
+                               Bit#(`Reg_width) data0 = dmemLSB.a.read();
+                       `endif*/
+                       Bit#(`Reg_width) data0= rg_peripheral_data;
+                       AXI4_Rd_Data#(`Reg_width,`USERSPACE) r = AXI4_Rd_Data { rresp: AXI4_OKAY, rdata: data0 ,
+                                                                                                                                       rlast: rg_peripheral_readburst_counter==rg_peripheral_readburst_value,
+                                                                                                                                       ruser: rg_peripheral_user, rid: rg_peripheral_id};
+                       if(rg_peripheral_transfer_size==2)begin // 32 bit
+                               if(rg_peripheral_address[`byte_offset:0]==0)
+                                       r.rdata={data0[31:0],data0[31:0]};
+                               else
+                                       r.rdata={data0[63:32],data0[63:32]};
+                       end
+                       else if (rg_peripheral_transfer_size=='d1)begin // half_word
+                               if(rg_peripheral_address[`byte_offset:0] ==0)
+                                       r.rdata = {data0[15:0],data0[15:0],data0[15:0],data0[15:0]};
+                               else if(rg_peripheral_address[`byte_offset:0] ==2)
+                                       r.rdata = {data0[31:16],data0[31:16],data0[31:16],data0[31:16]};
+                               `ifdef RV64
+                                       else if(rg_peripheral_address[`byte_offset:0] ==4)
+                                               r.rdata = {data0[47:32],data0[47:32],data0[47:32],data0[47:32]};
+                                       else if(rg_peripheral_address[`byte_offset:0] ==6)
+                                               r.rdata = {data0[63:48],data0[63:48],data0[63:48],data0[63:48]};
+                               `endif
+                       end
+                       else if (rg_peripheral_transfer_size=='d0) begin// one byte
+                               if(rg_peripheral_address[`byte_offset:0] ==0)
+                                       r.rdata = {data0[7:0],data0[7:0],data0[7:0],data0[7:0],data0[7:0],data0[7:0],data0[7:0],data0[7:0]};
+                               else if(rg_peripheral_address[`byte_offset:0] ==1)
+                                       r.rdata = {data0[15:8],data0[15:8],data0[15:8],data0[15:8],data0[15:8],data0[15:8],data0[15:8],data0[15:8]};
+                               else if(rg_peripheral_address[`byte_offset:0] ==2)
+                                       r.rdata = {data0[23:16],data0[23:16],data0[23:16],data0[23:16],data0[23:16],data0[23:16],data0[23:16],data0[23:16]};
+                               else if(rg_peripheral_address[`byte_offset:0] ==3)
+                                       r.rdata = {data0[31:24],data0[31:24],data0[31:24],data0[31:24],data0[31:24],data0[31:24],data0[31:24],data0[31:24]};
+                               `ifdef RV64
+                               else if(rg_peripheral_address[`byte_offset:0] ==4)
+                                       r.rdata = {data0[39:32],data0[39:32],data0[39:32],data0[39:32],data0[39:32],data0[39:32],data0[39:32],data0[39:32]};
+                               else if(rg_peripheral_address[`byte_offset:0] ==5)
+                               r.rdata = {data0[47:40],data0[47:40],data0[47:40],data0[47:40],data0[47:40],data0[47:40],data0[47:40],data0[47:40]};
+                               else if(rg_peripheral_address[`byte_offset:0] ==6)
+                               r.rdata = {data0[55:48],data0[55:48],data0[55:48],data0[55:48],data0[55:48],data0[55:48],data0[55:48],data0[55:48]};
+                               else if(rg_peripheral_address[`byte_offset:0] ==7)
+                                       r.rdata = {data0[63:56],data0[63:56],data0[63:56],data0[63:56],data0[63:56],data0[63:56],data0[63:56],data0[63:56]};
+                               `endif
+                       end
+                       slave_peripheral_xactor.i_rd_data.enq(r);
+                       if(rg_peripheral_readburst_counter==rg_peripheral_readburst_value)
+                               rg_peripheral_readburst_counter<=0;
+                       else
+                               rg_peripheral_readburst_counter<=rg_peripheral_readburst_counter+1;
+                       $display($time,"\tTBSlave_Peripheral: Responding Read Request with Data: %8h BurstCounter: %d BurstValue: %d for id: %d",r.rdata,rg_peripheral_readburst_counter,rg_peripheral_readburst_value,rg_peripheral_user);
+               endrule
+
+
+               ///////      SLAVE PERIPHERAL WRITE       ////////
+               rule rl_wr_respond_peripheral;
+                       // Get the wr request
+                       let aw <- pop_o (slave_peripheral_xactor.o_wr_addr);
+                       let w  <- pop_o (slave_peripheral_xactor.o_wr_data);
+                       //Bit#(TSub#(mem_size,2)) index_address=(aw.awaddr-fromInteger(valueOf(base_address)))[valueOf(mem_size)-1:`byte_offset+1];
+                       //dmemLSB.b.put(w.wstrb[3:0],index_address,truncate(w.wdata));
+                       //`ifdef RV64 dmmMSB.b.put(w.wstrb[7:4],index_address,truncateLSB(w.wdata)); `endif
+                       let b = AXI4_Wr_Resp {bresp: AXI4_OKAY, buser: aw.awuser, bid:aw.awid};
+                       if(rg_peripheral_writeburst_counter==aw.awlen)begin
+                               rg_peripheral_writeburst_counter<=0;
+                       slave_peripheral_xactor.i_wr_resp.enq (b);
+                       end
+                       else
+                               rg_peripheral_writeburst_counter<=rg_peripheral_writeburst_counter+1;
+                       $display($time,"\tTBSlave_Peripheral: Recieved Write Request for Address: %h data: %h strb: %b awlen: %d rg_peripheral_writeburst_counter: %d",aw.awaddr,w.wdata,w.wstrb,aw.awlen,rg_peripheral_writeburst_counter);
+               endrule
+
+               /////////////////////////        SEND INTERRUPT FROM PERIPHERAL        //////////////////////////////
+               rule rl_send_interrupt;
+                       dma.interrupt_from_peripherals('hA01);
+               endrule
+               
+       endmodule
+endpackage