ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/REU.cpp
Revision: 1.4
Committed: 2005-06-27T19:55:48Z (17 years, 7 months ago) by cebix
Branch: MAIN
CVS Tags: VERSION_4_2, HEAD
Changes since 1.3: +1 -1 lines
Log Message:
updated copyright dates

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * REU.cpp - 17xx REU emulation
3     *
4 cebix 1.4 * Frodo (C) 1994-1997,2002-2005 Christian Bauer
5 cebix 1.1 *
6     * This program is free software; you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation; either version 2 of the License, or
9     * (at your option) any later version.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19     */
20    
21     /*
22     * Incompatibilities:
23     * ------------------
24     *
25     * - REU interrupts are not emulated
26     * - Transfer time is not accounted for, all transfers
27     * are done in 0 cycles
28     */
29    
30     #include "sysdeps.h"
31    
32     #include "REU.h"
33     #include "CPUC64.h"
34     #include "Prefs.h"
35    
36    
37     /*
38     * Constructor
39     */
40    
41     REU::REU(MOS6510 *CPU) : the_cpu(CPU)
42     {
43     int i;
44    
45     // Init registers
46     regs[0] = 0x40;
47     for (i=1; i<11; i++)
48     regs[i] = 0;
49     for (i=11; i<16; i++)
50     regs[i] = 0xff;
51    
52     ex_ram = NULL;
53     ram_size = ram_mask = 0;
54    
55     // Allocate RAM
56     open_close_reu(REU_NONE, ThePrefs.REUSize);
57     }
58    
59    
60     /*
61     * Destructor
62     */
63    
64     REU::~REU()
65     {
66     // Free RAM
67     open_close_reu(ThePrefs.REUSize, REU_NONE);
68     }
69    
70    
71     /*
72     * Prefs may have changed, reallocate expansion RAM
73     */
74    
75     void REU::NewPrefs(Prefs *prefs)
76     {
77     open_close_reu(ThePrefs.REUSize, prefs->REUSize);
78     }
79    
80    
81     /*
82     * Allocate/free expansion RAM
83     */
84    
85     void REU::open_close_reu(int old_size, int new_size)
86     {
87     if (old_size == new_size)
88     return;
89    
90     // Free old RAM
91     if (old_size != REU_NONE) {
92     delete[] ex_ram;
93     ex_ram = NULL;
94     }
95    
96     // Allocate new RAM
97     if (new_size != REU_NONE) {
98     switch (new_size) {
99     case REU_128K:
100     ram_size = 0x20000;
101     break;
102     case REU_256K:
103     ram_size = 0x40000;
104     break;
105     case REU_512K:
106     ram_size = 0x80000;
107     break;
108     }
109     ram_mask = ram_size - 1;
110     ex_ram = new uint8[ram_size];
111    
112     // Set size bit in status register
113     if (ram_size > 0x20000)
114     regs[0] |= 0x10;
115     else
116     regs[0] &= 0xef;
117     }
118     }
119    
120    
121     /*
122     * Reset the REU
123     */
124    
125     void REU::Reset(void)
126     {
127     int i;
128    
129     for (i=1; i<11; i++)
130     regs[i] = 0;
131     for (i=11; i<16; i++)
132     regs[i] = 0xff;
133    
134     if (ram_size > 0x20000)
135     regs[0] = 0x50;
136     else
137     regs[0] = 0x40;
138     }
139    
140    
141     /*
142     * Read from REU register
143     */
144    
145     uint8 REU::ReadRegister(uint16 adr)
146     {
147     if (ex_ram == NULL)
148     return rand();
149    
150     switch (adr) {
151     case 0:{
152     uint8 ret = regs[0];
153     regs[0] &= 0x1f;
154     return ret;
155     }
156     case 6:
157     return regs[6] | 0xf8;
158     case 9:
159     return regs[9] | 0x1f;
160     case 10:
161     return regs[10] | 0x3f;
162     default:
163     return regs[adr];
164     }
165     }
166    
167    
168     /*
169     * Write to REU register
170     */
171    
172     void REU::WriteRegister(uint16 adr, uint8 byte)
173     {
174     if (ex_ram == NULL)
175     return;
176    
177     switch (adr) {
178     case 0: // Status register is read-only
179     case 11: // Unconnected registers
180     case 12:
181     case 13:
182     case 14:
183     case 15:
184     break;
185     case 1: // Command register
186     regs[1] = byte;
187     if ((byte & 0x90) == 0x90)
188     execute_dma();
189     break;
190     default:
191     regs[adr] = byte;
192     break;
193     }
194     }
195    
196    
197     /*
198     * CPU triggered REU by writing to $ff00
199     */
200    
201     void REU::FF00Trigger(void)
202     {
203     if (ex_ram == NULL)
204     return;
205    
206     if ((regs[1] & 0x90) == 0x80)
207     execute_dma();
208     }
209    
210    
211     /*
212     * Execute REU DMA transfer
213     */
214    
215     void REU::execute_dma(void)
216     {
217     // Get C64 and REU transfer base addresses
218     uint16 c64_adr = regs[2] | (regs[3] << 8);
219     uint32 reu_adr = regs[4] | (regs[5] << 8) | (regs[6] << 16);
220    
221     // Calculate transfer length
222     int length = regs[7] | (regs[8] << 8);
223     if (!length)
224     length = 0x10000;
225    
226     // Calculate address increments
227     uint32 c64_inc = (regs[10] & 0x80) ? 0 : 1;
228     uint32 reu_inc = (regs[10] & 0x40) ? 0 : 1;
229    
230     // Do transfer
231     switch (regs[1] & 3) {
232    
233     case 0: // C64 -> REU
234     for (; length--; c64_adr+=c64_inc, reu_adr+=reu_inc)
235     ex_ram[reu_adr & ram_mask] = the_cpu->REUReadByte(c64_adr);
236     break;
237    
238     case 1: // C64 <- REU
239     for (; length--; c64_adr+=c64_inc, reu_adr+=reu_inc)
240     the_cpu->REUWriteByte(c64_adr, ex_ram[reu_adr & ram_mask]);
241     break;
242    
243     case 2: // C64 <-> REU
244     for (; length--; c64_adr+=c64_inc, reu_adr+=reu_inc) {
245     uint8 tmp = the_cpu->REUReadByte(c64_adr);
246     the_cpu->REUWriteByte(c64_adr, ex_ram[reu_adr & ram_mask]);
247     ex_ram[reu_adr & ram_mask] = tmp;
248     }
249     break;
250    
251     case 3: // Compare
252     for (; length--; c64_adr+=c64_inc, reu_adr+=reu_inc)
253     if (ex_ram[reu_adr & ram_mask] != the_cpu->REUReadByte(c64_adr)) {
254     regs[0] |= 0x20;
255     break;
256     }
257     break;
258     }
259    
260     // Update address and length registers if autoload is off
261     if (!(regs[1] & 0x20)) {
262     regs[2] = c64_adr;
263     regs[3] = c64_adr >> 8;
264     regs[4] = reu_adr;
265     regs[5] = reu_adr >> 8;
266     regs[6] = reu_adr >> 16;
267     regs[7] = length + 1;
268     regs[8] = (length + 1) >> 8;
269     }
270    
271     // Set complete bit in status register
272     regs[0] |= 0x40;
273    
274     // Clear execute bit in command register
275     regs[1] &= 0x7f;
276     }