DMA.cpp

Go to the documentation of this file.
00001 /* ES40 emulator.
00002  * Copyright (C) 2007-2008 by the ES40 Emulator Project
00003  *
00004  * WWW    : http://sourceforge.net/projects/es40
00005  * E-mail : camiel@camicom.com
00006  * 
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  * 
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  * 
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00020  * 
00021  * Although this is not required, the author would appreciate being notified of, 
00022  * and receiving any modifications you may make to the source code that might serve
00023  * the general public.
00024  */
00025 
00047 #include "StdAfx.h"
00048 #include "System.h"
00049 #include "DMA.h"
00050 #include "AliM1543C.h"
00051 
00055 CDMA::CDMA(CConfigurator* cfg, CSystem* c) : CSystemComponent(cfg, c)
00056 {
00057   int i;
00058 
00059   // DMA Setup
00060   c->RegisterMemory(this, 0, U64(0x00000801fc000000), 16);  // dma 0-3
00061   c->RegisterMemory(this, 1, U64(0x00000801fc0000c0), 32);  // dma 4-7
00062   c->RegisterMemory(this, 2, U64(0x00000801fc000080), 16);  // dma 0-7 (memory base low page register)
00063   c->RegisterMemory(this, 3, U64(0x00000801fc000480), 16);  // dma 0-7 (memory base high page register)
00064   for(i = 0; i < 8; i++)
00065   {
00066     state.channel[i].c_lobyte = true;
00067     state.channel[i].a_lobyte = true;
00068   }
00069 
00070   printf("dma: $Id: DMA.cpp,v 1.5 2008/03/14 15:30:51 iamcamiel Exp $\n");
00071 }
00072 
00076 CDMA::~CDMA()
00077 { }
00078 int CDMA::DoClock()
00079 {
00080   return 0;
00081 }
00082 
00083 u64 CDMA::ReadMem(int index, u64 address, int dsize)
00084 {
00085   u64 ret;
00086   u8  data;
00087   int num;
00088   switch(dsize)
00089   {
00090   case 32:
00091     ret = ReadMem(index, address, 8);
00092     ret |= ReadMem(index, address + 1, 8) << 8;
00093     ret |= ReadMem(index, address + 2, 8) << 16;
00094     ret |= ReadMem(index, address + 3, 8) << 32;
00095     return ret;
00096 
00097   case 16:
00098     ret = ReadMem(index, address, 8);
00099     ret |= ReadMem(index, address + 1, 8) << 8;
00100     return ret;
00101 
00102   case 8:
00103     if(index == 1)
00104       address >>= 1;
00105     switch(index)
00106     {
00107     case 0:
00108     case 1:
00109       switch(address)
00110       {
00111       case 0x00:  // base address
00112       case 0x02:
00113       case 0x04:
00114       case 0x06:
00115         num = ((int) address / 2) + (index * 4);
00116         if(state.channel[num].a_lobyte)
00117         {
00118           data = state.channel[num].current & 0xff;
00119           state.channel[num].a_lobyte = false;
00120         }
00121         else
00122         {
00123           data = (state.channel[num].current >> 8) & 0xff;
00124           state.channel[num].a_lobyte = true;
00125         }
00126         break;
00127 
00128       case 0x01:  // word count
00129       case 0x03:
00130       case 0x05:
00131       case 0x07:
00132         num = (((int) address - 1) / 2) + (index * 4);
00133         if(state.channel[num].c_lobyte)
00134         {
00135           data = state.channel[num].count & 0xff;
00136           state.channel[num].c_lobyte = false;
00137         }
00138         else
00139         {
00140           data = (state.channel[num].count >> 8) & 0xff;
00141           state.channel[num].c_lobyte = true;
00142         }
00143         break;
00144 
00145       default:
00146         data = 0;
00147 
00148         //        FAILURE("dma: don't know what to do.\n");
00149       }
00150       break;
00151 
00152     case 2:
00153     case 3:
00154       data = 0;
00155       break;
00156 
00157     default:
00158       FAILURE(InvalidArgument, "dma: ReadMem index out of range");
00159     }
00160 
00161 #if defined(DEBUG_DMA)
00162     printf("dma: read %d,%02x: %02x.   \n", index, address, data);
00163 #endif
00164     return data;
00165   }
00166 }
00167 
00168 void CDMA::WriteMem(int index, u64 address, int dsize, u64 data)
00169 {
00170   int num;
00171   switch(dsize)
00172   {
00173   case 32:
00174     WriteMem(index, address + 0, 8, (data >> 0) & 0xff);
00175     WriteMem(index, address + 1, 8, (data >> 8) & 0xff);
00176     WriteMem(index, address + 2, 8, (data >> 16) & 0xff);
00177     WriteMem(index, address + 3, 8, (data >> 24) & 0xff);
00178     return;
00179 
00180   case 16:
00181     WriteMem(index, address + 0, 8, (data >> 0) & 0xff);
00182     WriteMem(index, address + 1, 8, (data >> 8) & 0xff);
00183     return;
00184 
00185   case 8:
00186     if(index == 1)
00187       address >>= 1;
00188 #if defined(DEBUG_DMA)
00189     printf("dma: write %d,%02x: %02x.   \n", index, address, data);
00190 #endif
00191     switch(index)
00192     {
00193     case 0:
00194     case 1:
00195       switch(address)
00196       {
00197       case 0x00:  // base address
00198       case 0x02:
00199       case 0x04:
00200       case 0x06:
00201         num = ((int) address / 2) + (index * 4);
00202         if(state.channel[num].a_lobyte)
00203         {
00204           state.channel[num].base = (u8) data;
00205           state.channel[num].a_lobyte = false;
00206         }
00207         else
00208         {
00209           state.channel[num].base |= ((u8) data << 8);
00210           state.channel[num].current = state.channel[num].base;
00211           state.channel[num].a_lobyte = true;
00212         }
00213         break;
00214 
00215       case 0x01:  // word count
00216       case 0x03:
00217       case 0x05:
00218       case 0x07:
00219         num = (((int) address - 1) / 2) + (index * 4);
00220         if(state.channel[num].c_lobyte)
00221         {
00222           state.channel[num].count = (u8) data;
00223           state.channel[num].c_lobyte = false;
00224         }
00225         else
00226         {
00227           state.channel[num].count |= ((u8) data << 8);
00228           state.channel[num].c_lobyte = true;
00229         }
00230         break;
00231 
00232       case 0x08:  // command register (2)
00233         /*
00234         Bit(s)  Description     (Table P0002)
00235         7      DACK sense active high
00236         6      DREQ sense active high
00237         5      =1 extended write selection
00238           =0 late write selection
00239         4      rotating priority instead of fixed priority
00240         3      compressed timing (two clocks instead of four per transfer)
00241           =1 normal timing (default)
00242           =0 compressed timing
00243         2      =1 enable controller
00244           =0 enable memory-to-memory
00245         1-0    channel number
00246          */
00247 
00248         /* we'll actually do the DMA here. */
00249         state.controller[index].command = data;
00250         break;
00251 
00252       case 0x09:  // write request register (3)
00253         /*
00254         Bit(s)  Description     (Table P0003)
00255         7-3    reserved (0)
00256         2      =0 clear request bit
00257           =1 set request bit
00258         1-0    channel number
00259           00 channel 0 select
00260           01 channel 1 select
00261           10 channel 2 select
00262           11 channel 3 select
00263          */
00264         state.controller[index].writereq = data;
00265         break;
00266 
00267       case 0x0a:  // mask register (4)
00268         /*
00269         Bit(s)  Description     (Table P0004)
00270         7-3    reserved (0)
00271         2      =0 clear mask bit
00272           =1 set mask bit
00273         1-0    channel number
00274           00 channel 0 select
00275           01 channel 1 select
00276           10 channel 2 select
00277           11 channel 3 select
00278          */
00279         state.controller[index].mask = data;
00280         break;
00281 
00282       case 0x0b:  // mode register (5)
00283         /*  Bit(s)  Description     (Table P0005)
00284              7-6    transfer mode
00285                     00 demand mode
00286                     01 single mode
00287                     10 block mode
00288                     11 cascade mode
00289              5      direction
00290                     =0 increment address after each transfer
00291                     =1 decrement address
00292              3-2    operation
00293                     00 verify operation
00294                     01 write to memory
00295                     10 read from memory
00296                     11 reserved
00297              1-0    channel number
00298                     00 channel 0 select
00299                     01 channel 1 select
00300                     10 channel 2 select
00301                     11 channel 3 select
00302          */
00303         state.controller[index].mode = data;
00304         break;
00305 
00306       case 0x0c:  // clear flip/flop:
00307         for(num = index * 4; num < (index * 4) + 3; num++)
00308         {
00309           state.channel[num].a_lobyte = true;
00310           state.channel[num].c_lobyte = true;
00311         }
00312         break;
00313 
00314       case 0x0d:  // dma channel master clear register
00315 #if defined(DEBUG_DMA)
00316         printf("DMA-I-RESET: DMA %d reset.", index);
00317 #endif
00318         state.controller[index].status = 0;
00319         state.controller[index].command = 0;
00320         state.controller[index].writereq = 0;
00321         state.controller[index].mode = 0;
00322         state.controller[index].mask = 0x0f;
00323         break;
00324 
00325       case 0x0e:  // clear mask register
00326         state.controller[index].mask = 0x00;
00327         break;
00328 
00329       case 0x0f:  // write mask register (6)
00330         /* Bit(s)  Description     (Table P0006)
00331            7-4    reserved
00332            3      channel 3 mask bit
00333            2      channel 2 mask bit
00334            1      channel 1 mask bit
00335            0      channel 0 mask bit
00336            Note:   each mask bit is automatically set when the corresponding channel
00337                    reaches terminal count or an extenal EOP sigmal is received
00338         */
00339         state.controller[index].mask = data;
00340         break;
00341 
00342       default:
00343         FAILURE(NotImplemented, "dma: don't know what to do");
00344       }
00345       break;
00346 
00347     case 2:
00348     case 3:
00349       switch(address)
00350       {
00351       case 1:   num = 2; break;
00352       case 2:   num = 3; break;
00353       case 3:   num = 1; break;
00354       case 7:   num = 0; break;
00355       case 9:   num = 6; break;
00356       case 0xa: num = 7; break;
00357       case 0xb: num = 5; break;
00358       default:  printf("dma: Unknown page register: %x\n", address); return;
00359       }
00360 
00361       if(index == 2)
00362         state.channel[num].pagebase = (state.channel[num].pagebase & 0xff00) | (u8) data;
00363       else
00364         state.channel[num].pagebase = (state.channel[num].pagebase & 0xff) | (data << 8);
00365 
00366       //      FAILURE("dma: don't know what to do.\n");
00367       break;
00368 
00369     default:
00370       FAILURE(InvalidArgument, "dma: ReadMem index out of range");
00371     }
00372 
00373     return;
00374   }
00375 }
00376 
00377 static u32  dma_magic1 = 0x65324387;
00378 static u32  dma_magic2 = 0x24092875;
00379 
00383 int CDMA::SaveState(FILE* f)
00384 {
00385   long  ss = sizeof(state);
00386 
00387   fwrite(&dma_magic1, sizeof(u32), 1, f);
00388   fwrite(&ss, sizeof(long), 1, f);
00389   fwrite(&state, sizeof(state), 1, f);
00390   fwrite(&dma_magic2, sizeof(u32), 1, f);
00391   printf("dma: %d bytes saved.\n", ss);
00392   return 0;
00393 }
00394 
00398 int CDMA::RestoreState(FILE* f)
00399 {
00400   long    ss;
00401   u32     m1;
00402   u32     m2;
00403   size_t  r;
00404 
00405   r = fread(&m1, sizeof(u32), 1, f);
00406   if(r != 1)
00407   {
00408     printf("dma: unexpected end of file!\n");
00409     return -1;
00410   }
00411 
00412   if(m1 != dma_magic1)
00413   {
00414     printf("dma: MAGIC 1 does not match!\n");
00415     return -1;
00416   }
00417 
00418   fread(&ss, sizeof(long), 1, f);
00419   if(r != 1)
00420   {
00421     printf("dma: unexpected end of file!\n");
00422     return -1;
00423   }
00424 
00425   if(ss != sizeof(state))
00426   {
00427     printf("dma: STRUCT SIZE does not match!\n");
00428     return -1;
00429   }
00430 
00431   fread(&state, sizeof(state), 1, f);
00432   if(r != 1)
00433   {
00434     printf("dma: unexpected end of file!\n");
00435     return -1;
00436   }
00437 
00438   r = fread(&m2, sizeof(u32), 1, f);
00439   if(r != 1)
00440   {
00441     printf("dma: unexpected end of file!\n");
00442     return -1;
00443   }
00444 
00445   if(m2 != dma_magic2)
00446   {
00447     printf("dma: MAGIC 1 does not match!\n");
00448     return -1;
00449   }
00450 
00451   printf("dma: %d bytes restored.\n", ss);
00452   return 0;
00453 }

SourceForge.net Logo
Project space on SourceForge.net