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 (19 years, 3 months ago) by cebix
Branch: MAIN
CVS Tags: VERSION_4_2, HEAD
Changes since 1.3: +1 -1 lines
Error occurred while calculating annotation data.
Log Message:
updated copyright dates

File Contents

# Content
1 /*
2 * REU.cpp - 17xx REU emulation
3 *
4 * Frodo (C) 1994-1997,2002-2005 Christian Bauer
5 *
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 }