Main Page | Class Hierarchy | Compound List | File List | Compound Members | File Members | Related Pages

REU.cpp

Go to the documentation of this file.
00001 /*
00002  *  REU.cpp - 17xx REU emulation
00003  *
00004  *  Frodo (C) 1994-1997 Christian Bauer
00005  *
00006 
00007  *
00008  * Incompatibilities:
00009  * ------------------
00010  *
00011  *  - REU interrupts are not emulated
00012  *  - Transfer time is not accounted for, all transfers
00013  *    are done in 0 cycles
00014  */
00015 
00016 #include "sysdeps.h"
00017 
00018 #include "REU.h"
00019 #include "CPUC64.h"
00020 #include "Prefs.h"
00021 
00022 
00023 /*
00024  *  Constructor
00025  */
00026 
00027 REU::REU(MOS6510 *CPU) : the_cpu(CPU)
00028 {
00029         __CHECK_NULL(CPU);
00030 
00031         int i;
00032 
00033         // Init registers
00034         regs[0] = 0x40;
00035         for (i=1; i<11; i++)
00036                 regs[i] = 0;
00037         for (i=11; i<16; i++)
00038                 regs[i] = 0xff;
00039 
00040         ex_ram = NULL;
00041         ram_size = ram_mask = 0;
00042 
00043         // Allocate RAM
00044 //      open_close_reu(REU_NONE, ThePrefs.REUSize);
00045         open_close_reu(REU_NONE, REU_NONE);     //TODO: use Prefs
00046 
00047         CTOR(REU);
00048 }
00049 
00050 
00051 /*
00052  *  Destructor
00053  */
00054 
00055 REU::~REU()
00056 {
00057         // Free RAM
00058 //      open_close_reu(ThePrefs.REUSize, REU_NONE);
00059         open_close_reu(REU_NONE, REU_NONE);     //TODO: use Prefs
00060 
00061         DTOR(REU);
00062 }
00063 
00064 
00065 /*
00066  *  Prefs may have changed, reallocate expansion RAM
00067  */
00068 
00069 void REU::NewPrefs(Prefs *prefs)
00070 {
00071 //      open_close_reu(ThePrefs.REUSize, prefs->REUSize);
00072         open_close_reu(REU_NONE, REU_NONE);     //TODO: use Prefs
00073 }
00074 
00075 
00076 /*
00077  *  Allocate/free expansion RAM
00078  */
00079 
00080 void REU::open_close_reu(int old_size, int new_size)
00081 {
00082         if (old_size == new_size)
00083                 return;
00084 
00085         // Free old RAM
00086         if (old_size != REU_NONE) {
00087                 delete[] ex_ram;
00088                 ex_ram = NULL;
00089         }
00090 
00091         // Allocate new RAM
00092         if (new_size != REU_NONE) {
00093                 switch (new_size) {
00094                         case REU_128K:
00095                                 ram_size = 0x20000;
00096                                 break;
00097                         case REU_256K:
00098                                 ram_size = 0x40000;
00099                                 break;
00100                         case REU_512K:
00101                                 ram_size = 0x80000;
00102                                 break;
00103                 }
00104                 ram_mask = ram_size - 1;
00105                 ex_ram = new uint8[ram_size];
00106 
00107                 // Set size bit in status register
00108                 if (ram_size > 0x20000)
00109                         regs[0] |= 0x10;
00110                 else
00111                         regs[0] &= 0xef;
00112         }
00113 }
00114 
00115 
00116 /*
00117  *  Reset the REU
00118  */
00119 
00120 void REU::Reset(void)
00121 {
00122         int i;
00123 
00124         for (i=1; i<11; i++)
00125                 regs[i] = 0;
00126         for (i=11; i<16; i++)
00127                 regs[i] = 0xff;
00128 
00129         if (ram_size > 0x20000)
00130                 regs[0] = 0x50;
00131         else
00132                 regs[0] = 0x40;
00133 
00134         ELOG1(_L8("REU reset\n"));
00135 }
00136 
00137 
00138 /*
00139  *  Read from REU register
00140  */
00141 
00142 uint8 REU::ReadRegister(uint16 adr)
00143 {
00144         if (ex_ram == NULL)
00145                 return rand();
00146 
00147         switch (adr) {
00148                 case 0:{
00149                         uint8 ret = regs[0];
00150                         regs[0] &= 0x1f;
00151                         return ret;
00152                 }
00153                 case 6:
00154                         return regs[6] | 0xf8;
00155                 case 9:
00156                         return regs[9] | 0x1f;
00157                 case 10:
00158                         return regs[10] | 0x3f;
00159                 default:
00160                         return regs[adr];
00161         }
00162 }
00163 
00164 
00165 /*
00166  *  Write to REU register
00167  */
00168 
00169 void REU::WriteRegister(uint16 adr, uint8 byte)
00170 {
00171         if (ex_ram == NULL)
00172                 return;
00173 
00174         switch (adr) {
00175                 case 0:         // Status register is read-only
00176                 case 11:        // Unconnected registers
00177                 case 12:
00178                 case 13:
00179                 case 14:
00180                 case 15:
00181                         break;
00182                 case 1:         // Command register
00183                         regs[1] = byte;
00184                         if ((byte & 0x90) == 0x90)
00185                                 execute_dma();
00186                         break;
00187                 default:
00188                         regs[adr] = byte;
00189                         break;
00190         }
00191 }
00192 
00193 
00194 /*
00195  *  CPU triggered REU by writing to $ff00
00196  */
00197 
00198 void REU::FF00Trigger(void)
00199 {
00200         if (ex_ram == NULL)
00201                 return;
00202 
00203         if ((regs[1] & 0x90) == 0x80)
00204                 execute_dma();
00205 }
00206 
00207 
00208 /*
00209  *  Execute REU DMA transfer
00210  */
00211 
00212 void REU::execute_dma(void)
00213 {
00214         // Get C64 and REU transfer base addresses
00215         uint16 c64_adr = regs[2] | (regs[3] << 8);
00216         uint32 reu_adr = regs[4] | (regs[5] << 8) | (regs[6] << 16);
00217 
00218         // Calculate transfer length
00219         int length = regs[7] | (regs[8] << 8);
00220         if (!length)
00221                 length = 0x10000;
00222 
00223         // Calculate address increments
00224         uint32 c64_inc = (regs[10] & 0x80) ? 0 : 1;
00225         uint32 reu_inc = (regs[10] & 0x40) ? 0 : 1;
00226 
00227         // Do transfer
00228         switch (regs[1] & 3) {
00229 
00230                 case 0:         // C64 -> REU
00231                         for (; length--; c64_adr+=c64_inc, reu_adr+=reu_inc)
00232                                 ex_ram[reu_adr & ram_mask] = the_cpu->REUReadByte(c64_adr);
00233                         break;
00234 
00235                 case 1:         // C64 <- REU
00236                         for (; length--; c64_adr+=c64_inc, reu_adr+=reu_inc)
00237                                 the_cpu->REUWriteByte(c64_adr, ex_ram[reu_adr & ram_mask]);
00238                         break;
00239 
00240                 case 2:         // C64 <-> REU
00241                         for (; length--; c64_adr+=c64_inc, reu_adr+=reu_inc) {
00242                                 uint8 tmp = the_cpu->REUReadByte(c64_adr);
00243                                 the_cpu->REUWriteByte(c64_adr, ex_ram[reu_adr & ram_mask]);
00244                                 ex_ram[reu_adr & ram_mask] = tmp;
00245                         }
00246                         break;
00247 
00248                 case 3:         // Compare
00249                         for (; length--; c64_adr+=c64_inc, reu_adr+=reu_inc)
00250                                 if (ex_ram[reu_adr & ram_mask] != the_cpu->REUReadByte(c64_adr)) {
00251                                         regs[0] |= 0x20;
00252                                         break;
00253                                 }
00254                         break;
00255         }
00256 
00257         // Update address and length registers if autoload is off
00258         if (!(regs[1] & 0x20)) {
00259                 regs[2] = c64_adr;
00260                 regs[3] = c64_adr >> 8;
00261                 regs[4] = reu_adr;
00262                 regs[5] = reu_adr >> 8;
00263                 regs[6] = reu_adr >> 16;
00264                 regs[7] = length + 1;
00265                 regs[8] = (length + 1) >> 8;
00266         }
00267 
00268         // Set complete bit in status register
00269         regs[0] |= 0x40;
00270 
00271         // Clear execute bit in command register
00272         regs[1] &= 0x7f;
00273 }

Generated on Tue Feb 8 04:08:07 2005 for E32frodo by doxygen 1.3.3