Subversion Repositories Open64

[/] [sim/] [fsim/] [device_sl1/] [dma.cpp] - Blame information for rev 2072

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2072 malin
/*
2
 *  File: dma.cpp
3
 *
4
 *  Copyright (c) 2006 Beijing SimpLight Nanoelectornics, Ltd.
5
 *  All rights reserved.
6
 *
7
 *  Redistribution and use in source and binary forms, with or without modification,
8
 *  are permitted provided that the following conditions are met:
9
 *
10
 *  1.Redistributions of source code must retain the above copyright notice,
11
 *    this list of conditions and the following disclaimer.
12
 *  2.Redistributions in binary form must reproduce the above copyright notice,
13
 *    this list of conditions and the following disclaimer in the documentation
14
 *    and/or other materials provided with the distribution.
15
 *
16
 *  THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT ``AS IS'' AND ANY EXPRESS
17
 *  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18
 *  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19
 *  IN NO EVENT SHALL THE FREEBSD PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
20
 *  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23
 *  OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
24
 *  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
25
 *  OF THE POSSIBILITY OF SUCH DAMAGE.
26
 */
27
#include "dma.h"
28
 
29
 
30
DMAController::DMAController(SL1System *sys,ADDR base) : SL1Device(sys, base)
31
{
32
  _delayWriteEnable = FALSE;
33
  _writeLogSize = 0;
34
  _writeLogAddr = NULL;
35
  _writeLogData = NULL;
36
  _orgData = NULL;
37
  _working_ch = INVALID_CH;
38
 
39
  for(int i = 0 ; i < DMA_MAX_CHANNELS; i++){
40
                _CH[i].dma_request_valid = 0;
41
 
42
                _CH[i].write_with_trigger = 0;
43
                _CH[i].read_with_trigger = 0;
44
 
45
                _CH[i].device = NULL;
46
  }
47
}
48
 
49
void DMAController::set_channel_status(int channel, int status)
50
{
51
  if(channel < 16){
52
    _STA &= ~(3<<(channel*2));
53
    _STA |= (status << (channel*2));
54
  }else{
55
    _STA_H.bit.dmaSTA_H &= ~(3<<((channel - 16) * 2));
56
    _STA_H.bit.dmaSTA_H |= (status << ((channel - 16) * 2));
57
  }
58
 
59
  if(status == DMA_STA_IDLE){
60
    _POL.bit.dmaPOL &= ~(1 << channel);
61
    _POL.bit.dmaPOL |= 1 << channel;
62
  }else{
63
    _POL.bit.dmaPOL &= ~(1 << channel);
64
  }
65
}
66
 
67
int DMAController::get_channel_status(int channel)
68
{
69
  int status;
70
  if(channel < 16)
71
    status = (_STA >> (channel*2)) & 0x3;
72
  else
73
    status = (_STA_H.bit.dmaSTA_H >> ((channel-16)*2)) & 0x3;
74
 
75
  return status;
76
}
77
 
78
int DMAController::in_internal_sram(ADDR addr)
79
{
80
  if((addr >= CORE_DARAM_BASE) && (addr < (CORE_IRAM_BASE + CORE_IRAM_SPACE)))
81
    return 1;
82
  else
83
    return 0;
84
}
85
 
86
inline void DMAController::syncReg(ADDR reg, dev_u32 val)
87
{
88
  system()->mmu().setWord(baddr()+reg, val);
89
}
90
 
91
void DMAController::tick()
92
{
93
  dma_update_working_channel();
94
 
95
  if (_working_ch != INVALID_CH)
96
  {
97
    system()->addSchedule(this, 100);
98
    dma_channel_clock(_working_ch);
99
  }
100
}
101
 
