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