1 /*
2 * @file emu68/mem68.c
3 * @brief 68K memory and IO access
4 * @author http://sourceforge.net/users/benjihan
5 *
6 * Copyright (c) 1998-2015 Benjamin Gerard
7 *
8 * This program is free software: you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation, either version 3 of the
11 * License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program.
20 *
21 * If not, see <http://www.gnu.org/licenses/>.
22 *
23 */
24
25 /* generated config include */
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include "mem68.h"
31 #include "error68.h"
32 #include "emu68.h"
33 #include "io68/io68.h"
34 #include "assert68.h"
35
36 /* ,--------------------------------------------------------.
37 * | |
38 * | 68000 memory access functions |
39 * | |
40 * | These functions don't check address/bus access nor |
41 * | and privilege access violation. |
42 * | |
43 * `--------------------------------------------------------'
44 */
45
46
47 /* ,--------------------------------------------------------.
48 * | Debug IO |
49 * `--------------------------------------------------------'
50 */
51
memchk_rb(io68_t * const io)52 static void memchk_rb(io68_t * const io) {
53 emu68_t * const emu68 = io->emu68;
54 const addr68_t addr = emu68->bus_addr;
55 assert(emu68->chk);
56 emu68->bus_data = emu68->mem[addr&MEMMSK68];
57 chkframe_b(emu68, EMU68_R);
58 }
59
memchk_rw(io68_t * const io)60 static void memchk_rw(io68_t * const io) {
61 emu68_t * const emu68 = io->emu68;
62 const u8 * const mem = emu68->mem+(emu68->bus_addr&MEMMSK68);
63 assert(emu68->chk);
64 emu68->bus_data = (mem[0]<<8) + mem[1];
65 chkframe_w(emu68, EMU68_R);
66 }
67
memchk_rl(io68_t * const io)68 static void memchk_rl(io68_t * const io) {
69 emu68_t * const emu68 = io->emu68;
70 const u8 * const mem = emu68->mem+(emu68->bus_addr&MEMMSK68);
71 assert(emu68->chk);
72 emu68->bus_data = (mem[0]<<24) + (mem[1]<<16) + (mem[2]<<8) + mem[3];
73 chkframe_l(emu68, EMU68_R);
74 }
75
memchk_wb(io68_t * const io)76 static void memchk_wb(io68_t * const io) {
77 emu68_t * const emu68 = io->emu68;
78 const addr68_t addr = emu68->bus_addr;
79 assert(emu68->chk);
80 emu68->mem[addr&MEMMSK68] = emu68->bus_data;
81 chkframe_b(emu68, EMU68_W);
82 }
83
memchk_ww(io68_t * const io)84 static void memchk_ww(io68_t * const io)
85 {
86 emu68_t * const emu68 = io->emu68;
87 u8 * mem = emu68->mem + (emu68->bus_addr&MEMMSK68);
88 int68_t v = emu68->bus_data;
89 assert(emu68->chk);
90 mem[1] = v; v>>=8; mem[0] = v;
91 chkframe_w(emu68, EMU68_W);
92 }
93
memchk_wl(io68_t * const io)94 static void memchk_wl(io68_t * const io)
95 {
96 emu68_t * const emu68 = io->emu68;
97 u8 * mem = emu68->mem + (emu68->bus_addr&MEMMSK68);
98 int68_t v = emu68->bus_data;
99 assert(emu68->chk);
100 mem[3] = v; v>>=8; mem[2] = v; v>>=8; mem[1] = v; v>>=8; mem[0] = v;
101 chkframe_l(emu68, EMU68_W);
102 }
103
104 /* ,--------------------------------------------------------.
105 * | Fault IO |
106 * `--------------------------------------------------------'
107 */
108
fault_rab(io68_t * const io)109 static void fault_rab(io68_t * const io)
110 {
111 emu68_t * const emu68 = io->emu68;
112 assert(emu68);
113 emu68_error_add(emu68, "Invalid byte R access pc:$%06x $%08x",
114 (unsigned)(u32)emu68->inst_pc,
115 (unsigned)(u32)emu68->bus_addr);
116 emu68->bus_data = -1;
117 emu68->status = EMU68_HLT;
118 }
119
fault_raw(io68_t * const io)120 static void fault_raw(io68_t * const io)
121 {
122 emu68_t * const emu68 = io->emu68;
123 assert(emu68);
124 emu68_error_add(emu68, "Invalid word R access pc:$%06x $%08x",
125 (unsigned)(u32)emu68->inst_pc,
126 (unsigned)(u32)emu68->bus_addr);
127 emu68->bus_data = -1;
128 emu68->status = EMU68_HLT;
129 }
130
fault_ral(io68_t * const io)131 static void fault_ral(io68_t * const io)
132 {
133 emu68_t * const emu68 = io->emu68;
134 assert(emu68);
135 emu68_error_add(emu68, "Invalid long R access pc:$%06x $%08x",
136 (unsigned)(u32)emu68->inst_pc,
137 (unsigned)(u32)emu68->bus_addr);
138 emu68->bus_data = -1;
139 emu68->status = EMU68_HLT;
140 }
141
fault_wab(io68_t * const io)142 static void fault_wab(io68_t * const io)
143 {
144 emu68_t * const emu68 = io->emu68;
145 assert(emu68);
146 emu68_error_add(emu68, "Invalid byte W access pc:$%06x $%08x <- $%02x",
147 (unsigned)(u32)emu68->inst_pc,
148 (unsigned)(u32)emu68->bus_addr,
149 (unsigned)(u8)emu68->bus_data);
150 emu68->status = EMU68_HLT;
151 }
152
fault_waw(io68_t * const io)153 static void fault_waw(io68_t * const io)
154 {
155 emu68_t * const emu68 = io->emu68;
156 assert(emu68);
157 emu68_error_add(emu68, "Invalid word W access pc:$%06x $%08x <- $%02x",
158 (unsigned)(u32)emu68->inst_pc,
159 (unsigned)(u32)emu68->bus_addr,
160 (unsigned)(u16)emu68->bus_data);
161 emu68->status = EMU68_HLT;
162 }
163
fault_wal(io68_t * const io)164 static void fault_wal(io68_t * const io)
165 {
166 emu68_t * const emu68 = io->emu68;
167 assert(emu68);
168 emu68_error_add(emu68, "Invalid long W access pc:$%06x $%08x <- $%02x",
169 (unsigned)(u32)emu68->inst_pc,
170 (unsigned)(u32)emu68->bus_addr,
171 (unsigned)(u32)emu68->bus_data);
172 emu68->status = EMU68_HLT;
173 }
174
nop_rwa(io68_t * const io)175 static void nop_rwa(io68_t * const io) {}
176
no_destroy(io68_t * const io)177 static void no_destroy(io68_t * const io) {}
178
179 static const io68_t fault_io = {
180 0,"Fault",0,0,
181 fault_rab,fault_raw,fault_ral,
182 fault_wab,fault_waw,fault_wal,
183 0,0,0,0,no_destroy
184 };
185
186 static const io68_t ram_io = {
187 0,"RAM",0,0,
188 memchk_rb,memchk_rw,memchk_rl,
189 memchk_wb,memchk_ww,memchk_wl,
190 0,0,0,0,no_destroy
191 };
192
193 static const io68_t nop_io = {
194 0,"NOP",0,0,
195 nop_rwa,nop_rwa,nop_rwa,
196 nop_rwa,nop_rwa,nop_rwa,
197 0,0,0,0,no_destroy
198 };
199
200
201 /* ,--------------------------------------------------------.
202 * | Read functions |
203 * `--------------------------------------------------------'
204 */
205
mem68_read_b(emu68_t * const emu68)206 void mem68_read_b(emu68_t * const emu68)
207 {
208 const addr68_t addr = emu68->bus_addr;
209
210 if (mem68_is_io(addr)) {
211 io68_t * const io = emu68->mapped_io[(u8)((addr)>>8)];
212 io->r_byte(io);
213 } else if (!emu68->memio) {
214 emu68->bus_data = emu68->mem[addr&MEMMSK68];
215 } else {
216 emu68->memio->r_byte(emu68->memio);
217 }
218 }
219
mem68_read_w(emu68_t * const emu68)220 void mem68_read_w(emu68_t * const emu68)
221 {
222 const addr68_t addr = emu68->bus_addr;
223 if (mem68_is_io(addr)) {
224 io68_t * const io = emu68->mapped_io[(u8)((addr)>>8)];
225 io->r_word(io);
226 } else if (!emu68->memio) {
227 const u8 * const mem = emu68->mem+(addr&MEMMSK68);
228 emu68->bus_data = (mem[0]<<8) + mem[1];
229 } else {
230 emu68->memio->r_word(emu68->memio);
231 }
232 }
233
mem68_read_l(emu68_t * const emu68)234 void mem68_read_l(emu68_t * const emu68)
235 {
236 const addr68_t addr = emu68->bus_addr;
237 if (mem68_is_io(addr)) {
238 io68_t * const io = emu68->mapped_io[(u8)((addr)>>8)];
239 io->r_long(io);
240 } else if (!emu68->memio) {
241 const u8 * const mem = emu68->mem+(addr&MEMMSK68);
242 emu68->bus_data = (mem[0]<<24) + (mem[1]<<16) + (mem[2]<<8) + mem[3];
243 } else {
244 emu68->memio->r_long(emu68->memio);
245 }
246 }
247
248 /* ,--------------------------------------------------------.
249 * | Write functions |
250 * `--------------------------------------------------------'
251 */
252
mem68_write_b(emu68_t * const emu68)253 void mem68_write_b(emu68_t * const emu68)
254 {
255 const addr68_t addr = emu68->bus_addr;
256 if (mem68_is_io(addr)) {
257 io68_t * const io = emu68->mapped_io[(u8)((addr)>>8)];
258 io->w_byte(io);
259 } else if (!emu68->memio) {
260 emu68->mem[addr&MEMMSK68] = emu68->bus_data;
261 } else {
262 emu68->memio->w_byte(emu68->memio);
263 }
264 }
265
mem68_write_w(emu68_t * const emu68)266 void mem68_write_w(emu68_t * const emu68)
267 {
268 const addr68_t addr = emu68->bus_addr;
269 if (mem68_is_io(addr)) {
270 io68_t * const io = emu68->mapped_io[(u8)((addr)>>8)];
271 io->w_word(io);
272 } else if (!emu68->memio) {
273 u8 * mem = emu68->mem + (addr&MEMMSK68);
274 int68_t v = emu68->bus_data;
275 mem[1] = v; v>>=8; mem[0] = v;
276 } else {
277 emu68->memio->w_word(emu68->memio);
278 }
279 }
280
mem68_write_l(emu68_t * const emu68)281 void mem68_write_l(emu68_t * const emu68)
282 {
283 const addr68_t addr = emu68->bus_addr;
284 if (mem68_is_io(addr)) {
285 io68_t * const io = emu68->mapped_io[(u8)((addr)>>8)];
286 io->w_long(io);
287 } else if (!emu68->memio) {
288 u8 * mem = emu68->mem + (addr&MEMMSK68);
289 int68_t v = emu68->bus_data;
290 mem[3] = v; v>>=8; mem[2] = v; v>>=8; mem[1] = v; v>>=8; mem[0] = v;
291 } else {
292 emu68->memio->w_long(emu68->memio);
293 }
294 }
295
296
297 /* Read 68000 (PC)+ word
298 * - This version assume PC is in 68000 memory
299 * as long I don't try to make 68000 execute
300 * @ IO address, I assume it is not possible !
301 */
mem68_nextw(emu68_t * const emu68)302 int68_t mem68_nextw(emu68_t * const emu68)
303 {
304 const addr68_t addr = REG68.pc;
305 io68_t * const io =
306 mem68_is_io(addr)
307 ? emu68->mapped_io[(u8)((addr)>>8)]
308 : emu68->memio
309 ;
310 REG68.pc += 2;
311
312 if (!io) {
313 u8 * const mem = emu68->mem + ( addr & MEMMSK68 );
314 return ( (int68_t) (s8)mem[0] << 8 ) | mem[1];
315 } else {
316 emu68->bus_addr = addr;
317 io->r_word(io);
318 return (int68_t)(s16)emu68->bus_data;
319 }
320 }
321
mem68_nextl(emu68_t * const emu68)322 int68_t mem68_nextl(emu68_t * const emu68)
323 {
324 const addr68_t addr = REG68.pc;
325 io68_t * const io =
326 mem68_is_io(addr)
327 ? emu68->mapped_io[(u8)((addr)>>8)]
328 : emu68->memio
329 ;
330 REG68.pc += 4;
331
332 if (!io) {
333 u8 * const mem= emu68->mem + ( addr & MEMMSK68 );
334 return
335 ( (int68_t)(s8)mem[0] << 24 ) |
336 ( (int68_t) mem[1] << 16 ) |
337 ( (int68_t) mem[2] << 8 ) |
338 ( mem[3] ) ;
339 } else {
340 emu68->bus_addr = addr;
341 io->r_long(io);
342 return (int68_t)(s32)emu68->bus_data;
343 }
344 }
345
mem68_pushw(emu68_t * const emu68,const int68_t v)346 void mem68_pushw(emu68_t * const emu68, const int68_t v)
347 {
348 REG68.a[7] -= 2;
349 write_W(REG68.a[7],v);
350 }
351
mem68_pushl(emu68_t * const emu68,const int68_t v)352 void mem68_pushl(emu68_t * const emu68, const int68_t v)
353 {
354 REG68.a[7] -= 4;
355 write_L(REG68.a[7],v);
356 }
357
mem68_popl(emu68_t * const emu68)358 int68_t mem68_popl(emu68_t * const emu68)
359 {
360 int68_t v = (s32)read_L(REG68.a[7]);
361 REG68.a[7] += 4;
362 return v;
363 }
364
mem68_popw(emu68_t * const emu68)365 int68_t mem68_popw(emu68_t * const emu68)
366 {
367 s32 v = read_W(REG68.a[7]);
368 REG68.a[7] += 2;
369 return v;
370 }
371
emu68_pushl(emu68_t * const emu68,int68_t val)372 void emu68_pushl(emu68_t * const emu68, int68_t val)
373 {
374 if (emu68)
375 mem68_pushl(emu68, val);
376 }
377
emu68_pushw(emu68_t * const emu68,int68_t val)378 void emu68_pushw(emu68_t * const emu68, int68_t val)
379 {
380 if (emu68)
381 mem68_pushw(emu68, val);
382 }
383
384
emu68_popl(emu68_t * const emu68)385 int68_t emu68_popl(emu68_t * const emu68)
386 {
387 return emu68
388 ? mem68_popl(emu68)
389 : -1
390 ;
391 }
392
emu68_popw(emu68_t * const emu68)393 int68_t emu68_popw(emu68_t * const emu68)
394 {
395 return emu68
396 ? mem68_popw(emu68)
397 : -1
398 ;
399 }
400
401 /* Init memory quick acces table for SC68
402 */
emu68_mem_init(emu68_t * const emu68)403 void emu68_mem_init(emu68_t * const emu68)
404 {
405 if (emu68) {
406 /* Copy RAM and Fault IOs for private use. */
407 emu68->ramio = ram_io;
408 emu68->ramio.emu68 = emu68;
409 emu68->ramio.addr_lo = 0;
410 emu68->ramio.addr_hi = emu68->memmsk;
411
412 emu68->errio = fault_io;
413 emu68->errio.emu68 = emu68;
414 emu68->errio.addr_lo = mem68_is_io(0xFFFFFF);
415 emu68->errio.addr_hi = 0xFFFFFFFF;
416
417 emu68->nopio = nop_io;
418 emu68->nopio.emu68 = emu68;
419 emu68->nopio.addr_lo = mem68_is_io(0xFFFFFF);
420 emu68->nopio.addr_hi = 0xFFFFFFFF;
421
422 emu68->memio = (emu68->chk) ? &emu68->ramio : 0;
423 }
424 emu68_mem_reset(emu68);
425 }
426
emu68_mem_destroy(emu68_t * const emu68)427 void emu68_mem_destroy(emu68_t * const emu68)
428 {
429 if (emu68) {
430 emu68->errio.emu68 = 0;
431 emu68->ramio.emu68 = 0;
432 io68_destroy(emu68->memio);
433 emu68->memio = 0;
434 }
435 }
436
437 /* Reset memory quick acces table
438 */
emu68_mem_reset(emu68_t * const emu68)439 void emu68_mem_reset(emu68_t * const emu68)
440 {
441 if (emu68) {
442 int i;
443 for(i=0; i<256; i++)
444 emu68_mem_reset_area(emu68, i);
445 }
446 }
447
448 /* Reset memory acces control area to normal state :
449 */
emu68_mem_reset_area(emu68_t * const emu68,u8 area)450 void emu68_mem_reset_area(emu68_t * const emu68, u8 area)
451 {
452 emu68->mapped_io[area] =
453 emu68->chk ? &emu68->errio : &emu68->nopio;
454 }
455