102
void DMAController::reset()
103
{
104
  for(int i = 0 ; i < DMA_MAX_CHANNELS; i++) {
105
    _CH[i]._SRC = 0;
106
    _CH[i]._DEST = 0;
107
    _CH[i]._LLP = 0;
108
    _CH[i]._CTL.value = 0;
109
    _CH[i]._CTL_H.value = 0;
110
    _CH[i]._CTL_H.bit.int_mask_blk = 1;
111
    _CH[i]._CTL_H.bit.int_mask_half = 1;
112
    _CH[i]._CTL_H.bit.all_half_switch =0;
113
    _CH[i]._CTL_H.bit.dynamic_ptr_en = 0; //Dynamic memory pointer
114
    _CH[i]._CTL_H.bit.channel_clear = 0;
115
 
116
    /* default, source and destination addr is automatically increase */
117
    _CH[i]._CTL_H.bit.dest_fixed = 0;
118
    _CH[i]._CTL_H.bit.src_fixed = 0;
119
    if(i==0 || i==1)
120
      _CH[i]._CTL_H.bit.sw_start_enable = 1;
121
 
122
    /* Forward all values to mmu */
123
    syncReg(DMA_REG_SRC * DMA_CHREG_OFFSET + (i << 2) , _CH[i]._SRC);
124
    syncReg(DMA_REG_DST * DMA_CHREG_OFFSET + (i << 2) , _CH[i]._DEST);
125
    syncReg(DMA_REG_LLP * DMA_CHREG_OFFSET + (i << 2) , _CH[i]._LLP);
126
    syncReg(DMA_REG_CTL * DMA_CHREG_OFFSET + (i << 2) , _CH[i]._CTL.value);
127
    syncReg(DMA_REG_CTL_H * DMA_CHREG_OFFSET + (i << 2) , _CH[i]._CTL_H.value);
128
 
129
    _CH[i].channel_pending = 0;
130
    _CH[i].load_next_descriptor_when_done = 0;
131
    _CH[i].source = 0;
132
    _CH[i].destination = 0;
133
    _CH[i].burst_size = 0;
134
    _CH[i].total_size = 0;
135
    _CH[i].words_transferred = 0;
136
    _CH[i].completed = 1;
137
    _CH[i].scramble_preblk_remain = 0;
138
 
139
    _CH[i].trans_mode = -1;
140
  }
141
 
142
  _IXM_L = 0x00000000;
143
  _IXM_H = 0x00000000;
144
  _SSN0.value = 0x0;
145
  _SSN1.value = 0x0;
146
  _STA = 0xAAAAAAAA; //all channels are idle
147
  _STA_H.bit.dmaSTA_H = 0xAAAA; //all channels are idle
148
  _POL.value = 0xFFFF;
149
  _IRC = 0;
150
 
151
  syncReg(DMA_REG_SSN0, _SSN0.value);
152
  syncReg(DMA_REG_SSN1, _SSN1.value);
153
  syncReg(DMA_REG_STA, _STA);
154
  syncReg(DMA_REG_STA_H, _STA_H.value);
155
  syncReg(DMA_REG_POL, _POL.value);
156
 
157
  system()->addSchedule(this, 1);
158
}
159
 
160
 
161
void DMAController::writeHook(ADDR addr)
162
{
163
  dev_u32 val = system()->mmu().getWord(addr);
164
  ADDR offset =  addr - baddr();
165
  AppFatal((offset % 4 == 0), (""));
166
  if (addr < DMA_REG_SSN0) {
167
    dev_u32 reg,ch;
168
    reg = offset / (DMA_MAX_CHANNELS << 2);
169
    ch = (offset >> 2) % DMA_MAX_CHANNELS;
170
    switch(reg){
171
      case DMA_REG_SRC:
172
        _CH[ch]._SRC = val;
173
        break;
174
      case DMA_REG_DST:
175
        _CH[ch]._DEST = val;
176
        break;
177
      case DMA_REG_LLP:
178
        _CH[ch]._LLP = val;
179
        if(_CH[ch]._LLP)
180
          _CH[ch].load_next_descriptor_when_done = 1;
181
        break;
182
      case DMA_REG_CTL:
183
        _CH[ch]._CTL.value = val;
184
        _CH[ch].trans_mode = _CH[ch]._CTL.bit.trans_mode;
185
        if(_CH[ch].trans_mode == DMA_TM_MULTIBLOCK)
186
          _CH[ch].load_next_descriptor_when_done = 1;
187
        break;
188
      case DMA_REG_CTL_H:
189
        _CH[ch]._CTL_H.value = val;
190
        /* reset channel */
191
        if(_CH[ch]._CTL_H.bit.channel_clear){
192
          _CH[ch]._CTL_H.bit.enable = 0;
193
          set_channel_status(ch, DMA_STA_IDLE);
194
          _CH[ch]._CTL_H.bit.channel_clear = 0;
195
          _CH[ch].completed = 1;
196
          break;
197
        }
198
 
199
 
200
        if(_CH[ch]._CTL_H.bit.int_cause_blk | _CH[ch]._CTL_H.bit.int_cause_half){
201
          if(_CH[ch]._CTL_H.bit.int_cause_blk)
202
            _CH[ch]._CTL_H.bit.int_cause_blk = 0;
203
          if(_CH[ch]._CTL_H.bit.int_cause_half)
204
            _CH[ch]._CTL_H.bit.int_cause_half = 0;
205
 
206
          //update _IRC
207
          _IRC = _IRC & (~(1<<ch));
208
        }
209
 
210
        if(_CH[ch]._CTL_H.bit.enable){
211
          if(_CH[ch].completed == 0){
212
            _CH[ch].channel_pending = 1;
213
            set_channel_status(ch, DMA_STA_PENDING);
214
            system()->addSchedule(this, 1);
215
          }
216
        }else{
217
           if(_CH[ch].completed){
218
            _CH[ch].channel_pending = 0;
219
            set_channel_status(ch, DMA_STA_IDLE);
220
          }else{
221
            _CH[ch].channel_pending = 1;
222
                        set_channel_status(ch, DMA_STA_PENDING);
223
          }
224
        }
225
 
226
        break;
227
      default:
228
        AppFatal((0), ("<writeHook>invalid addr: 0x%x reg = %x ch = %x!\n", offset, reg, ch));
229
    }
230
    }else{
231
    switch(addr){
232
    case DMA_REG_SSN0:
233
    {
234
      int dma_start = 0;
235
      _SSN0.bit.ch = val;
236
      if(_CH[_SSN0.bit.ch]._CTL_H.bit.enable && _CH[_SSN0.bit.ch]._CTL_H.bit.sw_start_enable)
237
      {
238
        _CH[_SSN0.bit.ch].channel_pending = 1;
239
        set_channel_status(_SSN0.bit.ch, DMA_STA_PENDING);
240
        system()->addSchedule(this, 1);
241
      }
242
      break;
243
    }
244
    case DMA_REG_SSN1:
245
    {
246
      int dma_start = 0;
247
      _SSN1.bit.ch = val;
248
      if(_CH[_SSN1.bit.ch]._CTL_H.bit.enable && _CH[_SSN1.bit.ch]._CTL_H.bit.sw_start_enable)
249
      {
250
        _CH[_SSN1.bit.ch].channel_pending = 1;
251
        set_channel_status(_SSN1.bit.ch, DMA_STA_PENDING);
252
        system()->addSchedule(this, 1);
253
      }
254
      break;
255
    }
256
 
257
    default:
258
      AppFatal((0), ("<writeHook>invalid addr: %x!\n", offset));
259
    }//end switch
260
  }//end if(addr <= DMA_REG_SSN)
261
}//end writeHook
262
 
263
void DMAController::readHook(dev_addr addr)
264
{
265
  ADDR offset = addr - baddr();
266
  AppFatal((offset % 4 == 0), (""));
267
  if(addr < DMA_REG_SSN0) {
268
    dev_u32 reg,ch;
269
    reg = offset / (DMA_MAX_CHANNELS << 2);
270
    ch = (offset >> 2) % DMA_MAX_CHANNELS;
271
 
272
    switch(reg) {
273
    case DMA_REG_SRC:
274
      if(!(_POL.bit.dmaPOL & (1<<ch))){
275
        if(_CH[ch]._CTL_H.bit.dynamic_ptr_en)
276
          syncReg(offset,_CH[ch]._SRC);
277
        else
278
          syncReg(offset, _CH[ch].source);
279
      }
280
      break;
281
    case DMA_REG_DST:
282
      if(!(_POL.bit.dmaPOL & (1<<ch))){
283
        if(_CH[ch]._CTL_H.bit.dynamic_ptr_en)
284
          syncReg(offset,_CH[ch]._DEST);
285
        else
286
          syncReg(offset,_CH[ch].destination);
287
      }
288
      break;
289
    case DMA_REG_LLP:
290
      syncReg(offset,_CH[ch]._LLP);
291
      break;
292
    case DMA_REG_CTL:
293
      syncReg(offset,_CH[ch]._CTL.value);
294
      break;
295
    case DMA_REG_CTL_H:
296
      syncReg(offset,_CH[ch]._CTL_H.value);
297
      break;
298
    default:
299
      AppFatal((0), ("<readHook>invalid addr: %x!\n", offset));
300
    }
301
  } else {
302
    switch(addr){
303
      case DMA_REG_SSN0:
304
        syncReg(offset,_SSN0.bit.ch);
305
        break;
306
      case DMA_REG_SSN1:
307
        syncReg(offset,_SSN1.bit.ch);
308
        break;
309
      case DMA_REG_STA:
310
  syncReg(offset,_STA);
311
  break;
312
      case DMA_REG_STA_H:
313
  syncReg(offset,_STA_H.bit.dmaSTA_H);
314
  break;
315
      case DMA_REG_IRC:
316
  syncReg(offset,_IRC);
317
  break;
318
      case DMA_REG_POL:
319
  syncReg(offset,_POL.bit.dmaPOL);
320
  break;
321
      default:
322
  AppFatal((0), ("<readHook>invalid addr: %x!\n", addr));
323
    }//end switch
324
  }//end if(addr <= DMA_REG_SSN)
325
}//end readHook
326
 
327
void DMAController::dmaUpdateIRQ(int int_type)
328
{
329
  if(int_type == BLK_DONE_INT)
330
    _CH[_working_ch]._CTL_H.bit.int_cause_blk = 1;
331
  if(int_type == HALF_DONE_INT)
332
    _CH[_working_ch]._CTL_H.bit.int_cause_half = 1;
333
  //update IRC at the same time
334
  _IRC = _IRC | (1 << _working_ch);
335
 
336
  system()->trap(SL1System::TRAP_INT_DMA);
337
}
338
 
339
void DMAController::dma_init_transfer(int ch)
340
{
341
  _CH[ch].source = _CH[ch]._SRC;
342
  _CH[ch].destination = _CH[ch]._DEST;
343
  _CH[ch].total_size = _CH[ch]._CTL.bit.blk_size;
344
 
345
  /* the least significant bit of sram is masked */
346
  switch(_CH[ch]._CTL.bit.trans_dir)
347
  {
348
    case DMA_TD_INTMEM2INTMEM:
349
      _CH[ch].source &= ~0x1;
350
      _CH[ch].destination &= ~0x1;
351
      _CH[ch].total_size = (_CH[ch].total_size + 1) & (~0x01);
352
      break;
353
    case DMA_TD_INTMEM2EXTMEM:
354
    case DMA_TD_INTMEM2PER:
355
      _CH[ch].source &= ~0x1;
356
      _CH[ch].total_size = (_CH[ch].total_size + 1) & (~0x01);
357
      break;
358
    case DMA_TD_PER2INTMEM:
359
    case DMA_TD_EXTMEM2INTMEM:
360
      _CH[ch].destination &= ~0x1;
361
      _CH[ch].total_size = (_CH[ch].total_size + 1) & (~0x01);
362
      break;
363
  }//end switch
364
 
365
  if(_CH[ch]._CTL.bit.burst_size == 0)
366
  {
367
      //transaction involves SRAM, change burst_size to 2
368
      if(in_internal_sram(_CH[ch].source) || in_internal_sram(_CH[ch].destination))
369
        _CH[ch].burst_size = 2;
370
      else
371
        _CH[ch].burst_size = 1;
372
 
373
      if(ch >= CH_TX_UART1 && ch <= CH_RX_UART3)
374
        _CH[ch].burst_size = 1;
375
  }
376
  else if(_CH[ch]._CTL.bit.burst_size <= 0x6)
377
    _CH[ch].burst_size = 1 << (_CH[ch]._CTL.bit.burst_size + 1);
378
  else
379
    _CH[ch].burst_size = 1024;
380
 
381
  switch(_CH[ch].trans_mode)
382
  {
383
    case DMA_TM_SINGLEBLOCK:
384
    case DMA_TM_AUTOINIT:
385
    case DMA_TM_MULTIBLOCK:
386
      break;
387
    case DMA_TM_IQ:
388
      //For IQ-MAC Transfer Mode, DMA controller fixes the burst sizes 16
389
      _CH[ch].burst_size = IQMAC_BURST_SIZE;
390
      AppFatal(((_CH[ch].total_size%_CH[ch].burst_size) == 0), (""));
391
      break;
392
  }
393
 
394
  //the minimum operation is a burst operation
395
  if(_CH[ch].burst_size > _CH[ch].total_size)
396
      _CH[ch].total_size = _CH[ch].burst_size;
397
 
398
  _CH[ch].words_transferred = 0;
399
}
400
 
401
void DMAController::dma_channel_clock(int ch)
402
{
403
  /* Do we need to abort? */
404
  if (!_CH[ch]._CTL_H.bit.enable) {
405
    //set_channel_status(ch, DMA_STA_IDLE);
406
    return;
407
  }
408
 
409
  /* In HW Handshake mode, only work when dma_request_valid asserted */
410
  if (!_CH[ch]._CTL_H.bit.sw_start_enable) {
411
    if(!_CH[ch].dma_request_valid)
412
      return; //wait next cycle
413
    else
414
      _CH[ch].dma_request_valid = 0; //reset dma_request_valid
415
  }
416
 
417
  /* If this is the first cycle of the transfer, initialize our state */
418
  //if ( get_channel_status(ch) == DMA_STA_PENDING) {
419
  if(_CH[ch].completed){
420
    _CH[ch].completed = 0;
421
    set_channel_status(ch, DMA_STA_ACTIVE);
422
 
423
    /* If using linked lists, copy the appropriate fields to our registers*/
424
    if (!((_CH[ch].trans_mode == DMA_TM_SINGLEBLOCK) || (_CH[ch].trans_mode == DMA_TM_AUTOINIT))){
425
      dma_load_descriptor(ch);
426
    }
427
    else{
428
        _CH[ch].load_next_descriptor_when_done = 0;
429
    }
430
 
431
    /* Set our internal status */
432
    dma_init_transfer(ch);
433
 
434
    /* Might need to skip descriptor */
435
   }
436
 
437
  int burst_size = _CH[ch].burst_size;
438
  int i = 0;
439
  if(_delayWriteEnable==TRUE) {
440
    IsTrue((_writeLogSize==0), ("DMA have been used twice!"));
441
    _writeLogSize = _CH[ch].total_size;
442
    _dmaReqThreadID = _CH[ch]._CTL.bit.conf_threadID;
443
    _writeLogAddr = new ADDR[_writeLogSize];
444
    _writeLogData = new BYTE[_writeLogSize];
445
    _orgData = new BYTE[_writeLogSize];
446
  }
447
  switch(_CH[ch].trans_mode)
448
  {
449
    case DMA_TM_SINGLEBLOCK:
450
    case DMA_TM_AUTOINIT:
451
    case DMA_TM_MULTIBLOCK:
452
    while(burst_size-- && (_CH[ch].words_transferred < _CH[ch].total_size)){
453
      if(_CH[ch]._CTL_H.bit.src_fixed)
454
      {
455
              AppFatal((_CH[ch].device!= NULL), (""));
456
              _CH[ch].device->readHook(_CH[ch].source);
457
      }
458
      ADDR addr = _CH[ch].destination;
459
      BYTE data = system()->mmu().getByte(_CH[ch].source);
460
 
461
      if(_delayWriteEnable==FALSE) {
462
          system()->mmu().setByte(addr,data);
463
      }
464
      else{
465
        _writeLogAddr[i] = addr;
466
        _writeLogData[i] = data;
467
        _orgData[i] = system()->mmu().getByte(addr);
468
        i++;
469
      }
470
 
471
      if(_CH[ch]._CTL_H.bit.dest_fixed)
472
      {
473
             AppFatal((_CH[ch].device!= NULL), (""));
474
            _CH[ch].device->writeHook(addr);
475
      }
476
 
477
      if(!_CH[ch]._CTL_H.bit.src_fixed)
478
        _CH[ch].source++;
479
      if(!_CH[ch]._CTL_H.bit.dest_fixed)
480
        _CH[ch].destination++;
481
 
482
      _CH[ch].words_transferred++;
483
 
484
      //trigger half done interrupt
485
      //if(_CH[ch].trans_mode == DMA_TM_AUTOINIT){
486
      if(_CH[ch]._CTL_H.bit.int_mask_half == 0){
487
        if(_CH[ch].words_transferred == (_CH[ch].total_size / 2 + 1))
488
          dmaUpdateIRQ(HALF_DONE_INT);
489
      }
490
    }
491
    break;
492
    case DMA_TM_IQ:
493
      printf("DMA_TM_IQ, not complete...\n");
494
    break;
495
  }
496
 
497
  /* When done with a chunk, check if it is working in linked list */
498
  if ( _CH[ch].words_transferred >= _CH[ch].total_size ){
499
 
500
    if (_CH[ch].load_next_descriptor_when_done){
501
      dma_channel_terminate_transfer( ch );
502
      return;
503
    }else{
504
      //we have done
505
      dma_channel_terminate_transfer( ch );
506
      return;
507
    }
508
  }//end if
509
}
510
 
511
void DMAController::dma_channel_terminate_transfer(int ch)
512
{
513
  /* Might be working in a linked list */
514
  if ( _CH[ch].load_next_descriptor_when_done ) {
515
    if (_CH[ch]._CTL_H.bit.int_mask_blk == 0)
516
            dmaUpdateIRQ(BLK_DONE_INT);
517
 
518
    dma_load_descriptor( ch );
519
    dma_init_transfer( ch );
520
    return;
521
  }
522
 
523
  /* Mark end of transfer */
524
  set_channel_status(ch, DMA_STA_IDLE);
525
 
526
  /* If needed, generate interrupt, If only all done interrupt is allowed,
527
         * blk done will be disabled in the middle of dma transfer
528
         */
529
  if((_CH[ch]._CTL_H.bit.all_half_switch== 0) && (_CH[ch]._CTL_H.bit.int_mask_blk == 0))
530
  {
531
    dmaUpdateIRQ(BLK_DONE_INT);
532
  }
533
 
534
  /* Might be in auto-restart mode */
535
  /* update _working_ch */
536
  if(_CH[ch].trans_mode == DMA_TM_AUTOINIT)
537
    dma_init_transfer(ch);
538
  else
539
  {
540
    //update channel_pending flag
541
      _CH[ch].channel_pending = 0;
542
        _CH[ch]._CTL_H.bit.enable = 0;
543
    _working_ch = INVALID_CH;
544
    _CH[ch].completed = 1;
545
  }
546
 
547
  /* check if there is no other channel to do */
548
  system()->addSchedule(this, 1);
549
}
550
 
551
void DMAController::dma_load_descriptor(int ch )
552
{
553
  struct LinkList_s{
554
    unsigned int dmaCTL;
555
    unsigned int dmaLLP;
556
    unsigned int dmaSRC;
557
    unsigned int dmaDST;
558
  };
559
 
560
  struct LinkList_s * llp = (struct LinkList_s *)_CH[ch]._LLP;
561
  if(llp){
562
    //update related registers
563
    _CH[ch]._LLP = system()->mmu().getWord((ADDR)&llp->dmaLLP);
564
    _CH[ch]._SRC = system()->mmu().getWord((ADDR)&llp->dmaSRC);
565
    _CH[ch]._DEST = system()->mmu().getWord((ADDR)&llp->dmaDST);
566
    _CH[ch]._CTL.value = system()->mmu().getWord((ADDR)&llp->dmaCTL);
567
    if(!_CH[ch]._LLP)
568
          _CH[ch].load_next_descriptor_when_done = 0;
569
        else
570
            _CH[ch].load_next_descriptor_when_done = 1;
571
  }else{
572
    _CH[ch].load_next_descriptor_when_done = 0;
573
  }
574
}
575
 
576
void DMAController::dma_update_working_channel()
577
{
578
  int min_prio = 8;
579
  int channel = INVALID_CH;
580
 
581
  //Lin: Does large priority number mean high priority?
582
  //if(_working_ch != INVALID_CH)
583
  //  return;
584
 
585
  for(int i = 0 ; i < DMA_MAX_CHANNELS; i++){
586
    if((_CH[i].channel_pending) && _CH[i]._CTL_H.bit.enable){
587
      if(min_prio > (int)_CH[i]._CTL.bit.priority){
588
        min_prio = _CH[i]._CTL.bit.priority;
589
        channel = i;
590
      }
591
    }
592
  }//end for
593
 
594
  _working_ch = channel;
595
}
596
 
597
 
598
/* Interfaces for communicating with peripherals */
599
void DMAController::registerDMAChannel(SL1Device* const device, int channel, enum DMA_ADDR_MODE mode)
600
{
601
      _CH[channel].device = device;
602
 
603
  switch(mode) {
604
    case SRC_FIXED:
605
//      _CH[channel].source_inc = 0;
606
//      _CH[channel].destination_inc = 1;
607
      _CH[channel].write_with_trigger = 0;
608
      _CH[channel].read_with_trigger = 1;
609
      break;
610
    case DEST_FIXED:
611
//      _CH[channel].source_inc = 1;
612
//      _CH[channel].destination_inc = 0;
613
      _CH[channel].write_with_trigger = 1;
614
      _CH[channel].read_with_trigger = 0;
615
      break;
616
    case SRCDEST_FIXED:
617
//      _CH[channel].source_inc = 0;
618
//      _CH[channel].destination_inc = 0;
619
      _CH[channel].write_with_trigger = 1;
620
      _CH[channel].read_with_trigger = 1;
621
      break;
622
    case SRCDEST_INC:
623
//      _CH[channel].source_inc = 1;
624
//      _CH[channel].destination_inc = 1;
625
      _CH[channel].write_with_trigger = 0;
626
      _CH[channel].read_with_trigger = 0;
627
      break;
628
    default:
629
      printf("don't support mode %x\n", mode);
630
  }
631
}
632
 
633
void DMAController::moveData(int channel)
634
{
635
  if(_CH[channel]._CTL_H.bit.enable)
636
  {
637
    if(_CH[channel].dma_request_valid)
638
      return;
639
 
640
    _CH[channel].dma_request_valid = 1;
641
    _CH[channel].channel_pending = 1;
642
 
643
    //schedule next cycle for dma module
644
    system()->addSchedule(this, 1);
645
 
646
//    printf("moveData channel = %d\n", channel);
647
  }
648
}
649
 
650
/*
651
 * For Cmodel interfacing functions
652
 */
653
 
654
//for Cmodel or multi-cyc simulation
655
pair<ADDR*, BYTE*> DMAController::resultWriteBack(INT thid) {
656
  pair<ADDR*, BYTE*> ret(NULL, NULL);
657
  if(_delayWriteEnable==TRUE) {
658
    AppFatal((_writeLogSize>0), ("DMAController: DMA data write log is empty."));
659
    AppFatal((_writeLogAddr!=NULL), ("DMAController: DMA addr log is NULL."));
660
    AppFatal((_writeLogData!=NULL), ("DMAController: DMA data log is NULL."));
661
    AppFatal((_orgData!=NULL), ("DMAController: DMA original data log is NULL."));
662
    INT cur_id = system()->mmu().curthread();
663
    system()->mmu().curthread(thid);
664
    for(INT i = 0; i<_writeLogSize; i++) {
665
      BYTE org_data = system()->mmu().getByte(_writeLogAddr[i]);
666
      AppFatal((_orgData[i]!=org_data), ("DMAController: The data @0x%x has been changed during the DMA execution.", _writeLogAddr[i]));
667
      system()->mmu().setByte(_writeLogAddr[i], _writeLogData[i]);
668
    }
669
    ret.first = _writeLogAddr;
670
    ret.second = _writeLogData;
671
    delete _orgData;
672
    clearLog();
673
    system()->mmu().curthread(cur_id);
674
  }
675
  return ret;
676
}
677