commit 021baa5
shrub
·
2026-07-14 21:24:37 +0000 UTC
parent 021baa5
init
161 files changed,
+83231,
-0
A
COPYING
A
README
A
arena.c
A
arena.h
A
config.c
A
config.h
A
debug.c
A
debug.h
A
dis.c
A
fib.s68
A
font.xcf
A
gen.c
A
gen.h
A
gst.c
A
gst.h
A
hash.c
A
hash.h
A
i2c.c
A
i2c.h
A
io.c
A
io.h
A
jcart.c
A
jcart.h
A
mem.c
A
mem.h
A
memmap.h
A
menu.c
A
menu.h
A
menu.s68
A
net.c
A
net.h
A
nor.c
A
nor.h
A
paths.c
A
paths.h
A
png.c
A
png.h
A
ppm.c
A
ppm.h
A
psg.c
A
psg.h
A
render.h
A
rom.db
A
romdb.c
A
romdb.h
A
saves.c
A
saves.h
A
sms.c
A
sms.h
A
svp.cpu
A
system.c
A
system.h
A
tern.c
A
tern.h
A
test.c
A
test.s68
A
todo.txt
A
trans.c
A
util.c
A
util.h
A
vdp.c
A
vdp.h
A
vgm.h
A
wave.c
A
wave.h
A
xband.c
A
xband.h
A
ym2612.c
A
ym2612.h
A
z80.cpu
A
zdis.c
A
zip.c
A
zip.h
+2644,
-0
1@@ -0,0 +1,2644 @@
2+/*
3+ Copyright 2013 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#include "68kinst.h"
8+#include <string.h>
9+#include <stdio.h>
10+
11+uint32_t sign_extend16(uint32_t val)
12+{
13+ return (val & 0x8000) ? val | 0xFFFF0000 : val;
14+}
15+
16+uint32_t sign_extend8(uint32_t val)
17+{
18+ return (val & 0x80) ? val | 0xFFFFFF00 : val;
19+}
20+
21+uint16_t *m68k_decode_op_ex(uint16_t *cur, uint8_t mode, uint8_t reg, uint8_t size, m68k_op_info *dst)
22+{
23+ uint16_t ext, tmp;
24+ dst->addr_mode = mode;
25+ switch(mode)
26+ {
27+ case MODE_REG:
28+ case MODE_AREG:
29+ case MODE_AREG_INDIRECT:
30+ case MODE_AREG_POSTINC:
31+ case MODE_AREG_PREDEC:
32+ dst->params.regs.pri = reg;
33+ break;
34+ case MODE_AREG_DISPLACE:
35+ ext = *(++cur);
36+ dst->params.regs.pri = reg;
37+ dst->params.regs.displacement = sign_extend16(ext);
38+ break;
39+ case MODE_AREG_INDEX_MEM:
40+ dst->params.regs.pri = reg;
41+ ext = *(++cur);
42+ dst->params.regs.sec = ext >> 11;//includes areg/dreg bit, reg num and word/long bit
43+#ifdef M68020
44+ dst->params.regs.scale = ext >> 9 & 3;
45+ if (ext & 0x100)
46+ {
47+ dst->params.regs.disp_sizes = ext >> 4 & 3;
48+ switch (dst->params.regs.disp_sizes)
49+ {
50+ case 0:
51+ //reserved
52+ return NULL;
53+ case 1:
54+ dst->params.regs.displacement = 0;
55+ break;
56+ case 2:
57+ dst->params.regs.displacement = sign_extend16(*(cur++));
58+ break;
59+ case 3:
60+ tmp = *(cur++);
61+ dst->params.regs.displacement = tmp << 16 | *(cur++);
62+ break;
63+ }
64+ if (ext & 0x3)
65+ {
66+ //memory indirect
67+ switch (ext & 0xC4)
68+ {
69+ case 0x00:
70+ dst->addr_mode = MODE_AREG_PREINDEX;
71+ break;
72+ case 0x04:
73+ dst->addr_mode = MODE_AREG_POSTINDEX;
74+ break;
75+ case 0x40:
76+ dst->addr_mode = MODE_AREG_MEM_INDIRECT;
77+ break;
78+ case 0x80:
79+ dst->addr_mode = MODE_PREINDEX;
80+ break;
81+ case 0x84:
82+ dst->addr_mode = MODE_POSTINDEX;
83+ break;
84+ case 0xC0:
85+ dst->addr_mode = MODE_MEM_INDIRECT;
86+ break;
87+ }
88+ dst->params.regs.disp_sizes |= ext << 4 & 0x30;
89+ switch (ext & 0x3)
90+ {
91+ case 0:
92+ //reserved
93+ return NULL;
94+ case 1:
95+ dst->params.regs.outer_disp = 0;
96+ break;
97+ case 2:
98+ dst->params.regs.outer_disp = sign_extend16(*(cur++));
99+ break;
100+ case 3:
101+ tmp = *(cur++);
102+ dst->params.regs.outer_disp = tmp << 16 | *(cur++);
103+ break;
104+ }
105+ } else {
106+ switch (ext >> 6 & 3)
107+ {
108+ case 0:
109+ dst->addr_mode = MODE_AREG_INDEX_BASE_DISP;
110+ break;
111+ case 1:
112+ dst->addr_mode = MODE_AREG_BASE_DISP;
113+ break;
114+ case 2:
115+ dst->addr_mode = MODE_INDEX_BASE_DISP;
116+ break;
117+ case 3:
118+ dst->addr_mode = MODE_BASE_DISP;
119+ break;
120+ }
121+ }
122+ } else {
123+#endif
124+ dst->addr_mode = MODE_AREG_INDEX_DISP8;
125+ dst->params.regs.displacement = sign_extend8(ext&0xFF);
126+#ifdef M68020
127+ }
128+#endif
129+ break;
130+ case MODE_PC_INDIRECT_ABS_IMMED:
131+ switch(reg)
132+ {
133+ case 0:
134+ dst->addr_mode = MODE_ABSOLUTE_SHORT;
135+ ext = *(++cur);
136+ dst->params.immed = sign_extend16(ext);
137+ break;
138+ case 1:
139+ dst->addr_mode = MODE_ABSOLUTE;
140+ ext = *(++cur);
141+ dst->params.immed = ext << 16 | *(++cur);
142+ break;
143+ case 3:
144+ ext = *(++cur);
145+ dst->params.regs.sec = ext >> 11;//includes areg/dreg bit, reg num and word/long bit
146+#ifdef M68020
147+ dst->params.regs.scale = ext >> 9 & 3;
148+ if (ext & 0x100)
149+ {
150+ dst->params.regs.disp_sizes = ext >> 4 & 3;
151+ switch (dst->params.regs.disp_sizes)
152+ {
153+ case 0:
154+ //reserved
155+ return NULL;
156+ case 1:
157+ dst->params.regs.displacement = 0;
158+ break;
159+ case 2:
160+ dst->params.regs.displacement = sign_extend16(*(cur++));
161+ break;
162+ case 3:
163+ tmp = *(cur++);
164+ dst->params.regs.displacement = tmp << 16 | *(cur++);
165+ break;
166+ }
167+ if (ext & 0x3)
168+ {
169+ //memory indirect
170+ switch (ext & 0xC4)
171+ {
172+ case 0x00:
173+ dst->addr_mode = MODE_PC_PREINDEX;
174+ break;
175+ case 0x04:
176+ dst->addr_mode = MODE_PC_POSTINDEX;
177+ break;
178+ case 0x40:
179+ dst->addr_mode = MODE_PC_MEM_INDIRECT;
180+ break;
181+ case 0x80:
182+ dst->addr_mode = MODE_ZPC_PREINDEX;
183+ break;
184+ case 0x84:
185+ dst->addr_mode = MODE_ZPC_POSTINDEX;
186+ break;
187+ case 0xC0:
188+ dst->addr_mode = MODE_ZPC_MEM_INDIRECT;
189+ break;
190+ }
191+ dst->params.regs.disp_sizes |= ext << 4 & 0x30;
192+ switch (ext & 0x3)
193+ {
194+ case 0:
195+ //reserved
196+ return NULL;
197+ case 1:
198+ dst->params.regs.outer_disp = 0;
199+ break;
200+ case 2:
201+ dst->params.regs.outer_disp = sign_extend16(*(cur++));
202+ break;
203+ case 3:
204+ tmp = *(cur++);
205+ dst->params.regs.outer_disp = tmp << 16 | *(cur++);
206+ break;
207+ }
208+ } else {
209+ switch (ext >> 6 & 3)
210+ {
211+ case 0:
212+ dst->addr_mode = MODE_PC_INDEX_BASE_DISP;
213+ break;
214+ case 1:
215+ dst->addr_mode = MODE_PC_BASE_DISP;
216+ break;
217+ case 2:
218+ dst->addr_mode = MODE_ZPC_INDEX_BASE_DISP;
219+ break;
220+ case 3:
221+ dst->addr_mode = MODE_ZPC_BASE_DISP;
222+ break;
223+ }
224+ }
225+ } else {
226+#endif
227+ dst->addr_mode = MODE_PC_INDEX_DISP8;
228+ dst->params.regs.displacement = sign_extend8(ext&0xFF);
229+#ifdef M68020
230+ }
231+#endif
232+ break;
233+ case 2:
234+ dst->addr_mode = MODE_PC_DISPLACE;
235+ ext = *(++cur);
236+ dst->params.regs.displacement = sign_extend16(ext);
237+ break;
238+ case 4:
239+ dst->addr_mode = MODE_IMMEDIATE;
240+ ext = *(++cur);
241+ switch (size)
242+ {
243+ case OPSIZE_BYTE:
244+ dst->params.immed = ext & 0xFF;
245+ break;
246+ case OPSIZE_WORD:
247+ dst->params.immed = ext;
248+ break;
249+ case OPSIZE_LONG:
250+ dst->params.immed = ext << 16 | *(++cur);
251+ break;
252+ }
253+ break;
254+ default:
255+ return NULL;
256+ }
257+ break;
258+ }
259+ return cur;
260+}
261+
262+uint8_t m68k_valid_immed_dst(m68k_op_info *dst)
263+{
264+ if (dst->addr_mode == MODE_AREG || dst->addr_mode == MODE_IMMEDIATE) {
265+ return 0;
266+ }
267+ return 1;
268+}
269+
270+uint8_t m68k_valid_immed_limited_dst(m68k_op_info *dst)
271+{
272+ if (dst->addr_mode == MODE_AREG || dst->addr_mode > MODE_ABSOLUTE) {
273+ return 0;
274+ }
275+ return 1;
276+}
277+
278+uint8_t m68k_valid_full_arith_dst(m68k_op_info *dst)
279+{
280+ if (dst->addr_mode < MODE_AREG_INDIRECT || dst->addr_mode > MODE_ABSOLUTE) {
281+ return 0;
282+ }
283+ return 1;
284+}
285+
286+uint8_t m68k_valid_movem_dst(m68k_op_info *dst)
287+{
288+ if (dst->addr_mode == MODE_REG || dst->addr_mode == MODE_AREG_POSTINC) {
289+ return 0;
290+ }
291+ return m68k_valid_immed_limited_dst(dst);
292+}
293+
294+uint16_t *m68k_decode_op(uint16_t *cur, uint8_t size, m68k_op_info *dst)
295+{
296+ uint8_t mode = (*cur >> 3) & 0x7;
297+ uint8_t reg = *cur & 0x7;
298+ return m68k_decode_op_ex(cur, mode, reg, size, dst);
299+}
300+
301+void m68k_decode_cond(uint16_t op, m68kinst * decoded)
302+{
303+ decoded->extra.cond = (op >> 0x8) & 0xF;
304+}
305+
306+uint8_t m68k_reg_quick_field(uint16_t op)
307+{
308+ return (op >> 9) & 0x7;
309+}
310+
311+uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
312+{
313+ uint16_t *start = istream;
314+ uint8_t optype = *istream >> 12;
315+ uint8_t size;
316+ uint8_t reg;
317+ uint8_t opmode;
318+ uint32_t immed;
319+ decoded->op = M68K_INVALID;
320+ decoded->src.addr_mode = decoded->dst.addr_mode = MODE_UNUSED;
321+ decoded->variant = VAR_NORMAL;
322+ decoded->address = address;
323+ switch(optype)
324+ {
325+ case BIT_MOVEP_IMMED:
326+ if ((*istream & 0x138) == 0x108) {
327+ //MOVEP
328+ decoded->op = M68K_MOVEP;
329+ decoded->extra.size = *istream & 0x40 ? OPSIZE_LONG : OPSIZE_WORD;
330+ if (*istream & 0x80) {
331+ //memory dest
332+ decoded->src.addr_mode = MODE_REG;
333+ decoded->src.params.regs.pri = m68k_reg_quick_field(*istream);
334+ decoded->dst.addr_mode = MODE_AREG_DISPLACE;
335+ decoded->dst.params.regs.pri = *istream & 0x7;
336+ decoded->dst.params.regs.displacement = *(++istream);
337+ } else {
338+ //memory source
339+ decoded->dst.addr_mode = MODE_REG;
340+ decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
341+ decoded->src.addr_mode = MODE_AREG_DISPLACE;
342+ decoded->src.params.regs.pri = *istream & 0x7;
343+ decoded->src.params.regs.displacement = *(++istream);
344+ }
345+ } else if (*istream & 0x100) {
346+ //BTST, BCHG, BCLR, BSET
347+ switch ((*istream >> 6) & 0x3)
348+ {
349+ case 0:
350+ decoded->op = M68K_BTST;
351+ break;
352+ case 1:
353+ decoded->op = M68K_BCHG;
354+ break;
355+ case 2:
356+ decoded->op = M68K_BCLR;
357+ break;
358+ case 3:
359+ decoded->op = M68K_BSET;
360+ break;
361+ }
362+ decoded->src.addr_mode = MODE_REG;
363+ decoded->src.params.regs.pri = m68k_reg_quick_field(*istream);
364+ decoded->extra.size = OPSIZE_BYTE;
365+ istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->dst));
366+ if (
367+ !istream || decoded->dst.addr_mode == MODE_AREG
368+ || (decoded->op != M68K_BTST && !m68k_valid_immed_limited_dst(&decoded->dst))
369+ ) {
370+ decoded->op = M68K_INVALID;
371+ break;
372+ }
373+ if (decoded->dst.addr_mode == MODE_REG) {
374+ decoded->extra.size = OPSIZE_LONG;
375+ }
376+ } else if ((*istream & 0xF00) == 0x800) {
377+ //BTST, BCHG, BCLR, BSET
378+ switch ((*istream >> 6) & 0x3)
379+ {
380+ case 0:
381+ decoded->op = M68K_BTST;
382+ break;
383+ case 1:
384+ decoded->op = M68K_BCHG;
385+ break;
386+ case 2:
387+ decoded->op = M68K_BCLR;
388+ break;
389+ case 3:
390+ decoded->op = M68K_BSET;
391+ break;
392+ }
393+ opmode = (*istream >> 3) & 0x7;
394+ reg = *istream & 0x7;
395+ decoded->src.addr_mode = MODE_IMMEDIATE_WORD;
396+ decoded->src.params.immed = *(++istream) & 0xFF;
397+ decoded->extra.size = OPSIZE_BYTE;
398+ istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->dst));
399+ if (
400+ !istream || !m68k_valid_immed_dst(&decoded->dst)
401+ || (decoded->op != M68K_BTST && !m68k_valid_immed_limited_dst(&decoded->dst))
402+ ) {
403+ decoded->op = M68K_INVALID;
404+ break;
405+ }
406+ if (decoded->dst.addr_mode == MODE_REG) {
407+ decoded->extra.size = OPSIZE_LONG;
408+ }
409+ } else if ((*istream & 0xC0) == 0xC0) {
410+#ifdef M68020
411+ //CMP2, CHK2, CAS, CAS2, RTM, CALLM
412+#endif
413+ } else {
414+ switch ((*istream >> 9) & 0x7)
415+ {
416+ case 0:
417+ if ((*istream & 0xFF) == 0x3C) {
418+ decoded->op = M68K_ORI_CCR;
419+ decoded->extra.size = OPSIZE_BYTE;
420+ decoded->src.addr_mode = MODE_IMMEDIATE;
421+ decoded->src.params.immed = *(++istream) & 0xFF;
422+ } else if((*istream & 0xFF) == 0x7C) {
423+ decoded->op = M68K_ORI_SR;
424+ decoded->extra.size = OPSIZE_WORD;
425+ decoded->src.addr_mode = MODE_IMMEDIATE;
426+ decoded->src.params.immed = *(++istream);
427+ } else {
428+ decoded->op = M68K_OR;
429+ decoded->variant = VAR_IMMEDIATE;
430+ decoded->src.addr_mode = MODE_IMMEDIATE;
431+ decoded->extra.size = size = (*istream >> 6) & 3;
432+ reg = *istream & 0x7;
433+ opmode = (*istream >> 3) & 0x7;
434+ switch (size)
435+ {
436+ case OPSIZE_BYTE:
437+ decoded->src.params.immed = *(++istream) & 0xFF;
438+ break;
439+ case OPSIZE_WORD:
440+ decoded->src.params.immed = *(++istream);
441+ break;
442+ case OPSIZE_LONG:
443+ immed = *(++istream);
444+ decoded->src.params.immed = immed << 16 | *(++istream);
445+ break;
446+ }
447+ istream = m68k_decode_op_ex(istream, opmode, reg, size, &(decoded->dst));
448+ if (!istream || !m68k_valid_immed_limited_dst(&(decoded->dst))) {
449+ decoded->op = M68K_INVALID;
450+ break;
451+ }
452+ }
453+ break;
454+ case 1:
455+ //ANDI, ANDI to CCR, ANDI to SR
456+ if ((*istream & 0xFF) == 0x3C) {
457+ decoded->op = M68K_ANDI_CCR;
458+ decoded->extra.size = OPSIZE_BYTE;
459+ decoded->src.addr_mode = MODE_IMMEDIATE;
460+ decoded->src.params.immed = *(++istream) & 0xFF;
461+ } else if((*istream & 0xFF) == 0x7C) {
462+ decoded->op = M68K_ANDI_SR;
463+ decoded->extra.size = OPSIZE_WORD;
464+ decoded->src.addr_mode = MODE_IMMEDIATE;
465+ decoded->src.params.immed = *(++istream);
466+ } else {
467+ decoded->op = M68K_AND;
468+ decoded->variant = VAR_IMMEDIATE;
469+ decoded->src.addr_mode = MODE_IMMEDIATE;
470+ decoded->extra.size = size = (*istream >> 6) & 3;
471+ reg = *istream & 0x7;
472+ opmode = (*istream >> 3) & 0x7;
473+ switch (size)
474+ {
475+ case OPSIZE_BYTE:
476+ decoded->src.params.immed = *(++istream) & 0xFF;
477+ break;
478+ case OPSIZE_WORD:
479+ decoded->src.params.immed = *(++istream);
480+ break;
481+ case OPSIZE_LONG:
482+ immed = *(++istream);
483+ decoded->src.params.immed = immed << 16 | *(++istream);
484+ break;
485+ }
486+ istream = m68k_decode_op_ex(istream, opmode, reg, size, &(decoded->dst));
487+ if (!istream || !m68k_valid_immed_limited_dst(&(decoded->dst))) {
488+ decoded->op = M68K_INVALID;
489+ break;
490+ }
491+ }
492+ break;
493+ case 2:
494+ decoded->op = M68K_SUB;
495+ decoded->variant = VAR_IMMEDIATE;
496+ decoded->src.addr_mode = MODE_IMMEDIATE;
497+ decoded->extra.size = size = (*istream >> 6) & 3;
498+ reg = *istream & 0x7;
499+ opmode = (*istream >> 3) & 0x7;
500+ switch (size)
501+ {
502+ case OPSIZE_BYTE:
503+ decoded->src.params.immed = *(++istream) & 0xFF;
504+ break;
505+ case OPSIZE_WORD:
506+ decoded->src.params.immed = *(++istream);
507+ break;
508+ case OPSIZE_LONG:
509+ immed = *(++istream);
510+ decoded->src.params.immed = immed << 16 | *(++istream);
511+ break;
512+ }
513+ istream = m68k_decode_op_ex(istream, opmode, reg, size, &(decoded->dst));
514+ if (!istream || !m68k_valid_immed_limited_dst(&(decoded->dst))) {
515+ decoded->op = M68K_INVALID;
516+ break;
517+ }
518+ break;
519+ case 3:
520+ decoded->op = M68K_ADD;
521+ decoded->variant = VAR_IMMEDIATE;
522+ decoded->src.addr_mode = MODE_IMMEDIATE;
523+ decoded->extra.size = size = (*istream >> 6) & 3;
524+ reg = *istream & 0x7;
525+ opmode = (*istream >> 3) & 0x7;
526+ switch (size)
527+ {
528+ case OPSIZE_BYTE:
529+ decoded->src.params.immed = *(++istream) & 0xFF;
530+ break;
531+ case OPSIZE_WORD:
532+ decoded->src.params.immed = *(++istream);
533+ break;
534+ case OPSIZE_LONG:
535+ immed = *(++istream);
536+ decoded->src.params.immed = immed << 16 | *(++istream);
537+ break;
538+ }
539+ istream = m68k_decode_op_ex(istream, opmode, reg, size, &(decoded->dst));
540+ if (!istream || !m68k_valid_immed_limited_dst(&(decoded->dst))) {
541+ decoded->op = M68K_INVALID;
542+ break;
543+ }
544+ break;
545+ case 4:
546+ //BTST, BCHG, BCLR, BSET
547+ //Seems like this should be unnecessary since bit instructions are explicitly handled above
548+ //Possible this is redundant or the case above is overly restrictive
549+ //TODO: Investigate whether this can be removed
550+ switch ((*istream >> 6) & 0x3)
551+ {
552+ case 0:
553+ decoded->op = M68K_BTST;
554+ break;
555+ case 1:
556+ decoded->op = M68K_BCHG;
557+ break;
558+ case 2:
559+ decoded->op = M68K_BCLR;
560+ break;
561+ case 3:
562+ decoded->op = M68K_BSET;
563+ break;
564+ }
565+ decoded->src.addr_mode = MODE_IMMEDIATE_WORD;
566+ decoded->src.params.immed = *(++istream) & 0xFF;
567+ istream = m68k_decode_op(istream, OPSIZE_BYTE, &(decoded->dst));
568+ if (
569+ !istream || !m68k_valid_immed_dst(&decoded->dst)
570+ || (decoded->op != M68K_BTST && !m68k_valid_immed_limited_dst(&decoded->dst))
571+ ) {
572+ decoded->op = M68K_INVALID;
573+ break;
574+ }
575+ break;
576+ case 5:
577+ //EORI, EORI to CCR, EORI to SR
578+ if ((*istream & 0xFF) == 0x3C) {
579+ decoded->op = M68K_EORI_CCR;
580+ decoded->extra.size = OPSIZE_BYTE;
581+ decoded->src.addr_mode = MODE_IMMEDIATE;
582+ decoded->src.params.immed = *(++istream) & 0xFF;
583+ } else if((*istream & 0xFF) == 0x7C) {
584+ decoded->op = M68K_EORI_SR;
585+ decoded->extra.size = OPSIZE_WORD;
586+ decoded->src.addr_mode = MODE_IMMEDIATE;
587+ decoded->src.params.immed = *(++istream);
588+ } else {
589+ decoded->op = M68K_EOR;
590+ decoded->variant = VAR_IMMEDIATE;
591+ decoded->src.addr_mode = MODE_IMMEDIATE;
592+ decoded->extra.size = size = (*istream >> 6) & 3;
593+ reg = *istream & 0x7;
594+ opmode = (*istream >> 3) & 0x7;
595+ switch (size)
596+ {
597+ case OPSIZE_BYTE:
598+ decoded->src.params.immed = *(++istream) & 0xFF;
599+ break;
600+ case OPSIZE_WORD:
601+ decoded->src.params.immed = *(++istream);
602+ break;
603+ case OPSIZE_LONG:
604+ immed = *(++istream);
605+ decoded->src.params.immed = immed << 16 | *(++istream);
606+ break;
607+ }
608+ istream = m68k_decode_op_ex(istream, opmode, reg, size, &(decoded->dst));
609+ if (!istream || !m68k_valid_immed_limited_dst(&(decoded->dst))) {
610+ decoded->op = M68K_INVALID;
611+ break;
612+ }
613+ }
614+ break;
615+ case 6:
616+ decoded->op = M68K_CMP;
617+ decoded->variant = VAR_IMMEDIATE;
618+ decoded->extra.size = (*istream >> 6) & 0x3;
619+ decoded->src.addr_mode = MODE_IMMEDIATE;
620+ reg = *istream & 0x7;
621+ opmode = (*istream >> 3) & 0x7;
622+ switch (decoded->extra.size)
623+ {
624+ case OPSIZE_BYTE:
625+ decoded->src.params.immed = *(++istream) & 0xFF;
626+ break;
627+ case OPSIZE_WORD:
628+ decoded->src.params.immed = *(++istream);
629+ break;
630+ case OPSIZE_LONG:
631+ immed = *(++istream);
632+ decoded->src.params.immed = (immed << 16) | *(++istream);
633+ break;
634+ }
635+ istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->dst));
636+ if (!istream || !m68k_valid_immed_limited_dst(&(decoded->dst))) {
637+ decoded->op = M68K_INVALID;
638+ break;
639+ }
640+ break;
641+ case 7:
642+#ifdef M68010
643+ decoded->op = M68K_MOVES;
644+ decoded->extra.size = *istream >> 6 & 0x3;
645+ immed = *(++istream);
646+ reg = immed >> 12 & 0x7;
647+ opmode = immed & 0x8000 ? MODE_AREG : MODE_REG;
648+ if (immed & 0x800) {
649+ decoded->src.addr_mode = opmode;
650+ decoded->src.params.regs.pri = reg;
651+ m68k_decode_op_ex(istream, *start >> 3 & 0x7, *start & 0x7, decoded->extra.size, &(decoded->dst));
652+ } else {
653+ m68k_decode_op_ex(istream, *start >> 3 & 0x7, *start & 0x7, decoded->extra.size, &(decoded->src));
654+ decoded->dst.addr_mode = opmode;
655+ decoded->dst.params.regs.pri = reg;
656+ }
657+#endif
658+ break;
659+ }
660+ }
661+ break;
662+ case MOVE_BYTE:
663+ case MOVE_LONG:
664+ case MOVE_WORD:
665+ decoded->op = M68K_MOVE;
666+ decoded->extra.size = optype == MOVE_BYTE ? OPSIZE_BYTE : (optype == MOVE_WORD ? OPSIZE_WORD : OPSIZE_LONG);
667+ opmode = (*istream >> 6) & 0x7;
668+ reg = m68k_reg_quick_field(*istream);
669+ istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
670+ if (!istream || (decoded->src.addr_mode == MODE_AREG && optype == MOVE_BYTE)) {
671+ decoded->op = M68K_INVALID;
672+ break;
673+ }
674+ istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->dst));
675+ if (!istream || decoded->dst.addr_mode > MODE_ABSOLUTE || (decoded->dst.addr_mode == MODE_AREG && optype == MOVE_BYTE)) {
676+ decoded->op = M68K_INVALID;
677+ break;
678+ }
679+ break;
680+ case MISC:
681+
682+ if ((*istream & 0x1C0) == 0x1C0) {
683+ decoded->op = M68K_LEA;
684+ decoded->extra.size = OPSIZE_LONG;
685+ decoded->dst.addr_mode = MODE_AREG;
686+ decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
687+ istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
688+ if (
689+ !istream || decoded->src.addr_mode == MODE_REG || decoded->src.addr_mode == MODE_AREG
690+ || decoded->src.addr_mode == MODE_AREG_POSTINC || decoded->src.addr_mode == MODE_AREG_PREDEC
691+ || decoded->src.addr_mode == MODE_IMMEDIATE
692+ ) {
693+ decoded->op = M68K_INVALID;
694+ break;
695+ }
696+ } else {
697+ if (*istream & 0x100) {
698+ decoded->op = M68K_CHK;
699+ if ((*istream & 0x180) == 0x180) {
700+ decoded->extra.size = OPSIZE_WORD;
701+ } else {
702+ //only on M68020+
703+#ifdef M68020
704+ decoded->extra.size = OPSIZE_LONG;
705+#else
706+ decoded->op = M68K_INVALID;
707+ break;
708+#endif
709+ }
710+ decoded->dst.addr_mode = MODE_REG;
711+ decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
712+ istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
713+ if (!istream || decoded->src.addr_mode == MODE_AREG) {
714+ decoded->op = M68K_INVALID;
715+ break;
716+ }
717+ } else {
718+ opmode = (*istream >> 3) & 0x7;
719+ if ((*istream & 0xB80) == 0x880 && opmode != MODE_REG && opmode != MODE_AREG) {
720+ //TODO: Check for invalid modes that are dependent on direction
721+ decoded->op = M68K_MOVEM;
722+ decoded->extra.size = *istream & 0x40 ? OPSIZE_LONG : OPSIZE_WORD;
723+ reg = *istream & 0x7;
724+ if(*istream & 0x400) {
725+ decoded->dst.addr_mode = MODE_REG;
726+ decoded->dst.params.immed = *(++istream);
727+ istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->src));
728+ if (!istream || decoded->src.addr_mode == MODE_AREG_PREDEC || decoded->src.addr_mode == MODE_IMMEDIATE) {
729+ decoded->op = M68K_INVALID;
730+ break;
731+ }
732+ if (decoded->src.addr_mode == MODE_PC_DISPLACE || decoded->src.addr_mode == MODE_PC_INDEX_DISP8) {
733+ //adjust displacement to account for extra instruction word
734+ decoded->src.params.regs.displacement += 2;
735+ }
736+ } else {
737+ decoded->src.addr_mode = MODE_REG;
738+ decoded->src.params.immed = *(++istream);
739+ istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->dst));
740+ if (!istream || !m68k_valid_movem_dst(&decoded->dst)) {
741+ decoded->op = M68K_INVALID;
742+ break;
743+ }
744+ }
745+ } else {
746+ optype = (*istream >> 9) & 0x7;
747+ size = (*istream >> 6) & 0x3;
748+ switch(optype)
749+ {
750+ case 0:
751+ //Move from SR or NEGX
752+ if (size == OPSIZE_INVALID) {
753+ decoded->op = M68K_MOVE_FROM_SR;
754+ size = OPSIZE_WORD;
755+ } else {
756+ decoded->op = M68K_NEGX;
757+ }
758+ decoded->extra.size = size;
759+ istream= m68k_decode_op(istream, size, &(decoded->dst));
760+ if (!istream || !m68k_valid_immed_limited_dst(&decoded->dst)) {
761+ decoded->op = M68K_INVALID;
762+ break;
763+ }
764+ break;
765+ case 1:
766+ //MOVE from CCR or CLR
767+ if (size == OPSIZE_INVALID) {
768+#ifdef M68010
769+ decoded->op = M68K_MOVE_FROM_CCR;
770+ size = OPSIZE_WORD;
771+#else
772+ break;
773+#endif
774+ } else {
775+ decoded->op = M68K_CLR;
776+ }
777+ decoded->extra.size = size;
778+ istream= m68k_decode_op(istream, size, &(decoded->dst));
779+ if (!istream || !m68k_valid_immed_limited_dst(&decoded->dst)) {
780+ decoded->op = M68K_INVALID;
781+ break;
782+ }
783+ break;
784+ case 2:
785+ //MOVE to CCR or NEG
786+ if (size == OPSIZE_INVALID) {
787+ decoded->op = M68K_MOVE_CCR;
788+ size = OPSIZE_WORD;
789+ istream= m68k_decode_op(istream, size, &(decoded->src));
790+ if (!istream || decoded->src.addr_mode == MODE_AREG) {
791+ decoded->op = M68K_INVALID;
792+ break;
793+ }
794+ } else {
795+ decoded->op = M68K_NEG;
796+ istream= m68k_decode_op(istream, size, &(decoded->dst));
797+ if (!istream || !m68k_valid_immed_limited_dst(&decoded->dst)) {
798+ decoded->op = M68K_INVALID;
799+ break;
800+ }
801+ }
802+ decoded->extra.size = size;
803+ break;
804+ case 3:
805+ //MOVE to SR or NOT
806+ if (size == OPSIZE_INVALID) {
807+ decoded->op = M68K_MOVE_SR;
808+ size = OPSIZE_WORD;
809+ istream= m68k_decode_op(istream, size, &(decoded->src));
810+ if (!istream || decoded->src.addr_mode == MODE_AREG) {
811+ decoded->op = M68K_INVALID;
812+ break;
813+ }
814+ } else {
815+ decoded->op = M68K_NOT;
816+ istream= m68k_decode_op(istream, size, &(decoded->dst));
817+ if (!istream || !m68k_valid_immed_limited_dst(&decoded->dst)) {
818+ decoded->op = M68K_INVALID;
819+ break;
820+ }
821+ }
822+ decoded->extra.size = size;
823+ break;
824+ case 4:
825+ //EXT, EXTB, LINK.l, NBCD, SWAP, BKPT, PEA
826+ switch((*istream >> 3) & 0x3F)
827+ {
828+ case 1:
829+#ifdef M68020
830+ decoded->op = M68K_LINK;
831+ decoded->extra.size = OPSIZE_LONG;
832+ reg = *istream & 0x7;
833+ immed = *(++istream) << 16;
834+ immed |= *(++istream);
835+#endif
836+ break;
837+ case 8:
838+ decoded->op = M68K_SWAP;
839+ decoded->src.addr_mode = MODE_REG;
840+ decoded->src.params.regs.pri = *istream & 0x7;
841+ decoded->extra.size = OPSIZE_WORD;
842+ break;
843+ case 9:
844+#ifdef M68010
845+ decoded->op = M68K_BKPT;
846+ decoded->src.addr_mode = MODE_IMMEDIATE;
847+ decoded->extra.size = OPSIZE_UNSIZED;
848+ decoded->src.params.immed = *istream & 0x7;
849+#endif
850+ break;
851+ case 0x10:
852+ decoded->op = M68K_EXT;
853+ decoded->dst.addr_mode = MODE_REG;
854+ decoded->dst.params.regs.pri = *istream & 0x7;
855+ decoded->extra.size = OPSIZE_WORD;
856+ break;
857+ case 0x18:
858+ decoded->op = M68K_EXT;
859+ decoded->dst.addr_mode = MODE_REG;
860+ decoded->dst.params.regs.pri = *istream & 0x7;
861+ decoded->extra.size = OPSIZE_LONG;
862+ break;
863+ case 0x38:
864+#ifdef M68020
865+#endif
866+ break;
867+ default:
868+ if (!(*istream & 0x1C0)) {
869+ decoded->op = M68K_NBCD;
870+ decoded->extra.size = OPSIZE_BYTE;
871+ istream = m68k_decode_op(istream, OPSIZE_BYTE, &(decoded->dst));
872+ if (!istream || !m68k_valid_immed_limited_dst(&decoded->dst)) {
873+ decoded->op = M68K_INVALID;
874+ break;
875+ }
876+ } else if((*istream & 0x1C0) == 0x40) {
877+ decoded->op = M68K_PEA;
878+ decoded->extra.size = OPSIZE_LONG;
879+ istream = m68k_decode_op(istream, OPSIZE_LONG, &(decoded->src));
880+ if (
881+ !istream || decoded->src.addr_mode == MODE_REG || decoded->src.addr_mode == MODE_AREG
882+ || decoded->src.addr_mode == MODE_AREG_POSTINC || decoded->src.addr_mode == MODE_AREG_PREDEC
883+ || decoded->src.addr_mode == MODE_IMMEDIATE
884+ ) {
885+ decoded->op = M68K_INVALID;
886+ break;
887+ }
888+ }
889+ }
890+ break;
891+ case 5:
892+ //BGND, ILLEGAL, TAS, TST
893+ optype = *istream & 0xFF;
894+ if (optype == 0xFA) {
895+ //BGND - CPU32 only
896+ } else if (optype == 0xFC) {
897+ decoded->op = M68K_ILLEGAL;
898+ decoded->extra.size = OPSIZE_UNSIZED;
899+ } else {
900+ if (size == OPSIZE_INVALID) {
901+ decoded->op = M68K_TAS;
902+ decoded->extra.size = OPSIZE_BYTE;
903+ istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->dst));
904+ if (!istream || !m68k_valid_immed_limited_dst(&decoded->dst)) {
905+ decoded->op = M68K_INVALID;
906+ break;
907+ }
908+ } else {
909+ decoded->op = M68K_TST;
910+ decoded->extra.size = size;
911+ istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
912+ if (!istream) {
913+ decoded->op = M68K_INVALID;
914+ break;
915+ }
916+#ifndef M68020
917+ if (!m68k_valid_immed_limited_dst(&decoded->src)) {
918+ decoded->op = M68K_INVALID;
919+ break;
920+ }
921+#endif
922+ }
923+ }
924+ break;
925+ case 6:
926+ //MULU, MULS, DIVU, DIVUL, DIVS, DIVSL
927+#ifdef M68020
928+ //TODO: Implement these for 68020+ support
929+#endif
930+ break;
931+ case 7:
932+ //TRAP, LINK.w, UNLNK, MOVE USP, RESET, NOP, STOP, RTE, RTD, RTS, TRAPV, RTR, MOVEC, JSR, JMP
933+ if (*istream & 0x80) {
934+ //JSR, JMP
935+ if (*istream & 0x40) {
936+ decoded->op = M68K_JMP;
937+ } else {
938+ decoded->op = M68K_JSR;
939+ }
940+ decoded->extra.size = OPSIZE_UNSIZED;
941+ istream = m68k_decode_op(istream, OPSIZE_UNSIZED, &(decoded->src));
942+ if (
943+ !istream
944+ || (decoded->src.addr_mode < MODE_AREG_DISPLACE && decoded->src.addr_mode != MODE_AREG_INDIRECT)
945+ || decoded->src.addr_mode == MODE_IMMEDIATE
946+ ) {
947+ decoded->op = M68K_INVALID;
948+ break;
949+ }
950+ } else {
951+ //it would appear bit 6 needs to be set for it to be a valid instruction here
952+ if (!(*istream & 0x40)) {
953+ decoded->op = M68K_INVALID;
954+ break;
955+ }
956+ switch((*istream >> 3) & 0x7)
957+ {
958+ case 0:
959+ case 1:
960+ //TRAP
961+ decoded->op = M68K_TRAP;
962+ decoded->extra.size = OPSIZE_UNSIZED;
963+ decoded->src.addr_mode = MODE_IMMEDIATE;
964+ decoded->src.params.immed = *istream & 0xF;
965+ break;
966+ case 2:
967+ //LINK.w
968+ decoded->op = M68K_LINK;
969+ decoded->extra.size = OPSIZE_WORD;
970+ decoded->src.addr_mode = MODE_AREG;
971+ decoded->src.params.regs.pri = *istream & 0x7;
972+ decoded->dst.addr_mode = MODE_IMMEDIATE;
973+ decoded->dst.params.immed = sign_extend16(*(++istream));
974+ break;
975+ case 3:
976+ //UNLK
977+ decoded->op = M68K_UNLK;
978+ decoded->extra.size = OPSIZE_UNSIZED;
979+ decoded->dst.addr_mode = MODE_AREG;
980+ decoded->dst.params.regs.pri = *istream & 0x7;
981+ break;
982+ case 4:
983+ case 5:
984+ //MOVE USP
985+ decoded->op = M68K_MOVE_USP;
986+ if (*istream & 0x8) {
987+ decoded->dst.addr_mode = MODE_AREG;
988+ decoded->dst.params.regs.pri = *istream & 0x7;
989+ } else {
990+ decoded->src.addr_mode = MODE_AREG;
991+ decoded->src.params.regs.pri = *istream & 0x7;
992+ }
993+ break;
994+ case 6:
995+ decoded->extra.size = OPSIZE_UNSIZED;
996+ switch(*istream & 0x7)
997+ {
998+ case 0:
999+ decoded->op = M68K_RESET;
1000+ break;
1001+ case 1:
1002+ decoded->op = M68K_NOP;
1003+ break;
1004+ case 2:
1005+ decoded->op = M68K_STOP;
1006+ decoded->src.addr_mode = MODE_IMMEDIATE;
1007+ decoded->src.params.immed =*(++istream);
1008+ break;
1009+ case 3:
1010+ decoded->op = M68K_RTE;
1011+ break;
1012+ case 4:
1013+#ifdef M68010
1014+ decoded->op = M68K_RTD;
1015+ decoded->src.addr_mode = MODE_IMMEDIATE;
1016+ decoded->src.params.immed =*(++istream);
1017+#endif
1018+ break;
1019+ case 5:
1020+ decoded->op = M68K_RTS;
1021+ break;
1022+ case 6:
1023+ decoded->op = M68K_TRAPV;
1024+ break;
1025+ case 7:
1026+ decoded->op = M68K_RTR;
1027+ break;
1028+ }
1029+ break;
1030+ case 7:
1031+ //MOVEC
1032+#ifdef M68010
1033+ decoded->op = M68K_MOVEC;
1034+ immed = *(++istream);
1035+ reg = immed >> 12 & 0x7;
1036+ opmode = immed & 0x8000 ? MODE_AREG : MODE_REG;
1037+ immed &= 0xFFF;
1038+ if (immed & 0x800) {
1039+ if (immed > MAX_HIGH_CR) {
1040+ decoded->op = M68K_INVALID;
1041+ break;
1042+ } else {
1043+ immed = immed - 0x800 + CR_USP;
1044+ }
1045+ } else {
1046+ if (immed > MAX_LOW_CR) {
1047+ decoded->op = M68K_INVALID;
1048+ break;
1049+ }
1050+ }
1051+ if (*start & 1) {
1052+ decoded->src.addr_mode = opmode;
1053+ decoded->src.params.regs.pri = reg;
1054+ decoded->dst.params.immed = immed;
1055+ } else {
1056+ decoded->dst.addr_mode = opmode;
1057+ decoded->dst.params.regs.pri = reg;
1058+ decoded->src.params.immed = immed;
1059+ }
1060+#endif
1061+ break;
1062+ }
1063+ }
1064+ break;
1065+ }
1066+ }
1067+ }
1068+ }
1069+ break;
1070+ case QUICK_ARITH_LOOP:
1071+ size = (*istream >> 6) & 3;
1072+ if (size == 0x3) {
1073+ //DBcc, TRAPcc or Scc
1074+ m68k_decode_cond(*istream, decoded);
1075+ if (((*istream >> 3) & 0x7) == 1) {
1076+ decoded->op = M68K_DBCC;
1077+ decoded->src.addr_mode = MODE_IMMEDIATE;
1078+ decoded->dst.addr_mode = MODE_REG;
1079+ decoded->dst.params.regs.pri = *istream & 0x7;
1080+ decoded->src.params.immed = sign_extend16(*(++istream));
1081+ } else if(((*istream >> 3) & 0x7) == 1 && (*istream & 0x7) > 1 && (*istream & 0x7) < 5) {
1082+#ifdef M68020
1083+ decoded->op = M68K_TRAPCC;
1084+ decoded->src.addr_mode = MODE_IMMEDIATE;
1085+ //TODO: Figure out what to do with OPMODE and optional extention words
1086+#endif
1087+ } else {
1088+ decoded->op = M68K_SCC;
1089+ decoded->extra.cond = (*istream >> 8) & 0xF;
1090+ istream = m68k_decode_op(istream, OPSIZE_BYTE, &(decoded->dst));
1091+ if (!istream || !m68k_valid_immed_limited_dst(&decoded->dst)) {
1092+ decoded->op = M68K_INVALID;
1093+ break;
1094+ }
1095+ }
1096+ } else {
1097+ //ADDQ, SUBQ
1098+ decoded->variant = VAR_QUICK;
1099+ decoded->extra.size = size;
1100+ decoded->src.addr_mode = MODE_IMMEDIATE;
1101+ immed = m68k_reg_quick_field(*istream);
1102+ if (!immed) {
1103+ immed = 8;
1104+ }
1105+ decoded->src.params.immed = immed;
1106+ if (*istream & 0x100) {
1107+ decoded->op = M68K_SUB;
1108+ } else {
1109+ decoded->op = M68K_ADD;
1110+ }
1111+ istream = m68k_decode_op(istream, size, &(decoded->dst));
1112+ if (!istream || decoded->dst.addr_mode > MODE_ABSOLUTE || (size == OPSIZE_BYTE && decoded->dst.addr_mode == MODE_AREG)) {
1113+ decoded->op = M68K_INVALID;
1114+ break;
1115+ }
1116+ }
1117+ break;
1118+ case BRANCH:
1119+ m68k_decode_cond(*istream, decoded);
1120+ decoded->op = decoded->extra.cond == COND_FALSE ? M68K_BSR : M68K_BCC;
1121+ decoded->src.addr_mode = MODE_IMMEDIATE;
1122+ immed = *istream & 0xFF;
1123+ if (immed == 0) {
1124+ decoded->variant = VAR_WORD;
1125+ immed = *(++istream);
1126+ immed = sign_extend16(immed);
1127+#ifdef M68020
1128+ } else if (immed == 0xFF) {
1129+ decoded->variant = VAR_LONG;
1130+ immed = *(++istream) << 16;
1131+ immed |= *(++istream);
1132+#endif
1133+ } else {
1134+ decoded->variant = VAR_BYTE;
1135+ immed = sign_extend8(immed);
1136+ }
1137+ decoded->src.params.immed = immed;
1138+ break;
1139+ case MOVEQ:
1140+ if (*istream & 0x100) {
1141+ decoded->op = M68K_INVALID;
1142+ break;
1143+ }
1144+ decoded->op = M68K_MOVE;
1145+ decoded->variant = VAR_QUICK;
1146+ decoded->extra.size = OPSIZE_LONG;
1147+ decoded->src.addr_mode = MODE_IMMEDIATE;
1148+ decoded->src.params.immed = sign_extend8(*istream & 0xFF);
1149+ decoded->dst.addr_mode = MODE_REG;
1150+ decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
1151+ immed = *istream & 0xFF;
1152+ break;
1153+ case OR_DIV_SBCD:
1154+ //for OR, if opmode bit 2 is 1, then src = Dn, dst = <ea>
1155+ opmode = (*istream >> 6) & 0x7;
1156+ size = opmode & 0x3;
1157+ if (size == OPSIZE_INVALID || (opmode & 0x4 && !(*istream & 0x30))) {
1158+ switch(opmode)
1159+ {
1160+ case 3:
1161+ decoded->op = M68K_DIVU;
1162+ decoded->extra.size = OPSIZE_WORD;
1163+ decoded->dst.addr_mode = MODE_REG;
1164+ decoded->dst.params.regs.pri = (*istream >> 9) & 0x7;
1165+ istream = m68k_decode_op(istream, OPSIZE_WORD, &(decoded->src));
1166+ if (!istream || decoded->src.addr_mode == MODE_AREG) {
1167+ decoded->op = M68K_INVALID;
1168+ break;
1169+ }
1170+ break;
1171+ case 4:
1172+ decoded->op = M68K_SBCD;
1173+ decoded->extra.size = OPSIZE_BYTE;
1174+ decoded->dst.addr_mode = decoded->src.addr_mode = *istream & 0x8 ? MODE_AREG_PREDEC : MODE_REG;
1175+ decoded->src.params.regs.pri = *istream & 0x7;
1176+ decoded->dst.params.regs.pri = (*istream >> 9) & 0x7;
1177+ break;
1178+ case 5:
1179+ #ifdef M68020
1180+ #endif
1181+ break;
1182+ case 6:
1183+ #ifdef M68020
1184+ #endif
1185+ break;
1186+ case 7:
1187+ decoded->op = M68K_DIVS;
1188+ decoded->extra.size = OPSIZE_WORD;
1189+ decoded->dst.addr_mode = MODE_REG;
1190+ decoded->dst.params.regs.pri = (*istream >> 9) & 0x7;
1191+ istream = m68k_decode_op(istream, OPSIZE_WORD, &(decoded->src));
1192+ if (!istream || decoded->src.addr_mode == MODE_AREG) {
1193+ decoded->op = M68K_INVALID;
1194+ break;
1195+ }
1196+ break;
1197+ }
1198+ } else {
1199+ decoded->op = M68K_OR;
1200+ decoded->extra.size = size;
1201+ if (opmode & 0x4) {
1202+ decoded->src.addr_mode = MODE_REG;
1203+ decoded->src.params.regs.pri = (*istream >> 9) & 0x7;
1204+ istream = m68k_decode_op(istream, size, &(decoded->dst));
1205+ if (!istream || !m68k_valid_full_arith_dst(&(decoded->dst))) {
1206+ decoded->op = M68K_INVALID;
1207+ break;
1208+ }
1209+ } else {
1210+ decoded->dst.addr_mode = MODE_REG;
1211+ decoded->dst.params.regs.pri = (*istream >> 9) & 0x7;
1212+ istream = m68k_decode_op(istream, size, &(decoded->src));
1213+ if (!istream || decoded->src.addr_mode == MODE_AREG) {
1214+ decoded->op = M68K_INVALID;
1215+ break;
1216+ }
1217+ }
1218+ }
1219+ break;
1220+ case SUB_SUBX:
1221+ size = (*istream >> 6) & 0x3;
1222+ decoded->op = M68K_SUB;
1223+ if (*istream & 0x100) {
1224+ //<ea> destination, SUBA.l or SUBX
1225+ if (*istream & 0x30 || size == OPSIZE_INVALID) {
1226+ if (size == OPSIZE_INVALID) {
1227+ //SUBA.l
1228+ decoded->extra.size = OPSIZE_LONG;
1229+ decoded->dst.addr_mode = MODE_AREG;
1230+ decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
1231+ istream = m68k_decode_op(istream, OPSIZE_LONG, &(decoded->src));
1232+ if (!istream) {
1233+ decoded->op = M68K_INVALID;
1234+ break;
1235+ }
1236+ } else {
1237+ decoded->extra.size = size;
1238+ decoded->src.addr_mode = MODE_REG;
1239+ decoded->src.params.regs.pri = m68k_reg_quick_field(*istream);
1240+ istream = m68k_decode_op(istream, size, &(decoded->dst));
1241+ if (!istream || !m68k_valid_full_arith_dst(&decoded->dst)) {
1242+ decoded->op = M68K_INVALID;
1243+ break;
1244+ }
1245+ }
1246+ } else {
1247+ //SUBX
1248+ decoded->op = M68K_SUBX;
1249+ decoded->extra.size = size;
1250+ decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
1251+ decoded->src.params.regs.pri = *istream & 0x7;
1252+ if (*istream & 0x8) {
1253+ decoded->dst.addr_mode = decoded->src.addr_mode = MODE_AREG_PREDEC;
1254+ } else {
1255+ decoded->dst.addr_mode = decoded->src.addr_mode = MODE_REG;
1256+ }
1257+ }
1258+ } else {
1259+ if (size == OPSIZE_INVALID) {
1260+ //SUBA.w
1261+ decoded->extra.size = OPSIZE_WORD;
1262+ decoded->dst.addr_mode = MODE_AREG;
1263+ } else {
1264+ decoded->extra.size = size;
1265+ decoded->dst.addr_mode = MODE_REG;
1266+ }
1267+ decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
1268+ istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
1269+ if (!istream || (decoded->src.addr_mode == MODE_AREG && decoded->extra.size == OPSIZE_BYTE)) {
1270+ decoded->op = M68K_INVALID;
1271+ break;
1272+ }
1273+ }
1274+ break;
1275+ case A_LINE:
1276+ decoded->op = M68K_A_LINE_TRAP;
1277+ break;
1278+ case CMP_XOR:
1279+ size = (*istream >> 6) & 0x3;
1280+ decoded->op = M68K_CMP;
1281+ if (*istream & 0x100) {
1282+ //CMPM or CMPA.l or EOR
1283+ if (size == OPSIZE_INVALID) {
1284+ decoded->extra.size = OPSIZE_LONG;
1285+ decoded->dst.addr_mode = MODE_AREG;
1286+ decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
1287+ istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
1288+ if (!istream) {
1289+ decoded->op = M68K_INVALID;
1290+ break;
1291+ }
1292+ } else {
1293+ reg = m68k_reg_quick_field(*istream);
1294+ istream = m68k_decode_op(istream, size, &(decoded->dst));
1295+ if (!istream) {
1296+ decoded->op = M68K_INVALID;
1297+ break;
1298+ }
1299+ decoded->extra.size = size;
1300+ if (decoded->dst.addr_mode == MODE_AREG) {
1301+ //CMPM
1302+ decoded->src.addr_mode = decoded->dst.addr_mode = MODE_AREG_POSTINC;
1303+ decoded->src.params.regs.pri = decoded->dst.params.regs.pri;
1304+ decoded->dst.params.regs.pri = reg;
1305+ } else if (!m68k_valid_immed_limited_dst(&decoded->dst)){
1306+ decoded->op = M68K_INVALID;
1307+ break;
1308+ } else {
1309+ //EOR
1310+ decoded->op = M68K_EOR;
1311+ decoded->src.addr_mode = MODE_REG;
1312+ decoded->src.params.regs.pri = reg;
1313+ }
1314+ }
1315+ } else {
1316+ //CMP or CMPA.w
1317+ if (size == OPSIZE_INVALID) {
1318+ decoded->extra.size = OPSIZE_WORD;
1319+ decoded->dst.addr_mode = MODE_AREG;
1320+ } else {
1321+ decoded->extra.size = size;
1322+ decoded->dst.addr_mode = MODE_REG;
1323+ }
1324+ decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
1325+ istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
1326+ if (!istream || (decoded->src.addr_mode == MODE_AREG && decoded->extra.size == OPSIZE_BYTE)) {
1327+ decoded->op = M68K_INVALID;
1328+ break;
1329+ }
1330+ }
1331+ break;
1332+ case AND_MUL_ABCD_EXG:
1333+ //page 575 for summary
1334+ //EXG opmodes:
1335+ //01000 -data regs
1336+ //01001 -addr regs
1337+ //10001 -one of each
1338+ //AND opmodes:
1339+ //operand order bit + 2 size bits (00 - 10)
1340+ //no address register direct addressing
1341+ //data register direct not allowed when <ea> is the source (operand order bit of 1)
1342+ if (*istream & 0x100) {
1343+ if ((*istream & 0xC0) == 0xC0) {
1344+ decoded->op = M68K_MULS;
1345+ decoded->extra.size = OPSIZE_WORD;
1346+ decoded->dst.addr_mode = MODE_REG;
1347+ decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
1348+ istream = m68k_decode_op(istream, OPSIZE_WORD, &(decoded->src));
1349+ if (!istream || decoded->src.addr_mode == MODE_AREG) {
1350+ decoded->op = M68K_INVALID;
1351+ break;
1352+ }
1353+ } else if(!(*istream & 0xF0)) {
1354+ decoded->op = M68K_ABCD;
1355+ decoded->extra.size = OPSIZE_BYTE;
1356+ decoded->src.params.regs.pri = *istream & 0x7;
1357+ decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
1358+ decoded->dst.addr_mode = decoded->src.addr_mode = (*istream & 8) ? MODE_AREG_PREDEC : MODE_REG;
1359+ } else if(!(*istream & 0x30)) {
1360+ decoded->op = M68K_EXG;
1361+ decoded->extra.size = OPSIZE_LONG;
1362+ decoded->src.params.regs.pri = m68k_reg_quick_field(*istream);
1363+ decoded->dst.params.regs.pri = *istream & 0x7;
1364+ if (*istream & 0x8) {
1365+ if (*istream & 0x80) {
1366+ decoded->src.addr_mode = MODE_REG;
1367+ decoded->dst.addr_mode = MODE_AREG;
1368+ } else {
1369+ decoded->src.addr_mode = decoded->dst.addr_mode = MODE_AREG;
1370+ }
1371+ } else if (*istream & 0x40) {
1372+ decoded->src.addr_mode = decoded->dst.addr_mode = MODE_REG;
1373+ } else {
1374+ decoded->op = M68K_INVALID;
1375+ break;
1376+ }
1377+ } else {
1378+ decoded->op = M68K_AND;
1379+ decoded->extra.size = (*istream >> 6) & 0x3;
1380+ decoded->src.addr_mode = MODE_REG;
1381+ decoded->src.params.regs.pri = m68k_reg_quick_field(*istream);
1382+ istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->dst));
1383+ if (!istream || !m68k_valid_full_arith_dst(&(decoded->dst))) {
1384+ decoded->op = M68K_INVALID;
1385+ break;
1386+ }
1387+ }
1388+ } else {
1389+ if ((*istream & 0xC0) == 0xC0) {
1390+ decoded->op = M68K_MULU;
1391+ decoded->extra.size = OPSIZE_WORD;
1392+ decoded->dst.addr_mode = MODE_REG;
1393+ decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
1394+ istream = m68k_decode_op(istream, OPSIZE_WORD, &(decoded->src));
1395+ if (!istream || decoded->src.addr_mode == MODE_AREG) {
1396+ decoded->op = M68K_INVALID;
1397+ break;
1398+ }
1399+ } else {
1400+ decoded->op = M68K_AND;
1401+ decoded->extra.size = (*istream >> 6) & 0x3;
1402+ decoded->dst.addr_mode = MODE_REG;
1403+ decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
1404+ istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
1405+ if (!istream || decoded->src.addr_mode == MODE_AREG) {
1406+ decoded->op = M68K_INVALID;
1407+ break;
1408+ }
1409+ }
1410+ }
1411+ break;
1412+ case ADD_ADDX:
1413+ size = (*istream >> 6) & 0x3;
1414+ decoded->op = M68K_ADD;
1415+ if (*istream & 0x100) {
1416+ //<ea> destination, ADDA.l or ADDX
1417+ if (*istream & 0x30 || size == OPSIZE_INVALID) {
1418+ if (size == OPSIZE_INVALID) {
1419+ //ADDA.l
1420+ decoded->extra.size = OPSIZE_LONG;
1421+ decoded->dst.addr_mode = MODE_AREG;
1422+ decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
1423+ istream = m68k_decode_op(istream, OPSIZE_LONG, &(decoded->src));
1424+ if (!istream) {
1425+ decoded->op = M68K_INVALID;
1426+ break;
1427+ }
1428+ } else {
1429+ decoded->extra.size = size;
1430+ decoded->src.addr_mode = MODE_REG;
1431+ decoded->src.params.regs.pri = m68k_reg_quick_field(*istream);
1432+ istream = m68k_decode_op(istream, size, &(decoded->dst));
1433+ if (!istream || !m68k_valid_full_arith_dst(&decoded->dst)) {
1434+ decoded->op = M68K_INVALID;
1435+ break;
1436+ }
1437+ }
1438+ } else {
1439+ //ADDX
1440+ decoded->op = M68K_ADDX;
1441+ decoded->extra.size = size;
1442+ decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
1443+ decoded->src.params.regs.pri = *istream & 0x7;
1444+ if (*istream & 0x8) {
1445+ decoded->dst.addr_mode = decoded->src.addr_mode = MODE_AREG_PREDEC;
1446+ } else {
1447+ decoded->dst.addr_mode = decoded->src.addr_mode = MODE_REG;
1448+ }
1449+ }
1450+ } else {
1451+ if (size == OPSIZE_INVALID) {
1452+ //ADDA.w
1453+ decoded->extra.size = OPSIZE_WORD;
1454+ decoded->dst.addr_mode = MODE_AREG;
1455+ } else {
1456+ decoded->extra.size = size;
1457+ decoded->dst.addr_mode = MODE_REG;
1458+ }
1459+ decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
1460+ istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
1461+ if (!istream || (decoded->src.addr_mode == MODE_AREG && decoded->extra.size == OPSIZE_BYTE)) {
1462+ decoded->op = M68K_INVALID;
1463+ break;
1464+ }
1465+ }
1466+ break;
1467+ case SHIFT_ROTATE:
1468+ if ((*istream & 0x8C0) == 0xC0) {
1469+ switch((*istream >> 8) & 0x7)
1470+ {
1471+ case 0:
1472+ decoded->op = M68K_ASR;
1473+ break;
1474+ case 1:
1475+ decoded->op = M68K_ASL;
1476+ break;
1477+ case 2:
1478+ decoded->op = M68K_LSR;
1479+ break;
1480+ case 3:
1481+ decoded->op = M68K_LSL;
1482+ break;
1483+ case 4:
1484+ decoded->op = M68K_ROXR;
1485+ break;
1486+ case 5:
1487+ decoded->op = M68K_ROXL;
1488+ break;
1489+ case 6:
1490+ decoded->op = M68K_ROR;
1491+ break;
1492+ case 7:
1493+ decoded->op = M68K_ROL;
1494+ break;
1495+ }
1496+ decoded->extra.size = OPSIZE_WORD;
1497+ istream = m68k_decode_op(istream, OPSIZE_WORD, &(decoded->dst));
1498+ if (!istream || !m68k_valid_full_arith_dst(&decoded->dst)) {
1499+ decoded->op = M68K_INVALID;
1500+ break;
1501+ }
1502+ } else if((*istream & 0xC0) != 0xC0) {
1503+ switch(((*istream >> 2) & 0x6) | ((*istream >> 8) & 1))
1504+ {
1505+ case 0:
1506+ decoded->op = M68K_ASR;
1507+ break;
1508+ case 1:
1509+ decoded->op = M68K_ASL;
1510+ break;
1511+ case 2:
1512+ decoded->op = M68K_LSR;
1513+ break;
1514+ case 3:
1515+ decoded->op = M68K_LSL;
1516+ break;
1517+ case 4:
1518+ decoded->op = M68K_ROXR;
1519+ break;
1520+ case 5:
1521+ decoded->op = M68K_ROXL;
1522+ break;
1523+ case 6:
1524+ decoded->op = M68K_ROR;
1525+ break;
1526+ case 7:
1527+ decoded->op = M68K_ROL;
1528+ break;
1529+ }
1530+ decoded->extra.size = (*istream >> 6) & 0x3;
1531+ immed = (*istream >> 9) & 0x7;
1532+ if (*istream & 0x20) {
1533+ decoded->src.addr_mode = MODE_REG;
1534+ decoded->src.params.regs.pri = immed;
1535+ } else {
1536+ decoded->src.addr_mode = MODE_IMMEDIATE;
1537+ if (!immed) {
1538+ immed = 8;
1539+ }
1540+ decoded->src.params.immed = immed;
1541+ decoded->variant = VAR_QUICK;
1542+ }
1543+ decoded->dst.addr_mode = MODE_REG;
1544+ decoded->dst.params.regs.pri = *istream & 0x7;
1545+
1546+ } else {
1547+#ifdef M68020
1548+ //TODO: Implement bitfield instructions for M68020+ support
1549+ switch (*istream >> 8 & 7)
1550+ {
1551+ case 0:
1552+ decoded->op = M68K_BFTST; //<ea>
1553+ break;
1554+ case 1:
1555+ decoded->op = M68K_BFEXTU; //<ea>, Dn
1556+ break;
1557+ case 2:
1558+ decoded->op = M68K_BFCHG; //<ea>
1559+ break;
1560+ case 3:
1561+ decoded->op = M68K_BFEXTS; //<ea>, Dn
1562+ break;
1563+ case 4:
1564+ decoded->op = M68K_BFCLR; //<ea>
1565+ break;
1566+ case 5:
1567+ decoded->op = M68K_BFFFO; //<ea>, Dn
1568+ break;
1569+ case 6:
1570+ decoded->op = M68K_BFSET; //<ea>
1571+ break;
1572+ case 7:
1573+ decoded->op = M68K_BFINS; //Dn, <ea>
1574+ break;
1575+ }
1576+ opmode = *istream >> 3 & 0x7;
1577+ reg = *istream & 0x7;
1578+ m68k_op_info *ea, *other;
1579+ if (decoded->op == M68K_BFEXTU || decoded->op == M68K_BFEXTS || decoded->op == M68K_BFFFO)
1580+ {
1581+ ea = &(decoded->src);
1582+ other = &(decoded->dst);
1583+ } else {
1584+ ea = &(decoded->dst);
1585+ other = &(decoded->dst);
1586+ }
1587+ if (*istream & 0x100)
1588+ {
1589+ immed = *(istream++);
1590+ other->addr_mode = MODE_REG;
1591+ other->params.regs.pri = immed >> 12 & 0x7;
1592+ } else {
1593+ immed = *(istream++);
1594+ }
1595+ decoded->extra.size = OPSIZE_UNSIZED;
1596+ istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, ea);
1597+ ea->addr_mode |= M68K_FLAG_BITFIELD;
1598+ ea->bitfield = immed & 0xFFF;
1599+#endif
1600+ }
1601+ break;
1602+ case F_LINE:
1603+ //TODO: Decode FPU instructions for members of the 68K family with an FPU
1604+ decoded->op = M68K_F_LINE_TRAP;
1605+ break;
1606+ }
1607+ if (decoded->op == M68K_INVALID) {
1608+ decoded->src.params.immed = *start;
1609+ decoded->bytes = 2;
1610+ return start + 1;
1611+ }
1612+ decoded->bytes = 2 * (istream + 1 - start);
1613+ return istream+1;
1614+}
1615+
1616+uint32_t m68k_branch_target(m68kinst * inst, uint32_t *dregs, uint32_t *aregs)
1617+{
1618+ if(inst->op == M68K_BCC || inst->op == M68K_BSR || inst->op == M68K_DBCC) {
1619+ return inst->address + 2 + inst->src.params.immed;
1620+ } else if(inst->op == M68K_JMP || inst->op == M68K_JSR) {
1621+ uint32_t ret = 0;
1622+ switch(inst->src.addr_mode)
1623+ {
1624+ case MODE_AREG_INDIRECT:
1625+ ret = aregs[inst->src.params.regs.pri];
1626+ break;
1627+ case MODE_AREG_DISPLACE:
1628+ ret = aregs[inst->src.params.regs.pri] + inst->src.params.regs.displacement;
1629+ break;
1630+ case MODE_AREG_INDEX_DISP8: {
1631+ uint8_t sec_reg = inst->src.params.regs.sec >> 1 & 0x7;
1632+ ret = aregs[inst->src.params.regs.pri];
1633+ uint32_t * regfile = inst->src.params.regs.sec & 0x10 ? aregs : dregs;
1634+ if (inst->src.params.regs.sec & 1) {
1635+ //32-bit index register
1636+ ret += regfile[sec_reg];
1637+ } else {
1638+ //16-bit index register
1639+ if (regfile[sec_reg] & 0x8000) {
1640+ ret += (0xFFFF0000 | regfile[sec_reg]);
1641+ } else {
1642+ ret += regfile[sec_reg];
1643+ }
1644+ }
1645+ ret += inst->src.params.regs.displacement;
1646+ break;
1647+ }
1648+ case MODE_PC_DISPLACE:
1649+ ret = inst->src.params.regs.displacement + inst->address + 2;
1650+ break;
1651+ case MODE_PC_INDEX_DISP8: {
1652+ uint8_t sec_reg = inst->src.params.regs.sec >> 1 & 0x7;
1653+ ret = inst->address + 2;
1654+ uint32_t * regfile = inst->src.params.regs.sec & 0x10 ? aregs : dregs;
1655+ if (inst->src.params.regs.sec & 1) {
1656+ //32-bit index register
1657+ ret += regfile[sec_reg];
1658+ } else {
1659+ //16-bit index register
1660+ if (regfile[sec_reg] & 0x8000) {
1661+ ret += (0xFFFF0000 | regfile[sec_reg]);
1662+ } else {
1663+ ret += regfile[sec_reg];
1664+ }
1665+ }
1666+ ret += inst->src.params.regs.displacement;
1667+ break;
1668+ }
1669+ case MODE_ABSOLUTE:
1670+ case MODE_ABSOLUTE_SHORT:
1671+ ret = inst->src.params.immed;
1672+ break;
1673+ }
1674+ return ret;
1675+ }
1676+ return 0;
1677+}
1678+
1679+uint8_t m68k_is_branch(m68kinst * inst)
1680+{
1681+ return (inst->op == M68K_BCC && inst->extra.cond != COND_FALSE)
1682+ || (inst->op == M68K_DBCC && inst->extra.cond != COND_TRUE)
1683+ || inst->op == M68K_BSR || inst->op == M68K_JMP || inst->op == M68K_JSR;
1684+}
1685+
1686+uint8_t m68k_is_noncall_branch(m68kinst * inst)
1687+{
1688+ return m68k_is_branch(inst) && inst->op != M68K_BSR && inst->op != M68K_JSR;
1689+}
1690+
1691+
1692+char * mnemonics[] = {
1693+ "abcd",
1694+ "add",
1695+ "addx",
1696+ "and",
1697+ "andi",//ccr
1698+ "andi",//sr
1699+ "asl",
1700+ "asr",
1701+ "bcc",
1702+ "bchg",
1703+ "bclr",
1704+ "bset",
1705+ "bsr",
1706+ "btst",
1707+ "chk",
1708+ "clr",
1709+ "cmp",
1710+ "dbcc",
1711+ "divs",
1712+ "divu",
1713+ "eor",
1714+ "eori",//ccr
1715+ "eori",//sr
1716+ "exg",
1717+ "ext",
1718+ "illegal",
1719+ "jmp",
1720+ "jsr",
1721+ "lea",
1722+ "link",
1723+ "lsl",
1724+ "lsr",
1725+ "move",
1726+ "move",//ccr
1727+ "move",//from_sr
1728+ "move",//sr
1729+ "move",//usp
1730+ "movem",
1731+ "movep",
1732+ "muls",
1733+ "mulu",
1734+ "nbcd",
1735+ "neg",
1736+ "negx",
1737+ "nop",
1738+ "not",
1739+ "or",
1740+ "ori",//ccr
1741+ "ori",//sr
1742+ "pea",
1743+ "reset",
1744+ "rol",
1745+ "ror",
1746+ "roxl",
1747+ "roxr",
1748+ "rte",
1749+ "rtr",
1750+ "rts",
1751+ "sbcd",
1752+ "scc",
1753+ "stop",
1754+ "sub",
1755+ "subx",
1756+ "swap",
1757+ "tas",
1758+ "trap",
1759+ "trapv",
1760+ "tst",
1761+ "unlk",
1762+ "invalid",
1763+#ifdef M68010
1764+ "bkpt",
1765+ "move", //from ccr
1766+ "movec",
1767+ "moves",
1768+ "rtd",
1769+#endif
1770+#ifdef M68020
1771+ "bfchg",
1772+ "bfclr",
1773+ "bfexts",
1774+ "bfextu",
1775+ "bfffo",
1776+ "bfins",
1777+ "bfset",
1778+ "bftst",
1779+ "callm",
1780+ "cas",
1781+ "cas2",
1782+ "chk2",
1783+ "cmp2",
1784+ "cpbcc",
1785+ "cpdbcc",
1786+ "cpgen",
1787+ "cprestore",
1788+ "cpsave",
1789+ "cpscc",
1790+ "cptrapcc",
1791+ "divsl",
1792+ "divul",
1793+ "extb",
1794+ "pack",
1795+ "rtm",
1796+ "trapcc",
1797+ "unpk"
1798+#endif
1799+};
1800+
1801+char * cond_mnem[] = {
1802+ "ra",
1803+ "f",
1804+ "hi",
1805+ "ls",
1806+ "cc",
1807+ "cs",
1808+ "ne",
1809+ "eq",
1810+ "vc",
1811+ "vs",
1812+ "pl",
1813+ "mi",
1814+ "ge",
1815+ "lt",
1816+ "gt",
1817+ "le"
1818+};
1819+#ifdef M68010
1820+char * cr_mnem[] = {
1821+ "SFC",
1822+ "DFC",
1823+#ifdef M68020
1824+ "CACR",
1825+#endif
1826+ "USP",
1827+ "VBR",
1828+#ifdef M68020
1829+ "CAAR",
1830+ "MSP",
1831+ "ISP"
1832+#endif
1833+};
1834+#endif
1835+
1836+int m68k_disasm_op(m68k_op_info *decoded, char *dst, int need_comma, uint8_t labels, uint32_t address, format_label_fun label_fun, void * data)
1837+{
1838+ char * c = need_comma ? "," : "";
1839+ int ret = 0;
1840+#ifdef M68020
1841+ uint8_t addr_mode = decoded->addr_mode & (~M68K_FLAG_BITFIELD);
1842+#else
1843+ uint8_t addr_mode = decoded->addr_mode;
1844+#endif
1845+ switch(addr_mode)
1846+ {
1847+ case MODE_REG:
1848+ ret = sprintf(dst, "%s d%d", c, decoded->params.regs.pri);
1849+ break;
1850+ case MODE_AREG:
1851+ ret = sprintf(dst, "%s a%d", c, decoded->params.regs.pri);
1852+ break;
1853+ case MODE_AREG_INDIRECT:
1854+ ret = sprintf(dst, "%s (a%d)", c, decoded->params.regs.pri);
1855+ break;
1856+ case MODE_AREG_POSTINC:
1857+ ret = sprintf(dst, "%s (a%d)+", c, decoded->params.regs.pri);
1858+ break;
1859+ case MODE_AREG_PREDEC:
1860+ ret = sprintf(dst, "%s -(a%d)", c, decoded->params.regs.pri);
1861+ break;
1862+ case MODE_AREG_DISPLACE:
1863+ ret = sprintf(dst, "%s (%d, a%d)", c, decoded->params.regs.displacement, decoded->params.regs.pri);
1864+ break;
1865+ case MODE_AREG_INDEX_DISP8:
1866+#ifdef M68020
1867+ if (decoded->params.regs.scale)
1868+ {
1869+ ret = sprintf(dst, "%s (%d, a%d, %c%d.%c*%d)", c, decoded->params.regs.displacement, decoded->params.regs.pri, (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
1870+ } else {
1871+#endif
1872+ ret = sprintf(dst, "%s (%d, a%d, %c%d.%c)", c, decoded->params.regs.displacement, decoded->params.regs.pri, (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w');
1873+#ifdef M68020
1874+ }
1875+#endif
1876+ break;
1877+#ifdef M68020
1878+ case MODE_AREG_INDEX_BASE_DISP:
1879+ if (decoded->params.regs.disp_sizes > 1)
1880+ {
1881+ ret = sprintf(dst, "%s (%d.%c, a%d, %c%d.%c*%d)", c, decoded->params.regs.displacement,
1882+ decoded->params.regs.disp_sizes == 2 ? 'w' : 'l', decoded->params.regs.pri,
1883+ (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
1884+ (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
1885+ } else {
1886+ ret = sprintf(dst, "%s (a%d, %c%d.%c*%d)", c, decoded->params.regs.pri,
1887+ (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
1888+ (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
1889+ }
1890+ break;
1891+ case MODE_AREG_PREINDEX:
1892+ switch (decoded->params.regs.disp_sizes)
1893+ {
1894+ case 0x11:
1895+ //no base displacement or outer displacement
1896+ ret = sprintf(dst, "%s ([a%d, %c%d.%c*%d])", c, decoded->params.regs.pri,
1897+ (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
1898+ (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
1899+ break;
1900+ case 0x12:
1901+ case 0x13:
1902+ //base displacement only
1903+ ret = sprintf(dst, "%s ([%d.%c, a%d, %c%d.%c*%d])", c, decoded->params.regs.displacement,
1904+ decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.pri,
1905+ (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
1906+ (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
1907+ break;
1908+ case 0x21:
1909+ case 0x31:
1910+ //outer displacement only
1911+ ret = sprintf(dst, "%s ([a%d, %c%d.%c*%d], %d.%c)", c, decoded->params.regs.pri,
1912+ (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
1913+ (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale,
1914+ decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
1915+ break;
1916+ case 0x22:
1917+ case 0x23:
1918+ case 0x32:
1919+ case 0x33:
1920+ //both outer and inner displacement
1921+ ret = sprintf(dst, "%s ([%d.%c, a%d, %c%d.%c*%d], %d.%c)", c, decoded->params.regs.displacement,
1922+ decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.pri,
1923+ (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
1924+ (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale,
1925+ decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
1926+ break;
1927+ }
1928+ break;
1929+ case MODE_AREG_POSTINDEX:
1930+ switch (decoded->params.regs.disp_sizes)
1931+ {
1932+ case 0x11:
1933+ //no base displacement or outer displacement
1934+ ret = sprintf(dst, "%s ([a%d], %c%d.%c*%d)", c, decoded->params.regs.pri,
1935+ (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
1936+ (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
1937+ break;
1938+ case 0x12:
1939+ case 0x13:
1940+ //base displacement only
1941+ ret = sprintf(dst, "%s ([%d.%c, a%d], %c%d.%c*%d)", c, decoded->params.regs.displacement,
1942+ decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.pri,
1943+ (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
1944+ (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
1945+ break;
1946+ case 0x21:
1947+ case 0x31:
1948+ //outer displacement only
1949+ ret = sprintf(dst, "%s ([a%d], %c%d.%c*%d, %d.%c)", c, decoded->params.regs.pri,
1950+ (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
1951+ (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale,
1952+ decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
1953+ break;
1954+ case 0x22:
1955+ case 0x23:
1956+ case 0x32:
1957+ case 0x33:
1958+ //both outer and inner displacement
1959+ ret = sprintf(dst, "%s ([%d.%c, a%d], %c%d.%c*%d, %d.%c)", c, decoded->params.regs.displacement,
1960+ decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.pri,
1961+ (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
1962+ (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale,
1963+ decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
1964+ break;
1965+ }
1966+ break;
1967+ case MODE_AREG_MEM_INDIRECT:
1968+ switch (decoded->params.regs.disp_sizes)
1969+ {
1970+ case 0x11:
1971+ //no base displacement or outer displacement
1972+ ret = sprintf(dst, "%s ([a%d])", c, decoded->params.regs.pri);
1973+ break;
1974+ case 0x12:
1975+ case 0x13:
1976+ //base displacement only
1977+ ret = sprintf(dst, "%s ([%d.%c, a%d])", c, decoded->params.regs.displacement,
1978+ decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.pri);
1979+ break;
1980+ case 0x21:
1981+ case 0x31:
1982+ //outer displacement only
1983+ ret = sprintf(dst, "%s ([a%d], %d.%c)", c, decoded->params.regs.pri, decoded->params.regs.outer_disp,
1984+ decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
1985+ break;
1986+ case 0x22:
1987+ case 0x23:
1988+ case 0x32:
1989+ case 0x33:
1990+ //both outer and inner displacement
1991+ ret = sprintf(dst, "%s ([%d.%c, a%d], %d.%c)", c, decoded->params.regs.displacement,
1992+ decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.pri,
1993+ decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
1994+ break;
1995+ }
1996+ break;
1997+ case MODE_AREG_BASE_DISP:
1998+ if (decoded->params.regs.disp_sizes > 1)
1999+ {
2000+ ret = sprintf(dst, "%s (%d.%c, a%d)", c, decoded->params.regs.displacement,
2001+ decoded->params.regs.disp_sizes == 2 ? 'w' : 'l', decoded->params.regs.pri);
2002+ } else {
2003+ //this is a lossy representation of the encoded instruction
2004+ //not sure if there's a better way to print it though
2005+ ret = sprintf(dst, "%s (a%d)", c, decoded->params.regs.pri);
2006+ }
2007+ break;
2008+ case MODE_INDEX_BASE_DISP:
2009+ if (decoded->params.regs.disp_sizes > 1)
2010+ {
2011+ ret = sprintf(dst, "%s (%d.%c, %c%d.%c*%d)", c, decoded->params.regs.displacement,
2012+ decoded->params.regs.disp_sizes == 2 ? 'w' : 'l',
2013+ (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2014+ (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
2015+ } else {
2016+ ret = sprintf(dst, "%s (%c%d.%c*%d)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2017+ (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2018+ 1 << decoded->params.regs.scale);
2019+ }
2020+ break;
2021+ case MODE_PREINDEX:
2022+ switch (decoded->params.regs.disp_sizes)
2023+ {
2024+ case 0x11:
2025+ //no base displacement or outer displacement
2026+ ret = sprintf(dst, "%s ([%c%d.%c*%d])", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2027+ (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2028+ 1 << decoded->params.regs.scale);
2029+ break;
2030+ case 0x12:
2031+ case 0x13:
2032+ //base displacement only
2033+ ret = sprintf(dst, "%s ([%d.%c, %c%d.%c*%d])", c, decoded->params.regs.displacement,
2034+ decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l',
2035+ (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2036+ (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
2037+ break;
2038+ case 0x21:
2039+ case 0x31:
2040+ //outer displacement only
2041+ ret = sprintf(dst, "%s ([%c%d.%c*%d], %d.%c)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2042+ (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2043+ 1 << decoded->params.regs.scale, decoded->params.regs.outer_disp,
2044+ decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2045+ break;
2046+ case 0x22:
2047+ case 0x23:
2048+ case 0x32:
2049+ case 0x33:
2050+ //both outer and inner displacement
2051+ ret = sprintf(dst, "%s ([%d.%c, %c%d.%c*%d], %d.%c)", c, decoded->params.regs.displacement,
2052+ decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l',
2053+ (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2054+ (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale,
2055+ decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2056+ break;
2057+ }
2058+ break;
2059+ case MODE_POSTINDEX:
2060+ switch (decoded->params.regs.disp_sizes)
2061+ {
2062+ case 0x11:
2063+ //no base displacement or outer displacement
2064+ ret = sprintf(dst, "%s ([], %c%d.%c*%d)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2065+ (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2066+ 1 << decoded->params.regs.scale);
2067+ break;
2068+ case 0x12:
2069+ case 0x13:
2070+ //base displacement only
2071+ ret = sprintf(dst, "%s ([%d.%c], %c%d.%c*%d)", c, decoded->params.regs.displacement,
2072+ decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l',
2073+ (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2074+ (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
2075+ break;
2076+ case 0x21:
2077+ case 0x31:
2078+ //outer displacement only
2079+ ret = sprintf(dst, "%s ([], %c%d.%c*%d, %d.%c)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2080+ (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2081+ 1 << decoded->params.regs.scale, decoded->params.regs.outer_disp,
2082+ decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2083+ break;
2084+ case 0x22:
2085+ case 0x23:
2086+ case 0x32:
2087+ case 0x33:
2088+ //both outer and inner displacement
2089+ ret = sprintf(dst, "%s ([%d.%c], %c%d.%c*%d, %d.%c)", c, decoded->params.regs.displacement,
2090+ decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l',
2091+ (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2092+ (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale,
2093+ decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2094+ break;
2095+ }
2096+ break;
2097+ case MODE_MEM_INDIRECT:
2098+ switch (decoded->params.regs.disp_sizes)
2099+ {
2100+ case 0x11:
2101+ //no base displacement or outer displacement
2102+ ret = sprintf(dst, "%s ([])", c);
2103+ break;
2104+ case 0x12:
2105+ case 0x13:
2106+ //base displacement only
2107+ ret = sprintf(dst, "%s ([%d.%c])", c, decoded->params.regs.displacement,
2108+ decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l');
2109+ break;
2110+ case 0x21:
2111+ case 0x31:
2112+ //outer displacement only
2113+ ret = sprintf(dst, "%s ([], %d.%c)", c, decoded->params.regs.outer_disp,
2114+ decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2115+ break;
2116+ case 0x22:
2117+ case 0x23:
2118+ case 0x32:
2119+ case 0x33:
2120+ //both outer and inner displacement
2121+ ret = sprintf(dst, "%s ([%d.%c], %d.%c)", c, decoded->params.regs.displacement,
2122+ decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.outer_disp,
2123+ decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2124+ break;
2125+ }
2126+ break;
2127+ case MODE_BASE_DISP:
2128+ if (decoded->params.regs.disp_sizes > 1)
2129+ {
2130+ ret = sprintf(dst, "%s (%d.%c)", c, decoded->params.regs.displacement,
2131+ decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l');
2132+ } else {
2133+ ret = sprintf(dst, "%s ()", c);
2134+ }
2135+ break;
2136+#endif
2137+ case MODE_IMMEDIATE:
2138+ case MODE_IMMEDIATE_WORD:
2139+ ret = sprintf(dst, (decoded->params.immed <= 128 ? "%s #%d" : "%s #$%X"), c, decoded->params.immed);
2140+ break;
2141+ case MODE_ABSOLUTE_SHORT:
2142+ if (labels) {
2143+ ret = sprintf(dst, "%s ", c);
2144+ ret += label_fun(dst+ret, decoded->params.immed, data);
2145+ strcat(dst+ret, ".w");
2146+ ret = ret + 2;
2147+ } else {
2148+ ret = sprintf(dst, "%s $%X.w", c, decoded->params.immed);
2149+ }
2150+ break;
2151+ case MODE_ABSOLUTE:
2152+ if (labels) {
2153+ ret = sprintf(dst, "%s ", c);
2154+ ret += label_fun(dst+ret, decoded->params.immed, data);
2155+ strcat(dst+ret, ".l");
2156+ ret = ret + 2;
2157+ } else {
2158+ ret = sprintf(dst, "%s $%X", c, decoded->params.immed);
2159+ }
2160+ break;
2161+ case MODE_PC_DISPLACE:
2162+ if (labels) {
2163+ ret = sprintf(dst, "%s ", c);
2164+ ret += label_fun(dst+ret, address + 2 + decoded->params.regs.displacement, data);
2165+ strcat(dst+ret, "(pc)");
2166+ ret = ret + 4;
2167+ } else {
2168+ ret = sprintf(dst, "%s (%d, pc)", c, decoded->params.regs.displacement);
2169+ }
2170+ break;
2171+ case MODE_PC_INDEX_DISP8:
2172+#ifdef M68020
2173+ if (decoded->params.regs.scale)
2174+ {
2175+ ret = sprintf(dst, "%s (%d, pc, %c%d.%c*%d)", c, decoded->params.regs.displacement, (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
2176+ } else {
2177+#endif
2178+ ret = sprintf(dst, "%s (%d, pc, %c%d.%c)", c, decoded->params.regs.displacement, (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w');
2179+#ifdef M68020
2180+ }
2181+#endif
2182+ break;
2183+#ifdef M68020
2184+ case MODE_PC_INDEX_BASE_DISP:
2185+ if (decoded->params.regs.disp_sizes > 1)
2186+ {
2187+ ret = sprintf(dst, "%s (%d.%c, pc, %c%d.%c*%d)", c, decoded->params.regs.displacement,
2188+ decoded->params.regs.disp_sizes == 2 ? 'w' : 'l',
2189+ (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2190+ (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
2191+ } else {
2192+ ret = sprintf(dst, "%s (pc, %c%d.%c*%d)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2193+ (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2194+ 1 << decoded->params.regs.scale);
2195+ }
2196+ break;
2197+ case MODE_PC_PREINDEX:
2198+ switch (decoded->params.regs.disp_sizes)
2199+ {
2200+ case 0x11:
2201+ //no base displacement or outer displacement
2202+ ret = sprintf(dst, "%s ([pc, %c%d.%c*%d])", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2203+ (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2204+ 1 << decoded->params.regs.scale);
2205+ break;
2206+ case 0x12:
2207+ case 0x13:
2208+ //base displacement only
2209+ ret = sprintf(dst, "%s ([%d.%c, pc, %c%d.%c*%d])", c, decoded->params.regs.displacement,
2210+ decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l',
2211+ (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2212+ (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
2213+ break;
2214+ case 0x21:
2215+ case 0x31:
2216+ //outer displacement only
2217+ ret = sprintf(dst, "%s ([pc, %c%d.%c*%d], %d.%c)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2218+ (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2219+ 1 << decoded->params.regs.scale, decoded->params.regs.outer_disp,
2220+ decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2221+ break;
2222+ case 0x22:
2223+ case 0x23:
2224+ case 0x32:
2225+ case 0x33:
2226+ //both outer and inner displacement
2227+ ret = sprintf(dst, "%s ([%d.%c, pc, %c%d.%c*%d], %d.%c)", c, decoded->params.regs.displacement,
2228+ decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l',
2229+ (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2230+ (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale,
2231+ decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2232+ break;
2233+ }
2234+ break;
2235+ case MODE_PC_POSTINDEX:
2236+ switch (decoded->params.regs.disp_sizes)
2237+ {
2238+ case 0x11:
2239+ //no base displacement or outer displacement
2240+ ret = sprintf(dst, "%s ([pc], %c%d.%c*%d)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2241+ (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2242+ 1 << decoded->params.regs.scale);
2243+ break;
2244+ case 0x12:
2245+ case 0x13:
2246+ //base displacement only
2247+ ret = sprintf(dst, "%s ([%d.%c, pc], %c%d.%c*%d)", c, decoded->params.regs.displacement,
2248+ decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l',
2249+ (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2250+ (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
2251+ break;
2252+ case 0x21:
2253+ case 0x31:
2254+ //outer displacement only
2255+ ret = sprintf(dst, "%s ([pc], %c%d.%c*%d, %d.%c)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2256+ (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2257+ 1 << decoded->params.regs.scale, decoded->params.regs.outer_disp,
2258+ decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2259+ break;
2260+ case 0x22:
2261+ case 0x23:
2262+ case 0x32:
2263+ case 0x33:
2264+ //both outer and inner displacement
2265+ ret = sprintf(dst, "%s ([%d.%c, pc], %c%d.%c*%d, %d.%c)", c, decoded->params.regs.displacement,
2266+ decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l',
2267+ (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2268+ (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale,
2269+ decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2270+ break;
2271+ }
2272+ break;
2273+ case MODE_PC_MEM_INDIRECT:
2274+ switch (decoded->params.regs.disp_sizes)
2275+ {
2276+ case 0x11:
2277+ //no base displacement or outer displacement
2278+ ret = sprintf(dst, "%s ([pc])", c);
2279+ break;
2280+ case 0x12:
2281+ case 0x13:
2282+ //base displacement only
2283+ ret = sprintf(dst, "%s ([%d.%c, pc])", c, decoded->params.regs.displacement,
2284+ decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l');
2285+ break;
2286+ case 0x21:
2287+ case 0x31:
2288+ //outer displacement only
2289+ ret = sprintf(dst, "%s ([pc], %d.%c)", c, decoded->params.regs.outer_disp,
2290+ decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2291+ break;
2292+ case 0x22:
2293+ case 0x23:
2294+ case 0x32:
2295+ case 0x33:
2296+ //both outer and inner displacement
2297+ ret = sprintf(dst, "%s ([%d.%c, pc], %d.%c)", c, decoded->params.regs.displacement,
2298+ decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.outer_disp,
2299+ decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2300+ break;
2301+ }
2302+ break;
2303+ case MODE_PC_BASE_DISP:
2304+ if (decoded->params.regs.disp_sizes > 1)
2305+ {
2306+ ret = sprintf(dst, "%s (%d.%c, pc)", c, decoded->params.regs.displacement,
2307+ decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l');
2308+ } else {
2309+ ret = sprintf(dst, "%s (pc)", c);
2310+ }
2311+ break;
2312+ case MODE_ZPC_INDEX_BASE_DISP:
2313+ if (decoded->params.regs.disp_sizes > 1)
2314+ {
2315+ ret = sprintf(dst, "%s (%d.%c, zpc, %c%d.%c*%d)", c, decoded->params.regs.displacement,
2316+ decoded->params.regs.disp_sizes == 2 ? 'w' : 'l',
2317+ (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2318+ (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
2319+ } else {
2320+ ret = sprintf(dst, "%s (zpc, %c%d.%c*%d)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2321+ (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2322+ 1 << decoded->params.regs.scale);
2323+ }
2324+ break;
2325+ case MODE_ZPC_PREINDEX:
2326+ switch (decoded->params.regs.disp_sizes)
2327+ {
2328+ case 0x11:
2329+ //no base displacement or outer displacement
2330+ ret = sprintf(dst, "%s ([zpc, %c%d.%c*%d])", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2331+ (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2332+ 1 << decoded->params.regs.scale);
2333+ break;
2334+ case 0x12:
2335+ case 0x13:
2336+ //base displacement only
2337+ ret = sprintf(dst, "%s ([%d.%c, zpc, %c%d.%c*%d])", c, decoded->params.regs.displacement,
2338+ decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l',
2339+ (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2340+ (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
2341+ break;
2342+ case 0x21:
2343+ case 0x31:
2344+ //outer displacement only
2345+ ret = sprintf(dst, "%s ([zpc, %c%d.%c*%d], %d.%c)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2346+ (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2347+ 1 << decoded->params.regs.scale, decoded->params.regs.outer_disp,
2348+ decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2349+ break;
2350+ case 0x22:
2351+ case 0x23:
2352+ case 0x32:
2353+ case 0x33:
2354+ //both outer and inner displacement
2355+ ret = sprintf(dst, "%s ([%d.%c, zpc, %c%d.%c*%d], %d.%c)", c, decoded->params.regs.displacement,
2356+ decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l',
2357+ (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2358+ (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale,
2359+ decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2360+ break;
2361+ }
2362+ break;
2363+ case MODE_ZPC_POSTINDEX:
2364+ switch (decoded->params.regs.disp_sizes)
2365+ {
2366+ case 0x11:
2367+ //no base displacement or outer displacement
2368+ ret = sprintf(dst, "%s ([zpc], %c%d.%c*%d)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2369+ (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2370+ 1 << decoded->params.regs.scale);
2371+ break;
2372+ case 0x12:
2373+ case 0x13:
2374+ //base displacement only
2375+ ret = sprintf(dst, "%s ([%d.%c, zpc], %c%d.%c*%d)", c, decoded->params.regs.displacement,
2376+ decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l',
2377+ (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2378+ (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
2379+ break;
2380+ case 0x21:
2381+ case 0x31:
2382+ //outer displacement only
2383+ ret = sprintf(dst, "%s ([zpc], %c%d.%c*%d, %d.%c)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2384+ (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2385+ 1 << decoded->params.regs.scale, decoded->params.regs.outer_disp,
2386+ decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2387+ break;
2388+ case 0x22:
2389+ case 0x23:
2390+ case 0x32:
2391+ case 0x33:
2392+ //both outer and inner displacement
2393+ ret = sprintf(dst, "%s ([%d.%c, zpc], %c%d.%c*%d, %d.%c)", c, decoded->params.regs.displacement,
2394+ decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l',
2395+ (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2396+ (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale,
2397+ decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2398+ break;
2399+ }
2400+ break;
2401+ case MODE_ZPC_MEM_INDIRECT:
2402+ switch (decoded->params.regs.disp_sizes)
2403+ {
2404+ case 0x11:
2405+ //no base displacement or outer displacement
2406+ ret = sprintf(dst, "%s ([zpc])", c);
2407+ break;
2408+ case 0x12:
2409+ case 0x13:
2410+ //base displacement only
2411+ ret = sprintf(dst, "%s ([%d.%c, zpc])", c, decoded->params.regs.displacement,
2412+ decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l');
2413+ break;
2414+ case 0x21:
2415+ case 0x31:
2416+ //outer displacement only
2417+ ret = sprintf(dst, "%s ([zpc], %d.%c)", c, decoded->params.regs.outer_disp,
2418+ decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2419+ break;
2420+ case 0x22:
2421+ case 0x23:
2422+ case 0x32:
2423+ case 0x33:
2424+ //both outer and inner displacement
2425+ ret = sprintf(dst, "%s ([%d.%c, zpc], %d.%c)", c, decoded->params.regs.displacement,
2426+ decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.outer_disp,
2427+ decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2428+ break;
2429+ }
2430+ break;
2431+ case MODE_ZPC_BASE_DISP:
2432+ if (decoded->params.regs.disp_sizes > 1)
2433+ {
2434+ ret = sprintf(dst, "%s (%d.%c, zpc)", c, decoded->params.regs.displacement,
2435+ decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l');
2436+ } else {
2437+ ret = sprintf(dst, "%s (zpc)", c);
2438+ }
2439+ break;
2440+#endif
2441+ default:
2442+ ret = 0;
2443+ }
2444+#ifdef M68020
2445+ if (decoded->addr_mode & M68K_FLAG_BITFIELD)
2446+ {
2447+ switch (decoded->bitfield & 0x820)
2448+ {
2449+ case 0:
2450+ return ret + sprintf(dst+ret, " {$%X:%d}", decoded->bitfield >> 6 & 0x1F, decoded->bitfield & 0x1F ? decoded->bitfield & 0x1F : 32);
2451+ case 0x20:
2452+ return ret + sprintf(dst+ret, " {$%X:d%d}", decoded->bitfield >> 6 & 0x1F, decoded->bitfield & 0x7);
2453+ case 0x800:
2454+ return ret + sprintf(dst+ret, " {d%d:%d}", decoded->bitfield >> 6 & 0x7, decoded->bitfield & 0x1F ? decoded->bitfield & 0x1F : 32);
2455+ case 0x820:
2456+ return ret + sprintf(dst+ret, " {d%d:d%d}", decoded->bitfield >> 6 & 0x7, decoded->bitfield & 0x7);
2457+ }
2458+ }
2459+#endif
2460+ return ret;
2461+}
2462+
2463+int m68k_disasm_movem_op(m68k_op_info *decoded, m68k_op_info *other, char *dst, int need_comma, uint8_t labels, uint32_t address, format_label_fun label_fun, void * data)
2464+{
2465+ int8_t dir, reg, bit, regnum, last=-1, lastreg, first=-1;
2466+ char *rtype, *last_rtype;
2467+ int oplen;
2468+ if (decoded->addr_mode == MODE_REG) {
2469+ if (other->addr_mode == MODE_AREG_PREDEC) {
2470+ bit = 15;
2471+ dir = -1;
2472+ } else {
2473+ dir = 1;
2474+ bit = 0;
2475+ }
2476+ if (need_comma) {
2477+ strcat(dst, ", ");
2478+ oplen = 2;
2479+ } else {
2480+ strcat(dst, " ");
2481+ oplen = 1;
2482+ }
2483+ for (reg=0; bit < 16 && bit > -1; bit += dir, reg++) {
2484+ if (decoded->params.immed & (1 << bit)) {
2485+ if (reg > 7) {
2486+ rtype = "a";
2487+ regnum = reg - 8;
2488+ } else {
2489+ rtype = "d";
2490+ regnum = reg;
2491+ }
2492+ if (last >= 0 && last == regnum - 1 && lastreg == reg - 1) {
2493+ last = regnum;
2494+ lastreg = reg;
2495+ } else if(last >= 0) {
2496+ if (first != last) {
2497+ oplen += sprintf(dst + oplen, "-%s%d/%s%d",last_rtype, last, rtype, regnum);
2498+ } else {
2499+ oplen += sprintf(dst + oplen, "/%s%d", rtype, regnum);
2500+ }
2501+ first = last = regnum;
2502+ last_rtype = rtype;
2503+ lastreg = reg;
2504+ } else {
2505+ oplen += sprintf(dst + oplen, "%s%d", rtype, regnum);
2506+ first = last = regnum;
2507+ last_rtype = rtype;
2508+ lastreg = reg;
2509+ }
2510+ }
2511+ }
2512+ if (last >= 0 && last != first) {
2513+ oplen += sprintf(dst + oplen, "-%s%d", last_rtype, last);
2514+ }
2515+ return oplen;
2516+ } else {
2517+ return m68k_disasm_op(decoded, dst, need_comma, labels, address, label_fun, data);
2518+ }
2519+}
2520+
2521+int m68k_default_label_fun(char * dst, uint32_t address, void * data)
2522+{
2523+ return sprintf(dst, "ADR_%X", address);
2524+}
2525+
2526+int m68k_disasm_ex(m68kinst * decoded, char * dst, uint8_t labels, format_label_fun label_fun, void * data)
2527+{
2528+ int ret,op1len;
2529+ uint8_t size;
2530+ char * special_op = "CCR";
2531+ switch (decoded->op)
2532+ {
2533+ case M68K_BCC:
2534+ case M68K_DBCC:
2535+ case M68K_SCC:
2536+ ret = strlen(mnemonics[decoded->op]) - 2;
2537+ memcpy(dst, mnemonics[decoded->op], ret);
2538+ dst[ret] = 0;
2539+ strcpy(dst+ret, cond_mnem[decoded->extra.cond]);
2540+ ret = strlen(dst);
2541+ if (decoded->op != M68K_SCC) {
2542+ if (labels) {
2543+ if (decoded->op == M68K_DBCC) {
2544+ ret += sprintf(dst+ret, " d%d, ", decoded->dst.params.regs.pri);
2545+ ret += label_fun(dst+ret, decoded->address + 2 + decoded->src.params.immed, data);
2546+ } else {
2547+ dst[ret++] = ' ';
2548+ ret += label_fun(dst+ret, decoded->address + 2 + decoded->src.params.immed, data);
2549+ }
2550+ } else {
2551+ if (decoded->op == M68K_DBCC) {
2552+ ret += sprintf(dst+ret, " d%d, #%d <%X>", decoded->dst.params.regs.pri, decoded->src.params.immed, decoded->address + 2 + decoded->src.params.immed);
2553+ } else {
2554+ ret += sprintf(dst+ret, " #%d <%X>", decoded->src.params.immed, decoded->address + 2 + decoded->src.params.immed);
2555+ }
2556+ }
2557+ return ret;
2558+ }
2559+ break;
2560+ case M68K_BSR:
2561+ if (labels) {
2562+ ret = sprintf(dst, "bsr%s ", decoded->variant == VAR_BYTE ? ".s" : "");
2563+ ret += label_fun(dst+ret, decoded->address + 2 + decoded->src.params.immed, data);
2564+ } else {
2565+ ret = sprintf(dst, "bsr%s #%d <%X>", decoded->variant == VAR_BYTE ? ".s" : "", decoded->src.params.immed, decoded->address + 2 + decoded->src.params.immed);
2566+ }
2567+ return ret;
2568+ case M68K_MOVE_FROM_SR:
2569+ ret = sprintf(dst, "%s", mnemonics[decoded->op]);
2570+ ret += sprintf(dst + ret, " SR");
2571+ ret += m68k_disasm_op(&(decoded->dst), dst + ret, 1, labels, decoded->address, label_fun, data);
2572+ return ret;
2573+ case M68K_ANDI_SR:
2574+ case M68K_EORI_SR:
2575+ case M68K_MOVE_SR:
2576+ case M68K_ORI_SR:
2577+ special_op = "SR";
2578+ case M68K_ANDI_CCR:
2579+ case M68K_EORI_CCR:
2580+ case M68K_MOVE_CCR:
2581+ case M68K_ORI_CCR:
2582+ ret = sprintf(dst, "%s", mnemonics[decoded->op]);
2583+ ret += m68k_disasm_op(&(decoded->src), dst + ret, 0, labels, decoded->address, label_fun, data);
2584+ ret += sprintf(dst + ret, ", %s", special_op);
2585+ return ret;
2586+ case M68K_MOVE_USP:
2587+ ret = sprintf(dst, "%s", mnemonics[decoded->op]);
2588+ if (decoded->src.addr_mode != MODE_UNUSED) {
2589+ ret += m68k_disasm_op(&(decoded->src), dst + ret, 0, labels, decoded->address, label_fun, data);
2590+ ret += sprintf(dst + ret, ", USP");
2591+ } else {
2592+ ret += sprintf(dst + ret, "USP, ");
2593+ ret += m68k_disasm_op(&(decoded->dst), dst + ret, 0, labels, decoded->address, label_fun, data);
2594+ }
2595+ return ret;
2596+ case M68K_INVALID:
2597+ ret = sprintf(dst, "dc.w $%X", decoded->src.params.immed);
2598+ return ret;
2599+#ifdef M68010
2600+ case M68K_MOVEC:
2601+ ret = sprintf(dst, "%s ", mnemonics[decoded->op]);
2602+ if (decoded->src.addr_mode == MODE_UNUSED) {
2603+ ret += sprintf(dst + ret, "%s, ", cr_mnem[decoded->src.params.immed]);
2604+ ret += m68k_disasm_op(&(decoded->dst), dst + ret, 0, labels, decoded->address, label_fun, data);
2605+ } else {
2606+ ret += m68k_disasm_op(&(decoded->src), dst + ret, 0, labels, decoded->address, label_fun, data);
2607+ ret += sprintf(dst + ret, ", %s", cr_mnem[decoded->dst.params.immed]);
2608+ }
2609+ return ret;
2610+#endif
2611+ default:
2612+ size = decoded->extra.size;
2613+ uint8_t is_quick = decoded->variant == VAR_QUICK && decoded->op != M68K_ASL && decoded->op != M68K_ASR
2614+ && decoded->op != M68K_LSL && decoded->op != M68K_LSR && decoded->op != M68K_ROXR && decoded->op != M68K_ROXL
2615+ && decoded->op != M68K_ROR && decoded->op != M68K_ROL;
2616+ ret = sprintf(dst, "%s%s%s",
2617+ mnemonics[decoded->op],
2618+ is_quick ? "q" : (decoded->variant == VAR_IMMEDIATE ? "i" : ""),
2619+ size == OPSIZE_BYTE ? ".b" : (size == OPSIZE_WORD ? ".w" : (size == OPSIZE_LONG ? ".l" : "")));
2620+ }
2621+ if (decoded->op == M68K_MOVEM) {
2622+ op1len = m68k_disasm_movem_op(&(decoded->src), &(decoded->dst), dst + ret, 0, labels, decoded->address, label_fun, data);
2623+ ret += op1len;
2624+ ret += m68k_disasm_movem_op(&(decoded->dst), &(decoded->src), dst + ret, op1len, labels, decoded->address, label_fun, data);
2625+ } else {
2626+ op1len = m68k_disasm_op(&(decoded->src), dst + ret, 0, labels, decoded->address, label_fun, data);
2627+ ret += op1len;
2628+ ret += m68k_disasm_op(&(decoded->dst), dst + ret, op1len, labels, decoded->address, label_fun, data);
2629+ }
2630+ return ret;
2631+}
2632+
2633+int m68k_disasm(m68kinst * decoded, char * dst)
2634+{
2635+ return m68k_disasm_ex(decoded, dst, 0, NULL, NULL);
2636+}
2637+
2638+int m68k_disasm_labels(m68kinst * decoded, char * dst, format_label_fun label_fun, void * data)
2639+{
2640+ if (!label_fun)
2641+ {
2642+ label_fun = m68k_default_label_fun;
2643+ }
2644+ return m68k_disasm_ex(decoded, dst, 1, label_fun, data);
2645+}
+347,
-0
1@@ -0,0 +1,347 @@
2+/*
3+ Copyright 2013 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#ifndef M68KINST_H_
8+#define M68KINST_H_
9+
10+#include <stdint.h>
11+
12+#ifdef M68030
13+#define M68020
14+#endif
15+#ifdef M68020
16+#define M68010
17+#endif
18+
19+typedef enum {
20+ BIT_MOVEP_IMMED = 0,
21+ MOVE_BYTE,
22+ MOVE_LONG,
23+ MOVE_WORD,
24+ MISC,
25+ QUICK_ARITH_LOOP,
26+ BRANCH,
27+ MOVEQ,
28+ OR_DIV_SBCD,
29+ SUB_SUBX,
30+ A_LINE,
31+ CMP_XOR,
32+ AND_MUL_ABCD_EXG,
33+ ADD_ADDX,
34+ SHIFT_ROTATE,
35+ F_LINE
36+} m68k_optypes;
37+
38+typedef enum {
39+ M68K_ABCD,
40+ M68K_ADD,
41+ M68K_ADDX,
42+ M68K_AND,
43+ M68K_ANDI_CCR,
44+ M68K_ANDI_SR,
45+ M68K_ASL,
46+ M68K_ASR,
47+ M68K_BCC,
48+ M68K_BCHG,
49+ M68K_BCLR,
50+ M68K_BSET,
51+ M68K_BSR,
52+ M68K_BTST,
53+ M68K_CHK,
54+ M68K_CLR,
55+ M68K_CMP,
56+ M68K_DBCC,
57+ M68K_DIVS,
58+ M68K_DIVU,
59+ M68K_EOR,
60+ M68K_EORI_CCR,
61+ M68K_EORI_SR,
62+ M68K_EXG,
63+ M68K_EXT,
64+ M68K_ILLEGAL,
65+ M68K_JMP,
66+ M68K_JSR,
67+ M68K_LEA,
68+ M68K_LINK,
69+ M68K_LSL,
70+ M68K_LSR,
71+ M68K_MOVE,
72+ M68K_MOVE_CCR,
73+ M68K_MOVE_FROM_SR,
74+ M68K_MOVE_SR,
75+ M68K_MOVE_USP,
76+ M68K_MOVEM,
77+ M68K_MOVEP,
78+ M68K_MULS,
79+ M68K_MULU,
80+ M68K_NBCD,
81+ M68K_NEG,
82+ M68K_NEGX,
83+ M68K_NOP,
84+ M68K_NOT,
85+ M68K_OR,
86+ M68K_ORI_CCR,
87+ M68K_ORI_SR,
88+ M68K_PEA,
89+ M68K_RESET,
90+ M68K_ROL,
91+ M68K_ROR,
92+ M68K_ROXL,
93+ M68K_ROXR,
94+ M68K_RTE,
95+ M68K_RTR,
96+ M68K_RTS,
97+ M68K_SBCD,
98+ M68K_SCC,
99+ M68K_STOP,
100+ M68K_SUB,
101+ M68K_SUBX,
102+ M68K_SWAP,
103+ M68K_TAS,
104+ M68K_TRAP,
105+ M68K_TRAPV,
106+ M68K_TST,
107+ M68K_UNLK,
108+ M68K_INVALID,
109+ M68K_A_LINE_TRAP,
110+ M68K_F_LINE_TRAP,
111+#ifdef M68010
112+ M68K_BKPT,
113+ M68K_MOVE_FROM_CCR,
114+ M68K_MOVEC,
115+ M68K_MOVES,
116+ M68K_RTD,
117+#endif
118+#ifdef M68020
119+ M68K_BFCHG,
120+ M68K_BFCLR,
121+ M68K_BFEXTS,
122+ M68K_BFEXTU,
123+ M68K_BFFFO,
124+ M68K_BFINS,
125+ M68K_BFSET,
126+ M68K_BFTST,
127+ M68K_CALLM,
128+ M68K_CAS,
129+ M68K_CAS2,
130+ M68K_CHK2,
131+ M68K_CMP2,
132+ M68K_CP_BCC,
133+ M68K_CP_DBCC,
134+ M68K_CP_GEN,
135+ M68K_CP_RESTORE,
136+ M68K_CP_SAVE,
137+ M68K_CP_SCC,
138+ M68K_CP_TRAPCC,
139+ M68K_DIVSL,
140+ M68K_DIVUL,
141+ M68K_EXTB,
142+ M68K_PACK,
143+ M68K_RTM,
144+ M68K_TRAPCC,
145+ M68K_UNPK,
146+#endif
147+} m68K_op;
148+
149+typedef enum {
150+ VAR_NORMAL,
151+ VAR_QUICK,
152+ VAR_IMMEDIATE,
153+ VAR_BYTE,
154+ VAR_WORD,
155+ VAR_LONG
156+} m68K_variant;
157+
158+typedef enum {
159+ OPSIZE_BYTE=0,
160+ OPSIZE_WORD,
161+ OPSIZE_LONG,
162+ OPSIZE_INVALID,
163+ OPSIZE_UNSIZED
164+} m68K_opsizes;
165+
166+typedef enum {
167+//actual addressing mode field values
168+ MODE_REG = 0,
169+ MODE_AREG,
170+ MODE_AREG_INDIRECT,
171+ MODE_AREG_POSTINC,
172+ MODE_AREG_PREDEC,
173+ MODE_AREG_DISPLACE,
174+ MODE_AREG_INDEX_MEM, //bunch of relatively complicated modes
175+ MODE_PC_INDIRECT_ABS_IMMED, //Modes that use the program counter, an absolute address or immediate value
176+//expanded values
177+ MODE_AREG_INDEX_DISP8,
178+#ifdef M68020
179+ MODE_AREG_INDEX_BASE_DISP,
180+ MODE_AREG_PREINDEX,
181+ MODE_AREG_POSTINDEX,
182+ MODE_AREG_MEM_INDIRECT,
183+ MODE_AREG_BASE_DISP,
184+ MODE_INDEX_BASE_DISP,
185+ MODE_PREINDEX,
186+ MODE_POSTINDEX,
187+ MODE_MEM_INDIRECT,
188+ MODE_BASE_DISP,
189+#endif
190+ MODE_ABSOLUTE_SHORT,
191+ MODE_ABSOLUTE,
192+ MODE_PC_DISPLACE,
193+ MODE_PC_INDEX_DISP8,
194+#ifdef M68020
195+ MODE_PC_INDEX_BASE_DISP,
196+ MODE_PC_PREINDEX,
197+ MODE_PC_POSTINDEX,
198+ MODE_PC_MEM_INDIRECT,
199+ MODE_PC_BASE_DISP,
200+ MODE_ZPC_INDEX_BASE_DISP,
201+ MODE_ZPC_PREINDEX,
202+ MODE_ZPC_POSTINDEX,
203+ MODE_ZPC_MEM_INDIRECT,
204+ MODE_ZPC_BASE_DISP,
205+#endif
206+ MODE_IMMEDIATE,
207+ MODE_IMMEDIATE_WORD,//used to indicate an immediate operand that only uses a single extension word even for a long operation
208+ MODE_UNUSED
209+} m68k_addr_modes;
210+#ifdef M68020
211+#define M68K_FLAG_BITFIELD 0x80
212+#endif
213+
214+typedef enum {
215+ COND_TRUE,
216+ COND_FALSE,
217+ COND_HIGH,
218+ COND_LOW_SAME,
219+ COND_CARRY_CLR,
220+ COND_CARRY_SET,
221+ COND_NOT_EQ,
222+ COND_EQ,
223+ COND_OVERF_CLR,
224+ COND_OVERF_SET,
225+ COND_PLUS,
226+ COND_MINUS,
227+ COND_GREATER_EQ,
228+ COND_LESS,
229+ COND_GREATER,
230+ COND_LESS_EQ
231+} m68K_condition;
232+
233+#ifdef M68010
234+typedef enum {
235+ CR_SFC,
236+ CR_DFC,
237+#ifdef M68020
238+ CR_CACR,
239+#endif
240+ CR_USP,
241+ CR_VBR,
242+#ifdef M68020
243+ CR_CAAR,
244+ CR_MSP,
245+ CR_ISP
246+#endif
247+} m68k_control_reg;
248+
249+#ifdef M68020
250+#define MAX_HIGH_CR 0x804
251+#define MAX_LOW_CR 0x002
252+#else
253+#define MAX_HIGH_CR 0x801
254+#define MAX_LOW_CR 0x001
255+#endif
256+
257+#endif
258+
259+typedef struct {
260+#ifdef M68020
261+ uint16_t bitfield;
262+#endif
263+ uint8_t addr_mode;
264+ union {
265+ struct {
266+ uint8_t pri;
267+ uint8_t sec;
268+#ifdef M68020
269+ uint8_t scale;
270+ uint8_t disp_sizes;
271+#endif
272+ int32_t displacement;
273+#ifdef M68020
274+ int32_t outer_disp;
275+#endif
276+ } regs;
277+ uint32_t immed;
278+ } params;
279+} m68k_op_info;
280+
281+typedef struct m68kinst {
282+ uint8_t op;
283+ uint8_t variant;
284+ union {
285+ uint8_t size;
286+ uint8_t cond;
287+ } extra;
288+ uint8_t bytes;
289+ uint32_t address;
290+ m68k_op_info src;
291+ m68k_op_info dst;
292+} m68kinst;
293+
294+typedef enum {
295+ VECTOR_RESET_STACK,
296+ VECTOR_RESET_PC,
297+ VECTOR_ACCESS_FAULT,
298+ VECTOR_ADDRESS_ERROR,
299+ VECTOR_ILLEGAL_INST,
300+ VECTOR_INT_DIV_ZERO,
301+ VECTOR_CHK,
302+ VECTOR_TRAPV,
303+ VECTOR_PRIV_VIOLATION,
304+ VECTOR_TRACE,
305+ VECTOR_LINE_1010,
306+ VECTOR_LINE_1111,
307+ VECTOR_COPROC_VIOLATION=13,
308+ VECTOR_FORMAT_ERROR,
309+ VECTOR_UNINIT_INTERRUPT,
310+ VECTOR_SPURIOUS_INTERRUPT=24,
311+ VECTOR_INT_1,
312+ VECTOR_INT_2,
313+ VECTOR_INT_3,
314+ VECTOR_INT_4,
315+ VECTOR_INT_5,
316+ VECTOR_INT_6,
317+ VECTOR_INT_7,
318+ VECTOR_TRAP_0,
319+ VECTOR_TRAP_1,
320+ VECTOR_TRAP_2,
321+ VECTOR_TRAP_3,
322+ VECTOR_TRAP_4,
323+ VECTOR_TRAP_5,
324+ VECTOR_TRAP_6,
325+ VECTOR_TRAP_7,
326+ VECTOR_TRAP_8,
327+ VECTOR_TRAP_9,
328+ VECTOR_TRAP_10,
329+ VECTOR_TRAP_11,
330+ VECTOR_TRAP_12,
331+ VECTOR_TRAP_13,
332+ VECTOR_TRAP_14,
333+ VECTOR_TRAP_15,
334+ VECTOR_USER0 = 64
335+} m68k_vector;
336+
337+typedef int (*format_label_fun)(char * dst, uint32_t address, void * data);
338+
339+uint16_t * m68k_decode(uint16_t * istream, m68kinst * dst, uint32_t address);
340+uint32_t m68k_branch_target(m68kinst * inst, uint32_t *dregs, uint32_t *aregs);
341+uint8_t m68k_is_branch(m68kinst * inst);
342+uint8_t m68k_is_noncall_branch(m68kinst * inst);
343+int m68k_disasm(m68kinst * decoded, char * dst);
344+int m68k_disasm_labels(m68kinst * decoded, char * dst, format_label_fun label_fun, void * data);
345+int m68k_default_label_fun(char * dst, uint32_t address, void * data);
346+
347+#endif
348+
A
COPYING
+674,
-0
1@@ -0,0 +1,674 @@
2+ GNU GENERAL PUBLIC LICENSE
3+ Version 3, 29 June 2007
4+
5+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
6+ Everyone is permitted to copy and distribute verbatim copies
7+ of this license document, but changing it is not allowed.
8+
9+ Preamble
10+
11+ The GNU General Public License is a free, copyleft license for
12+software and other kinds of works.
13+
14+ The licenses for most software and other practical works are designed
15+to take away your freedom to share and change the works. By contrast,
16+the GNU General Public License is intended to guarantee your freedom to
17+share and change all versions of a program--to make sure it remains free
18+software for all its users. We, the Free Software Foundation, use the
19+GNU General Public License for most of our software; it applies also to
20+any other work released this way by its authors. You can apply it to
21+your programs, too.
22+
23+ When we speak of free software, we are referring to freedom, not
24+price. Our General Public Licenses are designed to make sure that you
25+have the freedom to distribute copies of free software (and charge for
26+them if you wish), that you receive source code or can get it if you
27+want it, that you can change the software or use pieces of it in new
28+free programs, and that you know you can do these things.
29+
30+ To protect your rights, we need to prevent others from denying you
31+these rights or asking you to surrender the rights. Therefore, you have
32+certain responsibilities if you distribute copies of the software, or if
33+you modify it: responsibilities to respect the freedom of others.
34+
35+ For example, if you distribute copies of such a program, whether
36+gratis or for a fee, you must pass on to the recipients the same
37+freedoms that you received. You must make sure that they, too, receive
38+or can get the source code. And you must show them these terms so they
39+know their rights.
40+
41+ Developers that use the GNU GPL protect your rights with two steps:
42+(1) assert copyright on the software, and (2) offer you this License
43+giving you legal permission to copy, distribute and/or modify it.
44+
45+ For the developers' and authors' protection, the GPL clearly explains
46+that there is no warranty for this free software. For both users' and
47+authors' sake, the GPL requires that modified versions be marked as
48+changed, so that their problems will not be attributed erroneously to
49+authors of previous versions.
50+
51+ Some devices are designed to deny users access to install or run
52+modified versions of the software inside them, although the manufacturer
53+can do so. This is fundamentally incompatible with the aim of
54+protecting users' freedom to change the software. The systematic
55+pattern of such abuse occurs in the area of products for individuals to
56+use, which is precisely where it is most unacceptable. Therefore, we
57+have designed this version of the GPL to prohibit the practice for those
58+products. If such problems arise substantially in other domains, we
59+stand ready to extend this provision to those domains in future versions
60+of the GPL, as needed to protect the freedom of users.
61+
62+ Finally, every program is threatened constantly by software patents.
63+States should not allow patents to restrict development and use of
64+software on general-purpose computers, but in those that do, we wish to
65+avoid the special danger that patents applied to a free program could
66+make it effectively proprietary. To prevent this, the GPL assures that
67+patents cannot be used to render the program non-free.
68+
69+ The precise terms and conditions for copying, distribution and
70+modification follow.
71+
72+ TERMS AND CONDITIONS
73+
74+ 0. Definitions.
75+
76+ "This License" refers to version 3 of the GNU General Public License.
77+
78+ "Copyright" also means copyright-like laws that apply to other kinds of
79+works, such as semiconductor masks.
80+
81+ "The Program" refers to any copyrightable work licensed under this
82+License. Each licensee is addressed as "you". "Licensees" and
83+"recipients" may be individuals or organizations.
84+
85+ To "modify" a work means to copy from or adapt all or part of the work
86+in a fashion requiring copyright permission, other than the making of an
87+exact copy. The resulting work is called a "modified version" of the
88+earlier work or a work "based on" the earlier work.
89+
90+ A "covered work" means either the unmodified Program or a work based
91+on the Program.
92+
93+ To "propagate" a work means to do anything with it that, without
94+permission, would make you directly or secondarily liable for
95+infringement under applicable copyright law, except executing it on a
96+computer or modifying a private copy. Propagation includes copying,
97+distribution (with or without modification), making available to the
98+public, and in some countries other activities as well.
99+
100+ To "convey" a work means any kind of propagation that enables other
101+parties to make or receive copies. Mere interaction with a user through
102+a computer network, with no transfer of a copy, is not conveying.
103+
104+ An interactive user interface displays "Appropriate Legal Notices"
105+to the extent that it includes a convenient and prominently visible
106+feature that (1) displays an appropriate copyright notice, and (2)
107+tells the user that there is no warranty for the work (except to the
108+extent that warranties are provided), that licensees may convey the
109+work under this License, and how to view a copy of this License. If
110+the interface presents a list of user commands or options, such as a
111+menu, a prominent item in the list meets this criterion.
112+
113+ 1. Source Code.
114+
115+ The "source code" for a work means the preferred form of the work
116+for making modifications to it. "Object code" means any non-source
117+form of a work.
118+
119+ A "Standard Interface" means an interface that either is an official
120+standard defined by a recognized standards body, or, in the case of
121+interfaces specified for a particular programming language, one that
122+is widely used among developers working in that language.
123+
124+ The "System Libraries" of an executable work include anything, other
125+than the work as a whole, that (a) is included in the normal form of
126+packaging a Major Component, but which is not part of that Major
127+Component, and (b) serves only to enable use of the work with that
128+Major Component, or to implement a Standard Interface for which an
129+implementation is available to the public in source code form. A
130+"Major Component", in this context, means a major essential component
131+(kernel, window system, and so on) of the specific operating system
132+(if any) on which the executable work runs, or a compiler used to
133+produce the work, or an object code interpreter used to run it.
134+
135+ The "Corresponding Source" for a work in object code form means all
136+the source code needed to generate, install, and (for an executable
137+work) run the object code and to modify the work, including scripts to
138+control those activities. However, it does not include the work's
139+System Libraries, or general-purpose tools or generally available free
140+programs which are used unmodified in performing those activities but
141+which are not part of the work. For example, Corresponding Source
142+includes interface definition files associated with source files for
143+the work, and the source code for shared libraries and dynamically
144+linked subprograms that the work is specifically designed to require,
145+such as by intimate data communication or control flow between those
146+subprograms and other parts of the work.
147+
148+ The Corresponding Source need not include anything that users
149+can regenerate automatically from other parts of the Corresponding
150+Source.
151+
152+ The Corresponding Source for a work in source code form is that
153+same work.
154+
155+ 2. Basic Permissions.
156+
157+ All rights granted under this License are granted for the term of
158+copyright on the Program, and are irrevocable provided the stated
159+conditions are met. This License explicitly affirms your unlimited
160+permission to run the unmodified Program. The output from running a
161+covered work is covered by this License only if the output, given its
162+content, constitutes a covered work. This License acknowledges your
163+rights of fair use or other equivalent, as provided by copyright law.
164+
165+ You may make, run and propagate covered works that you do not
166+convey, without conditions so long as your license otherwise remains
167+in force. You may convey covered works to others for the sole purpose
168+of having them make modifications exclusively for you, or provide you
169+with facilities for running those works, provided that you comply with
170+the terms of this License in conveying all material for which you do
171+not control copyright. Those thus making or running the covered works
172+for you must do so exclusively on your behalf, under your direction
173+and control, on terms that prohibit them from making any copies of
174+your copyrighted material outside their relationship with you.
175+
176+ Conveying under any other circumstances is permitted solely under
177+the conditions stated below. Sublicensing is not allowed; section 10
178+makes it unnecessary.
179+
180+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
181+
182+ No covered work shall be deemed part of an effective technological
183+measure under any applicable law fulfilling obligations under article
184+11 of the WIPO copyright treaty adopted on 20 December 1996, or
185+similar laws prohibiting or restricting circumvention of such
186+measures.
187+
188+ When you convey a covered work, you waive any legal power to forbid
189+circumvention of technological measures to the extent such circumvention
190+is effected by exercising rights under this License with respect to
191+the covered work, and you disclaim any intention to limit operation or
192+modification of the work as a means of enforcing, against the work's
193+users, your or third parties' legal rights to forbid circumvention of
194+technological measures.
195+
196+ 4. Conveying Verbatim Copies.
197+
198+ You may convey verbatim copies of the Program's source code as you
199+receive it, in any medium, provided that you conspicuously and
200+appropriately publish on each copy an appropriate copyright notice;
201+keep intact all notices stating that this License and any
202+non-permissive terms added in accord with section 7 apply to the code;
203+keep intact all notices of the absence of any warranty; and give all
204+recipients a copy of this License along with the Program.
205+
206+ You may charge any price or no price for each copy that you convey,
207+and you may offer support or warranty protection for a fee.
208+
209+ 5. Conveying Modified Source Versions.
210+
211+ You may convey a work based on the Program, or the modifications to
212+produce it from the Program, in the form of source code under the
213+terms of section 4, provided that you also meet all of these conditions:
214+
215+ a) The work must carry prominent notices stating that you modified
216+ it, and giving a relevant date.
217+
218+ b) The work must carry prominent notices stating that it is
219+ released under this License and any conditions added under section
220+ 7. This requirement modifies the requirement in section 4 to
221+ "keep intact all notices".
222+
223+ c) You must license the entire work, as a whole, under this
224+ License to anyone who comes into possession of a copy. This
225+ License will therefore apply, along with any applicable section 7
226+ additional terms, to the whole of the work, and all its parts,
227+ regardless of how they are packaged. This License gives no
228+ permission to license the work in any other way, but it does not
229+ invalidate such permission if you have separately received it.
230+
231+ d) If the work has interactive user interfaces, each must display
232+ Appropriate Legal Notices; however, if the Program has interactive
233+ interfaces that do not display Appropriate Legal Notices, your
234+ work need not make them do so.
235+
236+ A compilation of a covered work with other separate and independent
237+works, which are not by their nature extensions of the covered work,
238+and which are not combined with it such as to form a larger program,
239+in or on a volume of a storage or distribution medium, is called an
240+"aggregate" if the compilation and its resulting copyright are not
241+used to limit the access or legal rights of the compilation's users
242+beyond what the individual works permit. Inclusion of a covered work
243+in an aggregate does not cause this License to apply to the other
244+parts of the aggregate.
245+
246+ 6. Conveying Non-Source Forms.
247+
248+ You may convey a covered work in object code form under the terms
249+of sections 4 and 5, provided that you also convey the
250+machine-readable Corresponding Source under the terms of this License,
251+in one of these ways:
252+
253+ a) Convey the object code in, or embodied in, a physical product
254+ (including a physical distribution medium), accompanied by the
255+ Corresponding Source fixed on a durable physical medium
256+ customarily used for software interchange.
257+
258+ b) Convey the object code in, or embodied in, a physical product
259+ (including a physical distribution medium), accompanied by a
260+ written offer, valid for at least three years and valid for as
261+ long as you offer spare parts or customer support for that product
262+ model, to give anyone who possesses the object code either (1) a
263+ copy of the Corresponding Source for all the software in the
264+ product that is covered by this License, on a durable physical
265+ medium customarily used for software interchange, for a price no
266+ more than your reasonable cost of physically performing this
267+ conveying of source, or (2) access to copy the
268+ Corresponding Source from a network server at no charge.
269+
270+ c) Convey individual copies of the object code with a copy of the
271+ written offer to provide the Corresponding Source. This
272+ alternative is allowed only occasionally and noncommercially, and
273+ only if you received the object code with such an offer, in accord
274+ with subsection 6b.
275+
276+ d) Convey the object code by offering access from a designated
277+ place (gratis or for a charge), and offer equivalent access to the
278+ Corresponding Source in the same way through the same place at no
279+ further charge. You need not require recipients to copy the
280+ Corresponding Source along with the object code. If the place to
281+ copy the object code is a network server, the Corresponding Source
282+ may be on a different server (operated by you or a third party)
283+ that supports equivalent copying facilities, provided you maintain
284+ clear directions next to the object code saying where to find the
285+ Corresponding Source. Regardless of what server hosts the
286+ Corresponding Source, you remain obligated to ensure that it is
287+ available for as long as needed to satisfy these requirements.
288+
289+ e) Convey the object code using peer-to-peer transmission, provided
290+ you inform other peers where the object code and Corresponding
291+ Source of the work are being offered to the general public at no
292+ charge under subsection 6d.
293+
294+ A separable portion of the object code, whose source code is excluded
295+from the Corresponding Source as a System Library, need not be
296+included in conveying the object code work.
297+
298+ A "User Product" is either (1) a "consumer product", which means any
299+tangible personal property which is normally used for personal, family,
300+or household purposes, or (2) anything designed or sold for incorporation
301+into a dwelling. In determining whether a product is a consumer product,
302+doubtful cases shall be resolved in favor of coverage. For a particular
303+product received by a particular user, "normally used" refers to a
304+typical or common use of that class of product, regardless of the status
305+of the particular user or of the way in which the particular user
306+actually uses, or expects or is expected to use, the product. A product
307+is a consumer product regardless of whether the product has substantial
308+commercial, industrial or non-consumer uses, unless such uses represent
309+the only significant mode of use of the product.
310+
311+ "Installation Information" for a User Product means any methods,
312+procedures, authorization keys, or other information required to install
313+and execute modified versions of a covered work in that User Product from
314+a modified version of its Corresponding Source. The information must
315+suffice to ensure that the continued functioning of the modified object
316+code is in no case prevented or interfered with solely because
317+modification has been made.
318+
319+ If you convey an object code work under this section in, or with, or
320+specifically for use in, a User Product, and the conveying occurs as
321+part of a transaction in which the right of possession and use of the
322+User Product is transferred to the recipient in perpetuity or for a
323+fixed term (regardless of how the transaction is characterized), the
324+Corresponding Source conveyed under this section must be accompanied
325+by the Installation Information. But this requirement does not apply
326+if neither you nor any third party retains the ability to install
327+modified object code on the User Product (for example, the work has
328+been installed in ROM).
329+
330+ The requirement to provide Installation Information does not include a
331+requirement to continue to provide support service, warranty, or updates
332+for a work that has been modified or installed by the recipient, or for
333+the User Product in which it has been modified or installed. Access to a
334+network may be denied when the modification itself materially and
335+adversely affects the operation of the network or violates the rules and
336+protocols for communication across the network.
337+
338+ Corresponding Source conveyed, and Installation Information provided,
339+in accord with this section must be in a format that is publicly
340+documented (and with an implementation available to the public in
341+source code form), and must require no special password or key for
342+unpacking, reading or copying.
343+
344+ 7. Additional Terms.
345+
346+ "Additional permissions" are terms that supplement the terms of this
347+License by making exceptions from one or more of its conditions.
348+Additional permissions that are applicable to the entire Program shall
349+be treated as though they were included in this License, to the extent
350+that they are valid under applicable law. If additional permissions
351+apply only to part of the Program, that part may be used separately
352+under those permissions, but the entire Program remains governed by
353+this License without regard to the additional permissions.
354+
355+ When you convey a copy of a covered work, you may at your option
356+remove any additional permissions from that copy, or from any part of
357+it. (Additional permissions may be written to require their own
358+removal in certain cases when you modify the work.) You may place
359+additional permissions on material, added by you to a covered work,
360+for which you have or can give appropriate copyright permission.
361+
362+ Notwithstanding any other provision of this License, for material you
363+add to a covered work, you may (if authorized by the copyright holders of
364+that material) supplement the terms of this License with terms:
365+
366+ a) Disclaiming warranty or limiting liability differently from the
367+ terms of sections 15 and 16 of this License; or
368+
369+ b) Requiring preservation of specified reasonable legal notices or
370+ author attributions in that material or in the Appropriate Legal
371+ Notices displayed by works containing it; or
372+
373+ c) Prohibiting misrepresentation of the origin of that material, or
374+ requiring that modified versions of such material be marked in
375+ reasonable ways as different from the original version; or
376+
377+ d) Limiting the use for publicity purposes of names of licensors or
378+ authors of the material; or
379+
380+ e) Declining to grant rights under trademark law for use of some
381+ trade names, trademarks, or service marks; or
382+
383+ f) Requiring indemnification of licensors and authors of that
384+ material by anyone who conveys the material (or modified versions of
385+ it) with contractual assumptions of liability to the recipient, for
386+ any liability that these contractual assumptions directly impose on
387+ those licensors and authors.
388+
389+ All other non-permissive additional terms are considered "further
390+restrictions" within the meaning of section 10. If the Program as you
391+received it, or any part of it, contains a notice stating that it is
392+governed by this License along with a term that is a further
393+restriction, you may remove that term. If a license document contains
394+a further restriction but permits relicensing or conveying under this
395+License, you may add to a covered work material governed by the terms
396+of that license document, provided that the further restriction does
397+not survive such relicensing or conveying.
398+
399+ If you add terms to a covered work in accord with this section, you
400+must place, in the relevant source files, a statement of the
401+additional terms that apply to those files, or a notice indicating
402+where to find the applicable terms.
403+
404+ Additional terms, permissive or non-permissive, may be stated in the
405+form of a separately written license, or stated as exceptions;
406+the above requirements apply either way.
407+
408+ 8. Termination.
409+
410+ You may not propagate or modify a covered work except as expressly
411+provided under this License. Any attempt otherwise to propagate or
412+modify it is void, and will automatically terminate your rights under
413+this License (including any patent licenses granted under the third
414+paragraph of section 11).
415+
416+ However, if you cease all violation of this License, then your
417+license from a particular copyright holder is reinstated (a)
418+provisionally, unless and until the copyright holder explicitly and
419+finally terminates your license, and (b) permanently, if the copyright
420+holder fails to notify you of the violation by some reasonable means
421+prior to 60 days after the cessation.
422+
423+ Moreover, your license from a particular copyright holder is
424+reinstated permanently if the copyright holder notifies you of the
425+violation by some reasonable means, this is the first time you have
426+received notice of violation of this License (for any work) from that
427+copyright holder, and you cure the violation prior to 30 days after
428+your receipt of the notice.
429+
430+ Termination of your rights under this section does not terminate the
431+licenses of parties who have received copies or rights from you under
432+this License. If your rights have been terminated and not permanently
433+reinstated, you do not qualify to receive new licenses for the same
434+material under section 10.
435+
436+ 9. Acceptance Not Required for Having Copies.
437+
438+ You are not required to accept this License in order to receive or
439+run a copy of the Program. Ancillary propagation of a covered work
440+occurring solely as a consequence of using peer-to-peer transmission
441+to receive a copy likewise does not require acceptance. However,
442+nothing other than this License grants you permission to propagate or
443+modify any covered work. These actions infringe copyright if you do
444+not accept this License. Therefore, by modifying or propagating a
445+covered work, you indicate your acceptance of this License to do so.
446+
447+ 10. Automatic Licensing of Downstream Recipients.
448+
449+ Each time you convey a covered work, the recipient automatically
450+receives a license from the original licensors, to run, modify and
451+propagate that work, subject to this License. You are not responsible
452+for enforcing compliance by third parties with this License.
453+
454+ An "entity transaction" is a transaction transferring control of an
455+organization, or substantially all assets of one, or subdividing an
456+organization, or merging organizations. If propagation of a covered
457+work results from an entity transaction, each party to that
458+transaction who receives a copy of the work also receives whatever
459+licenses to the work the party's predecessor in interest had or could
460+give under the previous paragraph, plus a right to possession of the
461+Corresponding Source of the work from the predecessor in interest, if
462+the predecessor has it or can get it with reasonable efforts.
463+
464+ You may not impose any further restrictions on the exercise of the
465+rights granted or affirmed under this License. For example, you may
466+not impose a license fee, royalty, or other charge for exercise of
467+rights granted under this License, and you may not initiate litigation
468+(including a cross-claim or counterclaim in a lawsuit) alleging that
469+any patent claim is infringed by making, using, selling, offering for
470+sale, or importing the Program or any portion of it.
471+
472+ 11. Patents.
473+
474+ A "contributor" is a copyright holder who authorizes use under this
475+License of the Program or a work on which the Program is based. The
476+work thus licensed is called the contributor's "contributor version".
477+
478+ A contributor's "essential patent claims" are all patent claims
479+owned or controlled by the contributor, whether already acquired or
480+hereafter acquired, that would be infringed by some manner, permitted
481+by this License, of making, using, or selling its contributor version,
482+but do not include claims that would be infringed only as a
483+consequence of further modification of the contributor version. For
484+purposes of this definition, "control" includes the right to grant
485+patent sublicenses in a manner consistent with the requirements of
486+this License.
487+
488+ Each contributor grants you a non-exclusive, worldwide, royalty-free
489+patent license under the contributor's essential patent claims, to
490+make, use, sell, offer for sale, import and otherwise run, modify and
491+propagate the contents of its contributor version.
492+
493+ In the following three paragraphs, a "patent license" is any express
494+agreement or commitment, however denominated, not to enforce a patent
495+(such as an express permission to practice a patent or covenant not to
496+sue for patent infringement). To "grant" such a patent license to a
497+party means to make such an agreement or commitment not to enforce a
498+patent against the party.
499+
500+ If you convey a covered work, knowingly relying on a patent license,
501+and the Corresponding Source of the work is not available for anyone
502+to copy, free of charge and under the terms of this License, through a
503+publicly available network server or other readily accessible means,
504+then you must either (1) cause the Corresponding Source to be so
505+available, or (2) arrange to deprive yourself of the benefit of the
506+patent license for this particular work, or (3) arrange, in a manner
507+consistent with the requirements of this License, to extend the patent
508+license to downstream recipients. "Knowingly relying" means you have
509+actual knowledge that, but for the patent license, your conveying the
510+covered work in a country, or your recipient's use of the covered work
511+in a country, would infringe one or more identifiable patents in that
512+country that you have reason to believe are valid.
513+
514+ If, pursuant to or in connection with a single transaction or
515+arrangement, you convey, or propagate by procuring conveyance of, a
516+covered work, and grant a patent license to some of the parties
517+receiving the covered work authorizing them to use, propagate, modify
518+or convey a specific copy of the covered work, then the patent license
519+you grant is automatically extended to all recipients of the covered
520+work and works based on it.
521+
522+ A patent license is "discriminatory" if it does not include within
523+the scope of its coverage, prohibits the exercise of, or is
524+conditioned on the non-exercise of one or more of the rights that are
525+specifically granted under this License. You may not convey a covered
526+work if you are a party to an arrangement with a third party that is
527+in the business of distributing software, under which you make payment
528+to the third party based on the extent of your activity of conveying
529+the work, and under which the third party grants, to any of the
530+parties who would receive the covered work from you, a discriminatory
531+patent license (a) in connection with copies of the covered work
532+conveyed by you (or copies made from those copies), or (b) primarily
533+for and in connection with specific products or compilations that
534+contain the covered work, unless you entered into that arrangement,
535+or that patent license was granted, prior to 28 March 2007.
536+
537+ Nothing in this License shall be construed as excluding or limiting
538+any implied license or other defenses to infringement that may
539+otherwise be available to you under applicable patent law.
540+
541+ 12. No Surrender of Others' Freedom.
542+
543+ If conditions are imposed on you (whether by court order, agreement or
544+otherwise) that contradict the conditions of this License, they do not
545+excuse you from the conditions of this License. If you cannot convey a
546+covered work so as to satisfy simultaneously your obligations under this
547+License and any other pertinent obligations, then as a consequence you may
548+not convey it at all. For example, if you agree to terms that obligate you
549+to collect a royalty for further conveying from those to whom you convey
550+the Program, the only way you could satisfy both those terms and this
551+License would be to refrain entirely from conveying the Program.
552+
553+ 13. Use with the GNU Affero General Public License.
554+
555+ Notwithstanding any other provision of this License, you have
556+permission to link or combine any covered work with a work licensed
557+under version 3 of the GNU Affero General Public License into a single
558+combined work, and to convey the resulting work. The terms of this
559+License will continue to apply to the part which is the covered work,
560+but the special requirements of the GNU Affero General Public License,
561+section 13, concerning interaction through a network will apply to the
562+combination as such.
563+
564+ 14. Revised Versions of this License.
565+
566+ The Free Software Foundation may publish revised and/or new versions of
567+the GNU General Public License from time to time. Such new versions will
568+be similar in spirit to the present version, but may differ in detail to
569+address new problems or concerns.
570+
571+ Each version is given a distinguishing version number. If the
572+Program specifies that a certain numbered version of the GNU General
573+Public License "or any later version" applies to it, you have the
574+option of following the terms and conditions either of that numbered
575+version or of any later version published by the Free Software
576+Foundation. If the Program does not specify a version number of the
577+GNU General Public License, you may choose any version ever published
578+by the Free Software Foundation.
579+
580+ If the Program specifies that a proxy can decide which future
581+versions of the GNU General Public License can be used, that proxy's
582+public statement of acceptance of a version permanently authorizes you
583+to choose that version for the Program.
584+
585+ Later license versions may give you additional or different
586+permissions. However, no additional obligations are imposed on any
587+author or copyright holder as a result of your choosing to follow a
588+later version.
589+
590+ 15. Disclaimer of Warranty.
591+
592+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
593+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
594+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
595+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
596+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
597+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
598+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
599+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
600+
601+ 16. Limitation of Liability.
602+
603+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
604+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
605+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
606+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
607+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
608+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
609+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
610+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
611+SUCH DAMAGES.
612+
613+ 17. Interpretation of Sections 15 and 16.
614+
615+ If the disclaimer of warranty and limitation of liability provided
616+above cannot be given local legal effect according to their terms,
617+reviewing courts shall apply local law that most closely approximates
618+an absolute waiver of all civil liability in connection with the
619+Program, unless a warranty or assumption of liability accompanies a
620+copy of the Program in return for a fee.
621+
622+ END OF TERMS AND CONDITIONS
623+
624+ How to Apply These Terms to Your New Programs
625+
626+ If you develop a new program, and you want it to be of the greatest
627+possible use to the public, the best way to achieve this is to make it
628+free software which everyone can redistribute and change under these terms.
629+
630+ To do so, attach the following notices to the program. It is safest
631+to attach them to the start of each source file to most effectively
632+state the exclusion of warranty; and each file should have at least
633+the "copyright" line and a pointer to where the full notice is found.
634+
635+ <one line to give the program's name and a brief idea of what it does.>
636+ Copyright (C) <year> <name of author>
637+
638+ This program is free software: you can redistribute it and/or modify
639+ it under the terms of the GNU General Public License as published by
640+ the Free Software Foundation, either version 3 of the License, or
641+ (at your option) any later version.
642+
643+ This program is distributed in the hope that it will be useful,
644+ but WITHOUT ANY WARRANTY; without even the implied warranty of
645+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
646+ GNU General Public License for more details.
647+
648+ You should have received a copy of the GNU General Public License
649+ along with this program. If not, see <http://www.gnu.org/licenses/>.
650+
651+Also add information on how to contact you by electronic and paper mail.
652+
653+ If the program does terminal interaction, make it output a short
654+notice like this when it starts in an interactive mode:
655+
656+ <program> Copyright (C) <year> <name of author>
657+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
658+ This is free software, and you are welcome to redistribute it
659+ under certain conditions; type `show c' for details.
660+
661+The hypothetical commands `show w' and `show c' should show the appropriate
662+parts of the General Public License. Of course, your program's commands
663+might be different; for a GUI interface, you would use an "about box".
664+
665+ You should also get your employer (if you work as a programmer) or school,
666+if any, to sign a "copyright disclaimer" for the program, if necessary.
667+For more information on this, and how to apply and follow the GNU GPL, see
668+<http://www.gnu.org/licenses/>.
669+
670+ The GNU General Public License does not permit incorporating your program
671+into proprietary programs. If your program is a subroutine library, you
672+may consider it more useful to permit linking proprietary applications with
673+the library. If this is what you want to do, use the GNU Lesser General
674+Public License instead of this License. But first, please read
675+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
A
README
+577,
-0
1@@ -0,0 +1,577 @@
2+BlastEm 0.6.0 shrub edition
3+---------------------------
4+this is my personal branch of the blastem mega drive emulator. it has been modified
5+to cut out code that i do not need and add other things i do need. the changes made
6+include but are not limited t0:
7+
8+- new wayland renderer only
9+- use system zlib, not vendored
10+- ninja based build
11+- no nuklear ui, sdl, fbdev or gl support
12+
13+to compile, you will need wayland, pkg-config, a and a zlib.
14+
15+i'd also like to note that i don't approve of this projects license and wish
16+i could offer it under something else.
17+
18+the original readme is preserved below, and you check out the original blastem
19+project at https://www.retrodev.com/blastem/
20+
21+Installation
22+------------
23+
24+Extract this archive to a directory of your choosing.
25+
26+NOTE: Prior to version 0.4.1, BlastEm was still using Unixy locations for config
27+and save files. If you're upgrading from a previous version on Windows, you will
28+need to move them manually. For config files, the relevant paths are in the
29+previous paragraph. For save files, move all the directories found in
30+%userprofile%\.local\share\blastem to %localappdata%\blastem
31+
32+Usage
33+-----
34+
35+This version of BlastEm has a GUI that allows access to most configuration options.
36+Simply start BlastEm without passing a ROM filename on the command line to access
37+the main menu. You can also access the menu by hitting the button mapped to the ui.exit
38+action (default Esc).
39+
40+If Open GL is disabled or unavaible, or you explicitly request it, the old ROM-based UI
41+will be used instead. This UI does not support configuration so you will need to modify
42+the configuration file manually if you use it. See the rest of this README for instructions
43+on modifying the configuration file.
44+
45+Some operations are currently only supported through the command line. To get a
46+list of supported command line options on Linux or OSX type:
47+
48+ ./blastem -h
49+
50+From within your BlastEm directory. On Windows type:
51+
52+ blastem.exe -h
53+
54+Lock-On Support
55+---------------
56+
57+This version of BlastEm has some preliminary support for Sonic & Knuckles lock
58+on technology. This is available via both the menu and the command line. To use
59+it from the menu, first load Sonic & Knuckles normally. Enter the menu (mapped
60+to the Escape key by default) and select the "Lock On" option to select a ROM
61+to lock on. The system will then reload with the combined game. To use it from
62+the command line, specify the Sonic & Knuckles ROM as the primary ROM and
63+specify the ROM to be locked on using the -o option. As an example:
64+
65+ ./blastem ~/romz/sonic_and_knuckles.bin -o ~/romz/sonic3.bin
66+
67+Please note that Sonic 2 lock-on does not work at this time.
68+
69+Configuration
70+-------------
71+
72+Configuration is read from the file at $HOME/.config/blastem/blastem.cfg on
73+Unix-like systems and %localappdata%\blastem\blastem.cfg if it exists.
74+Othwerise it is read from default.cfg from the same directory as the BlastEm
75+executable. Sections are denoted by a section name followed by an open curly
76+bracket, the section's contents and a closing curly bracket. Individual
77+configuration values are set by entering the value's name followed by a space
78+or tab and followed by the desired value.
79+
80+Bindings
81+--------
82+
83+The keys subsection of bindings maps keyboard keys to gamepad buttons or UI
84+actions. The key name goes on the left and the action is on the right.
85+Most keys are named for the character they produce when pressed. For keys that
86+don't correspond to a normal character, check the list below:
87+
88+ Name | Description
89+ -----------------
90+ up Up arrow
91+ down Down arrow
92+ left Left arrow
93+ right Right arrow
94+ space
95+ tab
96+ backspace Backspace on PC keyboards, Delete on Mac keyboards
97+ esc
98+ delete
99+ lshift Left shift
100+ rshift Right shift
101+ lctrl Left control
102+ rctrl Right control
103+ lalt Left alt on PC keyboards, Option on Mac keyboards
104+ ralt Right alt on PC keyboards, Option on Mac keyboards
105+ home
106+ end
107+ pageup
108+ pagedown
109+ f1
110+ f2
111+ f3
112+ f4
113+ f5
114+ f6
115+ f7
116+ f8
117+ f9
118+ f10
119+ f11
120+ f12
121+ select
122+ play
123+ search
124+ back
125+
126+The pads subsection is used to map gamepads and joysticks. Gamepads that are
127+recognized, can have their buttons and axes mapped with semantic names.
128+Xbox 360, PS4 and PS3 style names are supported. Unrecognized gamepads can be
129+mapped using numeric button and axis ids. The following button names are
130+recognized by BlastEm:
131+ a, cross
132+ b, circle
133+ x, square
134+ y, trinagle
135+ start, options
136+ back, select, share
137+ guide
138+ leftbutton, l1
139+ rightbutton, r1
140+ leftstick, l3
141+ rightstick, r3
142+The following axis names are recognized by BlastEm:
143+ leftx
144+ lefty
145+ rightx
146+ righty
147+ lefttrigger, l2
148+ righttrigger, r2
149+
150+
151+The mice subsection is used to map mice to emulated Mega/Sega mice. The default
152+configuration maps both the first and second host mice to the first emulated
153+mouse. This should not need modification for most users.
154+
155+One special mapping deserves a mention. By default, the 'r' key is mapped to
156+ui.release_mouse. When operating in windowed mode the mouse has a capture
157+behavior. Mouse events are ignored until you click in the window. The mouse
158+will then be "captured" and the cursor will be both made invisible and locked
159+to the window. The ui.release_mouse binding releases the mouse so it can be
160+used normally.
161+
162+UI Actions
163+----------
164+
165+This section lists the various "UI" actions that can be triggered by a key or
166+gamepad binding.
167+
168+ui.release_mouse Releases the mouse if it is currently captured
169+ui.plane_debug Toggles the VDP plane debug view
170+ui.vram_debug Toggles the VDP VRAM debug view
171+ui.cram_debug Toggles the VDP CRAM debug view
172+ui.compositing_debug Toggles the VDP compositing debug view
173+ui.vdp_debug_mode Cycles the mode/palette of the VDP debug view
174+ that currently has focus
175+ui.enter_debugger Enters the debugger for the main CPU of the
176+ currently emulated system
177+ui.screenshot Takes an internal screenshot
178+ui.exit Returns to the menu ROM if currently in a game
179+ that was launched from the menu. Exits otherwise
180+ui.save_state Saves a savestate to the quicksave slot
181+ui.set_speed.N Selects a specific machine speed specified by N
182+ which should be a number between 0-9. Speeds are
183+ specified in the "clocks" section of the config
184+ui.next_speed Selects the next machine speed
185+ui.prev_speed Selects the previous machine speed
186+ui.toggle_fullscreen Toggles between fullscreen and windowed mode
187+ui.soft_reset Resets a portion of the emulated machine
188+ Equivalent to pushing the reset button on the
189+ emulated device
190+ui.reload Reloads the current ROM from a file and performs
191+ a hard reset of the emulated device
192+ui.sms_pause Triggers a press of the pause button when in SMS
193+ mode
194+ui.toggle_keyboard_captured Toggles the capture state of the host keyboard
195+ when an emulated keyboard is present
196+
197+IO
198+--
199+
200+This section controls which peripherals are attached to the emulated console.
201+IO assignments can be overridden by the ROM database when appropriate. For
202+instance, games with mouse support can automatically use the mouse and games
203+that only support 3-button pads can automatically force an appropriate pad.
204+Unforunately, the ROM database is not yet exhaustive so manual configuration
205+may be needed here in some cases.
206+
207+Video
208+-----
209+
210+The video section contains settings that affect the visual output of BlastEm.
211+
212+"aspect" is used to control the aspect ratio of the emulated display. The
213+default of 4:3 matches that of a standard definition television.
214+
215+"width" is used to control the window width when not in fullscreen mode.
216+
217+"height" is used to control the window height when not in fullscreen mode. If
218+left unspecified, it will be calculated from "width" and "aspect".
219+
220+"vertex_shader" and "fragment_shader" define the GLSL shader program that
221+produces the final image for each frame. Shaders can be used to add various
222+visual effects or enhancements. Currently BlastEm only ships with the default
223+shader and a "subtle" crt shader. If you write your own shaders, place them in
224+$HOME/.config/blastem/shaders and then specify the basename of the new shader
225+files in the "vertex_shader" and "fragment_shader" config options. Note that
226+shaders are not available in the SDL fallback renderer.
227+
228+"scanlines" controls whether there is any emulation of the gaps between display
229+lines that are present when driving a CRT television with a 240p signal. This
230+emulation is very basic at the moment so this option is off by default.
231+
232+"vsync" controls whether the drawing of frames is synchronized to the monitor
233+refresh rate. Valid values for this setting are "off", "on" and "tear". The
234+latter will attempt to use the "late tear" option if it's available and normal
235+vsync otherwise. Currently it's recommended to leave this at the default of
236+"off" as it may not work well with the default "audio" sync method and the
237+"video" sync method will automatically enable "vsync". See "Sync Source and
238+VSync" for more details.
239+
240+"fullscreen" controls whether BlastEm starts in fullscreen or windowed mode.
241+This can be overridden on the command line with the -f flag. If fullscreen
242+is set to "off", -f will turn it on. Conversely, if fullscreen is set to "on"
243+in the config, -f will turn it off.
244+
245+"gl" controls whether OpenGL is used for rendering. The default value is on.
246+If it is set to off instead, the fallback renderer which uses SDL2's render API
247+will be used instead. This option is mostly useful for users on hardware that
248+lacks OpenGL 2 support. While BlastEm will fall back automatically even if gl
249+is set to on there will be a warning. Disabling gl eliminates this warning.
250+
251+"scaling" controls the type of scaling used for textures in both the GL and
252+SDL renderers. Valid values are "nearest" and "linear". Note that shaders also
253+impact how pixels are scaled.
254+
255+The "ntsc" and "pal" sub-sections control overscan settings for the emulated
256+video output for NTSC and PAL consoles respectively. More details are available
257+in the Overscan section.
258+
259+Overscan
260+--------
261+
262+Analog televisions generally don't display the entirety of a video frame. Some
263+portion is cropped at the edges of the display. This is called overscan.
264+Unfortunately, the amount of cropping performed varies considerably and is even
265+adjustable on many TV sets. To deal with this, BlastEm allows overscan to be
266+customized.
267+
268+Overscan values are specified in the "ntsc" and "pal" sub-sections of the
269+"video" section of the config file. The "overscan" sub-section contains four
270+settings for specifying the number of pixels cropped on each side of the
271+display: "top", "bottom", "left" and "right".
272+
273+The default settings hide the horizontal border completely for both NTSC and
274+PAL consoles. For the vertical borders, the NTSC overscan settings are chosen
275+to give square pixels with the default aspect ratio of 4:3. For PAL, the
276+default settings are set so that the PAL-exclusive V30 mode will produce a
277+visible border that is the same size as what is shown in V28 mode in NTSC. This
278+results in a slightly squished picture compared to NTSC which is probably
279+appropriate given that a PAL display has more lines than an NTSC one.
280+
281+Audio
282+-----
283+
284+The audio section contains settings that affect the audio output of BlastEm.
285+
286+"rate" selects the preferred sample rate for audio output. Your operating
287+system may not accept this value in which case a different rate will be chosen.
288+This should generally be either the native sample rate of your sound card or an
289+integral divisor of it. Most modern sound cards have a native output rate that
290+is a multiple of 48000 Hz so the default setting should work well for most users.
291+
292+"buffer size" controls how large of a buffer uses for audio data. Smaller values
293+will reduce latency, but too small of a value can lead to dropouts. 512 works
294+well for me, but a higher or lower value may be more appropriate for your system.
295+
296+"lowpass_cutoff" controls the cutoff, or knee, frequency of the RC-style
297+low-pass filter. The default value of 3390 Hz is supposedly what is present in
298+at least some Genesis/Megadrive models. Other models reportedly use an even
299+lower value.
300+
301+"gain" specifies the gain in decibels to be applied to the overall output.
302+
303+"fm_gain" specifies the gain to be applied to the emulated FM output before
304+mixing with the PSG.
305+
306+"psg_gain" specifies the gain to be applied to the emulated PSG output before
307+mixing with the FM chip.
308+
309+"fm_dac" controls the characteristics of the DAC in the emulated FM chip. If
310+this is set to "linear", then the DAC will have precise linear output similar
311+to the integrated YM3438 in later Gen/MD consoles. If it is set to "zero_offset",
312+there will be a larger gap between -1 and 0. This is commonly referred to as the
313+"ladder effect". This will also cause "leakage" on channels that are muted or
314+panned to one side in a similar manner to a discrete YM2612.
315+
316+
317+Clocks
318+------
319+
320+The clocks section contains settings that affect how fast things run.
321+
322+"m68k_divider" describes the relationsip between the master clock (which is
323+53693175 Hz for NTSC mode and 53203395 Hz for PAL mode). The default value of 7
324+matches the real hardware. Set this to a lower number to overclock the 68000
325+and set it to a higher number to underclock it.
326+
327+"max_cycles" controls how often the system is forced to synchronize all
328+hardware. BlastEm generally uses a sync on demand approach to synchronizing
329+components in the system. This can provide perfect synchronization for most
330+components, but since the Z80 can steal cycles from the 68000 at unpredictable
331+times 68000/Z80 synchronization is imperfect. The default value of 3420
332+corresponds to the number of master clock cycles per line. Larger numbers may
333+produce a modest performance improvement whereas smaller numbers will improve
334+68000/Z80 synchronization.
335+
336+"speeds" controls the speed of the overall emulated console at different
337+presets. Preset 0 is the default speed and should normally be set to 100. The
338+other presets enable the slow/turbo mode functionality.
339+
340+UI
341+--
342+
343+The UI section contains settings that affect the user interface.
344+
345+"rom" determines the path of the Genesis/Megadrive ROM that implements the UI.
346+Relative paths will be loaded relative to the BlastEm executable.
347+
348+"initial_path" specifies the starting path for the ROM browser. It can contain
349+the following special variables: $HOME, $EXEDIR. Additionally, variables
350+defined in the OS environment can be used.
351+
352+"remember_path" specifies whether BlastEm should remember the last path used in
353+the file browser. When it is set to "on", the last path will be remembered and
354+used instead of "initial_path" in subsequent runs. If it is set to "off",
355+"initial_path" will always be used.
356+
357+"screenshot_path" specifies the directory "internal" screenshots will be saved
358+in. It accepts the same special variables as "initial_path".
359+
360+"screenshot_template" specifies a template for creating screenshot filenames.
361+It is specified as a format string for the C library function strftime
362+
363+"save_path" specifies the directory that savestates, SRAM and EEPROM data will
364+be saved in for a given game. It can contain the following special variables:
365+$HOME, $EXEDIR, $USERDATA, $ROMNAME. Like "initial_path" it can also reference
366+variables from the environment.
367+
368+"extensions" specifies the file extensions that should be displayed in the file
369+browser.
370+
371+"state_format" specifies the preferred format for saving save states. Valid
372+values are "native" (the default) and "gst". "native" save states do a better
373+job of preserving the state of the emulated system, but "gst" save states are
374+compatible with other emulators like Kega and Gens. This setting has no effect
375+for systems other than the Genesis/Mega Drive
376+
377+Path Variables
378+--------------
379+
380+This section explains the meaning of the special path variables referenced
381+in the previous section.
382+
383+$HOME The home directory of the current user. On most Unix variants, it
384+ will be a subdirectory of /home. On Windows it will typically be a
385+ subdirectory of C:\Users
386+$EXEDIR The directory the BlastEm executable is located in
387+$USERDATA This is an OS-specific path used for storing application specific
388+ user data. On Unix variants, it will be $HOME/.local/share/blastem
389+ On Windows it will be %LOCALDATA%/blastem
390+$ROMNAME The name of the currently loaded ROM file without the extension
391+
392+System
393+------
394+
395+"ram_init" determines how the RAM in the emulated system is initialized. The
396+default value of "zero" will cause all RAM to be zeroed out before the system
397+is started. Alternatively, "random" can be used to initialize RAM with values
398+from a pseudo-random number generator. This option is mostly useful for
399+developers that want to debug initialization issues in their code.
400+
401+"default_region" determines the console region that will be used when region
402+detection fails and when there are multiple valid regions. The default of 'U'
403+specifies a 60Hz "foreign" console.
404+
405+"sync_source" controls whether BlastEm uses audio or video output to control
406+execution speed. "video" can provide a smoother experience when your display
407+has a similar refresh rate to the emulated system, but has some limitations
408+in the current version. The default value is "audio".
409+
410+"megawifi" enables or disables support for MegaWiFi cart emulation. MegaWiFi
411+is a cartridge that contains WiFi hardware for network functionality. Enabling
412+this means that ROMs potentially have access to your network (and the internet)
413+which obviously has security implications. For this reason, it is disabled by
414+default. If you wish to try out MegaWiFi emulation, set this to "on". Note that
415+the support for MegaWiFi hardware is preliminary in this release.
416+
417+Debugger
418+--------
419+
420+BlastEm has an integrated command-line debugger loosely based on GDB's
421+interface. The interface is very rough at the moment. Available commands in the
422+68K debugger are:
423+ b ADDRESS - Set a breakpoint at ADDRESS
424+ d BREAKPOINT - Delete a 68K breakpoint
425+ co BREAKPOINT - Run a list of debugger commands each time
426+ BREAKPOINT is hit
427+ a ADDRESS - Advance to address
428+ n - Advance to next instruction
429+ o - Advance to next instruction ignoring branches to
430+ lower addresses (good for breaking out of loops)
431+ s - Advance to next instruction (follows bsr/jsr)
432+ c - Continue
433+ bt - Print a backtrace
434+ p[/(x|X|d|c)] VALUE - Print a register or memory location
435+ di[/(x|X|d|c)] VALUE - Print a register or memory location each time
436+ a breakpoint is hit
437+ vs - Print VDP sprite list
438+ vr - Print VDP register info
439+ zb ADDRESS - Set a Z80 breakpoint
440+ zp[/(x|X|d|c)] VALUE - Display a Z80 value
441+ q - Quit BlastEm
442+Available commands in the Z80 debugger are:
443+ b ADDRESS - Set a breakpoint at ADDRESS
444+ de BREAKPOINT - Delete a Z80 breakpoint
445+ a ADDRESS - Advance to address
446+ n - Advance to next instruction
447+ c - Continue
448+ p[/(x|X|d|c)] VALUE - Print a register or memory location
449+ di[/(x|X|d|c)] VALUE - Print a register or memory location each time
450+ a breakpoint is hit
451+ q - Quit BlastEm
452+
453+The -d flag can be used to cause BlastEm to start in the debugger.
454+Alternatively, you can use the ui.enter_debugger action (mapped to the 'u' key
455+by default) to enter the debugger while a game is running. To debug the menu
456+ROM, use the -dm flag.
457+
458+GDB Remote Debugging
459+--------------------
460+
461+In addition to the native debugger, BlastEm can also act as a GDB remote
462+debugging stub. To use this, you'll want to configure your Makefile to produce
463+both an ELF executable and a raw binary. Invoke an m68k-elf targeted gdb with
464+the ELF file. Once inside the gdb session, type:
465+
466+ target remote | BLASTEM_PATH/blastem ROM_FILE.bin -D
467+
468+where BLASTEM_PATH is the relative or absolute path to your BlastEm
469+installation and ROM_FILE.bin is the name of the raw binary for your program.
470+BlastEm will halt at the beginning of your program's entry point and return
471+control to GDB. This will allow you to set breakpoints before your code runs.
472+
473+On Windows, the procedure is slightly different. First run
474+ blastem.exe ROM_FILE.bin -D
475+This will cause BlastEm to wait for a socket connection on port 1234. It will
476+appear to be frozen until gdb connects to it. Now open the ELF file in gdb
477+and type:
478+
479+ target remote :1234
480+
481+Trace points and watch points are not currently supported.
482+
483+Included Tools
484+--------------
485+
486+BlastEm ships with a few small utilities that leverage portions of the emulator
487+code.
488+
489+ dis - 68K disassembler
490+ zdis - Z80 disassembler
491+ vgmplay - Very basic VGM player
492+ stateview - GST save state viewer
493+
494+Sync Source and VSync
495+-----
496+
497+This section includes information about using VSync with BlastEm. Currently,
498+the best way to use VSync is to set the sync source to "video". This will force
499+VSync on and use video output for controlling the speed of emulation. In this
500+mode, audio will have it's rate automatically adjusted to keep pace with video.
501+The code for this is still a bit immature, so you may experience dropouts or
502+pitch changes in this mode.
503+
504+If you experience problems, please switch back to the "audio" sync source,
505+which is the default. You can also enable vsync when using the "audio" sync
506+source by changing the "vsync" setting. This will generally work okay as long
507+as the emulated refresh rate is below your monitor refresh rate (even if only
508+slightly), but you will occassionally get a doubled frame (or frequently if
509+the refresh rates are very different).
510+
511+Turbo mode will currently not work when vsync is on, regardless of which sync
512+source is used. Slow mode will work with "audio" sync, but not "video" sync.
513+
514+--------------
515+
516+My work has been made much easier by the contributions of those in the Genesis
517+community past and present. I'd like to thank the people below for their help.
518+
519+Nemesis - His work reverse engineering and documenting the VDP and
520+ YM-2612 has saved me an immeasurable amount of time. I've
521+ found both his sprite overflow test ROM and VDP FIFO
522+ Testing ROM to be quite helpful.
523+
524+Charles MacDonald - While it hasn't been updated in a while, I still find his
525+ VDP document to be my favorite reference. His Genesis
526+ hardware document has also come in handy.
527+
528+Eke-Eke - Eke-Eke wrote a great document on the use of I2C EEPROM in
529+ Genesis games and also left some useful very helpful
530+ comments about problematic games in Genesis Plus GX
531+
532+Sauraen - Sauraen has analyzed the YM2203 and YM2612 dies and written
533+ a VHDL operator implementation. These have been useful in
534+ improving the accuracy of my YM2612 core.
535+
536+Alexey Khokholov - Alexey (aka Nuke.YKT) has analyzed the YM3438 die and written
537+ a fairly direct C implementation from that analysis. This
538+ has been a useful reference for verifying and improving my
539+ YM2612 core.
540+
541+Bart Trzynadlowski - His documents on the Genecyst save-state format and the
542+ mapper used in Super Street Fighter 2 were definitely
543+ appreciated.
544+
545+KanedaFR - Kaneda's SpritesMind forum is a great resource for the
546+ Sega development community.
547+
548+Titan - Titan has created what are without a doubt the most
549+ impressive demos on the Megadrive. Additionally, I am very
550+ grateful for the documentation provided by Kabuto and the
551+ assistance of Kabuto, Sik and Jorge in getting Overdrive 2
552+ to run properly in BlastEm.
553+
554+flamewing - flamewing created a very handy exhaustive test ROM for 68K
555+ BCD instructions and documented the proper behavior for
556+ certain BCD edge cases
557+
558+r57shell - r57shell created a test ROM for 68K instruction sizes that
559+ was invaluable in fixing the remaining bugs in my 68K instruction
560+ decoder
561+
562+I'd also like to thank the following people who have performed compatibility
563+testing or submitted helpful bug reports
564+
565+micky, Sasha, lol-frank, Sik, Tim Lawrence, ComradeOj, Vladikcomper
566+
567+License
568+-------
569+
570+BlastEm is free software distributed under the terms of the GNU General Public
571+License version 3 or higher. This gives you the right to redistribute and/or
572+modify the program as long as you follow the terms of the license. See the file
573+COPYING for full license details.
574+
575+Binary releases of BlastEm are packaged with GLEW, SDL2 and zlib which have their
576+own licenses. See GLEW-LICENSE and SDL-LICENSE for details. For zlib license
577+information, please see zlib.h in the source code release.
578+
+192,
-0
1@@ -0,0 +1,192 @@
2+#!/usr/bin/env python
3+
4+#OLD
5+#0 - !SE
6+#1 - !CAS
7+#2 - A0
8+#3 - A1
9+#------
10+#4 - A2
11+#5 - A3
12+#6 - A7
13+#7 - EDCLK
14+#------
15+#8 - !HSYNC
16+#9 - A4
17+#A - A5
18+#B - A6
19+#------
20+#C - !RAS
21+#D - !WB/!WE
22+#E - !DT/!OE
23+#F - SC
24+
25+#NEW
26+#0 - !IPL2
27+#1 - !CAS
28+#2 - A0
29+#3 - A1
30+#------
31+#4 - A2
32+#5 - A3
33+#6 - A7
34+#7 - !HSYNC
35+#------
36+#8 - !VSYNC
37+#9 - A4
38+#A - A5
39+#B - A6
40+#------
41+#C - !RAS
42+#D - !WB/!WE
43+#E - !DT/!OE
44+#F - SC
45+
46+
47+#VRAM swizzling
48+#A0 = V0
49+#A1 = V1
50+#A8 = V2
51+#A9 = V3
52+#A10 = V4
53+#A11 = V5
54+#A12 = V6
55+#A13 = V7
56+#A14 = V8
57+#A15 = V9
58+#--guesses follow--
59+#A2 = V10
60+#A3 = V11
61+#A4 = V12
62+#A5 = V13
63+#A6 = V14
64+#A7 = V15
65+
66+
67+def get_addr(sample):
68+ return ((sample >> 2) & 0xF) | ((sample >> 5) & 0x70) | ((sample << 1) & 0x80)
69+
70+def swizzle_addr(addr):
71+ return (addr & 0x0003) | ((addr >> 6) & 0x03FC) | ((addr << 8) & 0xFC00)
72+
73+def print_addr_op(addr, addr_format, mode, samplenum, triggerpos, rate):
74+ print '{0:{1}} ({2:{1}}) {3}@{4} ns'.format(swizzle_addr(addr), addr_format, addr, mode, (samplenum - triggerpos)*rate)
75+
76+def detect_rise(last, sample, bit):
77+ mask = 1 << bit
78+ return (not last & mask) and (sample & mask)
79+
80+def detect_fall(last, sample, bit):
81+ mask = 1 << bit
82+ return (last & mask) and (not sample & mask)
83+
84+def detect_high(sample, bit):
85+ mask = 1 << bit
86+ return sample & mask
87+
88+
89+ipl2 = 0x0
90+cas = 0x1
91+ras = 0xC
92+vsync = 0x8
93+hsync = 0x7
94+wewb = 0xD
95+oedt = 0xE
96+sc = 0xF
97+
98+last = False
99+state = 'begin'
100+triggerpos = 0
101+readcounter = 0
102+sillyread = 0
103+lastaddr = -1
104+edclk_ticks = 0
105+sc_ticks = 0
106+tick_start = False
107+#f = open('street_fighter_vram_100mhz_hsync_trig_2.ols')
108+#f = open('street_fighter_vram_50mhz_hsync_trig.ols')
109+from sys import argv,exit
110+if len(argv) < 2:
111+ print 'usage: analyze.py filename'
112+ exit(1)
113+if '-b' in argv:
114+ addr_format = '016b'
115+else:
116+ addr_format = '04X'
117+f = open(argv[1])
118+for line in f:
119+ if line.startswith(';TriggerPosition'):
120+ _,_,triggerpos = line.partition(':')
121+ triggerpos = int(triggerpos.strip())
122+ elif line.startswith(';Rate'):
123+ _,_,rate = line.partition(':')
124+ #convert to nanoseconds between samples
125+ rate = (1.0/float(rate.strip())) * 1000000000.0
126+ elif not line.startswith(';'):
127+ sample,_,samplenum = line.partition('@')
128+ samplenum = int(samplenum.strip())
129+ sample = int(sample, 16)
130+ if detect_rise(last, sample, sc):
131+ sc_ticks += 1
132+ if not (last is False):
133+ #detect falling edge of !HSYNC
134+ if detect_fall(last, sample, hsync):
135+ if readcounter:
136+ print readcounter, 'reads,', sillyread, 'redundant reads'
137+ readcounter = sillyread = 0
138+ if not tick_start is False:
139+ print 'SC:', sc_ticks, ' ticks, {0}MHz'.format(float(sc_ticks)/((rate * (samplenum-tick_start)) / 1000.0))
140+ tick_start = samplenum
141+ edclk_ticks = sc_ticks = 0
142+ print 'HSYNC Start @ {0} ns'.format((samplenum - triggerpos)*rate)
143+ #detect rising edge of !HSYNC
144+ elif detect_rise(last, sample, hsync):
145+ if not tick_start is False:
146+ float(edclk_ticks)/((rate * (samplenum-tick_start)) / 1000.0)
147+ print 'EDCLK:', edclk_ticks, ' ticks, {0}MHz'.format(float(edclk_ticks)/((rate * (samplenum-tick_start)) / 1000.0))
148+ print 'SC:', sc_ticks, ' ticks, {0}MHz'.format(float(sc_ticks)/((rate * (samplenum-tick_start)) / 1000.0))
149+ tick_start = samplenum
150+ edclk_ticks = sc_ticks = 0
151+ print 'HSYNC End @ {0} ns'.format((samplenum - triggerpos)*rate)
152+ if detect_fall(last, sample, vsync):
153+ print 'VSYNC Start @ {0} ns'.format((samplenum - triggerpos)*rate)
154+ elif detect_rise(last, sample, vsync):
155+ print 'VSYNC End @ {0} ns'.format((samplenum - triggerpos)*rate)
156+ if detect_fall(last, sample, ipl2):
157+ print 'IPL2 Low @ {0} ns'.format((samplenum - triggerpos)*rate)
158+ elif detect_rise(last, sample, ipl2):
159+ print 'IPL2 High @ {0} ns'.format((samplenum - triggerpos)*rate)
160+ if state == 'begin':
161+ #detect falling edge of !RAS
162+ if detect_fall(last, sample, ras):
163+ state = 'ras'
164+ row = get_addr(sample)
165+ mode = 'ram' if detect_high(sample, oedt) else 'read transfer'
166+ elif detect_fall(last, sample, cas) and detect_high(sample, oedt):
167+ state = 'cas'
168+ elif state == 'ras':
169+ if detect_fall(last, sample, cas):
170+ state = 'begin'
171+ col = get_addr(sample)
172+ addr = (row << 8) | col
173+ if mode == 'ram':
174+ state = 'ras_cas'
175+ else:
176+ print_addr_op(addr, addr_format, mode, samplenum, triggerpos, rate)
177+ lastaddr = addr
178+ #print '{0:04X} {1} - {2:02X}:{3:02X} - {0:016b}'.format(addr, mode, row, col)
179+ elif state == 'cas':
180+ if detect_fall(last, sample, ras):
181+ state = 'begin'
182+ print 'refresh@{0} ns'.format((samplenum - triggerpos)*rate)
183+ elif state == 'ras_cas':
184+ if detect_fall(last, sample, oedt):
185+ readcounter += 1
186+ if addr == lastaddr:
187+ sillyread += 1
188+ print_addr_op(addr, addr_format, 'read', samplenum, triggerpos, rate)
189+ state = 'begin'
190+ elif detect_fall(last, sample, wewb):
191+ print_addr_op(addr, addr_format, 'write', samplenum, triggerpos, rate)
192+ state = 'begin'
193+ last = sample
+197,
-0
1@@ -0,0 +1,197 @@
2+#!/usr/bin/env python
3+
4+from zipfile import ZipFile
5+from sys import exit, argv
6+
7+def detect_rise(last, sample, bit):
8+ mask = 1 << bit
9+ return (not last & mask) and (sample & mask)
10+
11+def detect_fall(last, sample, bit):
12+ mask = 1 << bit
13+ return (last & mask) and (not sample & mask)
14+
15+def detect_high(sample, bit):
16+ mask = 1 << bit
17+ return sample & mask
18+
19+def detect_low(sample, bit):
20+ mask = 1 << bit
21+ return not sample & mask
22+
23+def get_value(sample, bits):
24+ value = 0
25+ for i in xrange(0, len(bits)):
26+ bit = bits[i]
27+ value |= (sample >> bit & 1) << i
28+ return value
29+
30+def swizzle_mode4(row, col):
31+ return (col & 1) | (row << 1) | (col << 8 & 0xFE00)
32+
33+def analyze_delays(chanmap, datafile):
34+ if 'M68K_CLK' in chanmap:
35+ m68k_clk = chanmap['M68K CLK']
36+ elif 'CLK' in chanmap:
37+ m68k_clk = chanmap['CLK']
38+ m_as = chanmap['!AS']
39+ ram_oe = chanmap['RAM !LOE/!RFSH']
40+ ram_ce = chanmap['RAM !CE']
41+ last = False
42+ prev = False
43+ prevRefresh = False
44+ clks = 0
45+ as_start = 0
46+ for line in datafile.readlines():
47+ line = line.strip()
48+ if line and not line.startswith(';'):
49+ sample,_,num = line.partition('@')
50+ sample = int(sample, 16)
51+ if not (last is False):
52+ if detect_rise(last, sample, m68k_clk):
53+ clks = clks + 1
54+ if detect_rise(last, sample, m_as):
55+ as_clks = clks - as_start
56+ if as_clks > 2:
57+ if not (prev is False):
58+ print '!AS held for', as_clks, 'cycles starting (delay of ' + str(as_clks - 2) + ') at', as_start, 'and ending at', clks, 'delta since last delay:', as_start - prev
59+ else:
60+ print '!AS held for', as_clks, 'cycles starting (delay of ' + str(as_clks - 2) + ') at', as_start, 'and ending at', clks
61+ prev = as_start
62+ elif detect_fall(last, sample, m_as):
63+ as_start = clks
64+ if detect_fall(last, sample, ram_oe) and detect_high( sample, ram_ce):
65+ if prevRefresh is False:
66+ print 'RAM refresh at ', clks
67+ else:
68+ print 'RAM refresh at', clks, 'delta since last:', clks-prevRefresh
69+ prevRefresh = clks
70+ last = sample
71+
72+def analyze_refresh(chanmap, datafile):
73+ if 'M68K_CLK' in chanmap:
74+ m68k_clk = chanmap['M68K CLK']
75+ elif 'CLK' in chanmap:
76+ m68k_clk = chanmap['CLK']
77+ ram_oe = chanmap['RAM !LOE/!RFSH']
78+ ram_ce = chanmap['RAM !CE']
79+ clks = 0
80+ last = False
81+ prevRefresh = False
82+ for line in datafile.readlines():
83+ line = line.strip()
84+ if line and not line.startswith(';'):
85+ sample,_,num = line.partition('@')
86+ sample = int(sample, 16)
87+ if not (last is False):
88+ if detect_rise(last, sample, m68k_clk):
89+ clks = clks + 1
90+ if detect_fall(last, sample, ram_oe) and detect_high( sample, ram_ce):
91+ if prevRefresh is False:
92+ print 'RAM refresh at ', clks
93+ else:
94+ print 'RAM refresh at', clks, 'delta since last:', clks-prevRefresh
95+ prevRefresh = clks
96+ last = sample
97+
98+
99+table_start = 0x3800
100+table_end = table_start + 0x600
101+sat_start = 0x3E00 #0x3F00
102+sat_xname = sat_start + 0x80
103+sat_end = sat_start + 0x100
104+
105+
106+def analyze_vram(chanmap, datafile):
107+ address_bits = [chanmap['AD{0}'.format(i)] for i in xrange(0, 8)]
108+ ras = chanmap['!RAS']
109+ cas = chanmap['!CAS']
110+ hsync = chanmap['!HSYNC']
111+ state = 'begin'
112+ last = False
113+ for line in datafile.readlines():
114+ line = line.strip()
115+ if line and not line.startswith(';'):
116+ sample,_,num = line.partition('@')
117+ sample = int(sample, 16)
118+ if not (last is False):
119+ if detect_fall(last, sample, hsync):
120+ print 'HSYNC low @ {0}'.format(num)
121+ elif detect_rise(last, sample, hsync):
122+ print 'HSYNC high @ {0}'.format(num)
123+ if state == 'begin':
124+ if detect_fall(last, sample, ras):
125+ state = 'ras'
126+ row = get_value(sample, address_bits)
127+ elif detect_fall(last, sample, cas):
128+ state = 'cas'
129+ elif state == 'ras':
130+ if detect_fall(last, sample, cas):
131+ col = get_value(sample, address_bits)
132+ address = swizzle_mode4(row, col)
133+
134+ if address < table_end and address >= table_start:
135+ offset = (address - table_start)/2
136+ desc = 'Map Row {0} Col {1}'.format(offset / 32, offset & 31)
137+ elif address >= sat_start and address < sat_xname:
138+ offset = address - sat_start
139+ desc = 'Sprite {0} Y Read'.format(offset)
140+ elif address >= sat_xname and address < sat_end:
141+ offset = address - sat_xname
142+ desc = 'Sprite {0} X/Name Read'.format(offset / 2)
143+ else:
144+ desc = 'Tile {0} Row {1}'.format(address / 32, ((address / 4) & 7) + (0.5 if address & 2 else 0))
145+ print '{0:02X}:{1:02X} - {2:04X} @ {3} - {4}'.format(row, col, address, num, desc)
146+ state = 'begin'
147+ elif state == 'cas':
148+ if detect_fall(last, sample, ras):
149+ print 'refresh @ {0}'.format(num)
150+ state = 'begin'
151+ last = sample
152+
153+def analyze_z80_mreq(chanmap, datafile):
154+ m1 = chanmap['!M1']
155+ mreq = chanmap['!MREQ']
156+ addressMask = 0x3FF
157+ last = None
158+ lastWasM1 = False
159+ for line in datafile.readlines():
160+ line = line.strip()
161+ if line and not line.startswith(';'):
162+ sample,_,num = line.partition('@')
163+ sample = int(sample, 16)
164+ if not (last is None):
165+ if detect_rise(last, sample, mreq):
166+ address = last & addressMask
167+ if detect_low(last, m1):
168+ print 'M1 read {0:02X} @ {1}'.format(address, num)
169+ lastWasM1 = True
170+ elif lastWasM1:
171+ print 'Refresh {0:02X} @ {1}'.format(address, num)
172+ lastWasM1 = False
173+ else:
174+ print 'Access {0:02X} @ {1}'.format(address, num)
175+ last = sample
176+
177+def main(args):
178+ if len(args) < 2:
179+ print 'Usage: analyze_olp.py filename'
180+ exit(1)
181+ olpfile = ZipFile(args[1], "r")
182+ channelfile = olpfile.open('channel.labels')
183+ channels = [line.strip() for line in channelfile.readlines()]
184+ channelfile.close()
185+ print channels
186+ chanmap = {}
187+ for i in xrange(0, len(channels)):
188+ chanmap[channels[i]] = i
189+ datafile = olpfile.open('data.ols')
190+ #analyze_delays(chanmap, datafile)
191+ #analyze_vram(chanmap, datafile)
192+ #analyze_refresh(chanmap, datafile)
193+ analyze_z80_mreq(chanmap, datafile)
194+ datafile.close()
195+
196+
197+if __name__ == '__main__':
198+ main(argv)
A
arena.c
+89,
-0
1@@ -0,0 +1,89 @@
2+/*
3+ Copyright 2015 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#include <stdlib.h>
8+#include <stdint.h>
9+#include "arena.h"
10+
11+struct arena {
12+ void **used_blocks;
13+ void **free_blocks;
14+
15+ size_t used_count;
16+ size_t used_storage;
17+ size_t free_count;
18+ size_t free_storage;
19+};
20+
21+#define DEFAULT_STORAGE_SIZE 8
22+
23+static arena *current_arena;
24+
25+arena *get_current_arena()
26+{
27+ if (!current_arena) {
28+ current_arena = calloc(1, sizeof(arena));
29+ }
30+ return current_arena;
31+}
32+
33+arena *set_current_arena(arena *a)
34+{
35+ arena *tmp = current_arena;
36+ current_arena = a;
37+ return tmp;
38+}
39+
40+arena *start_new_arena()
41+{
42+ arena *tmp = current_arena;
43+ current_arena = NULL;
44+ return tmp;
45+}
46+
47+void track_block(void *block)
48+{
49+ arena *cur = get_current_arena();
50+ if (cur->used_count == cur->used_storage) {
51+ if (cur->used_storage) {
52+ cur->used_storage *= 2;
53+ } else {
54+ cur->used_storage = DEFAULT_STORAGE_SIZE;
55+ }
56+ cur->used_blocks = realloc(cur->used_blocks, cur->used_storage * sizeof(void *));
57+ }
58+ cur->used_blocks[cur->used_count++] = block;
59+}
60+
61+void mark_all_free()
62+{
63+ arena *cur = get_current_arena();
64+ if (!cur->free_blocks) {
65+ cur->free_blocks = cur->used_blocks;
66+ cur->free_storage = cur->used_storage;
67+ cur->free_count = cur->used_count;
68+ cur->used_count = cur->used_storage = 0;
69+ cur->used_blocks = NULL;
70+ } else {
71+ if (cur->free_storage < cur->used_count + cur->free_count) {
72+ cur->free_storage = cur->used_count + cur->free_count;
73+ cur->free_blocks = realloc(cur->free_blocks, cur->free_storage * sizeof(void*));
74+ }
75+ for (; cur->used_count > 0; cur->used_count--)
76+ {
77+ cur->free_blocks[cur->free_count++] = cur->used_blocks[cur->used_count-1];
78+ }
79+ }
80+}
81+
82+void *try_alloc_arena()
83+{
84+ if (!current_arena || !current_arena->free_count) {
85+ return NULL;
86+ }
87+ void *ret = current_arena->free_blocks[--current_arena->free_count];
88+ track_block(ret);
89+ return ret;
90+}
A
arena.h
+18,
-0
1@@ -0,0 +1,18 @@
2+/*
3+ Copyright 2015 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#ifndef ARENA_H_
8+#define ARENA_H_
9+
10+typedef struct arena arena;
11+
12+arena *get_current_arena();
13+arena *set_current_arena(arena *a);
14+arena *start_new_arena();
15+void track_block(void *block);
16+void mark_all_free();
17+void *try_alloc_arena();
18+
19+#endif //ARENA_H_
+1,
-0
1@@ -0,0 +1 @@
2+arrow.png,16,0,raw,nopal,interlace,sprite
+0,
-0
+247,
-0
1@@ -0,0 +1,247 @@
2+/*
3+ Copyright 2013 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#include "backend.h"
8+#include <stdlib.h>
9+
10+deferred_addr * defer_address(deferred_addr * old_head, uint32_t address, uint8_t *dest)
11+{
12+ deferred_addr * new_head = malloc(sizeof(deferred_addr));
13+ new_head->next = old_head;
14+ new_head->address = address & 0xFFFFFF;
15+ new_head->dest = dest;
16+ return new_head;
17+}
18+
19+void remove_deferred_until(deferred_addr **head_ptr, deferred_addr * remove_to)
20+{
21+ for(deferred_addr *cur = *head_ptr; cur && cur != remove_to; cur = *head_ptr)
22+ {
23+ *head_ptr = cur->next;
24+ free(cur);
25+ }
26+}
27+
28+void process_deferred(deferred_addr ** head_ptr, void * context, native_addr_func get_native)
29+{
30+ deferred_addr * cur = *head_ptr;
31+ deferred_addr **last_next = head_ptr;
32+ while(cur)
33+ {
34+ code_ptr native = get_native(context, cur->address);//get_native_address(opts->native_code_map, cur->address);
35+ if (native) {
36+ int32_t disp = native - (cur->dest + 4);
37+ code_ptr out = cur->dest;
38+ *(out++) = disp;
39+ disp >>= 8;
40+ *(out++) = disp;
41+ disp >>= 8;
42+ *(out++) = disp;
43+ disp >>= 8;
44+ *out = disp;
45+ *last_next = cur->next;
46+ free(cur);
47+ cur = *last_next;
48+ } else {
49+ last_next = &(cur->next);
50+ cur = cur->next;
51+ }
52+ }
53+}
54+
55+memmap_chunk const *find_map_chunk(uint32_t address, cpu_options *opts, uint16_t flags, uint32_t *size_sum)
56+{
57+ if (size_sum) {
58+ *size_sum = 0;
59+ }
60+ address &= opts->address_mask;
61+ for (memmap_chunk const *cur = opts->memmap, *end = opts->memmap + opts->memmap_chunks; cur != end; cur++)
62+ {
63+ if (address >= cur->start && address < cur->end) {
64+ return cur;
65+ } else if (size_sum && (cur->flags & flags) == flags) {
66+ *size_sum += chunk_size(opts, cur);
67+ }
68+ }
69+ return NULL;
70+}
71+
72+void * get_native_pointer(uint32_t address, void ** mem_pointers, cpu_options * opts)
73+{
74+ memmap_chunk const * memmap = opts->memmap;
75+ address &= opts->address_mask;
76+ for (uint32_t chunk = 0; chunk < opts->memmap_chunks; chunk++)
77+ {
78+ if (address >= memmap[chunk].start && address < memmap[chunk].end) {
79+ if (!(memmap[chunk].flags & (MMAP_READ|MMAP_READ_CODE))) {
80+ return NULL;
81+ }
82+ uint8_t * base = memmap[chunk].flags & MMAP_PTR_IDX
83+ ? mem_pointers[memmap[chunk].ptr_index]
84+ : memmap[chunk].buffer;
85+ if (!base) {
86+ if (memmap[chunk].flags & MMAP_AUX_BUFF) {
87+ return memmap[chunk].buffer + (address & memmap[chunk].aux_mask);
88+ }
89+ return NULL;
90+ }
91+ return base + (address & memmap[chunk].mask);
92+ }
93+ }
94+ return NULL;
95+}
96+
97+void * get_native_write_pointer(uint32_t address, void ** mem_pointers, cpu_options * opts)
98+{
99+ memmap_chunk const * memmap = opts->memmap;
100+ address &= opts->address_mask;
101+ for (uint32_t chunk = 0; chunk < opts->memmap_chunks; chunk++)
102+ {
103+ if (address >= memmap[chunk].start && address < memmap[chunk].end) {
104+ if (!(memmap[chunk].flags & (MMAP_WRITE))) {
105+ return NULL;
106+ }
107+ uint8_t * base = memmap[chunk].flags & MMAP_PTR_IDX
108+ ? mem_pointers[memmap[chunk].ptr_index]
109+ : memmap[chunk].buffer;
110+ if (!base) {
111+ if (memmap[chunk].flags & MMAP_AUX_BUFF) {
112+ return memmap[chunk].buffer + (address & memmap[chunk].aux_mask);
113+ }
114+ return NULL;
115+ }
116+ return base + (address & memmap[chunk].mask);
117+ }
118+ }
119+ return NULL;
120+}
121+
122+uint16_t read_word(uint32_t address, void **mem_pointers, cpu_options *opts, void *context)
123+{
124+ memmap_chunk const *chunk = find_map_chunk(address, opts, 0, NULL);
125+ if (!chunk) {
126+ return 0xFFFF;
127+ }
128+ uint32_t offset = address & chunk->mask;
129+ if (chunk->flags & MMAP_READ) {
130+ uint8_t *base;
131+ if (chunk->flags & MMAP_PTR_IDX) {
132+ base = mem_pointers[chunk->ptr_index];
133+ } else {
134+ base = chunk->buffer;
135+ }
136+ if (base) {
137+ uint16_t val;
138+ if ((chunk->flags & MMAP_ONLY_ODD) || (chunk->flags & MMAP_ONLY_EVEN)) {
139+ offset /= 2;
140+ val = base[offset];
141+ if (chunk->flags & MMAP_ONLY_ODD) {
142+ val |= 0xFF00;
143+ } else {
144+ val = val << 8 | 0xFF;
145+ }
146+ } else {
147+ val = *(uint16_t *)(base + offset);
148+ }
149+ return val;
150+ }
151+ }
152+ if ((!(chunk->flags & MMAP_READ) || (chunk->flags & MMAP_FUNC_NULL)) && chunk->read_16) {
153+ return chunk->read_16(offset, context);
154+ }
155+ return 0xFFFF;
156+}
157+
158+uint8_t read_byte(uint32_t address, void **mem_pointers, cpu_options *opts, void *context)
159+{
160+ memmap_chunk const *chunk = find_map_chunk(address, opts, 0, NULL);
161+ if (!chunk) {
162+ return 0xFF;
163+ }
164+ uint32_t offset = address & chunk->mask;
165+ if (chunk->flags & MMAP_READ) {
166+ uint8_t *base;
167+ if (chunk->flags & MMAP_PTR_IDX) {
168+ base = mem_pointers[chunk->ptr_index];
169+ } else {
170+ base = chunk->buffer;
171+ }
172+ if (base) {
173+ if ((chunk->flags & MMAP_ONLY_ODD) || (chunk->flags & MMAP_ONLY_EVEN)) {
174+ if (address & 1) {
175+ if (chunk->flags & MMAP_ONLY_EVEN) {
176+ return 0xFF;
177+ }
178+ } else if (chunk->flags & MMAP_ONLY_ODD) {
179+ return 0xFF;
180+ }
181+ offset /= 2;
182+ }
183+ return base[offset];
184+ }
185+ }
186+ if ((!(chunk->flags & MMAP_READ) || (chunk->flags & MMAP_FUNC_NULL)) && chunk->read_8) {
187+ return chunk->read_8(offset, context);
188+ }
189+ return 0xFF;
190+}
191+
192+void write_byte(uint32_t address, uint8_t value, void **mem_pointers, cpu_options *opts, void *context)
193+{
194+ memmap_chunk const *chunk = find_map_chunk(address, opts, 0, NULL);
195+ if (!chunk) {
196+ return;
197+ }
198+ uint32_t offset = address & chunk->mask;
199+ if (chunk->flags & MMAP_WRITE) {
200+ uint8_t *base;
201+ if (chunk->flags & MMAP_PTR_IDX) {
202+ base = mem_pointers[chunk->ptr_index];
203+ } else {
204+ base = chunk->buffer;
205+ }
206+ if (base) {
207+ if ((chunk->flags & MMAP_ONLY_ODD) || (chunk->flags & MMAP_ONLY_EVEN)) {
208+ if (address & 1) {
209+ if (chunk->flags & MMAP_ONLY_EVEN) {
210+ return;
211+ }
212+ } else if (chunk->flags & MMAP_ONLY_ODD) {
213+ return;
214+ }
215+ offset /= 2;
216+ }
217+ base[offset] = value;
218+ }
219+ }
220+ if ((!(chunk->flags & MMAP_WRITE) || (chunk->flags & MMAP_FUNC_NULL)) && chunk->write_8) {
221+ chunk->write_8(offset, context, value);
222+ }
223+}
224+
225+uint32_t chunk_size(cpu_options *opts, memmap_chunk const *chunk)
226+{
227+ if (chunk->mask == opts->address_mask) {
228+ return chunk->end - chunk->start;
229+ } else {
230+ return chunk->mask + 1;
231+ }
232+}
233+
234+uint32_t ram_size(cpu_options *opts)
235+{
236+ uint32_t size = 0;
237+ for (int i = 0; i < opts->memmap_chunks; i++)
238+ {
239+ if (opts->memmap[i].flags & MMAP_CODE) {
240+ if (opts->memmap[i].mask == opts->address_mask) {
241+ size += opts->memmap[i].end - opts->memmap[i].start;
242+ } else {
243+ size += opts->memmap[i].mask + 1;
244+ }
245+ }
246+ }
247+ return size;
248+}
+107,
-0
1@@ -0,0 +1,107 @@
2+/*
3+ Copyright 2013 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#ifndef BACKEND_H_
8+#define BACKEND_H_
9+
10+#include <stdint.h>
11+#include <stdio.h>
12+#include "gen.h"
13+
14+#define INVALID_OFFSET 0xFFFFFFFF
15+#define EXTENSION_WORD 0xFFFFFFFE
16+#define CYCLE_NEVER 0xFFFFFFFF
17+
18+#if defined(X86_32) || defined(X86_64)
19+typedef struct {
20+ int32_t disp;
21+ uint8_t mode;
22+ uint8_t base;
23+ uint8_t index;
24+} host_ea;
25+#else
26+typedef struct {
27+ int32_t disp;
28+ uint8_t mode;
29+ uint8_t base;
30+} host_ea;
31+#endif
32+
33+typedef struct {
34+ uint8_t *base;
35+ int32_t *offsets;
36+} native_map_slot;
37+
38+typedef struct deferred_addr {
39+ struct deferred_addr *next;
40+ code_ptr dest;
41+ uint32_t address;
42+} deferred_addr;
43+
44+#include "memmap.h"
45+#include "system.h"
46+
47+typedef struct {
48+ uint32_t flags;
49+ native_map_slot *native_code_map;
50+ deferred_addr *deferred;
51+ code_info code;
52+ uint8_t **ram_inst_sizes;
53+ memmap_chunk const *memmap;
54+ code_ptr save_context;
55+ code_ptr load_context;
56+ code_ptr handle_cycle_limit;
57+ code_ptr handle_cycle_limit_int;
58+ code_ptr handle_code_write;
59+ code_ptr handle_align_error_write;
60+ code_ptr handle_align_error_read;
61+ system_str_fun_r8 debug_cmd_handler;
62+ uint32_t memmap_chunks;
63+ uint32_t address_mask;
64+ uint32_t max_address;
65+ uint32_t bus_cycles;
66+ uint32_t clock_divider;
67+ uint32_t move_pc_off;
68+ uint32_t move_pc_size;
69+ int32_t mem_ptr_off;
70+ int32_t ram_flags_off;
71+ uint8_t ram_flags_shift;
72+ uint8_t address_size;
73+ uint8_t byte_swap;
74+ int8_t context_reg;
75+ int8_t cycles;
76+ int8_t limit;
77+ int8_t scratch1;
78+ int8_t scratch2;
79+ uint8_t align_error_mask;
80+} cpu_options;
81+
82+typedef uint8_t * (*native_addr_func)(void * context, uint32_t address);
83+
84+deferred_addr * defer_address(deferred_addr * old_head, uint32_t address, uint8_t *dest);
85+void remove_deferred_until(deferred_addr **head_ptr, deferred_addr * remove_to);
86+void process_deferred(deferred_addr ** head_ptr, void * context, native_addr_func get_native);
87+
88+void cycles(cpu_options *opts, uint32_t num);
89+void check_cycles_int(cpu_options *opts, uint32_t address);
90+void check_cycles(cpu_options * opts);
91+void check_code_prologue(code_info *code);
92+void log_address(cpu_options *opts, uint32_t address, char * format);
93+
94+void retranslate_calc(cpu_options *opts);
95+void patch_for_retranslate(cpu_options *opts, code_ptr native_address, code_ptr handler);
96+
97+code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk const * memmap, uint32_t num_chunks, ftype fun_type, code_ptr *after_inc);
98+void * get_native_pointer(uint32_t address, void ** mem_pointers, cpu_options * opts);
99+void * get_native_write_pointer(uint32_t address, void ** mem_pointers, cpu_options * opts);
100+uint16_t read_word(uint32_t address, void **mem_pointers, cpu_options *opts, void *context);
101+uint8_t read_byte(uint32_t address, void **mem_pointers, cpu_options *opts, void *context);
102+void write_byte(uint32_t address, uint8_t value, void **mem_pointers, cpu_options *opts, void *context);
103+memmap_chunk const *find_map_chunk(uint32_t address, cpu_options *opts, uint16_t flags, uint32_t *size_sum);
104+uint32_t chunk_size(cpu_options *opts, memmap_chunk const *chunk);
105+uint32_t ram_size(cpu_options *opts);
106+
107+#endif //BACKEND_H_
108+
+322,
-0
1@@ -0,0 +1,322 @@
2+#include "backend.h"
3+#include "gen_x86.h"
4+#include <string.h>
5+
6+void cycles(cpu_options *opts, uint32_t num)
7+{
8+ if (opts->limit < 0) {
9+ sub_ir(&opts->code, num*opts->clock_divider, opts->cycles, SZ_D);
10+ } else {
11+ add_ir(&opts->code, num*opts->clock_divider, opts->cycles, SZ_D);
12+ }
13+}
14+
15+void check_cycles_int(cpu_options *opts, uint32_t address)
16+{
17+ code_info *code = &opts->code;
18+ uint8_t cc;
19+ if (opts->limit < 0) {
20+ cmp_ir(code, 1, opts->cycles, SZ_D);
21+ cc = CC_NS;
22+ } else {
23+ cmp_rr(code, opts->cycles, opts->limit, SZ_D);
24+ cc = CC_A;
25+ }
26+ code_ptr jmp_off = code->cur+1;
27+ jcc(code, cc, jmp_off+1);
28+ mov_ir(code, address, opts->scratch1, SZ_D);
29+ call(code, opts->handle_cycle_limit_int);
30+ *jmp_off = code->cur - (jmp_off+1);
31+}
32+
33+void retranslate_calc(cpu_options *opts)
34+{
35+ code_info *code = &opts->code;
36+ code_info tmp = *code;
37+ uint8_t cc;
38+ if (opts->limit < 0) {
39+ cmp_ir(code, 1, opts->cycles, SZ_D);
40+ cc = CC_NS;
41+ } else {
42+ cmp_rr(code, opts->cycles, opts->limit, SZ_D);
43+ cc = CC_A;
44+ }
45+ jcc(code, cc, code->cur+2);
46+ opts->move_pc_off = code->cur - tmp.cur;
47+ mov_ir(code, 0x1234, opts->scratch1, SZ_D);
48+ opts->move_pc_size = code->cur - tmp.cur - opts->move_pc_off;
49+ *code = tmp;
50+}
51+
52+void patch_for_retranslate(cpu_options *opts, code_ptr native_address, code_ptr handler)
53+{
54+ if (!is_mov_ir(native_address)) {
55+ //instruction is not already patched for either retranslation or a breakpoint
56+ //copy original mov_ir instruction containing PC to beginning of native code area
57+ memmove(native_address, native_address + opts->move_pc_off, opts->move_pc_size);
58+ }
59+ //jump to the retranslation handler
60+ code_info tmp = {
61+ .cur = native_address + opts->move_pc_size,
62+ .last = native_address + 256,
63+ .stack_off = 0
64+ };
65+ jmp(&tmp, handler);
66+}
67+
68+void check_cycles(cpu_options * opts)
69+{
70+ code_info *code = &opts->code;
71+ uint8_t cc;
72+ if (opts->limit < 0) {
73+ cmp_ir(code, 1, opts->cycles, SZ_D);
74+ cc = CC_NS;
75+ } else {
76+ cmp_rr(code, opts->cycles, opts->limit, SZ_D);
77+ cc = CC_A;
78+ }
79+ check_alloc_code(code, MAX_INST_LEN*2);
80+ code_ptr jmp_off = code->cur+1;
81+ jcc(code, cc, jmp_off+1);
82+ call(code, opts->handle_cycle_limit);
83+ *jmp_off = code->cur - (jmp_off+1);
84+}
85+
86+void log_address(cpu_options *opts, uint32_t address, char * format)
87+{
88+ code_info *code = &opts->code;
89+ call(code, opts->save_context);
90+ push_r(code, opts->context_reg);
91+ mov_rr(code, opts->cycles, RDX, SZ_D);
92+ mov_ir(code, (int64_t)format, RDI, SZ_PTR);
93+ mov_ir(code, address, RSI, SZ_D);
94+ call_args_abi(code, (code_ptr)printf, 3, RDI, RSI, RDX);
95+ pop_r(code, opts->context_reg);
96+ call(code, opts->load_context);
97+}
98+
99+void check_code_prologue(code_info *code)
100+{
101+ check_alloc_code(code, MAX_INST_LEN*4);
102+}
103+
104+code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk const * memmap, uint32_t num_chunks, ftype fun_type, code_ptr *after_inc)
105+{
106+ code_info *code = &opts->code;
107+ code_ptr start = code->cur;
108+ check_cycles(opts);
109+ uint8_t is_write = fun_type == WRITE_16 || fun_type == WRITE_8;
110+ uint8_t adr_reg = is_write ? opts->scratch2 : opts->scratch1;
111+ uint8_t size = (fun_type == READ_16 || fun_type == WRITE_16) ? SZ_W : SZ_B;
112+ if (size != SZ_B && opts->align_error_mask) {
113+ test_ir(code, opts->align_error_mask, adr_reg, SZ_D);
114+ jcc(code, CC_NZ, is_write ? opts->handle_align_error_write : opts->handle_align_error_read);
115+ }
116+ cycles(opts, opts->bus_cycles);
117+ if (after_inc) {
118+ *after_inc = code->cur;
119+ }
120+
121+ if (opts->address_size == SZ_D && opts->address_mask != 0xFFFFFFFF) {
122+ and_ir(code, opts->address_mask, adr_reg, SZ_D);
123+ } else if (opts->address_size == SZ_W && opts->address_mask != 0xFFFF) {
124+ and_ir(code, opts->address_mask, adr_reg, SZ_W);
125+ }
126+ code_ptr lb_jcc = NULL, ub_jcc = NULL;
127+ uint16_t access_flag = is_write ? MMAP_WRITE : MMAP_READ;
128+ uint32_t ram_flags_off = opts->ram_flags_off;
129+ uint32_t min_address = 0;
130+ uint32_t max_address = opts->max_address;
131+ for (uint32_t chunk = 0; chunk < num_chunks; chunk++)
132+ {
133+ if (memmap[chunk].start > min_address) {
134+ cmp_ir(code, memmap[chunk].start, adr_reg, opts->address_size);
135+ lb_jcc = code->cur + 1;
136+ jcc(code, CC_C, code->cur + 2);
137+ } else {
138+ min_address = memmap[chunk].end;
139+ }
140+ if (memmap[chunk].end < max_address) {
141+ cmp_ir(code, memmap[chunk].end, adr_reg, opts->address_size);
142+ ub_jcc = code->cur + 1;
143+ jcc(code, CC_NC, code->cur + 2);
144+ } else {
145+ max_address = memmap[chunk].start;
146+ }
147+
148+ if (memmap[chunk].mask != opts->address_mask) {
149+ and_ir(code, memmap[chunk].mask, adr_reg, opts->address_size);
150+ }
151+ void * cfun;
152+ switch (fun_type)
153+ {
154+ case READ_16:
155+ cfun = memmap[chunk].read_16;
156+ break;
157+ case READ_8:
158+ cfun = memmap[chunk].read_8;
159+ break;
160+ case WRITE_16:
161+ cfun = memmap[chunk].write_16;
162+ break;
163+ case WRITE_8:
164+ cfun = memmap[chunk].write_8;
165+ break;
166+ default:
167+ cfun = NULL;
168+ }
169+ if(memmap[chunk].flags & access_flag) {
170+ if (memmap[chunk].flags & MMAP_PTR_IDX) {
171+ if (memmap[chunk].flags & MMAP_FUNC_NULL) {
172+ cmp_irdisp(code, 0, opts->context_reg, opts->mem_ptr_off + sizeof(void*) * memmap[chunk].ptr_index, SZ_PTR);
173+ code_ptr not_null = code->cur + 1;
174+ jcc(code, CC_NZ, code->cur + 2);
175+ call(code, opts->save_context);
176+ if (is_write) {
177+ call_args_abi(code, cfun, 3, opts->scratch2, opts->context_reg, opts->scratch1);
178+ mov_rr(code, RAX, opts->context_reg, SZ_PTR);
179+ } else {
180+ push_r(code, opts->context_reg);
181+ call_args_abi(code, cfun, 2, opts->scratch1, opts->context_reg);
182+ pop_r(code, opts->context_reg);
183+ mov_rr(code, RAX, opts->scratch1, size);
184+ }
185+ jmp(code, opts->load_context);
186+
187+ *not_null = code->cur - (not_null + 1);
188+ }
189+ if ((opts->byte_swap || memmap[chunk].flags & MMAP_BYTESWAP) && size == SZ_B) {
190+ xor_ir(code, 1, adr_reg, opts->address_size);
191+ }
192+ if (opts->address_size != SZ_D) {
193+ movzx_rr(code, adr_reg, adr_reg, opts->address_size, SZ_D);
194+ }
195+ if (is_write && (memmap[chunk].flags & MMAP_CODE)) {
196+ push_r(code, adr_reg);
197+ }
198+ add_rdispr(code, opts->context_reg, opts->mem_ptr_off + sizeof(void*) * memmap[chunk].ptr_index, adr_reg, SZ_PTR);
199+ if (is_write) {
200+ mov_rrind(code, opts->scratch1, opts->scratch2, size);
201+ if (memmap[chunk].flags & MMAP_CODE) {
202+ pop_r(code, adr_reg);
203+ }
204+ } else {
205+ mov_rindr(code, opts->scratch1, opts->scratch1, size);
206+ }
207+ } else {
208+ uint8_t tmp_size = size;
209+ if (size == SZ_B) {
210+ if ((memmap[chunk].flags & MMAP_ONLY_ODD) || (memmap[chunk].flags & MMAP_ONLY_EVEN)) {
211+ bt_ir(code, 0, adr_reg, opts->address_size);
212+ code_ptr good_addr = code->cur + 1;
213+ jcc(code, (memmap[chunk].flags & MMAP_ONLY_ODD) ? CC_C : CC_NC, code->cur + 2);
214+ if (!is_write) {
215+ mov_ir(code, 0xFF, opts->scratch1, SZ_B);
216+ }
217+ retn(code);
218+ *good_addr = code->cur - (good_addr + 1);
219+ shr_ir(code, 1, adr_reg, opts->address_size);
220+ } else if (opts->byte_swap || memmap[chunk].flags & MMAP_BYTESWAP) {
221+ xor_ir(code, 1, adr_reg, opts->address_size);
222+ }
223+ } else if ((memmap[chunk].flags & MMAP_ONLY_ODD) || (memmap[chunk].flags & MMAP_ONLY_EVEN)) {
224+ tmp_size = SZ_B;
225+ shr_ir(code, 1, adr_reg, opts->address_size);
226+ if ((memmap[chunk].flags & MMAP_ONLY_EVEN) && is_write) {
227+ shr_ir(code, 8, opts->scratch1, SZ_W);
228+ }
229+ }
230+ if (opts->address_size != SZ_D) {
231+ movzx_rr(code, adr_reg, adr_reg, opts->address_size, SZ_D);
232+ }
233+ if ((intptr_t)memmap[chunk].buffer <= 0x7FFFFFFF && (intptr_t)memmap[chunk].buffer >= -2147483648) {
234+ if (is_write) {
235+ mov_rrdisp(code, opts->scratch1, opts->scratch2, (intptr_t)memmap[chunk].buffer, tmp_size);
236+ } else {
237+ mov_rdispr(code, opts->scratch1, (intptr_t)memmap[chunk].buffer, opts->scratch1, tmp_size);
238+ }
239+ } else {
240+ if (is_write) {
241+ push_r(code, opts->scratch2);
242+ mov_ir(code, (intptr_t)memmap[chunk].buffer, opts->scratch2, SZ_PTR);
243+ add_rdispr(code, RSP, 0, opts->scratch2, SZ_PTR);
244+ mov_rrind(code, opts->scratch1, opts->scratch2, tmp_size);
245+ if (is_write && (memmap[chunk].flags & MMAP_CODE)) {
246+ pop_r(code, opts->scratch2);
247+ } else {
248+ add_ir(code, sizeof(void*), RSP, SZ_PTR);
249+ code->stack_off -= sizeof(void *);
250+ }
251+ } else {
252+ push_r(code, opts->scratch2);
253+ mov_ir(code, (intptr_t)memmap[chunk].buffer, opts->scratch2, SZ_PTR);
254+ mov_rindexr(code, opts->scratch2, opts->scratch1, 1, opts->scratch1, tmp_size);
255+ pop_r(code, opts->scratch2);
256+ }
257+ }
258+ if (size != tmp_size && !is_write) {
259+ if (memmap[chunk].flags & MMAP_ONLY_EVEN) {
260+ shl_ir(code, 8, opts->scratch1, SZ_W);
261+ mov_ir(code, 0xFF, opts->scratch1, SZ_B);
262+ } else {
263+ or_ir(code, 0xFF00, opts->scratch1, SZ_W);
264+ }
265+ }
266+ }
267+ if (is_write && (memmap[chunk].flags & MMAP_CODE)) {
268+ mov_rr(code, opts->scratch2, opts->scratch1, opts->address_size);
269+ shr_ir(code, opts->ram_flags_shift, opts->scratch1, opts->address_size);
270+ bt_rrdisp(code, opts->scratch1, opts->context_reg, ram_flags_off, opts->address_size);
271+ code_ptr not_code = code->cur + 1;
272+ jcc(code, CC_NC, code->cur + 2);
273+ if (memmap[chunk].mask != opts->address_mask) {
274+ or_ir(code, memmap[chunk].start, opts->scratch2, opts->address_size);
275+ }
276+ call(code, opts->save_context);
277+ call_args(code, opts->handle_code_write, 2, opts->scratch2, opts->context_reg);
278+ mov_rr(code, RAX, opts->context_reg, SZ_PTR);
279+ jmp(code, opts->load_context);
280+ *not_code = code->cur - (not_code+1);
281+ }
282+ retn(code);
283+ } else if (cfun) {
284+ call(code, opts->save_context);
285+ if (is_write) {
286+ call_args_abi(code, cfun, 3, opts->scratch2, opts->context_reg, opts->scratch1);
287+ mov_rr(code, RAX, opts->context_reg, SZ_PTR);
288+ } else {
289+ push_r(code, opts->context_reg);
290+ call_args_abi(code, cfun, 2, opts->scratch1, opts->context_reg);
291+ pop_r(code, opts->context_reg);
292+ mov_rr(code, RAX, opts->scratch1, size);
293+ }
294+ jmp(code, opts->load_context);
295+ } else {
296+ //Not sure the best course of action here
297+ if (!is_write) {
298+ mov_ir(code, size == SZ_B ? 0xFF : 0xFFFF, opts->scratch1, size);
299+ }
300+ retn(code);
301+ }
302+ if (memmap[chunk].flags & MMAP_CODE) {
303+ if (memmap[chunk].mask == opts->address_mask) {
304+ ram_flags_off += (memmap[chunk].end - memmap[chunk].start) / (1 << opts->ram_flags_shift) / 8; ;
305+ } else {
306+ ram_flags_off += (memmap[chunk].mask + 1) / (1 << opts->ram_flags_shift) / 8;;
307+ }
308+ }
309+ if (lb_jcc) {
310+ *lb_jcc = code->cur - (lb_jcc+1);
311+ lb_jcc = NULL;
312+ }
313+ if (ub_jcc) {
314+ *ub_jcc = code->cur - (ub_jcc+1);
315+ ub_jcc = NULL;
316+ }
317+ }
318+ if (!is_write) {
319+ mov_ir(code, size == SZ_B ? 0xFF : 0xFFFF, opts->scratch1, size);
320+ }
321+ retn(code);
322+ return start;
323+}
+1072,
-0
1@@ -0,0 +1,1072 @@
2+#include <string.h>
3+#include <stdlib.h>
4+#include "render.h"
5+#include "system.h"
6+#include "io.h"
7+#include "blastem.h"
8+#include "saves.h"
9+#include "util.h"
10+#include "genesis.h"
11+#include "sms.h"
12+#include "menu.h"
13+#include "bindings.h"
14+#include "controller_info.h"
15+enum {
16+ BIND_NONE,
17+ BIND_UI,
18+ BIND_GAMEPAD,
19+ BIND_MOUSE
20+};
21+
22+typedef enum {
23+ UI_DEBUG_MODE_INC,
24+ UI_ENTER_DEBUGGER,
25+ UI_SAVE_STATE,
26+ UI_SET_SPEED,
27+ UI_NEXT_SPEED,
28+ UI_PREV_SPEED,
29+ UI_RELEASE_MOUSE,
30+ UI_TOGGLE_KEYBOARD_CAPTURE,
31+ UI_SOFT_RESET,
32+ UI_RELOAD,
33+ UI_SMS_PAUSE,
34+ UI_SCREENSHOT,
35+ UI_EXIT,
36+ UI_PLANE_DEBUG,
37+ UI_VRAM_DEBUG,
38+ UI_CRAM_DEBUG,
39+ UI_COMPOSITE_DEBUG
40+} ui_action;
41+
42+typedef struct {
43+ uint8_t bind_type;
44+ uint8_t subtype_a;
45+ uint8_t subtype_b;
46+} keybinding;
47+
48+typedef struct {
49+ keybinding bindings[4];
50+ uint8_t state;
51+} joydpad;
52+
53+typedef struct {
54+ keybinding positive;
55+ keybinding negative;
56+ int16_t value;
57+} joyaxis;
58+
59+typedef struct {
60+ keybinding *buttons;
61+ joydpad *dpads;
62+ joyaxis *axes;
63+ uint32_t num_buttons; //number of entries in the buttons array, not necessarily the number of buttons on the device
64+ uint32_t num_dpads; //number of entries in the dpads array, not necessarily the number of dpads on the device
65+ uint32_t num_axes; //number of entries in the axes array, not necessarily the number of dpads on the device
66+} joystick;
67+
68+typedef struct {
69+ keybinding buttons[MAX_MOUSE_BUTTONS];
70+ keybinding motion;
71+} mousebinding;
72+
73+#define DEFAULT_JOYBUTTON_ALLOC 12
74+static keybinding *bindings[0x10000];
75+static joystick joysticks[MAX_JOYSTICKS];
76+static mousebinding mice[MAX_MICE];
77+const uint8_t dpadbits[] = {RENDER_DPAD_UP, RENDER_DPAD_DOWN, RENDER_DPAD_LEFT, RENDER_DPAD_RIGHT};
78+
79+static void do_bind(keybinding *binding, uint8_t bind_type, uint8_t subtype_a, uint8_t subtype_b)
80+{
81+ binding->bind_type = bind_type;
82+ binding->subtype_a = subtype_a;
83+ binding->subtype_b = subtype_b;
84+}
85+
86+void bind_key(int keycode, uint8_t bind_type, uint8_t subtype_a, uint8_t subtype_b)
87+{
88+ int bucket = keycode >> 15 & 0xFFFF;
89+ if (!bindings[bucket]) {
90+ bindings[bucket] = malloc(sizeof(keybinding) * 0x8000);
91+ memset(bindings[bucket], 0, sizeof(keybinding) * 0x8000);
92+ }
93+ int idx = keycode & 0x7FFF;
94+ do_bind(bindings[bucket] + idx, bind_type, subtype_a, subtype_b);
95+}
96+
97+void bind_button(int joystick, int button, uint8_t bind_type, uint8_t subtype_a, uint8_t subtype_b)
98+{
99+ if (joystick >= MAX_JOYSTICKS) {
100+ return;
101+ }
102+ if (!joysticks[joystick].buttons) {
103+ joysticks[joystick].num_buttons = button < DEFAULT_JOYBUTTON_ALLOC ? DEFAULT_JOYBUTTON_ALLOC : button + 1;
104+ joysticks[joystick].buttons = calloc(joysticks[joystick].num_buttons, sizeof(keybinding));
105+ } else if (joysticks[joystick].num_buttons <= button) {
106+ uint32_t old_capacity = joysticks[joystick].num_buttons;
107+ joysticks[joystick].num_buttons *= 2;
108+ joysticks[joystick].buttons = realloc(joysticks[joystick].buttons, sizeof(keybinding) * joysticks[joystick].num_buttons);
109+ memset(joysticks[joystick].buttons + old_capacity, 0, joysticks[joystick].num_buttons - old_capacity);
110+ }
111+ do_bind(joysticks[joystick].buttons + button, bind_type, subtype_a, subtype_b);
112+}
113+
114+void bind_dpad(int joystick, int dpad, int direction, uint8_t bind_type, uint8_t subtype_a, uint8_t subtype_b)
115+{
116+ if (joystick >= MAX_JOYSTICKS) {
117+ return;
118+ }
119+ if (!joysticks[joystick].dpads) {
120+ //multiple D-pads/hats are not common, so don't allocate any extra space
121+ joysticks[joystick].dpads = calloc(dpad+1, sizeof(joydpad));
122+ joysticks[joystick].num_dpads = dpad+1;
123+ } else if (joysticks[joystick].num_dpads <= dpad) {
124+ uint32_t old_capacity = joysticks[joystick].num_dpads;
125+ joysticks[joystick].num_dpads *= 2;
126+ joysticks[joystick].dpads = realloc(joysticks[joystick].dpads, sizeof(joydpad) * joysticks[joystick].num_dpads);
127+ memset(joysticks[joystick].dpads + old_capacity, 0, (joysticks[joystick].num_dpads - old_capacity) * sizeof(joydpad));
128+ }
129+ for (int i = 0; i < 4; i ++) {
130+ if (dpadbits[i] & direction) {
131+ do_bind(joysticks[joystick].dpads[dpad].bindings + i, bind_type, subtype_a, subtype_b);
132+ break;
133+ }
134+ }
135+}
136+
137+void bind_axis(int joystick, int axis, int positive, uint8_t bind_type, uint8_t subtype_a, uint8_t subtype_b)
138+{
139+ if (joystick >= MAX_JOYSTICKS) {
140+ return;
141+ }
142+ if (!joysticks[joystick].axes) {
143+ //typical gamepad has 4 axes
144+ joysticks[joystick].num_axes = axis+1 > 4 ? axis+1 : 4;
145+ joysticks[joystick].axes = calloc(joysticks[joystick].num_axes, sizeof(joyaxis));
146+ } else if (joysticks[joystick].num_axes <= axis) {
147+ uint32_t old_capacity = joysticks[joystick].num_axes;
148+ joysticks[joystick].num_axes *= 2;
149+ joysticks[joystick].axes = realloc(joysticks[joystick].axes, sizeof(joyaxis) * joysticks[joystick].num_axes);
150+ memset(joysticks[joystick].axes + old_capacity, 0, (joysticks[joystick].num_axes - old_capacity) * sizeof(joyaxis));
151+ }
152+ if (positive) {
153+ do_bind(&joysticks[joystick].axes[axis].positive, bind_type, subtype_a, subtype_b);
154+ } else {
155+ do_bind(&joysticks[joystick].axes[axis].negative, bind_type, subtype_a, subtype_b);
156+ }
157+}
158+
159+void reset_joystick_bindings(int joystick)
160+{
161+ if (joystick >= MAX_JOYSTICKS) {
162+ return;
163+ }
164+ if (joysticks[joystick].buttons) {
165+ for (int i = 0; i < joysticks[joystick].num_buttons; i++)
166+ {
167+ joysticks[joystick].buttons[i].bind_type = BIND_NONE;
168+ }
169+ }
170+ if (joysticks[joystick].dpads) {
171+ for (int i = 0; i < joysticks[joystick].num_dpads; i++)
172+ {
173+ for (int dir = 0; dir < 4; dir++)
174+ {
175+ joysticks[joystick].dpads[i].bindings[dir].bind_type = BIND_NONE;
176+ }
177+ }
178+ }
179+ if (joysticks[joystick].axes) {
180+ for (int i = 0; i < joysticks[joystick].num_axes; i++)
181+ {
182+ joysticks[joystick].axes[i].positive.bind_type = BIND_NONE;
183+ joysticks[joystick].axes[i].negative.bind_type = BIND_NONE;
184+ }
185+ }
186+}
187+
188+static uint8_t content_binds_enabled = 1;
189+void set_content_binding_state(uint8_t enabled)
190+{
191+ content_binds_enabled = enabled;
192+}
193+
194+void handle_binding_down(keybinding * binding)
195+{
196+ if (!current_system) {
197+ return;
198+ }
199+ if (binding->bind_type == BIND_GAMEPAD && current_system && current_system->gamepad_down)
200+ {
201+ current_system->gamepad_down(current_system, binding->subtype_a, binding->subtype_b);
202+ }
203+ else if (binding->bind_type == BIND_MOUSE && current_system && current_system->mouse_down)
204+ {
205+ current_system->mouse_down(current_system, binding->subtype_a, binding->subtype_b);
206+ }
207+}
208+
209+static uint8_t keyboard_captured;
210+void handle_keydown(int keycode, uint8_t scancode)
211+{
212+ int bucket = keycode >> 15 & 0xFFFF;
213+ int idx = keycode & 0x7FFF;
214+ keybinding * binding = bindings[bucket] ? bindings[bucket] + idx : NULL;
215+ if (binding && (!keyboard_captured || (binding->bind_type == BIND_UI && binding->subtype_a == UI_TOGGLE_KEYBOARD_CAPTURE))) {
216+ handle_binding_down(binding);
217+ } else if (keyboard_captured && current_system && current_system->keyboard_down) {
218+ current_system->keyboard_down(current_system, scancode);
219+ }
220+}
221+
222+void handle_joydown(int joystick, int button)
223+{
224+ if (joystick >= MAX_JOYSTICKS || button >= joysticks[joystick].num_buttons) {
225+ return;
226+ }
227+ keybinding * binding = joysticks[joystick].buttons + button;
228+ handle_binding_down(binding);
229+}
230+
231+static uint8_t mouse_mode = MOUSE_NONE;
232+static uint8_t mouse_captured;
233+void handle_mousedown(int mouse, int button)
234+{
235+ if (mouse_mode == MOUSE_CAPTURE && !mouse_captured) {
236+ mouse_captured = 1;
237+ render_relative_mouse(1);
238+ return;
239+ }
240+ if (mouse >= MAX_MICE || button > MAX_MOUSE_BUTTONS || button <= 0) {
241+ return;
242+ }
243+ keybinding * binding = mice[mouse].buttons + button - 1;
244+ handle_binding_down(binding);
245+}
246+
247+static int current_speed = 0;
248+static int num_speeds = 1;
249+static uint32_t * speeds = NULL;
250+
251+static uint8_t mouse_captured;
252+
253+void handle_binding_up(keybinding * binding)
254+{
255+ uint8_t allow_content_binds = content_binds_enabled && current_system;
256+ switch(binding->bind_type)
257+ {
258+ case BIND_GAMEPAD:
259+ if (allow_content_binds && current_system->gamepad_up) {
260+ current_system->gamepad_up(current_system, binding->subtype_a, binding->subtype_b);
261+ }
262+ break;
263+ case BIND_MOUSE:
264+ if (allow_content_binds && current_system->mouse_up) {
265+ current_system->mouse_up(current_system, binding->subtype_a, binding->subtype_b);
266+ }
267+ break;
268+ case BIND_UI:
269+ switch (binding->subtype_a)
270+ {
271+ case UI_DEBUG_MODE_INC:
272+ if (allow_content_binds) {
273+ current_system->inc_debug_mode(current_system);
274+ }
275+ break;
276+ case UI_ENTER_DEBUGGER:
277+ if (allow_content_binds) {
278+ current_system->enter_debugger = 1;
279+ }
280+ break;
281+ case UI_SAVE_STATE:
282+ if (allow_content_binds) {
283+ current_system->save_state = QUICK_SAVE_SLOT+1;
284+ }
285+ break;
286+ case UI_NEXT_SPEED:
287+ if (allow_content_binds) {
288+ current_speed++;
289+ if (current_speed >= num_speeds) {
290+ current_speed = 0;
291+ }
292+ printf("Setting speed to %d: %d\n", current_speed, speeds[current_speed]);
293+ current_system->set_speed_percent(current_system, speeds[current_speed]);
294+ }
295+ break;
296+ case UI_PREV_SPEED:
297+ if (allow_content_binds) {
298+ current_speed--;
299+ if (current_speed < 0) {
300+ current_speed = num_speeds - 1;
301+ }
302+ printf("Setting speed to %d: %d\n", current_speed, speeds[current_speed]);
303+ current_system->set_speed_percent(current_system, speeds[current_speed]);
304+ }
305+ break;
306+ case UI_SET_SPEED:
307+ if (allow_content_binds) {
308+ if (binding->subtype_b < num_speeds) {
309+ current_speed = binding->subtype_b;
310+ printf("Setting speed to %d: %d\n", current_speed, speeds[current_speed]);
311+ current_system->set_speed_percent(current_system, speeds[current_speed]);
312+ } else {
313+ printf("Setting speed to %d\n", speeds[current_speed]);
314+ current_system->set_speed_percent(current_system, speeds[current_speed]);
315+ }
316+ }
317+ break;
318+ case UI_RELEASE_MOUSE:
319+ if (mouse_captured) {
320+ mouse_captured = 0;
321+ render_relative_mouse(0);
322+ }
323+ break;
324+ case UI_TOGGLE_KEYBOARD_CAPTURE:
325+ if (allow_content_binds && current_system->has_keyboard) {
326+ keyboard_captured = !keyboard_captured;
327+ }
328+ break;
329+ case UI_SOFT_RESET:
330+ if (allow_content_binds) {
331+ current_system->soft_reset(current_system);
332+ }
333+ break;
334+ case UI_RELOAD:
335+ if (allow_content_binds) {
336+ reload_media();
337+ }
338+ break;
339+ case UI_SMS_PAUSE:
340+ if (allow_content_binds && current_system->gamepad_down) {
341+ current_system->gamepad_down(current_system, GAMEPAD_MAIN_UNIT, MAIN_UNIT_PAUSE);
342+ }
343+ break;
344+ case UI_SCREENSHOT: {
345+ if (allow_content_binds) {
346+ char *screenshot_base = tern_find_path(config, "ui\0screenshot_path\0", TVAL_PTR).ptrval;
347+ if (!screenshot_base) {
348+ screenshot_base = "$HOME";
349+ }
350+ tern_node *vars = tern_insert_ptr(NULL, "HOME", get_home_dir());
351+ vars = tern_insert_ptr(vars, "EXEDIR", get_exe_dir());
352+ screenshot_base = replace_vars(screenshot_base, vars, 1);
353+ tern_free(vars);
354+ time_t now = time(NULL);
355+ struct tm local_store;
356+ char fname_part[256];
357+ char *template = tern_find_path(config, "ui\0screenshot_template\0", TVAL_PTR).ptrval;
358+ if (!template) {
359+ template = "blastem_%c.ppm";
360+ }
361+ strftime(fname_part, sizeof(fname_part), template, localtime_r(&now, &local_store));
362+ char const *parts[] = {screenshot_base, PATH_SEP, fname_part};
363+ char *path = alloc_concat_m(3, parts);
364+ free(screenshot_base);
365+ render_save_screenshot(path);
366+ }
367+ break;
368+ }
369+ case UI_EXIT:
370+ current_system->request_exit(current_system);
371+ if (current_system->type == SYSTEM_GENESIS) {
372+ genesis_context *gen = (genesis_context *)current_system;
373+ if (gen->extra) {
374+ //TODO: More robust mechanism for detecting menu
375+ menu_context *menu = gen->extra;
376+ menu->external_game_load = 1;
377+ }
378+ }
379+ break;
380+ case UI_PLANE_DEBUG:
381+ case UI_VRAM_DEBUG:
382+ case UI_CRAM_DEBUG:
383+ case UI_COMPOSITE_DEBUG:
384+ if (allow_content_binds) {
385+ vdp_context *vdp = NULL;
386+ if (current_system->type == SYSTEM_GENESIS) {
387+ genesis_context *gen = (genesis_context *)current_system;
388+ vdp = gen->vdp;
389+ } else if (current_system->type == SYSTEM_SMS) {
390+ sms_context *sms = (sms_context *)current_system;
391+ vdp = sms->vdp;
392+ }
393+ if (vdp) {
394+ uint8_t debug_type;
395+ switch(binding->subtype_a)
396+ {
397+ case UI_PLANE_DEBUG: debug_type = VDP_DEBUG_PLANE; break;
398+ case UI_VRAM_DEBUG: debug_type = VDP_DEBUG_VRAM; break;
399+ case UI_CRAM_DEBUG: debug_type = VDP_DEBUG_CRAM; break;
400+ case UI_COMPOSITE_DEBUG: debug_type = VDP_DEBUG_COMPOSITE; break;
401+ default: return;
402+ }
403+ vdp_toggle_debug_view(vdp, debug_type);
404+ }
405+ break;
406+ }
407+ }
408+ break;
409+ }
410+}
411+
412+void handle_keyup(int keycode, uint8_t scancode)
413+{
414+ int bucket = keycode >> 15 & 0xFFFF;
415+ int idx = keycode & 0x7FFF;
416+ keybinding * binding = bindings[bucket] ? bindings[bucket] + idx : NULL;
417+ if (binding && (!keyboard_captured || (binding->bind_type == BIND_UI && binding->subtype_a == UI_TOGGLE_KEYBOARD_CAPTURE))) {
418+ handle_binding_up(binding);
419+ } else if (keyboard_captured && current_system && current_system->keyboard_up) {
420+ current_system->keyboard_up(current_system, scancode);
421+ }
422+}
423+
424+void handle_joyup(int joystick, int button)
425+{
426+ if (joystick >= MAX_JOYSTICKS || button >= joysticks[joystick].num_buttons) {
427+ return;
428+ }
429+ keybinding * binding = joysticks[joystick].buttons + button;
430+ handle_binding_up(binding);
431+}
432+
433+void handle_joy_dpad(int joystick, int dpadnum, uint8_t value)
434+{
435+ if (joystick >= MAX_JOYSTICKS || dpadnum >= joysticks[joystick].num_dpads) {
436+ return;
437+ }
438+ joydpad * dpad = joysticks[joystick].dpads + dpadnum;
439+ uint8_t newdown = (value ^ dpad->state) & value;
440+ uint8_t newup = ((~value) ^ (~dpad->state)) & (~value);
441+ dpad->state = value;
442+ for (int i = 0; i < 4; i++) {
443+ if (newdown & dpadbits[i]) {
444+ handle_binding_down(dpad->bindings + i);
445+ } else if(newup & dpadbits[i]) {
446+ handle_binding_up(dpad->bindings + i);
447+ }
448+ }
449+}
450+
451+#define JOY_AXIS_THRESHOLD 2000
452+
453+void handle_joy_axis(int joystick, int axis, int16_t value)
454+{
455+ if (joystick >= MAX_JOYSTICKS || axis >= joysticks[joystick].num_axes) {
456+ return;
457+ }
458+ joyaxis *jaxis = joysticks[joystick].axes + axis;
459+ int old_active = abs(jaxis->value) > JOY_AXIS_THRESHOLD;
460+ int new_active = abs(value) > JOY_AXIS_THRESHOLD;
461+ int old_pos = jaxis->value > 0;
462+ int new_pos = value > 0;
463+ jaxis->value = value;
464+ if (old_active && (!new_active || old_pos != new_pos)) {
465+ //previously activated direction is no longer active
466+ handle_binding_up(old_pos ? &jaxis->positive : &jaxis->negative);
467+ }
468+ if (new_active && (!old_active || old_pos != new_pos)) {
469+ //previously unactivated direction is now active
470+ handle_binding_down(new_pos ? &jaxis->positive : &jaxis->negative);
471+ }
472+}
473+
474+void handle_mouse_moved(int mouse, uint16_t x, uint16_t y, int16_t deltax, int16_t deltay)
475+{
476+ if (mouse >= MAX_MICE || !current_system) {
477+ return;
478+ }
479+ if (mice[mouse].motion.bind_type == BIND_MOUSE && mice[mouse].motion.subtype_b == PSEUDO_BUTTON_MOTION) {
480+ uint8_t target_mouse = mice[mouse].motion.subtype_a;
481+ switch(mouse_mode)
482+ {
483+ case MOUSE_NONE:
484+ break;
485+ case MOUSE_ABSOLUTE: {
486+ if (current_system->mouse_motion_absolute) {
487+ float scale_x = (render_emulated_width() * 2.0f) / ((float)render_width());
488+ float scale_y = (render_emulated_height() * 2.0f) / ((float)render_height());
489+ int32_t adj_x = x * scale_x + 2 * render_overscan_left() - 2 * BORDER_LEFT;
490+ int32_t adj_y = y * scale_y + 2 * render_overscan_top() - 4;
491+
492+ current_system->mouse_motion_absolute(current_system, target_mouse, adj_x, adj_y);
493+ }
494+ break;
495+ }
496+ case MOUSE_RELATIVE: {
497+ if (current_system->mouse_motion_relative) {
498+ current_system->mouse_motion_relative(current_system, target_mouse, deltax, deltay);
499+ }
500+ break;
501+ }
502+ case MOUSE_CAPTURE: {
503+ if (mouse_captured && current_system->mouse_motion_relative) {
504+ current_system->mouse_motion_relative(current_system, target_mouse, deltax, deltay);
505+ }
506+ break;
507+ }
508+ }
509+ } else {
510+ handle_binding_up(&mice[mouse].motion);
511+ }
512+}
513+
514+void handle_mouseup(int mouse, int button)
515+{
516+ if (mouse >= MAX_MICE || button > MAX_MOUSE_BUTTONS || button <= 0) {
517+ return;
518+ }
519+ keybinding * binding = mice[mouse].buttons + button - 1;
520+ handle_binding_up(binding);
521+}
522+
523+void bindings_release_capture(void)
524+{
525+ if (mouse_mode == MOUSE_RELATIVE || (mouse_mode == MOUSE_CAPTURE && mouse_captured)) {
526+ render_relative_mouse(0);
527+ }
528+ keyboard_captured = 0;
529+}
530+
531+void bindings_reacquire_capture(void)
532+{
533+ if (mouse_mode == MOUSE_RELATIVE || (mouse_mode == MOUSE_CAPTURE && mouse_captured)) {
534+ render_relative_mouse(1);
535+ }
536+}
537+
538+int parse_binding_target(int device_num, char * target, tern_node * padbuttons, tern_node *mousebuttons, uint8_t * subtype_a, uint8_t * subtype_b)
539+{
540+ const int gpadslen = strlen("gamepads.");
541+ const int mouselen = strlen("mouse.");
542+ if (startswith(target, "gamepads.")) {
543+ int padnum = target[gpadslen] == 'n' ? device_num + 1 : target[gpadslen] - '0';
544+ if (padnum >= 1 && padnum <= 8) {
545+ int button = tern_find_int(padbuttons, target + gpadslen + 1, 0);
546+ if (button) {
547+ *subtype_a = padnum;
548+ *subtype_b = button;
549+ return BIND_GAMEPAD;
550+ } else {
551+ if (target[gpadslen+1]) {
552+ warning("Gamepad mapping string '%s' refers to an invalid button '%s'\n", target, target + gpadslen + 1);
553+ } else {
554+ warning("Gamepad mapping string '%s' has no button component\n", target);
555+ }
556+ }
557+ } else {
558+ warning("Gamepad mapping string '%s' refers to an invalid gamepad number %c\n", target, target[gpadslen]);
559+ }
560+ } else if(startswith(target, "mouse.")) {
561+ int mousenum = target[mouselen] == 'n' ? device_num + 1 : target[mouselen] - '0';
562+ if (mousenum >= 1 && mousenum <= 8) {
563+ int button = tern_find_int(mousebuttons, target + mouselen + 1, 0);
564+ if (button) {
565+ *subtype_a = mousenum;
566+ *subtype_b = button;
567+ return BIND_MOUSE;
568+ } else {
569+ if (target[mouselen+1]) {
570+ warning("Mouse mapping string '%s' refers to an invalid button '%s'\n", target, target + mouselen + 1);
571+ } else {
572+ warning("Mouse mapping string '%s' has no button component\n", target);
573+ }
574+ }
575+ } else {
576+ warning("Gamepad mapping string '%s' refers to an invalid mouse number %c\n", target, target[mouselen]);
577+ }
578+ } else if(startswith(target, "ui.")) {
579+ if (!strcmp(target + 3, "vdp_debug_mode")) {
580+ *subtype_a = UI_DEBUG_MODE_INC;
581+ } else if(!strcmp(target + 3, "vdp_debug_pal")) {
582+ //legacy binding, ignore
583+ return 0;
584+ } else if(!strcmp(target + 3, "enter_debugger")) {
585+ *subtype_a = UI_ENTER_DEBUGGER;
586+ } else if(!strcmp(target + 3, "save_state")) {
587+ *subtype_a = UI_SAVE_STATE;
588+ } else if(startswith(target + 3, "set_speed.")) {
589+ *subtype_a = UI_SET_SPEED;
590+ *subtype_b = atoi(target + 3 + strlen("set_speed."));
591+ } else if(!strcmp(target + 3, "next_speed")) {
592+ *subtype_a = UI_NEXT_SPEED;
593+ } else if(!strcmp(target + 3, "prev_speed")) {
594+ *subtype_a = UI_PREV_SPEED;
595+ } else if(!strcmp(target + 3, "release_mouse")) {
596+ *subtype_a = UI_RELEASE_MOUSE;
597+ } else if(!strcmp(target + 3, "toggle_keyboard_captured")) {
598+ *subtype_a = UI_TOGGLE_KEYBOARD_CAPTURE;
599+ } else if (!strcmp(target + 3, "soft_reset")) {
600+ *subtype_a = UI_SOFT_RESET;
601+ } else if (!strcmp(target + 3, "reload")) {
602+ *subtype_a = UI_RELOAD;
603+ } else if (!strcmp(target + 3, "sms_pause")) {
604+ *subtype_a = UI_SMS_PAUSE;
605+ } else if (!strcmp(target + 3, "screenshot")) {
606+ *subtype_a = UI_SCREENSHOT;
607+ } else if(!strcmp(target + 3, "exit")) {
608+ *subtype_a = UI_EXIT;
609+ } else if (!strcmp(target + 3, "plane_debug")) {
610+ *subtype_a = UI_PLANE_DEBUG;
611+ } else if (!strcmp(target + 3, "vram_debug")) {
612+ *subtype_a = UI_VRAM_DEBUG;
613+ } else if (!strcmp(target + 3, "cram_debug")) {
614+ *subtype_a = UI_CRAM_DEBUG;
615+ } else if (!strcmp(target + 3, "compositing_debug")) {
616+ *subtype_a = UI_COMPOSITE_DEBUG;
617+ } else {
618+ warning("Unreconized UI binding type %s\n", target);
619+ return 0;
620+ }
621+ return BIND_UI;
622+ } else {
623+ warning("Unrecognized binding type %s\n", target);
624+ }
625+ return 0;
626+}
627+
628+void process_keys(tern_node * cur, tern_node * special, tern_node * padbuttons, tern_node *mousebuttons, char * prefix)
629+{
630+ char * curstr = NULL;
631+ int len;
632+ if (!cur) {
633+ return;
634+ }
635+ char onec[2];
636+ if (prefix) {
637+ len = strlen(prefix);
638+ curstr = malloc(len + 2);
639+ memcpy(curstr, prefix, len);
640+ } else {
641+ curstr = onec;
642+ len = 0;
643+ }
644+ curstr[len] = cur->el;
645+ curstr[len+1] = 0;
646+ if (cur->el) {
647+ process_keys(cur->straight.next, special, padbuttons, mousebuttons, curstr);
648+ } else {
649+ int keycode = tern_find_int(special, curstr, 0);
650+ if (!keycode) {
651+ keycode = curstr[0];
652+ if (curstr[1] != 0) {
653+ warning("%s is not recognized as a key identifier, truncating to %c\n", curstr, curstr[0]);
654+ }
655+ }
656+ char * target = cur->straight.value.ptrval;
657+ uint8_t subtype_a = 0, subtype_b = 0;
658+ int bindtype = parse_binding_target(0, target, padbuttons, mousebuttons, &subtype_a, &subtype_b);
659+ bind_key(keycode, bindtype, subtype_a, subtype_b);
660+ }
661+ process_keys(cur->left, special, padbuttons, mousebuttons, prefix);
662+ process_keys(cur->right, special, padbuttons, mousebuttons, prefix);
663+ if (curstr && len) {
664+ free(curstr);
665+ }
666+}
667+
668+void process_speeds(tern_node * cur, char * prefix)
669+{
670+ char * curstr = NULL;
671+ int len;
672+ if (!cur) {
673+ return;
674+ }
675+ char onec[2];
676+ if (prefix) {
677+ len = strlen(prefix);
678+ curstr = malloc(len + 2);
679+ memcpy(curstr, prefix, len);
680+ } else {
681+ curstr = onec;
682+ len = 0;
683+ }
684+ curstr[len] = cur->el;
685+ curstr[len+1] = 0;
686+ if (cur->el) {
687+ process_speeds(cur->straight.next, curstr);
688+ } else {
689+ char *end;
690+ long speed_index = strtol(curstr, &end, 10);
691+ if (speed_index < 0 || end == curstr || *end) {
692+ warning("%s is not a valid speed index", curstr);
693+ } else {
694+ if (speed_index >= num_speeds) {
695+ speeds = realloc(speeds, sizeof(uint32_t) * (speed_index+1));
696+ for(; num_speeds < speed_index + 1; num_speeds++) {
697+ speeds[num_speeds] = 0;
698+ }
699+ }
700+ speeds[speed_index] = atoi(cur->straight.value.ptrval);
701+ if (speeds[speed_index] < 1) {
702+ warning("%s is not a valid speed percentage, setting speed %d to 100", cur->straight.value.ptrval, speed_index);
703+ speeds[speed_index] = 100;
704+ }
705+ }
706+ }
707+ process_speeds(cur->left, prefix);
708+ process_speeds(cur->right, prefix);
709+ if (curstr && len) {
710+ free(curstr);
711+ }
712+}
713+
714+typedef struct {
715+ tern_node *padbuttons;
716+ tern_node *mousebuttons;
717+ int mouseidx;
718+} pmb_state;
719+
720+void process_mouse_button(char *buttonstr, tern_val value, uint8_t valtype, void *data)
721+{
722+ pmb_state *state = data;
723+ int buttonnum = atoi(buttonstr);
724+ if (buttonnum < 1 || buttonnum > MAX_MOUSE_BUTTONS) {
725+ warning("Mouse button %s is out of the supported range of 1-8\n", buttonstr);
726+ return;
727+ }
728+ if (valtype != TVAL_PTR) {
729+ warning("Mouse button %s is not a scalar value!\n", buttonstr);
730+ return;
731+ }
732+ buttonnum--;
733+ uint8_t subtype_a = 0, subtype_b = 0;
734+ int bindtype = parse_binding_target(state->mouseidx, value.ptrval, state->padbuttons, state->mousebuttons, &subtype_a, &subtype_b);
735+ mice[state->mouseidx].buttons[buttonnum].bind_type = bindtype;
736+ mice[state->mouseidx].buttons[buttonnum].subtype_a = subtype_a;
737+ mice[state->mouseidx].buttons[buttonnum].subtype_b = subtype_b;
738+}
739+
740+void process_mouse(char *mousenum, tern_val value, uint8_t valtype, void *data)
741+{
742+ tern_node **buttonmaps = data;
743+ if (valtype != TVAL_NODE) {
744+ warning("Binding for mouse %s is a scalar!\n", mousenum);
745+ return;
746+ }
747+ tern_node *mousedef = value.ptrval;
748+ tern_node *padbuttons = buttonmaps[0];
749+ tern_node *mousebuttons = buttonmaps[1];
750+
751+ int mouseidx = atoi(mousenum);
752+ if (mouseidx < 0 || mouseidx >= MAX_MICE) {
753+ warning("Mouse numbers must be between 0 and %d, but %d is not\n", MAX_MICE, mouseidx);
754+ return;
755+ }
756+ char *motion = tern_find_ptr(mousedef, "motion");
757+ if (motion) {
758+ uint8_t subtype_a = 0, subtype_b = 0;
759+ int bindtype = parse_binding_target(mouseidx, motion, padbuttons, mousebuttons, &subtype_a, &subtype_b);
760+ mice[mouseidx].motion.bind_type = bindtype;
761+ mice[mouseidx].motion.subtype_a = subtype_a;
762+ mice[mouseidx].motion.subtype_b = subtype_b;
763+ }
764+ tern_node *buttons = tern_find_path(mousedef, "buttons\0\0", TVAL_NODE).ptrval;
765+ if (buttons) {
766+ pmb_state state = {padbuttons, mousebuttons, mouseidx};
767+ tern_foreach(buttons, process_mouse_button, &state);
768+ }
769+}
770+
771+typedef struct {
772+ int padnum;
773+ tern_node *padbuttons;
774+ tern_node *mousebuttons;
775+} pad_button_state;
776+
777+
778+static long map_warning_pad = -1;
779+void process_pad_button(char *key, tern_val val, uint8_t valtype, void *data)
780+{
781+ pad_button_state *state = data;
782+ int hostpadnum = state->padnum;
783+ if (valtype != TVAL_PTR) {
784+ warning("Pad button %s has a non-scalar value\n", key);
785+ return;
786+ }
787+ uint8_t subtype_a = 0, subtype_b = 0;
788+ int bindtype = parse_binding_target(hostpadnum, val.ptrval, state->padbuttons, state->mousebuttons, &subtype_a, &subtype_b);
789+ char *end;
790+ long hostbutton = strtol(key, &end, 10);
791+ if (*end) {
792+ //key is not a valid base 10 integer
793+ hostbutton = render_translate_input_name(hostpadnum, key, 0);
794+ if (hostbutton < 0) {
795+ if (hostbutton == RENDER_INVALID_NAME) {
796+ warning("%s is not a valid gamepad input name\n", key);
797+ } else if (hostbutton == RENDER_NOT_MAPPED && hostpadnum != map_warning_pad) {
798+ warning("No mapping exists for input %s on gamepad %d\n", key, hostpadnum);
799+ map_warning_pad = hostpadnum;
800+ }
801+ return;
802+ }
803+ if (hostbutton & RENDER_DPAD_BIT) {
804+ bind_dpad(hostpadnum, render_dpad_part(hostbutton), render_direction_part(hostbutton), bindtype, subtype_a, subtype_b);
805+ return;
806+ } else if (hostbutton & RENDER_AXIS_BIT) {
807+ bind_axis(hostpadnum, render_axis_part(hostbutton), hostbutton & RENDER_AXIS_POS, bindtype, subtype_a, subtype_b);
808+ return;
809+ }
810+ }
811+ bind_button(hostpadnum, hostbutton, bindtype, subtype_a, subtype_b);
812+}
813+
814+void process_pad_axis(char *key, tern_val val, uint8_t valtype, void *data)
815+{
816+ key = strdup(key);
817+ pad_button_state *state = data;
818+ int hostpadnum = state->padnum;
819+ if (valtype != TVAL_PTR) {
820+ warning("Mapping for axis %s has a non-scalar value", key);
821+ return;
822+ }
823+ uint8_t subtype_a = 0, subtype_b = 0;
824+ int bindtype = parse_binding_target(hostpadnum, val.ptrval, state->padbuttons, state->mousebuttons, &subtype_a, &subtype_b);
825+ char *modifier = strchr(key, '.');
826+ int positive = 1;
827+ if (modifier) {
828+ *modifier = 0;
829+ modifier++;
830+ if (!strcmp("negative", modifier)) {
831+ positive = 0;
832+ } else if(strcmp("positive", modifier)) {
833+ warning("Invalid axis modifier %s for axis %s on pad %d\n", modifier, key, hostpadnum);
834+ }
835+ }
836+ char *end;
837+ long axis = strtol(key, &end, 10);
838+ if (*end) {
839+ //key is not a valid base 10 integer
840+ axis = render_translate_input_name(hostpadnum, key, 1);
841+ if (axis < 0) {
842+ if (axis == RENDER_INVALID_NAME) {
843+ warning("%s is not a valid gamepad input name\n", key);
844+ } else if (axis == RENDER_NOT_MAPPED && hostpadnum != map_warning_pad) {
845+ warning("No mapping exists for input %s on gamepad %d\n", key, hostpadnum);
846+ map_warning_pad = hostpadnum;
847+ }
848+ goto done;
849+ }
850+ if (axis & RENDER_DPAD_BIT) {
851+ bind_dpad(hostpadnum, render_dpad_part(axis), render_direction_part(axis), bindtype, subtype_a, subtype_b);
852+ goto done;
853+ } else if (axis & RENDER_AXIS_BIT) {
854+ axis = render_axis_part(axis);
855+ } else {
856+ bind_button(hostpadnum, axis, bindtype, subtype_a, subtype_b);
857+ goto done;
858+ }
859+ }
860+ bind_axis(hostpadnum, axis, positive, bindtype, subtype_a, subtype_b);
861+done:
862+ free(key);
863+ return;
864+}
865+
866+static tern_node *get_pad_buttons()
867+{
868+ static tern_node *padbuttons;
869+ if (!padbuttons) {
870+ padbuttons = tern_insert_int(NULL, ".up", DPAD_UP);
871+ padbuttons = tern_insert_int(padbuttons, ".down", DPAD_DOWN);
872+ padbuttons = tern_insert_int(padbuttons, ".left", DPAD_LEFT);
873+ padbuttons = tern_insert_int(padbuttons, ".right", DPAD_RIGHT);
874+ padbuttons = tern_insert_int(padbuttons, ".a", BUTTON_A);
875+ padbuttons = tern_insert_int(padbuttons, ".b", BUTTON_B);
876+ padbuttons = tern_insert_int(padbuttons, ".c", BUTTON_C);
877+ padbuttons = tern_insert_int(padbuttons, ".x", BUTTON_X);
878+ padbuttons = tern_insert_int(padbuttons, ".y", BUTTON_Y);
879+ padbuttons = tern_insert_int(padbuttons, ".z", BUTTON_Z);
880+ padbuttons = tern_insert_int(padbuttons, ".start", BUTTON_START);
881+ padbuttons = tern_insert_int(padbuttons, ".mode", BUTTON_MODE);
882+ }
883+ return padbuttons;
884+}
885+
886+static tern_node *get_mouse_buttons()
887+{
888+ static tern_node *mousebuttons;
889+ if (!mousebuttons) {
890+ mousebuttons = tern_insert_int(NULL, ".left", MOUSE_LEFT);
891+ mousebuttons = tern_insert_int(mousebuttons, ".middle", MOUSE_MIDDLE);
892+ mousebuttons = tern_insert_int(mousebuttons, ".right", MOUSE_RIGHT);
893+ mousebuttons = tern_insert_int(mousebuttons, ".start", MOUSE_START);
894+ mousebuttons = tern_insert_int(mousebuttons, ".motion", PSEUDO_BUTTON_MOTION);
895+ }
896+ return mousebuttons;
897+}
898+
899+tern_node *get_binding_node_for_pad(int padnum)
900+{
901+ if (padnum > MAX_JOYSTICKS) {
902+ return NULL;
903+ }
904+ tern_node * pads = tern_find_path(config, "bindings\0pads\0", TVAL_NODE).ptrval;
905+ if (!pads) {
906+ return NULL;
907+ }
908+ char numstr[11];
909+ sprintf(numstr, "%d", padnum);
910+ tern_node * pad = tern_find_node(pads, numstr);
911+ if (!pad) {
912+ char *type_id = render_joystick_type_id(padnum);
913+ pad = tern_find_node(pads, type_id);
914+ free(type_id);
915+ }
916+ if (!pad) {
917+ controller_info info = get_controller_info(padnum);
918+ char *key = make_controller_type_key(&info);
919+ pad = tern_find_node(pads, key);
920+ free(key);
921+ }
922+ if (!pad) {
923+ pad = tern_find_node(pads, "default");
924+ }
925+ return pad;
926+}
927+
928+void handle_joy_added(int joystick)
929+{
930+ tern_node *pad = get_binding_node_for_pad(joystick);
931+ if (!pad) {
932+ return;
933+ }
934+ tern_node * dpad_node = tern_find_node(pad, "dpads");
935+ if (dpad_node) {
936+ for (int dpad = 0; dpad < 10; dpad++)
937+ {
938+ char numstr[2] = {dpad + '0', 0};
939+ tern_node * pad_dpad = tern_find_node(dpad_node, numstr);
940+ char * dirs[] = {"up", "down", "left", "right"};
941+ char *render_dirs[] = {"dpup", "dpdown", "dpleft", "dpright"};
942+ int dirnums[] = {RENDER_DPAD_UP, RENDER_DPAD_DOWN, RENDER_DPAD_LEFT, RENDER_DPAD_RIGHT};
943+ for (int dir = 0; dir < sizeof(dirs)/sizeof(dirs[0]); dir++) {
944+ char * target = tern_find_ptr(pad_dpad, dirs[dir]);
945+ if (target) {
946+ uint8_t subtype_a = 0, subtype_b = 0;
947+ int bindtype = parse_binding_target(joystick, target, get_pad_buttons(), get_mouse_buttons(), &subtype_a, &subtype_b);
948+ int32_t hostbutton = dpad >0 ? -1 : render_translate_input_name(joystick, render_dirs[dir], 0);
949+ if (hostbutton < 0) {
950+ //assume this is a raw dpad mapping
951+ bind_dpad(joystick, dpad, dirnums[dir], bindtype, subtype_a, subtype_b);
952+ } else if (hostbutton & RENDER_DPAD_BIT) {
953+ bind_dpad(joystick, render_dpad_part(hostbutton), render_direction_part(hostbutton), bindtype, subtype_a, subtype_b);
954+ } else if (hostbutton & RENDER_AXIS_BIT) {
955+ //Assume controllers with axes for a d-pad use the conventional directions.
956+ bind_axis(joystick, render_axis_part(hostbutton), dir == 1 || dir == 3 ? 1 : 0, bindtype, subtype_a, subtype_b);
957+ } else {
958+ bind_button(joystick, hostbutton, bindtype, subtype_a, subtype_b);
959+ }
960+ }
961+ }
962+ }
963+ }
964+ tern_node *button_node = tern_find_node(pad, "buttons");
965+ if (button_node) {
966+ pad_button_state state = {
967+ .padnum = joystick,
968+ .padbuttons = get_pad_buttons(),
969+ .mousebuttons = get_mouse_buttons()
970+ };
971+ tern_foreach(button_node, process_pad_button, &state);
972+ }
973+ tern_node *axes_node = tern_find_node(pad, "axes");
974+ if (axes_node) {
975+ pad_button_state state = {
976+ .padnum = joystick,
977+ .padbuttons = get_pad_buttons(),
978+ .mousebuttons = get_mouse_buttons()
979+ };
980+ tern_foreach(axes_node, process_pad_axis, &state);
981+ }
982+}
983+
984+//only handles keyboards and mice as gamepads are handled on hotplug events
985+void set_bindings(void)
986+{
987+ tern_node * special = tern_insert_int(NULL, "up", RENDERKEY_UP);
988+ special = tern_insert_int(special, "down", RENDERKEY_DOWN);
989+ special = tern_insert_int(special, "left", RENDERKEY_LEFT);
990+ special = tern_insert_int(special, "right", RENDERKEY_RIGHT);
991+ special = tern_insert_int(special, "enter", '\r');
992+ special = tern_insert_int(special, "space", ' ');
993+ special = tern_insert_int(special, "tab", '\t');
994+ special = tern_insert_int(special, "backspace", '\b');
995+ special = tern_insert_int(special, "esc", RENDERKEY_ESC);
996+ special = tern_insert_int(special, "delete", RENDERKEY_DEL);
997+ special = tern_insert_int(special, "lshift", RENDERKEY_LSHIFT);
998+ special = tern_insert_int(special, "rshift", RENDERKEY_RSHIFT);
999+ special = tern_insert_int(special, "lctrl", RENDERKEY_LCTRL);
1000+ special = tern_insert_int(special, "rctrl", RENDERKEY_RCTRL);
1001+ special = tern_insert_int(special, "lalt", RENDERKEY_LALT);
1002+ special = tern_insert_int(special, "ralt", RENDERKEY_RALT);
1003+ special = tern_insert_int(special, "home", RENDERKEY_HOME);
1004+ special = tern_insert_int(special, "end", RENDERKEY_END);
1005+ special = tern_insert_int(special, "pageup", RENDERKEY_PAGEUP);
1006+ special = tern_insert_int(special, "pagedown", RENDERKEY_PAGEDOWN);
1007+ special = tern_insert_int(special, "f1", RENDERKEY_F1);
1008+ special = tern_insert_int(special, "f2", RENDERKEY_F2);
1009+ special = tern_insert_int(special, "f3", RENDERKEY_F3);
1010+ special = tern_insert_int(special, "f4", RENDERKEY_F4);
1011+ special = tern_insert_int(special, "f5", RENDERKEY_F5);
1012+ special = tern_insert_int(special, "f6", RENDERKEY_F6);
1013+ special = tern_insert_int(special, "f7", RENDERKEY_F7);
1014+ special = tern_insert_int(special, "f8", RENDERKEY_F8);
1015+ special = tern_insert_int(special, "f9", RENDERKEY_F9);
1016+ special = tern_insert_int(special, "f10", RENDERKEY_F10);
1017+ special = tern_insert_int(special, "f11", RENDERKEY_F11);
1018+ special = tern_insert_int(special, "f12", RENDERKEY_F12);
1019+ special = tern_insert_int(special, "select", RENDERKEY_SELECT);
1020+ special = tern_insert_int(special, "play", RENDERKEY_PLAY);
1021+ special = tern_insert_int(special, "search", RENDERKEY_SEARCH);
1022+ special = tern_insert_int(special, "back", RENDERKEY_BACK);
1023+ special = tern_insert_int(special, "np0", RENDERKEY_NP0);
1024+ special = tern_insert_int(special, "np1", RENDERKEY_NP1);
1025+ special = tern_insert_int(special, "np2", RENDERKEY_NP2);
1026+ special = tern_insert_int(special, "np3", RENDERKEY_NP3);
1027+ special = tern_insert_int(special, "np4", RENDERKEY_NP4);
1028+ special = tern_insert_int(special, "np5", RENDERKEY_NP5);
1029+ special = tern_insert_int(special, "np6", RENDERKEY_NP6);
1030+ special = tern_insert_int(special, "np7", RENDERKEY_NP7);
1031+ special = tern_insert_int(special, "np8", RENDERKEY_NP8);
1032+ special = tern_insert_int(special, "np9", RENDERKEY_NP9);
1033+ special = tern_insert_int(special, "np/", RENDERKEY_NP_DIV);
1034+ special = tern_insert_int(special, "np*", RENDERKEY_NP_MUL);
1035+ special = tern_insert_int(special, "np-", RENDERKEY_NP_MIN);
1036+ special = tern_insert_int(special, "np+", RENDERKEY_NP_PLUS);
1037+ special = tern_insert_int(special, "npenter", RENDERKEY_NP_ENTER);
1038+ special = tern_insert_int(special, "np.", RENDERKEY_NP_STOP);
1039+
1040+ tern_node *padbuttons = get_pad_buttons();
1041+
1042+ tern_node *mousebuttons = get_mouse_buttons();
1043+
1044+ tern_node * keys = tern_find_path(config, "bindings\0keys\0", TVAL_NODE).ptrval;
1045+ process_keys(keys, special, padbuttons, mousebuttons, NULL);
1046+ tern_free(special);
1047+
1048+ memset(mice, 0, sizeof(mice));
1049+ tern_node * mice = tern_find_path(config, "bindings\0mice\0", TVAL_NODE).ptrval;
1050+ if (mice) {
1051+ tern_node *buttonmaps[2] = {padbuttons, mousebuttons};
1052+ tern_foreach(mice, process_mouse, buttonmaps);
1053+ }
1054+ tern_node * speed_nodes = tern_find_path(config, "clocks\0speeds\0", TVAL_NODE).ptrval;
1055+ speeds = malloc(sizeof(uint32_t));
1056+ speeds[0] = 100;
1057+ process_speeds(speed_nodes, NULL);
1058+ for (int i = 0; i < num_speeds; i++)
1059+ {
1060+ if (!speeds[i]) {
1061+ warning("Speed index %d was not set to a valid percentage!", i);
1062+ speeds[i] = 100;
1063+ }
1064+ }
1065+}
1066+
1067+void bindings_set_mouse_mode(uint8_t mode)
1068+{
1069+ mouse_mode = mode;
1070+ if (mode == MOUSE_RELATIVE) {
1071+ render_relative_mouse(1);
1072+ }
1073+}
+30,
-0
1@@ -0,0 +1,30 @@
2+#ifndef BINDINGS_H_
3+#define BINDINGS_H_
4+#include <stdint.h>
5+
6+typedef enum {
7+ MOUSE_NONE, //mouse is ignored
8+ MOUSE_ABSOLUTE, //really only useful for menu ROM
9+ MOUSE_RELATIVE, //for full screen
10+ MOUSE_CAPTURE //for windowed mode
11+} mouse_modes;
12+
13+void set_bindings(void);
14+void bindings_set_mouse_mode(uint8_t mode);
15+tern_node *get_binding_node_for_pad(int padnum);
16+void handle_keydown(int keycode, uint8_t scancode);
17+void handle_keyup(int keycode, uint8_t scancode);
18+void handle_joydown(int joystick, int button);
19+void handle_joyup(int joystick, int button);
20+void handle_joy_dpad(int joystick, int dpad, uint8_t state);
21+void handle_joy_axis(int joystick, int axis, int16_t value);
22+void handle_joy_added(int joystick);
23+void handle_mouse_moved(int mouse, uint16_t x, uint16_t y, int16_t deltax, int16_t deltay);
24+void handle_mousedown(int mouse, int button);
25+void handle_mouseup(int mouse, int button);
26+
27+void bindings_release_capture(void);
28+void bindings_reacquire_capture(void);
29+void set_content_binding_state(uint8_t enabled);
30+
31+#endif //BINDINGS_H_
+122,
-0
1@@ -0,0 +1,122 @@
2+#include <stdio.h>
3+#include <stdlib.h>
4+#include <stddef.h>
5+#include <string.h>
6+#include <time.h>
7+#include <sys/select.h>
8+
9+#include "z80_to_x86.h"
10+#include "util.h"
11+
12+uint8_t ram[64 * 1024];
13+
14+#define START_OFF 0x100
15+#define OS_START 0xE400
16+#define OS_RESET 0xE403
17+int headless = 1;
18+
19+void z80_next_int_pulse(z80_context * context)
20+{
21+ context->int_pulse_start = context->int_pulse_end = CYCLE_NEVER;
22+}
23+
24+void render_errorbox(char *title, char *message)
25+{
26+}
27+
28+void render_infobox(char *title, char *message)
29+{
30+}
31+
32+void *console_write(uint32_t address, void *context, uint8_t value)
33+{
34+ putchar(value);
35+ return context;
36+}
37+
38+uint8_t console_read(uint32_t address, void *context)
39+{
40+ return getchar();
41+}
42+
43+void *console_flush_write(uint32_t address, void *context, uint8_t value)
44+{
45+ fflush(stdout);
46+ return context;
47+}
48+
49+uint8_t console_status_read(uint32_t address, void *context)
50+{
51+ fd_set read_fds;
52+ FD_ZERO(&read_fds);
53+ struct timeval timeout;
54+ timeout.tv_sec = 0;
55+ timeout.tv_usec = 0;
56+ FD_SET(fileno(stdin), &read_fds);
57+ return select(fileno(stdin)+1, &read_fds, NULL, NULL, &timeout) > 0;
58+}
59+
60+time_t start;
61+uint64_t total_cycles;
62+void *exit_write(uint32_t address, void *context, uint8_t value)
63+{
64+ time_t duration = time(NULL) - start;
65+ z80_context *z80 = context;
66+ total_cycles += context->current_cycle;
67+ printf("Effective clock speed: %f MHz\n", ((double)total_cycles) / (1000000.0 * duration));
68+ exit(0);
69+ return context;
70+}
71+
72+const memmap_chunk z80_map[] = {
73+ { 0x0000, 0x10000, 0xFFFF, 0, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, ram, NULL, NULL, NULL, NULL},
74+};
75+
76+memmap_chunk io_map[] = {
77+ { 0x0, 0x1, 0xFFFF, 0, 0, 0, NULL, NULL, NULL, console_read, console_write},
78+ { 0x1, 0x2, 0xFFFF, 0, 0, 0, NULL, NULL, NULL, console_status_read, console_flush_write},
79+ { 0x2, 0x3, 0xFFFF, 0, 0, 0, NULL, NULL, NULL, NULL, exit_write},
80+};
81+
82+int main(int argc, char **argv)
83+{
84+ FILE *f = fopen("fake_cpm.bin", "rb");
85+ long fsize = file_size(f);
86+ if (fsize > sizeof(ram) - OS_START) {
87+ fsize = sizeof(ram) - OS_START;
88+ }
89+ if (fread(ram + OS_START, 1, fsize, f) != fsize) {
90+ fprintf(stderr, "Error reading from fake_cpm.bin\n");
91+ exit(1);
92+ }
93+ f = fopen(argv[1], "rb");
94+ fsize = file_size(f);
95+ if (fsize > OS_START - START_OFF) {
96+ fsize = OS_START - START_OFF;
97+ }
98+ if (fread(ram + START_OFF, 1, fsize, f) != fsize) {
99+ fprintf(stderr, "Error reading from file %s\n", argv[1]);
100+ exit(1);
101+ }
102+ fclose(f);
103+ ram[0] = 0xC3;
104+ ram[1] = OS_RESET & 0xFF;
105+ ram[2] = OS_RESET >> 8;
106+ ram[5] = 0xC3;
107+ ram[6] = OS_START & 0xFF;
108+ ram[7] = OS_START >> 8;
109+
110+ z80_options opts;
111+ z80_context *context;
112+ init_z80_opts(&opts, z80_map, 1, io_map, 3, 1, 0xFF);
113+ context = init_z80_context(&opts);
114+ start = time(NULL);
115+ for(;;)
116+ {
117+ z80_run(context, 1000000);
118+ total_cycles += context->current_cycle;
119+ context->current_cycle = 0;
120+
121+ }
122+ return 0;
123+}
+628,
-0
1@@ -0,0 +1,628 @@
2+/*
3+ Copyright 2013-2016 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#include <stdio.h>
8+#include <stdlib.h>
9+#include <string.h>
10+#include <ctype.h>
11+
12+#include "system.h"
13+#include "68kinst.h"
14+#include "m68k_core.h"
15+#include "z80_to_x86.h"
16+#include "mem.h"
17+#include "vdp.h"
18+#include "render.h"
19+#include "genesis.h"
20+#include "gdb_remote.h"
21+#include "gst.h"
22+#include "util.h"
23+#include "romdb.h"
24+#include "terminal.h"
25+#include "arena.h"
26+#include "config.h"
27+#include "bindings.h"
28+#include "menu.h"
29+#include "zip.h"
30+#define BLASTEM_VERSION "0.6.2"
31+
32+int headless = 0;
33+int exit_after = 0;
34+int z80_enabled = 1;
35+int frame_limit = 0;
36+uint8_t use_native_states = 1;
37+
38+tern_node * config;
39+
40+#define SMD_HEADER_SIZE 512
41+#define SMD_MAGIC1 0x03
42+#define SMD_MAGIC2 0xAA
43+#define SMD_MAGIC3 0xBB
44+#define SMD_BLOCK_SIZE 0x4000
45+
46+#include <zlib.h>
47+#define ROMFILE gzFile
48+#define romopen gzopen
49+#define romread gzfread
50+#define romseek gzseek
51+#define romgetc gzgetc
52+#define romclose gzclose
53+
54+uint16_t *process_smd_block(uint16_t *dst, uint8_t *src, size_t bytes)
55+{
56+ for (uint8_t *low = src, *high = (src+bytes/2), *end = src+bytes; high < end; high++, low++) {
57+ *(dst++) = *low << 8 | *high;
58+ }
59+ return dst;
60+}
61+
62+int load_smd_rom(ROMFILE f, void **buffer)
63+{
64+ uint8_t block[SMD_BLOCK_SIZE];
65+ romseek(f, SMD_HEADER_SIZE, SEEK_SET);
66+
67+ size_t filesize = 512 * 1024;
68+ size_t readsize = 0;
69+ uint16_t *dst, *buf;
70+ dst = buf = malloc(filesize);
71+
72+
73+ size_t read;
74+ do {
75+ if ((readsize + SMD_BLOCK_SIZE > filesize)) {
76+ filesize *= 2;
77+ buf = realloc(buf, filesize);
78+ dst = buf + readsize/sizeof(uint16_t);
79+ }
80+ read = romread(block, 1, SMD_BLOCK_SIZE, f);
81+ if (read > 0) {
82+ dst = process_smd_block(dst, block, read);
83+ readsize += read;
84+ }
85+ } while(read > 0);
86+ romclose(f);
87+
88+ *buffer = buf;
89+
90+ return readsize;
91+}
92+
93+uint8_t is_smd_format(const char *filename, uint8_t *header)
94+{
95+ if (header[1] == SMD_MAGIC1 && header[8] == SMD_MAGIC2 && header[9] == SMD_MAGIC3) {
96+ int i;
97+ for (i = 3; i < 8; i++) {
98+ if (header[i] != 0) {
99+ return 0;
100+ }
101+ }
102+ if (i == 8) {
103+ if (header[2]) {
104+ fatal_error("%s is a split SMD ROM which is not currently supported", filename);
105+ }
106+ return 1;
107+ }
108+ }
109+ return 0;
110+}
111+
112+uint32_t load_rom_zip(const char *filename, void **dst)
113+{
114+ static const char *valid_exts[] = {"bin", "md", "gen", "sms", "rom", "smd"};
115+ const uint32_t num_exts = sizeof(valid_exts)/sizeof(*valid_exts);
116+ zip_file *z = zip_open(filename);
117+ if (!z) {
118+ return 0;
119+ }
120+
121+ for (uint32_t i = 0; i < z->num_entries; i++)
122+ {
123+ char *ext = path_extension(z->entries[i].name);
124+ if (!ext) {
125+ continue;
126+ }
127+ for (uint32_t j = 0; j < num_exts; j++)
128+ {
129+ if (!strcasecmp(ext, valid_exts[j])) {
130+ size_t out_size = nearest_pow2(z->entries[i].size);
131+ *dst = zip_read(z, i, &out_size);
132+ if (*dst) {
133+ if (is_smd_format(z->entries[i].name, *dst)) {
134+ size_t offset;
135+ for (offset = 0; offset + SMD_BLOCK_SIZE + SMD_HEADER_SIZE <= out_size; offset += SMD_BLOCK_SIZE)
136+ {
137+ uint8_t tmp[SMD_BLOCK_SIZE];
138+ memcpy(tmp, *dst + offset + SMD_HEADER_SIZE, SMD_BLOCK_SIZE);
139+ process_smd_block(*dst + offset, tmp, SMD_BLOCK_SIZE);
140+ }
141+ out_size = offset;
142+ }
143+ free(ext);
144+ zip_close(z);
145+ return out_size;
146+ }
147+ }
148+ }
149+ free(ext);
150+ }
151+ zip_close(z);
152+ return 0;
153+}
154+
155+uint32_t load_rom(const char * filename, void **dst, system_type *stype)
156+{
157+ uint8_t header[10];
158+ char *ext = path_extension(filename);
159+ if (ext && !strcasecmp(ext, "zip")) {
160+ free(ext);
161+ return load_rom_zip(filename, dst);
162+ }
163+ free(ext);
164+ ROMFILE f = romopen(filename, "rb");
165+ if (!f) {
166+ return 0;
167+ }
168+ if (sizeof(header) != romread(header, 1, sizeof(header), f)) {
169+ fatal_error("Error reading from %s\n", filename);
170+ }
171+
172+ if (is_smd_format(filename, header)) {
173+ if (stype) {
174+ *stype = SYSTEM_GENESIS;
175+ }
176+ return load_smd_rom(f, dst);
177+ }
178+
179+ size_t filesize = 512 * 1024;
180+ size_t readsize = sizeof(header);
181+
182+ char *buf = malloc(filesize);
183+ memcpy(buf, header, readsize);
184+
185+ size_t read;
186+ do {
187+ read = romread(buf + readsize, 1, filesize - readsize, f);
188+ if (read > 0) {
189+ readsize += read;
190+ if (readsize == filesize) {
191+ int one_more = romgetc(f);
192+ if (one_more >= 0) {
193+ filesize *= 2;
194+ buf = realloc(buf, filesize);
195+ buf[readsize++] = one_more;
196+ } else {
197+ read = 0;
198+ }
199+ }
200+ }
201+ } while (read > 0);
202+
203+ *dst = buf;
204+
205+ romclose(f);
206+ return readsize;
207+}
208+
209+
210+
211+int break_on_sync = 0;
212+char *save_state_path;
213+
214+
215+
216+
217+
218+char * save_filename;
219+system_header *current_system;
220+system_header *menu_system;
221+system_header *game_system;
222+void persist_save()
223+{
224+ if (!game_system) {
225+ return;
226+ }
227+ game_system->persist_save(game_system);
228+}
229+
230+char *title;
231+void update_title(char *rom_name)
232+{
233+ if (title) {
234+ free(title);
235+ title = NULL;
236+ }
237+ title = alloc_concat(rom_name, " - BlastEm");
238+ render_update_caption(title);
239+}
240+
241+static char *get_save_dir(system_media *media)
242+{
243+ char *savedir_template = tern_find_path(config, "ui\0save_path\0", TVAL_PTR).ptrval;
244+ if (!savedir_template) {
245+ savedir_template = "$USERDATA/blastem/$ROMNAME";
246+ }
247+ tern_node *vars = tern_insert_ptr(NULL, "ROMNAME", media->name);
248+ vars = tern_insert_ptr(vars, "HOME", get_home_dir());
249+ vars = tern_insert_ptr(vars, "EXEDIR", get_exe_dir());
250+ vars = tern_insert_ptr(vars, "USERDATA", (char *)get_userdata_dir());
251+ char *save_dir = replace_vars(savedir_template, vars, 1);
252+ tern_free(vars);
253+ if (!ensure_dir_exists(save_dir)) {
254+ warning("Failed to create save directory %s\n", save_dir);
255+ }
256+ return save_dir;
257+}
258+
259+void setup_saves(system_media *media, system_header *context)
260+{
261+ static uint8_t persist_save_registered;
262+ rom_info *info = &context->info;
263+ char *save_dir = get_save_dir(info->is_save_lock_on ? media->chain : media);
264+ char const *parts[] = {save_dir, PATH_SEP, info->save_type == SAVE_I2C ? "save.eeprom" : info->save_type == SAVE_NOR ? "save.nor" : "save.sram"};
265+ free(save_filename);
266+ save_filename = alloc_concat_m(3, parts);
267+ if (info->is_save_lock_on) {
268+ //initial save dir was calculated based on lock-on cartridge because that's where the save device is
269+ //save directory used for save states should still be located in the normal place
270+ free(save_dir);
271+ parts[0] = save_dir = get_save_dir(media);
272+ }
273+ if (use_native_states || context->type != SYSTEM_GENESIS) {
274+ parts[2] = "quicksave.state";
275+ } else {
276+ parts[2] = "quicksave.gst";
277+ }
278+ free(save_state_path);
279+ save_state_path = alloc_concat_m(3, parts);
280+ context->save_dir = save_dir;
281+ if (info->save_type != SAVE_NONE) {
282+ context->load_save(context);
283+ if (!persist_save_registered) {
284+ atexit(persist_save);
285+ persist_save_registered = 1;
286+ }
287+ }
288+}
289+
290+void apply_updated_config(void)
291+{
292+ render_config_updated();
293+ if (current_system && current_system->config_updated) {
294+ current_system->config_updated(current_system);
295+ }
296+}
297+
298+static system_media cart, lock_on;
299+void reload_media(void)
300+{
301+ if (!current_system) {
302+ return;
303+ }
304+ if (current_system->next_rom) {
305+ free(current_system->next_rom);
306+ }
307+ char const *parts[] = {
308+ cart.dir, PATH_SEP, cart.name, ".", cart.extension
309+ };
310+ char const **start = parts[0] ? parts : parts + 2;
311+ int num_parts = parts[0] ? 5 : 3;
312+ if (!parts[4]) {
313+ num_parts--;
314+ }
315+ current_system->next_rom = alloc_concat_m(num_parts, start);
316+ current_system->request_exit(current_system);
317+}
318+
319+void lockon_media(char *lock_on_path)
320+{
321+ reload_media();
322+ cart.chain = &lock_on;
323+ free(lock_on.dir);
324+ free(lock_on.name);
325+ free(lock_on.extension);
326+ lock_on.dir = path_dirname(lock_on_path);
327+ lock_on.name = basename_no_extension(lock_on_path);
328+ lock_on.extension = path_extension(lock_on_path);
329+ lock_on.size = load_rom(lock_on_path, &lock_on.buffer, NULL);
330+}
331+
332+static uint32_t opts = 0;
333+static uint8_t force_region = 0;
334+void init_system_with_media(const char *path, system_type force_stype)
335+{
336+ if (game_system) {
337+ game_system->persist_save(game_system);
338+ //swap to game context arena and mark all allocated pages in it free
339+ if (current_system == menu_system) {
340+ current_system->arena = set_current_arena(game_system->arena);
341+ }
342+ mark_all_free();
343+ game_system->free_context(game_system);
344+ } else if(current_system) {
345+ //start a new arena and save old one in suspended system context
346+ current_system->arena = start_new_arena();
347+ }
348+ system_type stype = SYSTEM_UNKNOWN;
349+ if (!(cart.size = load_rom(path, &cart.buffer, &stype))) {
350+ fatal_error("Failed to open %s for reading\n", path);
351+ }
352+ free(cart.dir);
353+ free(cart.name);
354+ free(cart.extension);
355+ cart.dir = path_dirname(path);
356+ cart.name = basename_no_extension(path);
357+ cart.extension = path_extension(path);
358+ if (force_stype != SYSTEM_UNKNOWN) {
359+ stype = force_stype;
360+ }
361+ if (stype == SYSTEM_UNKNOWN) {
362+ stype = detect_system_type(&cart);
363+ }
364+ if (stype == SYSTEM_UNKNOWN) {
365+ fatal_error("Failed to detect system type for %s\n", path);
366+ }
367+ //allocate new system context
368+ game_system = alloc_config_system(stype, &cart, opts, force_region);
369+ if (!game_system) {
370+ fatal_error("Failed to configure emulated machine for %s\n", path);
371+ }
372+ if (menu_system) {
373+ menu_system->next_context = game_system;
374+ }
375+ game_system->next_context = menu_system;
376+ setup_saves(&cart, game_system);
377+ update_title(game_system->info.name);
378+}
379+
380+int main(int argc, char ** argv)
381+{
382+ set_exe_str(argv[0]);
383+ config = load_config();
384+ int width = -1;
385+ int height = -1;
386+ int loaded = 0;
387+ system_type stype = SYSTEM_UNKNOWN, force_stype = SYSTEM_UNKNOWN;
388+ char * romfname = NULL;
389+ char * statefile = NULL;
390+ debugger_type dtype = DEBUGGER_NATIVE;
391+ uint8_t start_in_debugger = 0;
392+ uint8_t debug_target = 0;
393+ for (int i = 1; i < argc; i++) {
394+ if (argv[i][0] == '-') {
395+ switch(argv[i][1]) {
396+ case 'b':
397+ i++;
398+ if (i >= argc) {
399+ fatal_error("-b must be followed by a frame count\n");
400+ }
401+ headless = 1;
402+ exit_after = atoi(argv[i]);
403+ break;
404+ case 'd':
405+ start_in_debugger = 1;
406+ //allow debugging the menu
407+ if (argv[i][2] == 'm') {
408+ debug_target = 1;
409+ }
410+ break;
411+ case 'D':
412+ gdb_remote_init();
413+ dtype = DEBUGGER_GDB;
414+ start_in_debugger = 1;
415+ break;
416+ case 'l':
417+ opts |= OPT_ADDRESS_LOG;
418+ break;
419+ case 'v':
420+ info_message("blastem %s\n", BLASTEM_VERSION);
421+ return 0;
422+ break;
423+ case 'n':
424+ z80_enabled = 0;
425+ break;
426+ case 'r':
427+ i++;
428+ if (i >= argc) {
429+ fatal_error("-r must be followed by region (J, U or E)\n");
430+ }
431+ force_region = translate_region_char(toupper(argv[i][0]));
432+ if (!force_region) {
433+ fatal_error("'%c' is not a valid region character for the -r option\n", argv[i][0]);
434+ }
435+ break;
436+ case 'm':
437+ i++;
438+ if (i >= argc) {
439+ fatal_error("-r must be followed by a machine type (sms, gen or jag)\n");
440+ }
441+ if (!strcmp("sms", argv[i])) {
442+ stype = force_stype = SYSTEM_SMS;
443+ } else if (!strcmp("gen", argv[i])) {
444+ stype = force_stype = SYSTEM_GENESIS;
445+ } else {
446+ fatal_error("Unrecognized machine type %s\n", argv[i]);
447+ }
448+ break;
449+ case 's':
450+ i++;
451+ if (i >= argc) {
452+ fatal_error("-s must be followed by a savestate filename\n");
453+ }
454+ statefile = argv[i];
455+ break;
456+ case 't':
457+ force_no_terminal();
458+ break;
459+ case 'y':
460+ opts |= YM_OPT_WAVE_LOG;
461+ break;
462+ case 'o': {
463+ i++;
464+ if (i >= argc) {
465+ fatal_error("-o must be followed by a lock on cartridge filename\n");
466+ }
467+ lock_on.size = load_rom(argv[i], &lock_on.buffer, NULL);
468+ if (!lock_on.size) {
469+ fatal_error("Failed to load lock on cartridge %s\n", argv[i]);
470+ }
471+ lock_on.name = basename_no_extension(argv[i]);
472+ lock_on.extension = path_extension(argv[i]);
473+ cart.chain = &lock_on;
474+ break;
475+ }
476+ case 'h':
477+ info_message(
478+ "Usage: blastem [OPTIONS] ROMFILE [WIDTH] [HEIGHT]\n"
479+ "Options:\n"
480+ " -h Print this help text\n"
481+ " -r (J|U|E) Force region to Japan, US or Europe respectively\n"
482+ " -m MACHINE Force emulated machine type to MACHINE. Valid values are:\n"
483+ " sms - Sega Master System/Mark III\n"
484+ " gen - Sega Genesis/Megadrive\n"
485+ " -s FILE Load a GST format savestate from FILE\n"
486+ " -o FILE Load FILE as a lock-on cartridge\n"
487+ " -d Enter debugger on startup\n"
488+ " -n Disable Z80\n"
489+ " -v Display version number and exit\n"
490+ " -l Log 68K code addresses (useful for assemblers)\n"
491+ " -y Log individual YM-2612 channels to WAVE files\n"
492+ );
493+ return 0;
494+ default:
495+ fatal_error("Unrecognized switch %s\n", argv[i]);
496+ }
497+ } else if (!loaded) {
498+ if (!(cart.size = load_rom(argv[i], &cart.buffer, stype == SYSTEM_UNKNOWN ? &stype : NULL))) {
499+ fatal_error("Failed to open %s for reading\n", argv[i]);
500+ }
501+ cart.dir = path_dirname(argv[i]);
502+ cart.name = basename_no_extension(argv[i]);
503+ cart.extension = path_extension(argv[i]);
504+ romfname = argv[i];
505+ loaded = 1;
506+ } else if (width < 0) {
507+ width = atoi(argv[i]);
508+ } else if (height < 0) {
509+ height = atoi(argv[i]);
510+ }
511+ }
512+
513+ int def_width = 0, def_height = 0;
514+ char *config_width = tern_find_path(config, "video\0width\0", TVAL_PTR).ptrval;
515+ if (config_width) {
516+ def_width = atoi(config_width);
517+ }
518+ if (!def_width) {
519+ def_width = 640;
520+ }
521+ char *config_height = tern_find_path(config, "video\0height\0", TVAL_PTR).ptrval;
522+ if (config_height) {
523+ def_height = atoi(config_height);
524+ }
525+ if (!def_height) {
526+ def_height = -1;
527+ }
528+ width = width < 1 ? def_width : width;
529+ height = height < 1 ? def_height : height;
530+
531+ if (!headless) {
532+ render_init(width, height, "BlastEm");
533+ }
534+ set_bindings();
535+
536+ uint8_t menu = !loaded;
537+ if (!loaded) {
538+ //load menu
539+ romfname = tern_find_path(config, "ui\0rom\0", TVAL_PTR).ptrval;
540+ if (!romfname) {
541+ romfname = "menu.bin";
542+ }
543+ if (is_absolute_path(romfname)) {
544+ if (!(cart.size = load_rom(romfname, &cart.buffer, &stype))) {
545+ fatal_error("Failed to open UI ROM %s for reading", romfname);
546+ }
547+ } else {
548+ cart.buffer = (uint16_t *)read_bundled_file(romfname, &cart.size);
549+ if (!cart.buffer) {
550+ fatal_error("Failed to open UI ROM %s for reading", romfname);
551+ }
552+ uint32_t rom_size = nearest_pow2(cart.size);
553+ if (rom_size > cart.size) {
554+ cart.buffer = realloc(cart.buffer, rom_size);
555+ cart.size = rom_size;
556+ }
557+ }
558+ //force system detection, value on command line is only for games not the menu
559+ stype = detect_system_type(&cart);
560+ cart.dir = path_dirname(romfname);
561+ cart.name = basename_no_extension(romfname);
562+ cart.extension = path_extension(romfname);
563+ loaded = 1;
564+ }
565+ char *state_format = tern_find_path(config, "ui\0state_format\0", TVAL_PTR).ptrval;
566+ if (state_format && !strcmp(state_format, "gst")) {
567+ use_native_states = 0;
568+ } else if (state_format && strcmp(state_format, "native")) {
569+ warning("%s is not a valid value for the ui.state_format setting. Valid values are gst and native\n", state_format);
570+ }
571+
572+ if (loaded) {
573+ if (stype == SYSTEM_UNKNOWN) {
574+ stype = detect_system_type(&cart);
575+ }
576+ if (stype == SYSTEM_UNKNOWN) {
577+ fatal_error("Failed to detect system type for %s\n", romfname);
578+ }
579+ current_system = alloc_config_system(stype, &cart, menu ? 0 : opts, force_region);
580+ if (!current_system) {
581+ fatal_error("Failed to configure emulated machine for %s\n", romfname);
582+ }
583+
584+ setup_saves(&cart, current_system);
585+ update_title(current_system->info.name);
586+ if (menu) {
587+ menu_system = current_system;
588+ } else {
589+ game_system = current_system;
590+ }
591+ }
592+
593+ current_system->debugger_type = dtype;
594+ current_system->enter_debugger = start_in_debugger && menu == debug_target;
595+ current_system->start_context(current_system, menu ? NULL : statefile);
596+ for(;;)
597+ {
598+ if (current_system->should_exit) {
599+ break;
600+ }
601+ if (current_system->next_rom) {
602+ char *next_rom = current_system->next_rom;
603+ current_system->next_rom = NULL;
604+ init_system_with_media(next_rom, force_stype);
605+ free(next_rom);
606+ menu = 0;
607+ current_system = game_system;
608+ current_system->debugger_type = dtype;
609+ current_system->enter_debugger = start_in_debugger && menu == debug_target;
610+ current_system->start_context(current_system, statefile);
611+ } else if (menu && game_system) {
612+ current_system->arena = set_current_arena(game_system->arena);
613+ current_system = game_system;
614+ menu = 0;
615+ current_system->resume_context(current_system);
616+ } else if (!menu && menu_system) {
617+ current_system->arena = set_current_arena(menu_system->arena);
618+ current_system = menu_system;
619+ menu = 1;
620+ if (!current_system->next_rom) {
621+ current_system->resume_context(current_system);
622+ }
623+ } else {
624+ break;
625+ }
626+ }
627+
628+ return 0;
629+}
+23,
-0
1@@ -0,0 +1,23 @@
2+#ifndef BLASTEM_H_
3+#define BLASTEM_H_
4+
5+#include "tern.h"
6+#include "system.h"
7+
8+extern int headless;
9+extern int exit_after;
10+extern int z80_enabled;
11+extern int frame_limit;
12+
13+extern tern_node * config;
14+extern system_header *current_system;
15+
16+extern char *save_state_path;
17+extern char *save_filename;
18+extern uint8_t use_native_states;
19+void reload_media(void);
20+void lockon_media(char *lock_on_path);
21+void init_system_with_media(const char *path, system_type force_stype);
22+void apply_updated_config(void);
23+
24+#endif //BLASTEM_H_
+97,
-0
1@@ -0,0 +1,97 @@
2+# i know this is a ninja file, but you're allowed to edit it.
3+# you can also pass things on the command line if you like, eg
4+#
5+# CC=clang ninja
6+
7+cc = $${CC:-cc}
8+cflags = $${CFLAGS:--O2 -flto -std=gnu11 -Wreturn-type -Werror=return-type -Werror=implicit-function-declaration -Wno-unused-value -m64 -pthread $$(pkg-config --cflags wayland-client)}
9+ldflags = $${LDFLAGS:--O2 -flto -m64 -pthread}
10+libs = $${LIBS:--lm $$(pkg-config --libs wayland-client) -lasound -lz}
11+prefix = $${PREFIX:-/usr}
12+destdir = $${DESTDIR:-}
13+bindir = $${BINDIR:-$${DESTDIR:-}$${PREFIX:-/usr}/bin}
14+xdg_shell_xml = $${XDG_SHELL_XML:-/usr/share/wayland-protocols/stable/xdg-shell/xdg-shell.xml}
15+
16+rule wayland_client_header
17+ command = wayland-scanner client-header $xdg_shell_xml $out
18+ description = wl $out
19+
20+rule wayland_private_code
21+ command = wayland-scanner private-code $xdg_shell_xml $out
22+ description = wl $out
23+
24+rule cc
25+ command = $cc $cflags -MMD -MF $out.d -c -o $out $in
26+ deps = gcc
27+ depfile = $out.d
28+ description = cc $out
29+
30+rule link
31+ command = $cc $ldflags -o $out $in $libs
32+ description = link $out
33+
34+rule install
35+ command = mkdir -p $bindir && cp $in $bindir/
36+ description = install $in
37+
38+build xdg-shell-client-protocol.h: wayland_client_header
39+build xdg-shell-protocol.c: wayland_private_code
40+
41+build blastem.o: cc blastem.c
42+build system.o: cc system.c
43+build genesis.o: cc genesis.c
44+build debug.o: cc debug.c
45+build gdb_remote.o: cc gdb_remote.c
46+build vdp.o: cc vdp.c
47+build ppm.o: cc ppm.c
48+build controller_info.o: cc controller_info.c
49+build render_wayland.o: cc render_wayland.c | xdg-shell-client-protocol.h
50+build xdg-shell-protocol.o: cc xdg-shell-protocol.c | xdg-shell-client-protocol.h
51+build png.o: cc png.c
52+build io.o: cc io.c
53+build romdb.o: cc romdb.c
54+build hash.o: cc hash.c
55+build menu.o: cc menu.c
56+build xband.o: cc xband.c
57+build realtec.o: cc realtec.c
58+build i2c.o: cc i2c.c
59+build nor.o: cc nor.c
60+build sega_mapper.o: cc sega_mapper.c
61+build multi_game.o: cc multi_game.c
62+build megawifi.o: cc megawifi.c
63+build net.o: cc net.c
64+build serialize.o: cc serialize.c
65+build terminal.o: cc terminal.c
66+build config.o: cc config.c
67+build tern.o: cc tern.c
68+build util.o: cc util.c
69+build paths.o: cc paths.c
70+build gst.o: cc gst.c
71+build 68kinst.o: cc 68kinst.c
72+build m68k_core.o: cc m68k_core.c
73+build m68k_core_x86.o: cc m68k_core_x86.c
74+build gen.o: cc gen.c
75+build backend.o: cc backend.c
76+build mem.o: cc mem.c
77+build arena.o: cc arena.c
78+build gen_x86.o: cc gen_x86.c
79+build backend_x86.o: cc backend_x86.c
80+build ym2612.o: cc ym2612.c
81+build psg.o: cc psg.c
82+build wave.o: cc wave.c
83+build saves.o: cc saves.c
84+build zip.o: cc zip.c
85+build bindings.o: cc bindings.c
86+build jcart.o: cc jcart.c
87+build sms.o: cc sms.c
88+build z80inst.o: cc z80inst.c
89+build z80_to_x86.o: cc z80_to_x86.c
90+
91+build blastem: link blastem.o system.o genesis.o debug.o gdb_remote.o vdp.o ppm.o controller_info.o render_wayland.o xdg-shell-protocol.o png.o io.o romdb.o hash.o menu.o xband.o realtec.o i2c.o nor.o sega_mapper.o multi_game.o megawifi.o net.o serialize.o terminal.o config.o tern.o util.o paths.o gst.o 68kinst.o m68k_core.o m68k_core_x86.o gen.o backend.o mem.o arena.o gen_x86.o backend_x86.o ym2612.o psg.o wave.o saves.o zip.o bindings.o jcart.o sms.o z80inst.o z80_to_x86.o
92+build all: phony blastem
93+build install-blastem: install blastem
94+build install-default-config: install default.cfg
95+build install-rom-db: install rom.db
96+build install: phony install-blastem install-default-config install-rom-db
97+
98+default all
1@@ -0,0 +1 @@
2+button.png,4,0,raw,interlace,nopal
+96,
-0
1@@ -0,0 +1,96 @@
2+#!/usr/bin/env python
3+from glob import glob
4+import subprocess
5+from sys import exit,argv
6+
7+prefixes = []
8+skip = set()
9+for i in range(1, len(argv)):
10+ if '.' in argv[i]:
11+ f = open(argv[i])
12+ for line in f:
13+ parts = line.split()
14+ for part in parts:
15+ if part.endswith('.bin'):
16+ skip.add(part)
17+ f.close()
18+ print 'Skipping',len(skip),'entries from previous report.'
19+ else:
20+ prefixes.append(argv[i])
21+
22+def print_mismatch(path, b, m):
23+ blines = b.split('\n')
24+ mlines = m.split('\n')
25+ if len(blines) != len(mlines):
26+ print '-----------------------------'
27+ print 'Unknown mismatch in', path
28+ print 'blastem output:'
29+ print b
30+ print 'musashi output:'
31+ print m
32+ print '-----------------------------'
33+ return
34+ prevline = ''
35+ differences = []
36+ flagmismatch = False
37+ regmismatch = False
38+ for i in xrange(0, len(blines)):
39+ if blines[i] != mlines[i]:
40+ if prevline == 'XNZVC':
41+ differences.append((prevline, prevline))
42+ flagmismatch = True
43+ else:
44+ regmismatch = True
45+ differences.append((blines[i], mlines[i]))
46+ prevline = blines[i]
47+ if flagmismatch and regmismatch:
48+ mtype = 'General'
49+ elif flagmismatch:
50+ mtype = 'Flag'
51+ elif regmismatch:
52+ mtype = 'Register'
53+ else:
54+ mtype = 'Unknown'
55+ print '-----------------------------'
56+ print mtype, 'mismatch in', path
57+ for i in xrange(0, 2):
58+ print 'musashi' if i else 'blastem', 'output:'
59+ for diff in differences:
60+ print diff[i]
61+ print '-----------------------------'
62+
63+
64+
65+for path in glob('generated_tests/*/*.bin'):
66+ if path in skip:
67+ continue
68+ if prefixes:
69+ good = False
70+ fname = path.split('/')[-1]
71+ for prefix in prefixes:
72+ if fname.startswith(prefix):
73+ good = True
74+ break
75+ if not good:
76+ continue
77+ try:
78+ b = subprocess.check_output(['./trans', path])
79+ try:
80+ m = subprocess.check_output(['musashi/mustrans', path])
81+ #_,_,b = b.partition('\n')
82+ if b != m:
83+ print_mismatch(path, b, m)
84+
85+ else:
86+ print path, 'passed'
87+ except subprocess.CalledProcessError as e:
88+ print '-----------------------------'
89+ print 'musashi exited with code', e.returncode, 'for test', path
90+ print 'blastem output:'
91+ print b
92+ print '-----------------------------'
93+ except subprocess.CalledProcessError as e:
94+ print '-----------------------------'
95+ print 'blastem exited with code', e.returncode, 'for test', path
96+ print '-----------------------------'
97+
A
config.c
+295,
-0
1@@ -0,0 +1,295 @@
2+/*
3+ Copyright 2013 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#include "tern.h"
8+#include "util.h"
9+#include "paths.h"
10+#include <stdio.h>
11+#include <stdlib.h>
12+#include <string.h>
13+
14+static tern_node * parse_config_int(char **state, int started, int *line)
15+{
16+ char *config_data, *curline;
17+ tern_node * head = NULL;
18+ config_data = started ? NULL : *state;
19+ while ((curline = strtok_r(config_data, "\n", state)))
20+ {
21+
22+ config_data = NULL;
23+ curline = strip_ws(curline);
24+ int len = strlen(curline);
25+ if (!len) {
26+ (*line)++;
27+ continue;
28+ }
29+ if (curline[0] == '#') {
30+ (*line)++;
31+ continue;
32+ }
33+ if (curline[0] == '}') {
34+ if (started) {
35+ return head;
36+ }
37+ fatal_error("unexpected } on line %d\n", *line);
38+ }
39+
40+ char * end = curline + len - 1;
41+ if (*end == '{') {
42+ *end = 0;
43+ curline = strip_ws(curline);
44+ (*line)++;
45+ head = tern_insert_node(head, curline, parse_config_int(state, 1, line));
46+ } else {
47+ char * val = strip_ws(split_keyval(curline));
48+ char * key = curline;
49+ if (*val) {
50+ head = tern_insert_ptr(head, key, strdup(val));
51+ } else {
52+ fprintf(stderr, "Key %s is missing a value on line %d\n", key, *line);
53+ }
54+ (*line)++;
55+ }
56+ }
57+ return head;
58+}
59+
60+tern_node *parse_config(char * config_data)
61+{
62+ int line = 1;
63+ return parse_config_int(&config_data, 0, &line);
64+}
65+
66+typedef struct {
67+ char *buf;
68+ uint32_t capacity;
69+ uint32_t size;
70+ uint32_t indent;
71+} serialize_state;
72+
73+static void ensure_buf_capacity(uint32_t ensure, serialize_state *state)
74+{
75+ if (ensure + state->size > state->capacity) {
76+ state->capacity = state->capacity * 2;
77+ state->buf = realloc(state->buf, state->capacity);
78+ }
79+}
80+
81+static void indent(serialize_state *state)
82+{
83+ memset(state->buf + state->size, '\t', state->indent);
84+ state->size += state->indent;
85+}
86+
87+static void serialize_config_int(tern_node *config, serialize_state *state);
88+
89+static void serialize_iter(char *key, tern_val val, uint8_t valtype, void *data)
90+{
91+ serialize_state *state = data;
92+ uint32_t keylen = strlen(key);
93+ uint32_t vallen = 0;
94+ if (valtype == TVAL_PTR) {
95+ vallen = strlen(val.ptrval);
96+ }
97+ ensure_buf_capacity(state->indent + keylen + 2 + vallen, state);
98+ state->buf[state->size++] = '\n';
99+ indent(state);
100+ memcpy(state->buf + state->size, key, keylen);
101+ state->size += keylen;
102+ state->buf[state->size++] = ' ';
103+ if (valtype == TVAL_PTR) {
104+ memcpy(state->buf + state->size, val.ptrval, vallen);
105+ state->size += vallen;
106+ } else {
107+ serialize_config_int(val.ptrval, state);
108+ }
109+}
110+
111+static void serialize_config_int(tern_node *config, serialize_state *state)
112+{
113+ ensure_buf_capacity(1, state);
114+ state->buf[state->size++] = '{';
115+ state->indent++;
116+
117+ tern_foreach(config, serialize_iter, state);
118+
119+ --state->indent;
120+ ensure_buf_capacity(2 + state->indent, state);
121+ state->buf[state->size++] = '\n';
122+ indent(state);
123+ state->buf[state->size++] = '}';
124+}
125+
126+char *serialize_config(tern_node *config, uint32_t *size_out)
127+{
128+ serialize_state state = {
129+ .size = 0,
130+ .capacity = 1024,
131+ .indent = 0
132+ };
133+ state.buf = malloc(state.capacity);
134+ tern_foreach(config, serialize_iter, &state);
135+ //serialize_config_int(config, &state);
136+ *size_out = state.size;
137+ return state.buf;
138+}
139+
140+tern_node *parse_config_file(char *config_path)
141+{
142+ tern_node * ret = NULL;
143+ FILE * config_file = fopen(config_path, "rb");
144+ if (!config_file) {
145+ goto open_fail;
146+ }
147+ long config_size = file_size(config_file);
148+ if (!config_size) {
149+ goto config_empty;
150+ }
151+ char *config_data = calloc(config_size + 1, 1);
152+ if (fread(config_data, 1, config_size, config_file) != config_size) {
153+ goto config_read_fail;
154+ }
155+
156+ ret = parse_config(config_data);
157+config_read_fail:
158+ free(config_data);
159+config_empty:
160+ fclose(config_file);
161+open_fail:
162+ return ret;
163+}
164+
165+uint8_t serialize_config_file(tern_node *config, char *path)
166+{
167+ FILE *f = fopen(path, "w");
168+ if (!f) {
169+ return 0;
170+ }
171+ uint32_t buf_size;
172+ char *buffer = serialize_config(config, &buf_size);
173+ uint8_t ret = buf_size == fwrite(buffer, 1, buf_size, f);
174+ free(buffer);
175+ fclose(f);
176+ return ret;
177+}
178+
179+tern_node *parse_bundled_config(char *config_name)
180+{
181+ tern_node *ret = NULL;
182+#ifdef CONFIG_PATH
183+ if (!strcmp("default.cfg", config_name) || !strcmp("blastem.cfg", config_name)) {
184+ char *confpath = path_append(CONFIG_PATH, config_name);
185+ ret = parse_config_file(confpath);
186+ free(confpath);
187+ } else {
188+#endif
189+ uint32_t confsize;
190+ char *confdata = read_bundled_file(config_name, &confsize);
191+ if (confdata) {
192+ confdata[confsize] = 0;
193+ ret = parse_config(confdata);
194+ free(confdata);
195+ }
196+#ifdef CONFIG_PATH
197+ }
198+#endif
199+ return ret;
200+}
201+
202+tern_node *load_overrideable_config(char *name, char *bundled_name)
203+{
204+ char const *confdir = get_config_dir();
205+ char *confpath = NULL;
206+ tern_node *ret;
207+ if (confdir) {
208+ confpath = path_append(confdir, name);
209+ ret = parse_config_file(confpath);
210+ if (ret) {
211+ free(confpath);
212+ return ret;
213+ }
214+ }
215+
216+ ret = parse_bundled_config(bundled_name);
217+ if (ret) {
218+ free(confpath);
219+ return ret;
220+ }
221+ return NULL;
222+}
223+
224+tern_node *load_config()
225+{
226+ char const *confdir = get_config_dir();
227+ char *confpath = NULL;
228+ tern_node *ret = load_overrideable_config("blastem.cfg", "default.cfg");
229+ if (confdir) {
230+ confpath = path_append(confdir, "blastem.cfg");
231+ ret = parse_config_file(confpath);
232+ if (ret) {
233+ free(confpath);
234+ return ret;
235+ }
236+ }
237+
238+ ret = parse_bundled_config("default.cfg");
239+ if (ret) {
240+ free(confpath);
241+ return ret;
242+ }
243+
244+ if (get_config_dir()) {
245+ fatal_error("Failed to find a config file at %s or in the blastem executable directory\n", get_config_dir());
246+ } else {
247+ fatal_error("Failed to find a config file in the BlastEm executable directory and the config directory path could not be determined\n");
248+ }
249+ //this will never get reached, but the compiler doesn't know that. Let's make it happy
250+ return NULL;
251+}
252+
253+void persist_config_at(tern_node *config, char *fname)
254+{
255+ char const *confdir = get_config_dir();
256+ if (!confdir) {
257+ fatal_error("Failed to locate config file directory\n");
258+ }
259+ ensure_dir_exists(confdir);
260+ char *confpath = path_append(confdir, fname);
261+ if (!serialize_config_file(config, confpath)) {
262+ fatal_error("Failed to write config to %s\n", confpath);
263+ }
264+ free(confpath);
265+}
266+
267+void persist_config(tern_node *config)
268+{
269+ persist_config_at(config, "blastem.cfg");
270+}
271+
272+char **get_extension_list(tern_node *config, uint32_t *num_exts_out)
273+{
274+ char *ext_filter = strdup(tern_find_path_default(config, "ui\0extensions\0", (tern_val){.ptrval = "bin gen md smd sms gg"}, TVAL_PTR).ptrval);
275+ uint32_t num_exts = 0, ext_storage = 5;
276+ char **ext_list = malloc(sizeof(char *) * ext_storage);
277+ char *cur_filter = ext_filter;
278+ while (*cur_filter)
279+ {
280+ if (num_exts == ext_storage) {
281+ ext_storage *= 2;
282+ ext_list = realloc(ext_list, sizeof(char *) * ext_storage);
283+ }
284+ ext_list[num_exts++] = cur_filter;
285+ cur_filter = split_keyval(cur_filter);
286+ }
287+ *num_exts_out = num_exts;
288+ return ext_list;
289+}
290+
291+#define DEFAULT_LOWPASS_CUTOFF 3390
292+uint32_t get_lowpass_cutoff(tern_node *config)
293+{
294+ char * lowpass_cutoff_str = tern_find_path(config, "audio\0lowpass_cutoff\0", TVAL_PTR).ptrval;
295+ return lowpass_cutoff_str ? atoi(lowpass_cutoff_str) : DEFAULT_LOWPASS_CUTOFF;
296+}
A
config.h
+22,
-0
1@@ -0,0 +1,22 @@
2+/*
3+ Copyright 2013 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#ifndef CONFIG_H_
8+#define CONFIG_H_
9+#include "tern.h"
10+
11+tern_node *parse_config_file(char *config_path);
12+tern_node *parse_bundled_config(char *config_name);
13+tern_node *load_overrideable_config(char *name, char *bundled_name);
14+tern_node *load_config();
15+char *serialize_config(tern_node *config, uint32_t *size_out);
16+uint8_t serialize_config_file(tern_node *config, char *path);
17+void persist_config_at(tern_node *config, char *fname);
18+void persist_config(tern_node *config);
19+char **get_extension_list(tern_node *config, uint32_t *num_exts_out);
20+uint32_t get_lowpass_cutoff(tern_node *config);
21+
22+#endif //CONFIG_H_
23+
+217,
-0
1@@ -0,0 +1,217 @@
2+#include <string.h>
3+#include <stdlib.h>
4+#include "controller_info.h"
5+#include "config.h"
6+#include "util.h"
7+
8+typedef struct {
9+ char const *name;
10+ controller_info info;
11+} heuristic;
12+
13+static heuristic heuristics[] = {
14+ //TODO: Add more heuristic rules
15+ {"DualShock 4", {.type = TYPE_PSX, .subtype = SUBTYPE_PS4}},
16+ {"PS4", {.type = TYPE_PSX, .subtype = SUBTYPE_PS4}},
17+ {"PS3", {.type = TYPE_PSX, .subtype = SUBTYPE_PS3}},
18+ {"X360", {.type = TYPE_XBOX, .subtype = SUBTYPE_X360}},
19+ {"Xbox 360", {.type = TYPE_XBOX, .subtype = SUBTYPE_X360}},
20+ {"X-box 360", {.type = TYPE_XBOX, .subtype = SUBTYPE_X360}},
21+ {"Xbox One", {.type = TYPE_XBOX, .subtype = SUBTYPE_XBONE}},
22+ {"X-box One", {.type = TYPE_XBOX, .subtype = SUBTYPE_XBONE}},
23+ {"WiiU", {.type = TYPE_NINTENDO, .subtype = SUBTYPE_WIIU}},
24+ {"Wii U", {.type = TYPE_NINTENDO, .subtype = SUBTYPE_WIIU}},
25+ {"Nintendo Switch", {.type = TYPE_NINTENDO, .subtype = SUBTYPE_SWITCH}},
26+ {"Saturn", {.type = TYPE_SEGA, .subtype = SUBTYPE_SATURN}}
27+};
28+const uint32_t num_heuristics = sizeof(heuristics)/sizeof(*heuristics);
29+
30+static tern_node *info_config;
31+static uint8_t loaded;
32+static const char *subtype_names[] = {
33+ "unknown",
34+ "xbox",
35+ "xbox 360",
36+ "xbone",
37+ "ps2",
38+ "ps3",
39+ "ps4",
40+ "wiiu",
41+ "switch",
42+ "genesis",
43+ "saturn"
44+};
45+static const char *subtype_human_names[] = {
46+ "unknown",
47+ "Xbos",
48+ "Xbox 360",
49+ "Xbox One",
50+ "PS2",
51+ "PS3",
52+ "PS4",
53+ "Wii-U",
54+ "Switch",
55+ "Genesis",
56+ "Saturn"
57+};
58+static const char *variant_names[] = {
59+ "normal",
60+ "6b bumpers",
61+ "6b right"
62+};
63+
64+static void load_ctype_config(void)
65+{
66+ if (!loaded) {
67+ info_config = load_overrideable_config("controller_types.cfg", "controller_types.cfg");
68+ loaded = 1;
69+ }
70+}
71+
72+controller_info get_controller_info(int joystick)
73+{
74+ const char *name = "Unknown";
75+ return (controller_info){
76+ .type = TYPE_GENERIC_MAPPING,
77+ .subtype = SUBTYPE_UNKNOWN,
78+ .variant = VARIANT_NORMAL,
79+ .name = name
80+ };
81+}
82+
83+static void mappings_iter(char *key, tern_val val, uint8_t valtype, void *data)
84+{
85+}
86+
87+void controller_add_mappings(void)
88+{
89+ load_ctype_config();
90+ if (info_config) {
91+ tern_foreach(info_config, mappings_iter, NULL);
92+ }
93+}
94+
95+void save_controller_info(int joystick, controller_info *info)
96+{
97+}
98+
99+void save_controller_mapping(int joystick, char *mapping_string)
100+{
101+}
102+
103+char const *labels_xbox[] = {
104+ "A", "B", "X", "Y", "Back", NULL, "Start", "Click", "Click", "White", "Black", "LT", "RT"
105+};
106+char const *labels_360[] = {
107+ "A", "B", "X", "Y", "Back", "Xbox", "Start", "Click", "Click", "LB", "RB", "LT", "RT"
108+};
109+static char const *labels_xbone[] = {
110+ "A", "B", "X", "Y", "View", "Xbox", "Menu", "Click", "Click", "LB", "RB", "LT", "RT"
111+};
112+static char const *labels_ps3[] = {
113+ "cross", "circle", "square", "triangle", "Select", "PS", "Start", "L3", "R3", "L1", "R1", "L2", "R2"
114+};
115+static char const *labels_ps4[] = {
116+ "cross", "circle", "square", "triangle", "Share", "PS", "Options", "L3", "R3", "L1", "R1", "L2", "R2"
117+};
118+static char const *labels_nintendo[] = {
119+ "B", "A", "Y", "X", "-", "Home", "+", "Click", "Click", "L", "R", "ZL", "ZR"
120+};
121+static char const *labels_genesis[] = {
122+ "A", "B", "X", "Y", NULL, NULL, "Start", NULL, NULL, "Z", "C", NULL, "Mode"
123+};
124+static char const *labels_saturn[] = {
125+ "A", "B", "X", "Y", NULL, NULL, "Start", NULL, NULL, "Z", "C", "LT", "RT"
126+};
127+
128+static const char** label_source(controller_info *info)
129+{
130+ if (info->type == TYPE_UNKNOWN || info->type == TYPE_GENERIC_MAPPING || info->subtype ==SUBTYPE_X360) {
131+ return labels_360;
132+ } else if (info->type == TYPE_NINTENDO) {
133+ return labels_nintendo;
134+ } else if (info->type == TYPE_PSX) {
135+ if (info->subtype == SUBTYPE_PS4) {
136+ return labels_ps4;
137+ } else {
138+ return labels_ps3;
139+ }
140+ } else if (info->type == TYPE_XBOX) {
141+ if (info->subtype == SUBTYPE_XBONE) {
142+ return labels_xbone;
143+ } else {
144+ return labels_xbox;
145+ }
146+ } else {
147+ if (info->subtype == SUBTYPE_GENESIS) {
148+ return labels_genesis;
149+ } else {
150+ return labels_saturn;
151+ }
152+ }
153+}
154+
155+const char *get_button_label(controller_info *info, int button)
156+{
157+ return label_source(info)[button];
158+}
159+
160+static char const *axis_labels[] = {
161+ "Left X", "Left Y", "Right X", "Right Y"
162+};
163+const char *get_axis_label(controller_info *info, int axis)
164+{
165+ return NULL;
166+}
167+
168+char *make_controller_type_key(controller_info *info)
169+{
170+ const char *subtype;
171+ if (info->subtype == SUBTYPE_UNKNOWN) {
172+ switch(info->type)
173+ {
174+ case TYPE_XBOX:
175+ subtype = subtype_names[SUBTYPE_X360];
176+ break;
177+ case TYPE_PSX:
178+ subtype = subtype_names[SUBTYPE_PS4];
179+ break;
180+ case TYPE_NINTENDO:
181+ subtype = subtype_names[SUBTYPE_SWITCH];
182+ break;
183+ default:
184+ subtype = "unknown";
185+ }
186+ } else {
187+ subtype = subtype_names[info->subtype];
188+ }
189+ const char *variant = variant_names[info->variant];
190+ const char *parts[] = {subtype, "_", variant};
191+ char *ret = alloc_concat_m(3, parts);
192+ for (char *cur = ret; *cur; cur++)
193+ {
194+ if (*cur == ' ')
195+ {
196+ *cur = '_';
197+ }
198+ }
199+ return ret;
200+}
201+
202+char *make_human_readable_type_name(controller_info *info)
203+{
204+ const char *base = subtype_human_names[info->subtype];
205+ char *prefix;
206+ if (info->variant == VARIANT_NORMAL) {
207+ prefix = "Normal ";
208+ } else {
209+ static const char *parts[] = {"6 button (", NULL, "/", NULL, ") "};
210+ parts[1] = parts[3] = "??";
211+ prefix = alloc_concat_m(5, parts);
212+ }
213+ char *ret = alloc_concat(prefix, base);
214+ if (info->variant != VARIANT_NORMAL) {
215+ free(prefix);
216+ }
217+ return ret;
218+}
+52,
-0
1@@ -0,0 +1,52 @@
2+#ifndef CONTROLLER_INFO_H_
3+#define CONTROLLER_INFO_H_
4+#include <stdint.h>
5+
6+enum {
7+ TYPE_UNKNOWN,
8+ TYPE_GENERIC_MAPPING,
9+ TYPE_XBOX,
10+ TYPE_PSX,
11+ TYPE_NINTENDO,
12+ TYPE_SEGA
13+};
14+
15+enum {
16+ SUBTYPE_UNKNOWN,
17+ SUBTYPE_XBOX,
18+ SUBTYPE_X360,
19+ SUBTYPE_XBONE,
20+ SUBTYPE_PS2,
21+ SUBTYPE_PS3,
22+ SUBTYPE_PS4,
23+ SUBTYPE_WIIU,
24+ SUBTYPE_SWITCH,
25+ SUBTYPE_GENESIS,
26+ SUBTYPE_SATURN,
27+ SUBTYPE_NUM
28+};
29+
30+enum {
31+ VARIANT_NORMAL,
32+ VARIANT_6B_BUMPERS, //C and Z positions are RB and LB respectively
33+ VARIANT_6B_RIGHT, //C and Z positions are RT and RB respectively
34+ VARIANT_NUM
35+};
36+
37+typedef struct {
38+ char const *name;
39+ uint8_t type;
40+ uint8_t subtype;
41+ uint8_t variant;
42+} controller_info;
43+
44+controller_info get_controller_info(int index);
45+const char *get_button_label(controller_info *info, int button);
46+const char *get_axis_label(controller_info *info, int axis);
47+void save_controller_info(int joystick, controller_info *info);
48+void save_controller_mapping(int joystick, char *mapping_string);
49+void controller_add_mappings(void);
50+char *make_controller_type_key(controller_info *info);
51+char *make_human_readable_type_name(controller_info *info);
52+
53+#endif //CONTROLLER_INFO_H_
+1697,
-0
1@@ -0,0 +1,1697 @@
2+#!/usr/bin/env python3
3+
4+
5+class Block:
6+ def addOp(self, op):
7+ pass
8+
9+ def processLine(self, parts):
10+ if parts[0] == 'switch':
11+ o = Switch(self, parts[1])
12+ self.addOp(o)
13+ return o
14+ elif parts[0] == 'if':
15+ o = If(self, parts[1])
16+ self.addOp(o)
17+ return o
18+ elif parts[0] == 'end':
19+ raise Exception('end is only allowed inside a switch or if block')
20+ else:
21+ self.addOp(NormalOp(parts))
22+ return self
23+
24+ def processOps(self, prog, fieldVals, output, otype, oplist):
25+ for i in range(0, len(oplist)):
26+ if i + 1 < len(oplist) and oplist[i+1].op == 'update_flags':
27+ flagUpdates, _ = prog.flags.parseFlagUpdate(oplist[i+1].params[0])
28+ else:
29+ flagUpdates = None
30+ oplist[i].generate(prog, self, fieldVals, output, otype, flagUpdates)
31+
32+ def resolveLocal(self, name):
33+ return None
34+
35+class ChildBlock(Block):
36+ def processLine(self, parts):
37+ if parts[0] == 'end':
38+ return self.parent
39+ return super().processLine(parts)
40+
41+#Represents an instruction of the emulated CPU
42+class Instruction(Block):
43+ def __init__(self, value, fields, name):
44+ self.value = value
45+ self.fields = fields
46+ self.name = name
47+ self.implementation = []
48+ self.locals = {}
49+ self.regValues = {}
50+ self.varyingBits = 0
51+ self.invalidFieldValues = {}
52+ self.newLocals = []
53+ for field in fields:
54+ self.varyingBits += fields[field][1]
55+
56+ def addOp(self, op):
57+ if op.op == 'local':
58+ name = op.params[0]
59+ size = int(op.params[1])
60+ self.locals[name] = size
61+ elif op.op == 'invalid':
62+ name = op.params[0]
63+ value = int(op.params[1])
64+ self.invalidFieldValues.setdefault(name, set()).add(value)
65+ else:
66+ self.implementation.append(op)
67+
68+ def resolveLocal(self, name):
69+ if name in self.locals:
70+ return name
71+ return None
72+
73+ def addLocal(self, name, size):
74+ self.locals[name] = size
75+ self.newLocals.append(name)
76+
77+ def localSize(self, name):
78+ return self.locals.get(name)
79+
80+ def __lt__(self, other):
81+ if isinstance(other, Instruction):
82+ if self.varyingBits != other.varyingBits:
83+ return self.varyingBits < other.varyingBits
84+ return self.value < other.value
85+ else:
86+ return NotImplemented
87+
88+ def allValues(self):
89+ values = []
90+ for i in range(0, 1 << self.varyingBits):
91+ iword = self.value
92+ doIt = True
93+ for field in self.fields:
94+ shift,bits = self.fields[field]
95+ val = i & ((1 << bits) - 1)
96+ if field in self.invalidFieldValues and val in self.invalidFieldValues[field]:
97+ doIt = False
98+ break
99+ i >>= bits
100+ iword |= val << shift
101+ if doIt:
102+ values.append(iword)
103+ return values
104+
105+ def getFieldVals(self, value):
106+ fieldVals = {}
107+ fieldBits = {}
108+ for field in self.fields:
109+ shift,bits = self.fields[field]
110+ val = (value >> shift) & ((1 << bits) - 1)
111+ fieldVals[field] = val
112+ fieldBits[field] = bits
113+ return (fieldVals, fieldBits)
114+
115+ def generateName(self, value):
116+ fieldVals,fieldBits = self.getFieldVals(value)
117+ names = list(fieldVals.keys())
118+ names.sort()
119+ funName = self.name
120+ for name in names:
121+ funName += '_{0}_{1:0>{2}}'.format(name, bin(fieldVals[name])[2:], fieldBits[name])
122+ return funName
123+
124+ def generateBody(self, value, prog, otype):
125+ output = []
126+ prog.meta = {}
127+ prog.pushScope(self)
128+ self.regValues = {}
129+ for var in self.locals:
130+ output.append('\n\tuint{sz}_t {name};'.format(sz=self.locals[var], name=var))
131+ self.newLocals = []
132+ fieldVals,_ = self.getFieldVals(value)
133+ self.processOps(prog, fieldVals, output, otype, self.implementation)
134+
135+ if prog.dispatch == 'call':
136+ begin = '\nvoid ' + self.generateName(value) + '(' + prog.context_type + ' *context)\n{'
137+ elif prog.dispatch == 'goto':
138+ begin = '\n' + self.generateName(value) + ': {'
139+ else:
140+ raise Exception('Unsupported dispatch type ' + prog.dispatch)
141+ if prog.needFlagCoalesce:
142+ begin += prog.flags.coalesceFlags(prog, otype)
143+ if prog.needFlagDisperse:
144+ output.append(prog.flags.disperseFlags(prog, otype))
145+ for var in self.newLocals:
146+ begin += '\n\tuint{sz}_t {name};'.format(sz=self.locals[var], name=var)
147+ prog.popScope()
148+ if prog.dispatch == 'goto':
149+ output += prog.nextInstruction(otype)
150+ return begin + ''.join(output) + '\n}'
151+
152+ def __str__(self):
153+ pieces = [self.name + ' ' + hex(self.value) + ' ' + str(self.fields)]
154+ for name in self.locals:
155+ pieces.append('\n\tlocal {0} {1}'.format(name, self.locals[name]))
156+ for op in self.implementation:
157+ pieces.append(str(op))
158+ return ''.join(pieces)
159+
160+#Represents the definition of a helper function
161+class SubRoutine(Block):
162+ def __init__(self, name):
163+ self.name = name
164+ self.implementation = []
165+ self.args = []
166+ self.arg_map = {}
167+ self.locals = {}
168+ self.regValues = {}
169+ self.argValues = {}
170+
171+ def addOp(self, op):
172+ if op.op == 'arg':
173+ name = op.params[0]
174+ size = int(op.params[1])
175+ self.arg_map[name] = len(self.args)
176+ self.args.append((name, size))
177+ elif op.op == 'local':
178+ name = op.params[0]
179+ size = int(op.params[1])
180+ self.locals[name] = size
181+ else:
182+ self.implementation.append(op)
183+
184+ def resolveLocal(self, name):
185+ if name in self.locals:
186+ return self.name + '_' + name
187+ return None
188+
189+ def addLocal(self, name, size):
190+ self.locals[name] = size
191+
192+ def localSize(self, name):
193+ if name in self.locals:
194+ return self.locals[name]
195+ if name in self.arg_map:
196+ argIndex = self.arg_map[name]
197+ return self.args[argIndex][1]
198+ return None
199+
200+ def inline(self, prog, params, output, otype, parent):
201+ if len(params) != len(self.args):
202+ raise Exception('{0} expects {1} arguments, but was called with {2}'.format(self.name, len(self.args), len(params)))
203+ argValues = {}
204+ if parent:
205+ self.regValues = parent.regValues
206+ prog.pushScope(self)
207+ i = 0
208+ for name,size in self.args:
209+ argValues[name] = params[i]
210+ i += 1
211+ for name in self.locals:
212+ size = self.locals[name]
213+ output.append('\n\tuint{size}_t {sub}_{local};'.format(size=size, sub=self.name, local=name))
214+ self.argValues = argValues
215+ self.processOps(prog, argValues, output, otype, self.implementation)
216+ prog.popScope()
217+
218+ def __str__(self):
219+ pieces = [self.name]
220+ for name,size in self.args:
221+ pieces.append('\n\targ {0} {1}'.format(name, size))
222+ for name in self.locals:
223+ pieces.append('\n\tlocal {0} {1}'.format(name, self.locals[name]))
224+ for op in self.implementation:
225+ pieces.append(str(op))
226+ return ''.join(pieces)
227+
228+class Op:
229+ def __init__(self, evalFun = None):
230+ self.evalFun = evalFun
231+ self.impls = {}
232+ self.outOp = ()
233+ def cBinaryOperator(self, op):
234+ def _impl(prog, params, rawParams, flagUpdates):
235+ if op == '-':
236+ a = params[1]
237+ b = params[0]
238+ else:
239+ a = params[0]
240+ b = params[1]
241+ needsCarry = needsOflow = needsHalf = False
242+ if flagUpdates:
243+ for flag in flagUpdates:
244+ calc = prog.flags.flagCalc[flag]
245+ if calc == 'carry':
246+ needsCarry = True
247+ elif calc == 'half-carry':
248+ needsHalf = True
249+ elif calc == 'overflow':
250+ needsOflow = True
251+ decl = ''
252+ if needsCarry or needsOflow or needsHalf:
253+ size = prog.paramSize(rawParams[2])
254+ if needsCarry and op != 'lsr':
255+ size *= 2
256+ decl,name = prog.getTemp(size)
257+ dst = prog.carryFlowDst = name
258+ prog.lastA = a
259+ prog.lastB = b
260+ prog.lastBFlow = b if op == '-' else '(~{b})'.format(b=b)
261+ else:
262+ dst = params[2]
263+ return decl + '\n\t{dst} = {a} {op} {b};'.format(
264+ dst = dst, a = a, b = b, op = op
265+ )
266+ self.impls['c'] = _impl
267+ self.outOp = (2,)
268+ return self
269+ def cUnaryOperator(self, op):
270+ def _impl(prog, params, rawParams, flagUpdates):
271+ dst = params[1]
272+ decl = ''
273+ if op == '-':
274+ if flagUpdates:
275+ for flag in flagUpdates:
276+ calc = prog.flags.flagCalc[flag]
277+ if calc == 'carry':
278+ needsCarry = True
279+ elif calc == 'half-carry':
280+ needsHalf = True
281+ elif calc == 'overflow':
282+ needsOflow = True
283+ if needsCarry or needsOflow or needsHalf:
284+ size = prog.paramSize(rawParams[1])
285+ if needsCarry:
286+ size *= 2
287+ decl,name = prog.getTemp(size)
288+ dst = prog.carryFlowDst = name
289+ prog.lastA = 0
290+ prog.lastB = params[0]
291+ prog.lastBFlow = params[0]
292+ return decl + '\n\t{dst} = {op}{a};'.format(
293+ dst = dst, a = params[0], op = op
294+ )
295+ self.impls['c'] = _impl
296+ self.outOp = (1,)
297+ return self
298+ def addImplementation(self, lang, outOp, impl):
299+ self.impls[lang] = impl
300+ if not outOp is None:
301+ if type(outOp) is tuple:
302+ self.outOp = outOp
303+ else:
304+ self.outOp = (outOp,)
305+ return self
306+ def evaluate(self, params):
307+ return self.evalFun(*params)
308+ def canEval(self):
309+ return not self.evalFun is None
310+ def numArgs(self):
311+ return self.evalFun.__code__.co_argcount
312+ def numParams(self):
313+ if self.outOp:
314+ params = max(self.outOp) + 1
315+ else:
316+ params = 0
317+ if self.evalFun:
318+ params = max(params, self.numArgs())
319+ return params
320+ def generate(self, otype, prog, params, rawParams, flagUpdates):
321+ if self.impls[otype].__code__.co_argcount == 2:
322+ return self.impls[otype](prog, params)
323+ elif self.impls[otype].__code__.co_argcount == 3:
324+ return self.impls[otype](prog, params, rawParams)
325+ else:
326+ return self.impls[otype](prog, params, rawParams, flagUpdates)
327+
328+
329+def _xchgCImpl(prog, params, rawParams):
330+ size = prog.paramSize(rawParams[0])
331+ decl,name = prog.getTemp(size)
332+ return decl + '\n\t{tmp} = {a};\n\t{a} = {b};\n\t{b} = {tmp};'.format(a = params[0], b = params[1], tmp = name)
333+
334+def _dispatchCImpl(prog, params):
335+ if len(params) == 1:
336+ table = 'main'
337+ else:
338+ table = params[1]
339+ if prog.dispatch == 'call':
340+ return '\n\timpl_{tbl}[{op}](context);'.format(tbl = table, op = params[0])
341+ elif prog.dispatch == 'goto':
342+ return '\n\tgoto *impl_{tbl}[{op}];'.format(tbl = table, op = params[0])
343+ else:
344+ raise Exception('Unsupported dispatch type ' + prog.dispatch)
345+
346+def _updateFlagsCImpl(prog, params, rawParams):
347+ autoUpdate, explicit = prog.flags.parseFlagUpdate(params[0])
348+ output = []
349+ parity = None
350+ directFlags = {}
351+ for flag in autoUpdate:
352+ calc = prog.flags.flagCalc[flag]
353+ calc,_,resultBit = calc.partition('-')
354+ if prog.carryFlowDst:
355+ lastDst = prog.carryFlowDst
356+ else:
357+ lastDst = prog.resolveParam(prog.lastDst, prog.currentScope, {})
358+ storage = prog.flags.getStorage(flag)
359+ if calc == 'bit' or calc == 'sign' or calc == 'carry' or calc == 'half' or calc == 'overflow':
360+ myRes = lastDst
361+ if calc == 'sign':
362+ resultBit = prog.paramSize(prog.lastDst) - 1
363+ elif calc == 'carry':
364+ if prog.lastOp.op in ('asr', 'lsr'):
365+ resultBit = 0
366+ myRes = prog.lastA
367+ else:
368+ resultBit = prog.paramSize(prog.lastDst)
369+ if prog.lastOp.op == 'ror':
370+ resultBit -= 1
371+ elif calc == 'half':
372+ resultBit = prog.paramSize(prog.lastDst) - 4
373+ myRes = '({a} ^ {b} ^ {res})'.format(a = prog.lastA, b = prog.lastB, res = lastDst)
374+ elif calc == 'overflow':
375+ resultBit = prog.paramSize(prog.lastDst) - 1
376+ myRes = '((({a} ^ {b})) & ({a} ^ {res}))'.format(a = prog.lastA, b = prog.lastBFlow, res = lastDst)
377+ else:
378+ #Note: offsetting this by the operation size - 8 makes sense for the Z80
379+ #but might not for other CPUs with this kind of fixed bit flag behavior
380+ resultBit = int(resultBit) + prog.paramSize(prog.lastDst) - 8
381+ if type(storage) is tuple:
382+ reg,storageBit = storage
383+ if storageBit == resultBit:
384+ directFlags.setdefault((reg, myRes), []).append(resultBit)
385+ else:
386+ reg = prog.resolveParam(reg, None, {})
387+ if resultBit > storageBit:
388+ op = '>>'
389+ shift = resultBit - storageBit
390+ else:
391+ op = '<<'
392+ shift = storageBit - resultBit
393+ output.append('\n\t{reg} = ({reg} & ~{mask}U) | ({res} {op} {shift}U & {mask}U);'.format(
394+ reg = reg, mask = 1 << storageBit, res = myRes, op = op, shift = shift
395+ ))
396+ else:
397+ reg = prog.resolveParam(storage, None, {})
398+ maxBit = prog.paramSize(storage) - 1
399+ if resultBit > maxBit:
400+ output.append('\n\t{reg} = {res} >> {shift} & {mask}U;'.format(reg=reg, res=myRes, shift = resultBit - maxBit, mask = 1 << maxBit))
401+ else:
402+ output.append('\n\t{reg} = {res} & {mask}U;'.format(reg=reg, res=myRes, mask = 1 << resultBit))
403+ elif calc == 'zero':
404+ if prog.carryFlowDst:
405+ realSize = prog.paramSize(prog.lastDst)
406+ if realSize != prog.paramSize(prog.carryFlowDst):
407+ lastDst = '({res} & {mask})'.format(res=lastDst, mask = (1 << realSize) - 1)
408+ if type(storage) is tuple:
409+ reg,storageBit = storage
410+ reg = prog.resolveParam(reg, None, {})
411+ output.append('\n\t{reg} = {res} ? ({reg} & {mask}U) : ({reg} | {bit}U);'.format(
412+ reg = reg, mask = ~(1 << storageBit), res = lastDst, bit = 1 << storageBit
413+ ))
414+ else:
415+ reg = prog.resolveParam(storage, None, {})
416+ output.append('\n\t{reg} = {res} == 0;'.format(
417+ reg = reg, res = lastDst
418+ ))
419+ elif calc == 'parity':
420+ parity = storage
421+ paritySize = prog.paramSize(prog.lastDst)
422+ if prog.carryFlowDst:
423+ parityDst = paritySrc = prog.carryFlowDst
424+ else:
425+ paritySrc = lastDst
426+ decl,name = prog.getTemp(paritySize)
427+ output.append(decl)
428+ parityDst = name
429+ else:
430+ raise Exception('Unknown flag calc type: ' + calc)
431+ for reg, myRes in directFlags:
432+ bits = directFlags[(reg, myRes)]
433+ resolved = prog.resolveParam(reg, None, {})
434+ if len(bits) == len(prog.flags.storageToFlags[reg]):
435+ output.append('\n\t{reg} = {res};'.format(reg = resolved, res = myRes))
436+ else:
437+ mask = 0
438+ for bit in bits:
439+ mask |= 1 << bit
440+ output.append('\n\t{reg} = ({reg} & ~{mask}U) | ({res} & {mask}U);'.format(
441+ reg = resolved, mask = mask, res = myRes
442+ ))
443+ if prog.carryFlowDst:
444+ if prog.lastOp.op != 'cmp':
445+ output.append('\n\t{dst} = {tmpdst};'.format(dst = prog.resolveParam(prog.lastDst, prog.currentScope, {}), tmpdst = prog.carryFlowDst))
446+ prog.carryFlowDst = None
447+ if parity:
448+ if paritySize > 8:
449+ if paritySize > 16:
450+ output.append('\n\t{dst} = {src} ^ ({src} >> 16);'.format(dst=parityDst, src=paritySrc))
451+ paritySrc = parityDst
452+ output.append('\n\t{dst} = {src} ^ ({src} >> 8);'.format(dst=parityDst, src=paritySrc))
453+ paritySrc = parityDst
454+ output.append('\n\t{dst} = ({src} ^ ({src} >> 4)) & 0xF;'.format(dst=parityDst, src=paritySrc))
455+ if type(parity) is tuple:
456+ reg,bit = parity
457+ reg = prog.resolveParam(reg, None, {})
458+ output.append('\n\t{flag} = ({flag} & ~{mask}U) | ((0x6996 >> {parity}) << {bit} & {mask}U);'.format(
459+ flag=reg, mask = 1 << bit, bit = bit, parity = parityDst
460+ ))
461+ else:
462+ reg = prog.resolveParam(parity, None, {})
463+ output.append('\n\t{flag} = 0x9669 >> {parity} & 1;'.format(flag=reg, parity=parityDst))
464+
465+ #TODO: combine explicit flags targeting the same storage location
466+ for flag in explicit:
467+ location = prog.flags.getStorage(flag)
468+ if type(location) is tuple:
469+ reg,bit = location
470+ reg = prog.resolveReg(reg, None, {})
471+ value = str(1 << bit)
472+ if explicit[flag]:
473+ operator = '|='
474+ else:
475+ operator = '&='
476+ value = '~' + value
477+ output.append('\n\t{reg} {op} {val};'.format(reg=reg, op=operator, val=value))
478+ else:
479+ reg = prog.resolveReg(location, None, {})
480+ output.append('\n\t{reg} = {val};'.format(reg=reg, val=explicit[flag]))
481+ return ''.join(output)
482+
483+def _cmpCImpl(prog, params, rawParams, flagUpdates):
484+ size = prog.paramSize(rawParams[1])
485+ needsCarry = False
486+ if flagUpdates:
487+ for flag in flagUpdates:
488+ calc = prog.flags.flagCalc[flag]
489+ if calc == 'carry':
490+ needsCarry = True
491+ break
492+ if needsCarry:
493+ size *= 2
494+ tmpvar = 'cmp_tmp{sz}__'.format(sz=size)
495+ if flagUpdates:
496+ prog.carryFlowDst = tmpvar
497+ prog.lastA = params[1]
498+ prog.lastB = params[0]
499+ prog.lastBFlow = params[0]
500+ scope = prog.getRootScope()
501+ if not scope.resolveLocal(tmpvar):
502+ scope.addLocal(tmpvar, size)
503+ prog.lastDst = rawParams[1]
504+ return '\n\t{var} = {b} - {a};'.format(var = tmpvar, a = params[0], b = params[1])
505+
506+def _asrCImpl(prog, params, rawParams, flagUpdates):
507+ needsCarry = False
508+ if flagUpdates:
509+ for flag in flagUpdates:
510+ calc = prog.flags.flagCalc[flag]
511+ if calc == 'carry':
512+ needsCarry = True
513+ decl = ''
514+ size = prog.paramSize(rawParams[2])
515+ if needsCarry:
516+ decl,name = prog.getTemp(size * 2)
517+ dst = prog.carryFlowDst = name
518+ prog.lastA = params[0]
519+ else:
520+ dst = params[2]
521+ mask = 1 << (size - 1)
522+ return decl + '\n\t{dst} = ({a} >> {b}) | ({a} & {mask} ? 0xFFFFFFFFU << ({size} - {b}) : 0);'.format(
523+ a = params[0], b = params[1], dst = dst, mask = mask, size=size)
524+
525+def _sext(size, src):
526+ if size == 16:
527+ return src | 0xFF00 if src & 0x80 else src
528+ else:
529+ return src | 0xFFFF0000 if src & 0x8000 else src
530+
531+def _sextCImpl(prog, params, rawParms):
532+ if params[0] == 16:
533+ fmt = '\n\t{dst} = {src} & 0x80 ? {src} | 0xFF00 : {src};'
534+ else:
535+ fmt = '\n\t{dst} = {src} & 0x8000 ? {src} | 0xFFFF0000 : {src};'
536+ return fmt.format(src=params[1], dst=params[2])
537+
538+def _getCarryCheck(prog):
539+ carryFlag = None
540+ for flag in prog.flags.flagCalc:
541+ if prog.flags.flagCalc[flag] == 'carry':
542+ carryFlag = flag
543+ if carryFlag is None:
544+ raise Exception('adc requires a defined carry flag')
545+ carryStorage = prog.flags.getStorage(carryFlag)
546+ if type(carryStorage) is tuple:
547+ reg,bit = carryStorage
548+ reg = prog.resolveReg(reg, None, (), False)
549+ return '({reg} & 1 << {bit})'.format(reg=reg, bit=bit)
550+ else:
551+ return prog.resolveReg(carryStorage, None, (), False)
552+
553+def _adcCImpl(prog, params, rawParams, flagUpdates):
554+ needsCarry = needsOflow = needsHalf = False
555+ if flagUpdates:
556+ for flag in flagUpdates:
557+ calc = prog.flags.flagCalc[flag]
558+ if calc == 'carry':
559+ needsCarry = True
560+ elif calc == 'half-carry':
561+ needsHalf = True
562+ elif calc == 'overflow':
563+ needsOflow = True
564+ decl = ''
565+ carryCheck = _getCarryCheck(prog)
566+ if needsCarry or needsOflow or needsHalf:
567+ size = prog.paramSize(rawParams[2])
568+ if needsCarry:
569+ size *= 2
570+ decl,name = prog.getTemp(size)
571+ dst = prog.carryFlowDst = name
572+ prog.lastA = params[0]
573+ prog.lastB = params[1]
574+ prog.lastBFlow = '(~{b})'.format(b=params[1])
575+ else:
576+ dst = params[2]
577+ return decl + '\n\t{dst} = {a} + {b} + ({check} ? 1 : 0);'.format(dst = dst,
578+ a = params[0], b = params[1], check = carryCheck
579+ )
580+
581+def _sbcCImpl(prog, params, rawParams, flagUpdates):
582+ needsCarry = needsOflow = needsHalf = False
583+ if flagUpdates:
584+ for flag in flagUpdates:
585+ calc = prog.flags.flagCalc[flag]
586+ if calc == 'carry':
587+ needsCarry = True
588+ elif calc == 'half-carry':
589+ needsHalf = True
590+ elif calc == 'overflow':
591+ needsOflow = True
592+ decl = ''
593+ carryCheck = _getCarryCheck(prog)
594+ if needsCarry or needsOflow or needsHalf:
595+ size = prog.paramSize(rawParams[2])
596+ if needsCarry:
597+ size *= 2
598+ decl,name = prog.getTemp(size)
599+ dst = prog.carryFlowDst = name
600+ prog.lastA = params[1]
601+ prog.lastB = params[0]
602+ prog.lastBFlow = params[0]
603+ else:
604+ dst = params[2]
605+ return decl + '\n\t{dst} = {b} - {a} - ({check} ? 1 : 0);'.format(dst = dst,
606+ a = params[0], b = params[1], check=_getCarryCheck(prog)
607+ )
608+
609+def _rolCImpl(prog, params, rawParams, flagUpdates):
610+ needsCarry = False
611+ if flagUpdates:
612+ for flag in flagUpdates:
613+ calc = prog.flags.flagCalc[flag]
614+ if calc == 'carry':
615+ needsCarry = True
616+ decl = ''
617+ size = prog.paramSize(rawParams[2])
618+ if needsCarry:
619+ decl,name = prog.getTemp(size * 2)
620+ dst = prog.carryFlowDst = name
621+ else:
622+ dst = params[2]
623+ return decl + '\n\t{dst} = {a} << {b} | {a} >> ({size} - {b});'.format(dst = dst,
624+ a = params[0], b = params[1], size=size
625+ )
626+
627+def _rlcCImpl(prog, params, rawParams, flagUpdates):
628+ needsCarry = False
629+ if flagUpdates:
630+ for flag in flagUpdates:
631+ calc = prog.flags.flagCalc[flag]
632+ if calc == 'carry':
633+ needsCarry = True
634+ decl = ''
635+ carryCheck = _getCarryCheck(prog)
636+ size = prog.paramSize(rawParams[2])
637+ if needsCarry:
638+ decl,name = prog.getTemp(size * 2)
639+ dst = prog.carryFlowDst = name
640+ else:
641+ dst = params[2]
642+ return decl + '\n\t{dst} = {a} << {b} | {a} >> ({size} + 1 - {b}) | ({check} ? 1 : 0) << ({b} - 1);'.format(dst = dst,
643+ a = params[0], b = params[1], size=size, check=carryCheck
644+ )
645+
646+def _rorCImpl(prog, params, rawParams, flagUpdates):
647+ size = prog.paramSize(rawParams[2])
648+ return '\n\t{dst} = {a} >> {b} | {a} << ({size} - {b});'.format(dst = params[2],
649+ a = params[0], b = params[1], size=size
650+ )
651+
652+def _rrcCImpl(prog, params, rawParams, flagUpdates):
653+ needsCarry = False
654+ if flagUpdates:
655+ for flag in flagUpdates:
656+ calc = prog.flags.flagCalc[flag]
657+ if calc == 'carry':
658+ needsCarry = True
659+ decl = ''
660+ carryCheck = _getCarryCheck(prog)
661+ size = prog.paramSize(rawParams[2])
662+ if needsCarry:
663+ decl,name = prog.getTemp(size * 2)
664+ dst = prog.carryFlowDst = name
665+ else:
666+ dst = params[2]
667+ return decl + '\n\t{dst} = {a} >> {b} | {a} << ({size} + 1 - {b}) | ({check} ? 1 : 0) << ({size}-{b});'.format(dst = dst,
668+ a = params[0], b = params[1], size=size, check=carryCheck
669+ )
670+
671+def _updateSyncCImpl(prog, params):
672+ return '\n\t{sync}(context, target_cycle);'.format(sync=prog.sync_cycle)
673+
674+_opMap = {
675+ 'mov': Op(lambda val: val).cUnaryOperator(''),
676+ 'not': Op(lambda val: ~val).cUnaryOperator('~'),
677+ 'lnot': Op(lambda val: 0 if val else 1).cUnaryOperator('!'),
678+ 'neg': Op(lambda val: -val).cUnaryOperator('-'),
679+ 'add': Op(lambda a, b: a + b).cBinaryOperator('+'),
680+ 'adc': Op().addImplementation('c', 2, _adcCImpl),
681+ 'sub': Op(lambda a, b: b - a).cBinaryOperator('-'),
682+ 'sbc': Op().addImplementation('c', 2, _sbcCImpl),
683+ 'lsl': Op(lambda a, b: a << b).cBinaryOperator('<<'),
684+ 'lsr': Op(lambda a, b: a >> b).cBinaryOperator('>>'),
685+ 'asr': Op(lambda a, b: a >> b).addImplementation('c', 2, _asrCImpl),
686+ 'rol': Op().addImplementation('c', 2, _rolCImpl),
687+ 'rlc': Op().addImplementation('c', 2, _rlcCImpl),
688+ 'ror': Op().addImplementation('c', 2, _rorCImpl),
689+ 'rrc': Op().addImplementation('c', 2, _rrcCImpl),
690+ 'and': Op(lambda a, b: a & b).cBinaryOperator('&'),
691+ 'or': Op(lambda a, b: a | b).cBinaryOperator('|'),
692+ 'xor': Op(lambda a, b: a ^ b).cBinaryOperator('^'),
693+ 'abs': Op(lambda val: abs(val)).addImplementation(
694+ 'c', 1, lambda prog, params: '\n\t{dst} = abs({src});'.format(dst=params[1], src=params[0])
695+ ),
696+ 'cmp': Op().addImplementation('c', None, _cmpCImpl),
697+ 'sext': Op(_sext).addImplementation('c', 2, _sextCImpl),
698+ 'ocall': Op().addImplementation('c', None, lambda prog, params: '\n\t{pre}{fun}({args});'.format(
699+ pre = prog.prefix, fun = params[0], args = ', '.join(['context'] + [str(p) for p in params[1:]])
700+ )),
701+ 'cycles': Op().addImplementation('c', None,
702+ lambda prog, params: '\n\tcontext->cycles += context->opts->gen.clock_divider * {0};'.format(
703+ params[0]
704+ )
705+ ),
706+ 'addsize': Op(
707+ lambda a, b: b + (2 * a if a else 1)
708+ ).addImplementation('c', 2, lambda prog, params: '\n\t{dst} = {val} + {sz} ? {sz} * 2 : 1;'.format(
709+ dst = params[2], sz = params[0], val = params[1]
710+ )),
711+ 'decsize': Op(
712+ lambda a, b: b - (2 * a if a else 1)
713+ ).addImplementation('c', 2, lambda prog, params: '\n\t{dst} = {val} - {sz} ? {sz} * 2 : 1;'.format(
714+ dst = params[2], sz = params[0], val = params[1]
715+ )),
716+ 'xchg': Op().addImplementation('c', (0,1), _xchgCImpl),
717+ 'dispatch': Op().addImplementation('c', None, _dispatchCImpl),
718+ 'update_flags': Op().addImplementation('c', None, _updateFlagsCImpl),
719+ 'update_sync': Op().addImplementation('c', None, _updateSyncCImpl)
720+}
721+
722+#represents a simple DSL instruction
723+class NormalOp:
724+ def __init__(self, parts):
725+ self.op = parts[0]
726+ self.params = parts[1:]
727+
728+ def generate(self, prog, parent, fieldVals, output, otype, flagUpdates):
729+ procParams = []
730+ allParamsConst = flagUpdates is None and not prog.conditional
731+ opDef = _opMap.get(self.op)
732+ for param in self.params:
733+ allowConst = (self.op in prog.subroutines or len(procParams) != len(self.params) - 1) and param in parent.regValues
734+ isDst = (not opDef is None) and len(procParams) in opDef.outOp
735+ if isDst and self.op == 'xchg':
736+ #xchg uses its regs as both source and destination
737+ #we need to resolve as both so that disperse/coalesce flag stuff gets done
738+ prog.resolveParam(param, parent, fieldVals, allowConst, False)
739+ param = prog.resolveParam(param, parent, fieldVals, allowConst, isDst)
740+
741+ if (not type(param) is int) and len(procParams) != len(self.params) - 1:
742+ allParamsConst = False
743+ procParams.append(param)
744+
745+ if self.op == 'meta':
746+ param,_,index = self.params[1].partition('.')
747+ if index:
748+ index = (parent.resolveLocal(index) or index)
749+ if index in fieldVals:
750+ index = str(fieldVals[index])
751+ param = param + '.' + index
752+ else:
753+ param = parent.resolveLocal(param) or param
754+ if param in fieldVals:
755+ param = fieldVals[index]
756+ prog.meta[self.params[0]] = param
757+ elif self.op == 'dis':
758+ #TODO: Disassembler
759+ pass
760+ elif not opDef is None:
761+ if opDef.numParams() > len(procParams):
762+ raise Exception('Insufficient params for ' + self.op + ' (' + ', '.join(self.params) + ')')
763+ if opDef.canEval() and allParamsConst:
764+ #do constant folding
765+ if opDef.numArgs() >= len(procParams):
766+ raise Exception('Insufficient args for ' + self.op + ' (' + ', '.join(self.params) + ')')
767+ dst = self.params[opDef.numArgs()]
768+ result = opDef.evaluate(procParams[:opDef.numArgs()])
769+ while dst in prog.meta:
770+ dst = prog.meta[dst]
771+ maybeLocal = parent.resolveLocal(dst)
772+ if maybeLocal:
773+ dst = maybeLocal
774+ parent.regValues[dst] = result
775+ if prog.isReg(dst):
776+ shortProc = (procParams[0], procParams[-1])
777+ shortParams = (self.params[0], self.params[-1])
778+ output.append(_opMap['mov'].generate(otype, prog, shortProc, shortParams, None))
779+ else:
780+ output.append(opDef.generate(otype, prog, procParams, self.params, flagUpdates))
781+ for dstIdx in opDef.outOp:
782+ dst = self.params[dstIdx]
783+ while dst in prog.meta:
784+ dst = prog.meta[dst]
785+ if dst in parent.regValues:
786+ del parent.regValues[dst]
787+
788+ elif self.op in prog.subroutines:
789+ procParams = []
790+ for param in self.params:
791+ begin,sep,end = param.partition('.')
792+ if sep:
793+ if end in fieldVals:
794+ param = begin + '.' + str(fieldVals[end])
795+ else:
796+ if param in fieldVals:
797+ param = fieldVals[param]
798+ procParams.append(param)
799+ prog.subroutines[self.op].inline(prog, procParams, output, otype, parent)
800+ else:
801+ output.append('\n\t' + self.op + '(' + ', '.join([str(p) for p in procParams]) + ');')
802+ prog.lastOp = self
803+
804+ def __str__(self):
805+ return '\n\t' + self.op + ' ' + ' '.join(self.params)
806+
807+#represents a DSL switch construct
808+class Switch(ChildBlock):
809+ def __init__(self, parent, param):
810+ self.op = 'switch'
811+ self.parent = parent
812+ self.param = param
813+ self.cases = {}
814+ self.regValues = None
815+ self.current_locals = {}
816+ self.case_locals = {}
817+ self.current_case = None
818+ self.default = None
819+ self.default_locals = None
820+
821+ def addOp(self, op):
822+ if op.op == 'case':
823+ val = int(op.params[0], 16) if op.params[0].startswith('0x') else int(op.params[0])
824+ self.cases[val] = self.current_case = []
825+ self.case_locals[val] = self.current_locals = {}
826+ elif op.op == 'default':
827+ self.default = self.current_case = []
828+ self.default_locals = self.current_locals = {}
829+ elif self.current_case == None:
830+ raise ion('Orphan instruction in switch')
831+ elif op.op == 'local':
832+ name = op.params[0]
833+ size = op.params[1]
834+ self.current_locals[name] = size
835+ else:
836+ self.current_case.append(op)
837+
838+ def resolveLocal(self, name):
839+ if name in self.current_locals:
840+ return name
841+ return self.parent.resolveLocal(name)
842+
843+ def addLocal(self, name, size):
844+ self.current_locals[name] = size
845+
846+ def localSize(self, name):
847+ if name in self.current_locals:
848+ return self.current_locals[name]
849+ return self.parent.localSize(name)
850+
851+ def generate(self, prog, parent, fieldVals, output, otype, flagUpdates):
852+ prog.pushScope(self)
853+ param = prog.resolveParam(self.param, parent, fieldVals)
854+ if type(param) is int:
855+ self.regValues = self.parent.regValues
856+ if param in self.cases:
857+ self.current_locals = self.case_locals[param]
858+ output.append('\n\t{')
859+ for local in self.case_locals[param]:
860+ output.append('\n\tuint{0}_t {1};'.format(self.case_locals[param][local], local))
861+ self.processOps(prog, fieldVals, output, otype, self.cases[param])
862+ output.append('\n\t}')
863+ elif self.default:
864+ self.current_locals = self.default_locals
865+ output.append('\n\t{')
866+ for local in self.default_locals:
867+ output.append('\n\tuint{0}_t {1};'.format(self.default[local], local))
868+ self.processOps(prog, fieldVals, output, otype, self.default)
869+ output.append('\n\t}')
870+ else:
871+ oldCond = prog.conditional
872+ prog.conditional = True
873+ output.append('\n\tswitch(' + param + ')')
874+ output.append('\n\t{')
875+ for case in self.cases:
876+ temp = prog.temp.copy()
877+ self.current_locals = self.case_locals[case]
878+ self.regValues = dict(self.parent.regValues)
879+ output.append('\n\tcase {0}U: '.format(case) + '{')
880+ for local in self.case_locals[case]:
881+ output.append('\n\tuint{0}_t {1};'.format(self.case_locals[case][local], local))
882+ self.processOps(prog, fieldVals, output, otype, self.cases[case])
883+ output.append('\n\tbreak;')
884+ output.append('\n\t}')
885+ prog.temp = temp
886+ if self.default:
887+ temp = prog.temp.copy()
888+ self.current_locals = self.default_locals
889+ self.regValues = dict(self.parent.regValues)
890+ output.append('\n\tdefault: {')
891+ for local in self.default_locals:
892+ output.append('\n\tuint{0}_t {1};'.format(self.default_locals[local], local))
893+ self.processOps(prog, fieldVals, output, otype, self.default)
894+ prog.temp = temp
895+ output.append('\n\t}')
896+ prog.conditional = oldCond
897+ prog.popScope()
898+
899+ def __str__(self):
900+ keys = self.cases.keys()
901+ keys.sort()
902+ lines = ['\n\tswitch']
903+ for case in keys:
904+ lines.append('\n\tcase {0}'.format(case))
905+ lines.append(''.join([str(op) for op in self.cases[case]]))
906+ lines.append('\n\tend')
907+ return ''.join(lines)
908+
909+
910+def _geuCImpl(prog, parent, fieldVals, output):
911+ if prog.lastOp.op == 'cmp':
912+ output.pop()
913+ params = [prog.resolveParam(p, parent, fieldVals) for p in prog.lastOp.params]
914+ return '\n\tif ({a} >= {b}) '.format(a=params[1], b = params[0]) + '{'
915+ else:
916+ raise Exception(">=U not implemented in the general case yet")
917+
918+def _eqCImpl(prog, parent, fieldVals, output):
919+ return '\n\tif (!{a}) {'.format(a=prog.resolveParam(prog.lastDst, None, {}))
920+
921+def _neqCImpl(prog, parent, fieldVals, output):
922+ return '\n\tif ({a}) {'.format(a=prog.resolveParam(prog.lastDst, None, {}))
923+
924+_ifCmpImpl = {
925+ 'c': {
926+ '>=U': _geuCImpl,
927+ '=': _eqCImpl,
928+ '!=': _neqCImpl
929+ }
930+}
931+#represents a DSL conditional construct
932+class If(ChildBlock):
933+ def __init__(self, parent, cond):
934+ self.op = 'if'
935+ self.parent = parent
936+ self.cond = cond
937+ self.body = []
938+ self.elseBody = []
939+ self.curBody = self.body
940+ self.locals = {}
941+ self.elseLocals = {}
942+ self.curLocals = self.locals
943+ self.regValues = None
944+
945+ def addOp(self, op):
946+ if op.op in ('case', 'arg'):
947+ raise Exception(self.op + ' is not allows inside an if block')
948+ if op.op == 'local':
949+ name = op.params[0]
950+ size = op.params[1]
951+ self.curLocals[name] = size
952+ elif op.op == 'else':
953+ self.curLocals = self.elseLocals
954+ self.curBody = self.elseBody
955+ else:
956+ self.curBody.append(op)
957+
958+ def localSize(self, name):
959+ return self.curLocals.get(name)
960+
961+ def resolveLocal(self, name):
962+ if name in self.curLocals:
963+ return name
964+ return self.parent.resolveLocal(name)
965+
966+ def _genTrueBody(self, prog, fieldVals, output, otype):
967+ self.curLocals = self.locals
968+ subOut = []
969+ self.processOps(prog, fieldVals, subOut, otype, self.body)
970+ for local in self.locals:
971+ output.append('\n\tuint{sz}_t {nm};'.format(sz=self.locals[local], nm=local))
972+ output += subOut
973+
974+ def _genFalseBody(self, prog, fieldVals, output, otype):
975+ self.curLocals = self.elseLocals
976+ subOut = []
977+ self.processOps(prog, fieldVals, subOut, otype, self.elseBody)
978+ for local in self.elseLocals:
979+ output.append('\n\tuint{sz}_t {nm};'.format(sz=self.elseLocals[local], nm=local))
980+ output += subOut
981+
982+ def _genConstParam(self, param, prog, fieldVals, output, otype):
983+ if param:
984+ self._genTrueBody(prog, fieldVals, output, otype)
985+ else:
986+ self._genFalseBody(prog, fieldVals, output, otype)
987+
988+ def generate(self, prog, parent, fieldVals, output, otype, flagUpdates):
989+ self.regValues = parent.regValues
990+ try:
991+ self._genConstParam(prog.checkBool(self.cond), prog, fieldVals, output, otype)
992+ except Exception:
993+ if self.cond in _ifCmpImpl[otype]:
994+ oldCond = prog.conditional
995+ prog.conditional = True
996+ temp = prog.temp.copy()
997+ output.append(_ifCmpImpl[otype][self.cond](prog, parent, fieldVals, output))
998+ self._genTrueBody(prog, fieldVals, output, otype)
999+ prog.temp = temp
1000+ if self.elseBody:
1001+ temp = prog.temp.copy()
1002+ output.append('\n\t} else {')
1003+ self._genFalseBody(prog, fieldVals, output, otype)
1004+ prog.temp = temp
1005+ output.append('\n\t}')
1006+ prog.conditional = oldCond
1007+ else:
1008+ cond = prog.resolveParam(self.cond, parent, fieldVals)
1009+ if type(cond) is int:
1010+ self._genConstParam(cond, prog, fieldVals, output, otype)
1011+ else:
1012+ temp = prog.temp.copy()
1013+ output.append('\n\tif ({cond}) '.format(cond=cond) + '{')
1014+ oldCond = prog.conditional
1015+ prog.conditional = True
1016+ self._genTrueBody(prog, fieldVals, output, otype)
1017+ prog.temp = temp
1018+ if self.elseBody:
1019+ temp = prog.temp.copy()
1020+ output.append('\n\t} else {')
1021+ self._genFalseBody(prog, fieldVals, output, otype)
1022+ prog.temp = temp
1023+ output.append('\n\t}')
1024+ prog.conditional = oldCond
1025+
1026+
1027+ def __str__(self):
1028+ lines = ['\n\tif']
1029+ for op in self.body:
1030+ lines.append(str(op))
1031+ lines.append('\n\tend')
1032+ return ''.join(lines)
1033+
1034+class Registers:
1035+ def __init__(self):
1036+ self.regs = {}
1037+ self.pointers = {}
1038+ self.regArrays = {}
1039+ self.regToArray = {}
1040+ self.addReg('cycles', 32)
1041+ self.addReg('sync_cycle', 32)
1042+
1043+ def addReg(self, name, size):
1044+ self.regs[name] = size
1045+
1046+ def addPointer(self, name, size, count):
1047+ self.pointers[name] = (size, count)
1048+
1049+ def addRegArray(self, name, size, regs):
1050+ self.regArrays[name] = (size, regs)
1051+ idx = 0
1052+ if not type(regs) is int:
1053+ for reg in regs:
1054+ self.regs[reg] = size
1055+ self.regToArray[reg] = (name, idx)
1056+ idx += 1
1057+
1058+ def isReg(self, name):
1059+ return name in self.regs
1060+
1061+ def isRegArray(self, name):
1062+ return name in self.regArrays
1063+
1064+ def isRegArrayMember(self, name):
1065+ return name in self.regToArray
1066+
1067+ def arrayMemberParent(self, name):
1068+ return self.regToArray[name][0]
1069+
1070+ def arrayMemberIndex(self, name):
1071+ return self.regToArray[name][1]
1072+
1073+ def arrayMemberName(self, array, index):
1074+ if type(index) is int and not type(self.regArrays[array][1]) is int:
1075+ return self.regArrays[array][1][index]
1076+ else:
1077+ return None
1078+
1079+ def isNamedArray(self, array):
1080+ return array in self.regArrays and type(self.regArrays[array][1]) is int
1081+
1082+ def processLine(self, parts):
1083+ if len(parts) == 3:
1084+ if parts[1].startswith('ptr'):
1085+ self.addPointer(parts[0], parts[1][3:], int(parts[2]))
1086+ else:
1087+ self.addRegArray(parts[0], int(parts[1]), int(parts[2]))
1088+ elif len(parts) > 2:
1089+ self.addRegArray(parts[0], int(parts[1]), parts[2:])
1090+ else:
1091+ if parts[1].startswith('ptr'):
1092+ self.addPointer(parts[0], parts[1][3:], 1)
1093+ else:
1094+ self.addReg(parts[0], int(parts[1]))
1095+ return self
1096+
1097+ def writeHeader(self, otype, hFile):
1098+ fieldList = []
1099+ for pointer in self.pointers:
1100+ stars = '*'
1101+ ptype, count = self.pointers[pointer]
1102+ while ptype.startswith('ptr'):
1103+ stars += '*'
1104+ ptype = ptype[3:]
1105+ if ptype.isdigit():
1106+ ptype = 'uint{sz}_t'.format(sz=ptype)
1107+ if count > 1:
1108+ arr = '[{n}]'.format(n=count)
1109+ else:
1110+ arr = ''
1111+ hFile.write('\n\t{ptype} {stars}{nm}{arr};'.format(nm=pointer, ptype=ptype, stars=stars, arr=arr))
1112+ for reg in self.regs:
1113+ if not self.isRegArrayMember(reg):
1114+ fieldList.append((self.regs[reg], 1, reg))
1115+ for arr in self.regArrays:
1116+ size,regs = self.regArrays[arr]
1117+ if not type(regs) is int:
1118+ regs = len(regs)
1119+ fieldList.append((size, regs, arr))
1120+ fieldList.sort()
1121+ fieldList.reverse()
1122+ for size, count, name in fieldList:
1123+ if count > 1:
1124+ hFile.write('\n\tuint{sz}_t {nm}[{ct}];'.format(sz=size, nm=name, ct=count))
1125+ else:
1126+ hFile.write('\n\tuint{sz}_t {nm};'.format(sz=size, nm=name))
1127+
1128+class Flags:
1129+ def __init__(self):
1130+ self.flagBits = {}
1131+ self.flagCalc = {}
1132+ self.flagStorage = {}
1133+ self.flagReg = None
1134+ self.storageToFlags = {}
1135+ self.maxBit = -1
1136+
1137+ def processLine(self, parts):
1138+ if parts[0] == 'register':
1139+ self.flagReg = parts[1]
1140+ else:
1141+ flag,bit,calc,storage = parts
1142+ bit,_,top = bit.partition('-')
1143+ bit = int(bit)
1144+ if top:
1145+ top = int(bit)
1146+ if top > self.maxBit:
1147+ self.maxBit = top
1148+ self.flagBits[flag] = (bit,top)
1149+ else:
1150+ if bit > self.maxBit:
1151+ self.maxBit = bit
1152+ self.flagBits[flag] = bit
1153+ self.flagCalc[flag] = calc
1154+ self.flagStorage[flag] = storage
1155+ storage,_,storebit = storage.partition('.')
1156+ self.storageToFlags.setdefault(storage, []).append((storebit, flag))
1157+ return self
1158+
1159+ def getStorage(self, flag):
1160+ if not flag in self.flagStorage:
1161+ raise Exception('Undefined flag ' + flag)
1162+ loc,_,bit = self.flagStorage[flag].partition('.')
1163+ if bit:
1164+ return (loc, int(bit))
1165+ else:
1166+ return loc
1167+
1168+ def parseFlagUpdate(self, flagString):
1169+ last = ''
1170+ autoUpdate = set()
1171+ explicit = {}
1172+ for c in flagString:
1173+ if c.isdigit():
1174+ if last.isalpha():
1175+ num = int(c)
1176+ if num > 1:
1177+ raise Exception(c + ' is not a valid digit for update_flags')
1178+ explicit[last] = num
1179+ last = c
1180+ else:
1181+ raise Exception('Digit must follow flag letter in update_flags')
1182+ else:
1183+ if last.isalpha():
1184+ autoUpdate.add(last)
1185+ last = c
1186+ if last.isalpha():
1187+ autoUpdate.add(last)
1188+ return (autoUpdate, explicit)
1189+
1190+ def disperseFlags(self, prog, otype):
1191+ bitToFlag = [None] * (self.maxBit+1)
1192+ src = prog.resolveReg(self.flagReg, None, {})
1193+ output = []
1194+ for flag in self.flagBits:
1195+ bit = self.flagBits[flag]
1196+ if type(bit) is tuple:
1197+ bot,top = bit
1198+ mask = ((1 << (top + 1 - bot)) - 1) << bot
1199+ output.append('\n\t{dst} = {src} & mask;'.format(
1200+ dst=prog.resolveReg(self.flagStorage[flag], None, {}), src=src, mask=mask
1201+ ))
1202+ else:
1203+ bitToFlag[self.flagBits[flag]] = flag
1204+ multi = {}
1205+ for bit in range(len(bitToFlag)-1,-1,-1):
1206+ flag = bitToFlag[bit]
1207+ if not flag is None:
1208+ field,_,dstbit = self.flagStorage[flag].partition('.')
1209+ dst = prog.resolveReg(field, None, {})
1210+ if dstbit:
1211+ dstbit = int(dstbit)
1212+ multi.setdefault(dst, []).append((dstbit, bit))
1213+ else:
1214+ output.append('\n\t{dst} = {src} & {mask};'.format(dst=dst, src=src, mask=(1 << bit)))
1215+ for dst in multi:
1216+ didClear = False
1217+ direct = []
1218+ for dstbit, bit in multi[dst]:
1219+ if dstbit == bit:
1220+ direct.append(bit)
1221+ else:
1222+ if not didClear:
1223+ output.append('\n\t{dst} = 0;'.format(dst=dst))
1224+ didClear = True
1225+ if dstbit > bit:
1226+ shift = '<<'
1227+ diff = dstbit - bit
1228+ else:
1229+ shift = '>>'
1230+ diff = bit - dstbit
1231+ output.append('\n\t{dst} |= {src} {shift} {diff} & {mask};'.format(
1232+ src=src, dst=dst, shift=shift, diff=diff, mask=(1 << dstbit)
1233+ ))
1234+ if direct:
1235+ if len(direct) == len(multi[dst]):
1236+ output.append('\n\t{dst} = {src};'.format(dst=dst, src=src))
1237+ else:
1238+ mask = 0
1239+ for bit in direct:
1240+ mask = mask | (1 << bit)
1241+ output.append('\n\t{dst} = {src} & {mask};'.format(dst=dst, src=src, mask=mask))
1242+ return ''.join(output)
1243+
1244+ def coalesceFlags(self, prog, otype):
1245+ dst = prog.resolveReg(self.flagReg, None, {})
1246+ output = ['\n\t{dst} = 0;'.format(dst=dst)]
1247+ bitToFlag = [None] * (self.maxBit+1)
1248+ for flag in self.flagBits:
1249+ bit = self.flagBits[flag]
1250+ if type(bit) is tuple:
1251+ bot,_ = bit
1252+ src = prog.resolveReg(self.flagStorage[flag], None, {})
1253+ if bot:
1254+ output.append('\n\t{dst} |= {src} << {shift};'.format(
1255+ dst=dst, src = src, shift = bot
1256+ ))
1257+ else:
1258+ output.append('\n\t{dst} |= {src};'.format(
1259+ dst=dst, src = src
1260+ ))
1261+ else:
1262+ bitToFlag[bit] = flag
1263+ multi = {}
1264+ for bit in range(len(bitToFlag)-1,-1,-1):
1265+ flag = bitToFlag[bit]
1266+ if not flag is None:
1267+ field,_,srcbit = self.flagStorage[flag].partition('.')
1268+ src = prog.resolveReg(field, None, {})
1269+ if srcbit:
1270+ srcbit = int(srcbit)
1271+ multi.setdefault(src, []).append((srcbit,bit))
1272+ else:
1273+ output.append('\n\tif ({src}) {{\n\t\t{dst} |= 1 << {bit};\n\t}}'.format(
1274+ dst=dst, src=src, bit=bit
1275+ ))
1276+ for src in multi:
1277+ direct = 0
1278+ for srcbit, dstbit in multi[src]:
1279+ if srcbit == dstbit:
1280+ direct = direct | (1 << srcbit)
1281+ else:
1282+ output.append('\n\tif ({src} & (1 << {srcbit})) {{\n\t\t{dst} |= 1 << {dstbit};\n\t}}'.format(
1283+ src=src, dst=dst, srcbit=srcbit, dstbit=dstbit
1284+ ))
1285+ if direct:
1286+ output.append('\n\t{dst} |= {src} & {mask};'.format(
1287+ dst=dst, src=src, mask=direct
1288+ ))
1289+ return ''.join(output)
1290+
1291+
1292+class Program:
1293+ def __init__(self, regs, instructions, subs, info, flags):
1294+ self.regs = regs
1295+ self.instructions = instructions
1296+ self.subroutines = subs
1297+ self.meta = {}
1298+ self.booleans = {}
1299+ self.prefix = info.get('prefix', [''])[0]
1300+ self.opsize = int(info.get('opcode_size', ['8'])[0])
1301+ self.extra_tables = info.get('extra_tables', [])
1302+ self.context_type = self.prefix + 'context'
1303+ self.body = info.get('body', [None])[0]
1304+ self.interrupt = info.get('interrupt', [None])[0]
1305+ self.sync_cycle = info.get('sync_cycle', [None])[0]
1306+ self.includes = info.get('include', [])
1307+ self.flags = flags
1308+ self.lastDst = None
1309+ self.scopes = []
1310+ self.currentScope = None
1311+ self.lastOp = None
1312+ self.carryFlowDst = None
1313+ self.lastA = None
1314+ self.lastB = None
1315+ self.lastBFlow = None
1316+ self.conditional = False
1317+ self.declares = []
1318+
1319+ def __str__(self):
1320+ pieces = []
1321+ for reg in self.regs:
1322+ pieces.append(str(self.regs[reg]))
1323+ for name in self.subroutines:
1324+ pieces.append('\n'+str(self.subroutines[name]))
1325+ for instruction in self.instructions:
1326+ pieces.append('\n'+str(instruction))
1327+ return ''.join(pieces)
1328+
1329+ def writeHeader(self, otype, header):
1330+ hFile = open(header, 'w')
1331+ macro = header.upper().replace('.', '_')
1332+ hFile.write('#ifndef {0}_'.format(macro))
1333+ hFile.write('\n#define {0}_'.format(macro))
1334+ hFile.write('\n#include "backend.h"')
1335+ hFile.write('\n\ntypedef struct {')
1336+ hFile.write('\n\tcpu_options gen;')
1337+ hFile.write('\n}} {0}options;'.format(self.prefix))
1338+ hFile.write('\n\ntypedef struct {')
1339+ hFile.write('\n\t{0}options *opts;'.format(self.prefix))
1340+ self.regs.writeHeader(otype, hFile)
1341+ hFile.write('\n}} {0}context;'.format(self.prefix))
1342+ hFile.write('\n')
1343+ hFile.write('\nvoid {pre}execute({type} *context, uint32_t target_cycle);'.format(pre = self.prefix, type = self.context_type))
1344+ for decl in self.declares:
1345+ hFile.write('\n' + decl)
1346+ hFile.write('\n#endif //{0}_'.format(macro))
1347+ hFile.write('\n')
1348+ hFile.close()
1349+
1350+ def _buildTable(self, otype, table, body, lateBody):
1351+ pieces = []
1352+ opmap = [None] * (1 << self.opsize)
1353+ bodymap = {}
1354+ if table in self.instructions:
1355+ instructions = self.instructions[table]
1356+ instructions.sort()
1357+ for inst in instructions:
1358+ for val in inst.allValues():
1359+ if opmap[val] is None:
1360+ self.meta = {}
1361+ self.temp = {}
1362+ self.needFlagCoalesce = False
1363+ self.needFlagDisperse = False
1364+ self.lastOp = None
1365+ opmap[val] = inst.generateName(val)
1366+ bodymap[val] = inst.generateBody(val, self, otype)
1367+
1368+ if self.dispatch == 'call':
1369+ pieces.append('\nstatic impl_fun impl_{name}[{sz}] = {{'.format(name = table, sz=len(opmap)))
1370+ for inst in range(0, len(opmap)):
1371+ op = opmap[inst]
1372+ if op is None:
1373+ pieces.append('\n\tunimplemented,')
1374+ else:
1375+ pieces.append('\n\t' + op + ',')
1376+ body.append(bodymap[inst])
1377+ pieces.append('\n};')
1378+ elif self.dispatch == 'goto':
1379+ body.append('\n\tstatic void *impl_{name}[{sz}] = {{'.format(name = table, sz=len(opmap)))
1380+ for inst in range(0, len(opmap)):
1381+ op = opmap[inst]
1382+ if op is None:
1383+ body.append('\n\t\t&&unimplemented,')
1384+ else:
1385+ body.append('\n\t\t&&' + op + ',')
1386+ lateBody.append(bodymap[inst])
1387+ body.append('\n\t};')
1388+ else:
1389+ raise Exception("unimplmeneted dispatch type " + self.dispatch)
1390+ body.extend(pieces)
1391+
1392+ def nextInstruction(self, otype):
1393+ output = []
1394+ if self.dispatch == 'goto':
1395+ if self.interrupt in self.subroutines:
1396+ output.append('\n\tif (context->cycles >= context->sync_cycle) {')
1397+ output.append('\n\tif (context->cycles >= target_cycle) { return; }')
1398+ if self.interrupt in self.subroutines:
1399+ self.meta = {}
1400+ self.temp = {}
1401+ self.subroutines[self.interrupt].inline(self, [], output, otype, None)
1402+ output.append('\n\t}')
1403+
1404+ self.meta = {}
1405+ self.temp = {}
1406+ self.subroutines[self.body].inline(self, [], output, otype, None)
1407+ return output
1408+
1409+ def build(self, otype):
1410+ body = []
1411+ pieces = []
1412+ for include in self.includes:
1413+ body.append('#include "{0}"\n'.format(include))
1414+ if self.dispatch == 'call':
1415+ body.append('\nstatic void unimplemented({pre}context *context)'.format(pre = self.prefix))
1416+ body.append('\n{')
1417+ body.append('\n\tfatal_error("Unimplemented instruction\\n");')
1418+ body.append('\n}\n')
1419+ body.append('\ntypedef void (*impl_fun)({pre}context *context);'.format(pre=self.prefix))
1420+ for table in self.extra_tables:
1421+ body.append('\nstatic impl_fun impl_{name}[{sz}];'.format(name = table, sz=(1 << self.opsize)))
1422+ body.append('\nstatic impl_fun impl_main[{sz}];'.format(sz=(1 << self.opsize)))
1423+ elif self.dispatch == 'goto':
1424+ body.append('\nvoid {pre}execute({type} *context, uint32_t target_cycle)'.format(pre = self.prefix, type = self.context_type))
1425+ body.append('\n{')
1426+
1427+ for table in self.extra_tables:
1428+ self._buildTable(otype, table, body, pieces)
1429+ self._buildTable(otype, 'main', body, pieces)
1430+ if self.dispatch == 'call' and self.body in self.subroutines:
1431+ pieces.append('\nvoid {pre}execute({type} *context, uint32_t target_cycle)'.format(pre = self.prefix, type = self.context_type))
1432+ pieces.append('\n{')
1433+ pieces.append('\n\t{sync}(context, target_cycle);'.format(sync=self.sync_cycle))
1434+ pieces.append('\n\twhile (context->cycles < target_cycle)')
1435+ pieces.append('\n\t{')
1436+ #TODO: Handle interrupts in call dispatch mode
1437+ self.meta = {}
1438+ self.temp = {}
1439+ self.subroutines[self.body].inline(self, [], pieces, otype, None)
1440+ pieces.append('\n\t}')
1441+ pieces.append('\n}')
1442+ elif self.dispatch == 'goto':
1443+ body.append('\n\t{sync}(context, target_cycle);'.format(sync=self.sync_cycle))
1444+ body += self.nextInstruction(otype)
1445+ pieces.append('\nunimplemented:')
1446+ pieces.append('\n\tfatal_error("Unimplemented instruction\\n");')
1447+ pieces.append('\n}')
1448+ return ''.join(body) + ''.join(pieces)
1449+
1450+ def checkBool(self, name):
1451+ if not name in self.booleans:
1452+ raise Exception(name + ' is not a defined boolean flag')
1453+ return self.booleans[name]
1454+
1455+ def getTemp(self, size):
1456+ if size in self.temp:
1457+ return ('', self.temp[size])
1458+ self.temp[size] = 'gen_tmp{sz}__'.format(sz=size);
1459+ return ('\n\tuint{sz}_t gen_tmp{sz}__;'.format(sz=size), self.temp[size])
1460+
1461+ def resolveParam(self, param, parent, fieldVals, allowConstant=True, isdst=False):
1462+ keepGoing = True
1463+ while keepGoing:
1464+ keepGoing = False
1465+ try:
1466+ if type(param) is int:
1467+ pass
1468+ elif param.startswith('0x'):
1469+ param = int(param, 16)
1470+ else:
1471+ param = int(param)
1472+ except ValueError:
1473+
1474+ if parent:
1475+ if param in parent.regValues and allowConstant:
1476+ return parent.regValues[param]
1477+ maybeLocal = parent.resolveLocal(param)
1478+ if maybeLocal:
1479+ if isdst:
1480+ self.lastDst = param
1481+ return maybeLocal
1482+ if param in fieldVals:
1483+ param = fieldVals[param]
1484+ fieldVals = {}
1485+ keepGoing = True
1486+ elif param in self.meta:
1487+ param = self.meta[param]
1488+ keepGoing = True
1489+ elif self.isReg(param):
1490+ return self.resolveReg(param, parent, fieldVals, isdst)
1491+ if isdst:
1492+ self.lastDst = param
1493+ return param
1494+
1495+ def isReg(self, name):
1496+ if not type(name) is str:
1497+ return False
1498+ begin,sep,_ = name.partition('.')
1499+ if sep:
1500+ if begin in self.meta:
1501+ begin = self.meta[begin]
1502+ return self.regs.isRegArray(begin)
1503+ else:
1504+ return self.regs.isReg(name)
1505+
1506+ def resolveReg(self, name, parent, fieldVals, isDst=False):
1507+ begin,sep,end = name.partition('.')
1508+ if sep:
1509+ if begin in self.meta:
1510+ begin = self.meta[begin]
1511+ if not self.regs.isRegArrayMember(end):
1512+ end = self.resolveParam(end, parent, fieldVals)
1513+ if not type(end) is int and self.regs.isRegArrayMember(end):
1514+ arrayName = self.regs.arrayMemberParent(end)
1515+ end = self.regs.arrayMemberIndex(end)
1516+ if arrayName != begin:
1517+ end = 'context->{0}[{1}]'.format(arrayName, end)
1518+ if self.regs.isNamedArray(begin):
1519+ regName = self.regs.arrayMemberName(begin, end)
1520+ else:
1521+ regName = '{0}.{1}'.format(begin, end)
1522+ ret = 'context->{0}[{1}]'.format(begin, end)
1523+ else:
1524+ regName = name
1525+ if self.regs.isRegArrayMember(name):
1526+ arr,idx = self.regs.regToArray[name]
1527+ ret = 'context->{0}[{1}]'.format(arr, idx)
1528+ else:
1529+ ret = 'context->' + name
1530+ if regName == self.flags.flagReg:
1531+ if isDst:
1532+ self.needFlagDisperse = True
1533+ else:
1534+ self.needFlagCoalesce = True
1535+ if isDst:
1536+ self.lastDst = regName
1537+ return ret
1538+
1539+
1540+
1541+ def paramSize(self, name):
1542+ if name in self.meta:
1543+ return self.paramSize(self.meta[name])
1544+ for i in range(len(self.scopes) -1, -1, -1):
1545+ size = self.scopes[i].localSize(name)
1546+ if size:
1547+ return size
1548+ begin,sep,_ = name.partition('.')
1549+ if sep and self.regs.isRegArray(begin):
1550+ return self.regs.regArrays[begin][0]
1551+ if self.regs.isReg(name):
1552+ return self.regs.regs[name]
1553+ return 32
1554+
1555+ def pushScope(self, scope):
1556+ self.scopes.append(scope)
1557+ self.currentScope = scope
1558+
1559+ def popScope(self):
1560+ ret = self.scopes.pop()
1561+ self.currentScope = self.scopes[-1] if self.scopes else None
1562+ return ret
1563+
1564+ def getRootScope(self):
1565+ return self.scopes[0]
1566+
1567+def parse(args):
1568+ f = args.source
1569+ instructions = {}
1570+ subroutines = {}
1571+ registers = None
1572+ flags = None
1573+ declares = []
1574+ errors = []
1575+ info = {}
1576+ line_num = 0
1577+ cur_object = None
1578+ for line in f:
1579+ line_num += 1
1580+ line,_,comment = line.partition('#')
1581+ if not line.strip():
1582+ continue
1583+ if line[0].isspace():
1584+ if not cur_object is None:
1585+ sep = True
1586+ parts = []
1587+ while sep:
1588+ before,sep,after = line.partition('"')
1589+ before = before.strip()
1590+ if before:
1591+ parts += [el.strip() for el in before.split(' ')]
1592+ if sep:
1593+ #TODO: deal with escaped quotes
1594+ inside,sep,after = after.partition('"')
1595+ parts.append('"' + inside + '"')
1596+ line = after
1597+ if type(cur_object) is dict:
1598+ cur_object[parts[0]] = parts[1:]
1599+ elif type(cur_object) is list:
1600+ cur_object.append(' '.join(parts))
1601+ else:
1602+ cur_object = cur_object.processLine(parts)
1603+
1604+# if type(cur_object) is Registers:
1605+# if len(parts) > 2:
1606+# cur_object.addRegArray(parts[0], int(parts[1]), parts[2:])
1607+# else:
1608+# cur_object.addReg(parts[0], int(parts[1]))
1609+# elif type(cur_object) is dict:
1610+# cur_object[parts[0]] = parts[1:]
1611+# elif parts[0] == 'switch':
1612+# o = Switch(cur_object, parts[1])
1613+# cur_object.addOp(o)
1614+# cur_object = o
1615+# elif parts[0] == 'if':
1616+# o = If(cur_object, parts[1])
1617+# cur_object.addOp(o)
1618+# cur_object = o
1619+# elif parts[0] == 'end':
1620+# cur_object = cur_object.parent
1621+# else:
1622+# cur_object.addOp(NormalOp(parts))
1623+ else:
1624+ errors.append("Orphan instruction on line {0}".format(line_num))
1625+ else:
1626+ parts = line.split(' ')
1627+ if len(parts) > 1:
1628+ if len(parts) > 2:
1629+ table,bitpattern,name = parts
1630+ else:
1631+ bitpattern,name = parts
1632+ table = 'main'
1633+ value = 0
1634+ fields = {}
1635+ curbit = len(bitpattern) - 1
1636+ for char in bitpattern:
1637+ value <<= 1
1638+ if char in ('0', '1'):
1639+ value |= int(char)
1640+ else:
1641+ if char in fields:
1642+ fields[char] = (curbit, fields[char][1] + 1)
1643+ else:
1644+ fields[char] = (curbit, 1)
1645+ curbit -= 1
1646+ cur_object = Instruction(value, fields, name.strip())
1647+ instructions.setdefault(table, []).append(cur_object)
1648+ elif line.strip() == 'regs':
1649+ if registers is None:
1650+ registers = Registers()
1651+ cur_object = registers
1652+ elif line.strip() == 'info':
1653+ cur_object = info
1654+ elif line.strip() == 'flags':
1655+ if flags is None:
1656+ flags = Flags()
1657+ cur_object = flags
1658+ elif line.strip() == 'declare':
1659+ cur_object = declares
1660+ else:
1661+ cur_object = SubRoutine(line.strip())
1662+ subroutines[cur_object.name] = cur_object
1663+ if errors:
1664+ print(errors)
1665+ else:
1666+ p = Program(registers, instructions, subroutines, info, flags)
1667+ p.dispatch = args.dispatch
1668+ p.declares = declares
1669+ p.booleans['dynarec'] = False
1670+ p.booleans['interp'] = True
1671+ if args.define:
1672+ for define in args.define:
1673+ name,sep,val = define.partition('=')
1674+ name = name.strip()
1675+ val = val.strip()
1676+ if sep:
1677+ p.booleans[name] = bool(val)
1678+ else:
1679+ p.booleans[name] = True
1680+
1681+ if 'header' in info:
1682+ print('#include "{0}"'.format(info['header'][0]))
1683+ p.writeHeader('c', info['header'][0])
1684+ print('#include "util.h"')
1685+ print('#include <stdlib.h>')
1686+ print(p.build('c'))
1687+
1688+def main(argv):
1689+ from argparse import ArgumentParser, FileType
1690+ argParser = ArgumentParser(description='CPU emulator DSL compiler')
1691+ argParser.add_argument('source', type=FileType('r'))
1692+ argParser.add_argument('-D', '--define', action='append')
1693+ argParser.add_argument('-d', '--dispatch', choices=('call', 'switch', 'goto'), default='call')
1694+ parse(argParser.parse_args(argv[1:]))
1695+
1696+if __name__ == '__main__':
1697+ from sys import argv
1698+ main(argv)
+1,
-0
1@@ -0,0 +1 @@
2+cursor.png,16,0,raw,nopal,interlace,sprite
+0,
-0
A
debug.c
+1037,
-0
1@@ -0,0 +1,1037 @@
2+#include "debug.h"
3+#include "genesis.h"
4+#include "68kinst.h"
5+#include <stdlib.h>
6+#include <string.h>
7+#include <sys/select.h>
8+#include "render.h"
9+#include "util.h"
10+#include "terminal.h"
11+#include "z80inst.h"
12+
13+#define Z80_OPTS options
14+
15+static bp_def * breakpoints = NULL;
16+static bp_def * zbreakpoints = NULL;
17+static uint32_t bp_index = 0;
18+static uint32_t zbp_index = 0;
19+
20+bp_def ** find_breakpoint(bp_def ** cur, uint32_t address)
21+{
22+ while (*cur) {
23+ if ((*cur)->address == address) {
24+ break;
25+ }
26+ cur = &((*cur)->next);
27+ }
28+ return cur;
29+}
30+
31+bp_def ** find_breakpoint_idx(bp_def ** cur, uint32_t index)
32+{
33+ while (*cur) {
34+ if ((*cur)->index == index) {
35+ break;
36+ }
37+ cur = &((*cur)->next);
38+ }
39+ return cur;
40+}
41+
42+disp_def * displays = NULL;
43+disp_def * zdisplays = NULL;
44+uint32_t disp_index = 0;
45+uint32_t zdisp_index = 0;
46+
47+void add_display(disp_def ** head, uint32_t *index, char format_char, char * param)
48+{
49+ disp_def * ndisp = malloc(sizeof(*ndisp));
50+ ndisp->format_char = format_char;
51+ ndisp->param = strdup(param);
52+ ndisp->next = *head;
53+ ndisp->index = *index++;
54+ *head = ndisp;
55+}
56+
57+void remove_display(disp_def ** head, uint32_t index)
58+{
59+ while (*head) {
60+ if ((*head)->index == index) {
61+ disp_def * del_disp = *head;
62+ *head = del_disp->next;
63+ free(del_disp->param);
64+ free(del_disp);
65+ } else {
66+ head = &(*head)->next;
67+ }
68+ }
69+}
70+
71+char * find_param(char * buf)
72+{
73+ for (; *buf; buf++) {
74+ if (*buf == ' ') {
75+ if (*(buf+1)) {
76+ return buf+1;
77+ }
78+ }
79+ }
80+ return NULL;
81+}
82+
83+void strip_nl(char * buf)
84+{
85+ for(; *buf; buf++) {
86+ if (*buf == '\n') {
87+ *buf = 0;
88+ return;
89+ }
90+ }
91+}
92+
93+uint16_t m68k_read_word(uint32_t address, m68k_context *context)
94+{
95+ return read_word(address, (void **)context->mem_pointers, &context->options->gen, context);
96+}
97+
98+uint32_t m68k_read_long(uint32_t address, m68k_context *context)
99+{
100+ return m68k_read_word(address, context) << 16 | m68k_read_word(address + 2, context);
101+}
102+
103+void debugger_print(m68k_context *context, char format_char, char *param)
104+{
105+ uint32_t value;
106+ char format[8];
107+ strcpy(format, "%s: %d\n");
108+ switch (format_char)
109+ {
110+ case 'x':
111+ case 'X':
112+ case 'd':
113+ case 'c':
114+ format[5] = format_char;
115+ break;
116+ case '\0':
117+ break;
118+ default:
119+ fprintf(stderr, "Unrecognized format character: %c\n", format_char);
120+ }
121+ if (param[0] == 'd' && param[1] >= '0' && param[1] <= '7') {
122+ value = context->dregs[param[1]-'0'];
123+ if (param[2] == '.') {
124+ if (param[3] == 'w') {
125+ value &= 0xFFFF;
126+ } else if (param[3] == 'b') {
127+ value &= 0xFF;
128+ }
129+ }
130+ } else if (param[0] == 'a' && param[1] >= '0' && param[1] <= '7') {
131+ value = context->aregs[param[1]-'0'];
132+ if (param[2] == '.') {
133+ if (param[3] == 'w') {
134+ value &= 0xFFFF;
135+ } else if (param[3] == 'b') {
136+ value &= 0xFF;
137+ }
138+ }
139+ } else if (param[0] == 'S' && param[1] == 'R') {
140+ value = (context->status << 8);
141+ for (int flag = 0; flag < 5; flag++) {
142+ value |= context->flags[flag] << (4-flag);
143+ }
144+ } else if(param[0] == 'c') {
145+ value = context->current_cycle;
146+ } else if(param[0] == 'f') {
147+ genesis_context *gen = context->system;
148+ value = gen->vdp->frame;
149+ } else if ((param[0] == '0' && param[1] == 'x') || param[0] == '$') {
150+ char *after;
151+ uint32_t p_addr = strtol(param+(param[0] == '0' ? 2 : 1), &after, 16);
152+ if (after[0] == '.' && after[1] == 'l') {
153+ value = m68k_read_long(p_addr, context);
154+ } else {
155+ value = m68k_read_word(p_addr, context);
156+ }
157+ } else if(param[0] == '(' && (param[1] == 'a' || param[1] == 'd') && param[2] >= '0' && param[2] <= '7' && param[3] == ')') {
158+ uint8_t reg = param[2] - '0';
159+ uint32_t p_addr = param[1] == 'a' ? context->aregs[reg] : context->dregs[reg];
160+ if (param[4] == '.' && param[5] == 'l') {
161+ value = m68k_read_long(p_addr, context);
162+ } else {
163+ value = m68k_read_word(p_addr, context);
164+ }
165+ } else {
166+ fprintf(stderr, "Unrecognized parameter to p: %s\n", param);
167+ return;
168+ }
169+ printf(format, param, value);
170+}
171+
172+void zdebugger_print(z80_context * context, char format_char, char * param)
173+{
174+ uint32_t value;
175+ char format[8];
176+ strcpy(format, "%s: %d\n");
177+ genesis_context *system = context->system;
178+ switch (format_char)
179+ {
180+ case 'x':
181+ case 'X':
182+ case 'd':
183+ case 'c':
184+ format[5] = format_char;
185+ break;
186+ case '\0':
187+ break;
188+ default:
189+ fprintf(stderr, "Unrecognized format character: %c\n", format_char);
190+ }
191+ switch (param[0])
192+ {
193+ case 'a':
194+ if (param[1] == 'f') {
195+ if(param[2] == '\'') {
196+ value = context->alt_regs[Z80_A] << 8;
197+ value |= context->alt_flags[ZF_S] << 7;
198+ value |= context->alt_flags[ZF_Z] << 6;
199+ value |= context->alt_flags[ZF_H] << 4;
200+ value |= context->alt_flags[ZF_PV] << 2;
201+ value |= context->alt_flags[ZF_N] << 1;
202+ value |= context->alt_flags[ZF_C];
203+ } else {
204+ value = context->regs[Z80_A] << 8;
205+ value |= context->flags[ZF_S] << 7;
206+ value |= context->flags[ZF_Z] << 6;
207+ value |= context->flags[ZF_H] << 4;
208+ value |= context->flags[ZF_PV] << 2;
209+ value |= context->flags[ZF_N] << 1;
210+ value |= context->flags[ZF_C];
211+ }
212+ } else if(param[1] == '\'') {
213+ value = context->alt_regs[Z80_A];
214+ } else {
215+ value = context->regs[Z80_A];
216+ }
217+ break;
218+ case 'b':
219+ if (param[1] == 'c') {
220+ if(param[2] == '\'') {
221+ value = context->alt_regs[Z80_B] << 8;
222+ value |= context->alt_regs[Z80_C];
223+ } else {
224+ value = context->regs[Z80_B] << 8;
225+ value |= context->regs[Z80_C];
226+ }
227+ } else if(param[1] == '\'') {
228+ value = context->alt_regs[Z80_B];
229+ } else if(param[1] == 'a') {
230+ value = context->bank_reg << 15;
231+ } else {
232+ value = context->regs[Z80_B];
233+ }
234+ break;
235+ case 'c':
236+ if(param[1] == '\'') {
237+ value = context->alt_regs[Z80_C];
238+ } else if(param[1] == 'y') {
239+ value = context->current_cycle;
240+ } else {
241+ value = context->regs[Z80_C];
242+ }
243+ break;
244+ case 'd':
245+ if (param[1] == 'e') {
246+ if(param[2] == '\'') {
247+ value = context->alt_regs[Z80_D] << 8;
248+ value |= context->alt_regs[Z80_E];
249+ } else {
250+ value = context->regs[Z80_D] << 8;
251+ value |= context->regs[Z80_E];
252+ }
253+ } else if(param[1] == '\'') {
254+ value = context->alt_regs[Z80_D];
255+ } else {
256+ value = context->regs[Z80_D];
257+ }
258+ break;
259+ case 'e':
260+ if(param[1] == '\'') {
261+ value = context->alt_regs[Z80_E];
262+ } else {
263+ value = context->regs[Z80_E];
264+ }
265+ break;
266+ case 'f':
267+ if(param[2] == '\'') {
268+ value = context->alt_flags[ZF_S] << 7;
269+ value |= context->alt_flags[ZF_Z] << 6;
270+ value |= context->alt_flags[ZF_H] << 4;
271+ value |= context->alt_flags[ZF_PV] << 2;
272+ value |= context->alt_flags[ZF_N] << 1;
273+ value |= context->alt_flags[ZF_C];
274+ } else {
275+ value = context->flags[ZF_S] << 7;
276+ value |= context->flags[ZF_Z] << 6;
277+ value |= context->flags[ZF_H] << 4;
278+ value |= context->flags[ZF_PV] << 2;
279+ value |= context->flags[ZF_N] << 1;
280+ value |= context->flags[ZF_C];
281+ }
282+ break;
283+ case 'h':
284+ if (param[1] == 'l') {
285+ if(param[2] == '\'') {
286+ value = context->alt_regs[Z80_H] << 8;
287+ value |= context->alt_regs[Z80_L];
288+ } else {
289+ value = context->regs[Z80_H] << 8;
290+ value |= context->regs[Z80_L];
291+ }
292+ } else if(param[1] == '\'') {
293+ value = context->alt_regs[Z80_H];
294+ } else {
295+ value = context->regs[Z80_H];
296+ }
297+ break;
298+ case 'l':
299+ if(param[1] == '\'') {
300+ value = context->alt_regs[Z80_L];
301+ } else {
302+ value = context->regs[Z80_L];
303+ }
304+ break;
305+ case 'i':
306+ if(param[1] == 'x') {
307+ if (param[2] == 'h') {
308+ value = context->regs[Z80_IXH];
309+ } else if(param[2] == 'l') {
310+ value = context->regs[Z80_IXL];
311+ } else {
312+ value = context->regs[Z80_IXH] << 8;
313+ value |= context->regs[Z80_IXL];
314+ }
315+ } else if(param[1] == 'y') {
316+ if (param[2] == 'h') {
317+ value = context->regs[Z80_IYH];
318+ } else if(param[2] == 'l') {
319+ value = context->regs[Z80_IYL];
320+ } else {
321+ value = context->regs[Z80_IYH] << 8;
322+ value |= context->regs[Z80_IYL];
323+ }
324+ } else if(param[1] == 'n') {
325+ value = context->int_cycle;
326+ } else if(param[1] == 'f' && param[2] == 'f' && param[3] == '1') {
327+ value = context->iff1;
328+ } else if(param[1] == 'f' && param[2] == 'f' && param[3] == '2') {
329+ value = context->iff2;
330+ } else {
331+ value = context->im;
332+ }
333+ break;
334+ case 's':
335+ if (param[1] == 'p') {
336+ value = context->sp;
337+ }
338+ break;
339+ case '0':
340+ if (param[1] == 'x') {
341+ uint16_t p_addr = strtol(param+2, NULL, 16);
342+ if (p_addr < 0x4000) {
343+ value = system->zram[p_addr & 0x1FFF];
344+ } else if(p_addr >= 0x8000) {
345+ uint32_t v_addr = system->z80_bank_reg << 15;
346+ v_addr += p_addr & 0x7FFF;
347+ if (v_addr < 0x400000) {
348+ value = system->cart[v_addr/2];
349+ } else if(v_addr > 0xE00000) {
350+ value = system->work_ram[(v_addr & 0xFFFF)/2];
351+ }
352+ if (v_addr & 1) {
353+ value &= 0xFF;
354+ } else {
355+ value >>= 8;
356+ }
357+ }
358+ }
359+ break;
360+ }
361+ printf(format, param, value);
362+}
363+
364+z80_context * zdebugger(z80_context * context, uint16_t address)
365+{
366+ static char last_cmd[1024];
367+ char input_buf[1024];
368+ static uint16_t branch_t;
369+ static uint16_t branch_f;
370+ z80inst inst;
371+ genesis_context *system = context->system;
372+ init_terminal();
373+ //Check if this is a user set breakpoint, or just a temporary one
374+ bp_def ** this_bp = find_breakpoint(&zbreakpoints, address);
375+ if (*this_bp) {
376+ printf("Z80 Breakpoint %d hit\n", (*this_bp)->index);
377+ } else {
378+ zremove_breakpoint(context, address);
379+ }
380+ uint8_t * pc = get_native_pointer(address, (void **)context->mem_pointers, &context->Z80_OPTS->gen);
381+ if (!pc) {
382+ fatal_error("Failed to get native pointer on entering Z80 debugger at address %X\n", address);
383+ }
384+ for (disp_def * cur = zdisplays; cur; cur = cur->next) {
385+ zdebugger_print(context, cur->format_char, cur->param);
386+ }
387+ uint8_t * after_pc = z80_decode(pc, &inst);
388+ z80_disasm(&inst, input_buf, address);
389+ printf("%X:\t%s\n", address, input_buf);
390+ uint16_t after = address + (after_pc-pc);
391+ int debugging = 1;
392+ while(debugging) {
393+ fputs(">", stdout);
394+ if (!fgets(input_buf, sizeof(input_buf), stdin)) {
395+ fputs("fgets failed", stderr);
396+ break;
397+ }
398+ strip_nl(input_buf);
399+ //hitting enter repeats last command
400+ if (input_buf[0]) {
401+ strcpy(last_cmd, input_buf);
402+ } else {
403+ strcpy(input_buf, last_cmd);
404+ }
405+ char * param;
406+ char format[8];
407+ uint32_t value;
408+ bp_def * new_bp;
409+ switch(input_buf[0])
410+ {
411+ case 'a':
412+ param = find_param(input_buf);
413+ if (!param) {
414+ fputs("a command requires a parameter\n", stderr);
415+ break;
416+ }
417+ value = strtol(param, NULL, 16);
418+ zinsert_breakpoint(context, value, (uint8_t *)zdebugger);
419+ debugging = 0;
420+ break;
421+ case 'b':
422+ param = find_param(input_buf);
423+ if (!param) {
424+ fputs("b command requires a parameter\n", stderr);
425+ break;
426+ }
427+ value = strtol(param, NULL, 16);
428+ zinsert_breakpoint(context, value, (uint8_t *)zdebugger);
429+ new_bp = malloc(sizeof(bp_def));
430+ new_bp->next = zbreakpoints;
431+ new_bp->address = value;
432+ new_bp->index = zbp_index++;
433+ new_bp->commands = NULL;
434+ zbreakpoints = new_bp;
435+ printf("Z80 Breakpoint %d set at %X\n", new_bp->index, value);
436+ break;
437+ case 'c':
438+ puts("Continuing");
439+ debugging = 0;
440+ break;
441+ case 'd':
442+ if (input_buf[1] == 'i') {
443+ char format_char = 0;
444+ for(int i = 2; input_buf[i] != 0 && input_buf[i] != ' '; i++) {
445+ if (input_buf[i] == '/') {
446+ format_char = input_buf[i+1];
447+ break;
448+ }
449+ }
450+ param = find_param(input_buf);
451+ if (!param) {
452+ fputs("display command requires a parameter\n", stderr);
453+ break;
454+ }
455+ zdebugger_print(context, format_char, param);
456+ add_display(&zdisplays, &zdisp_index, format_char, param);
457+ } else if (input_buf[1] == 'e' || input_buf[1] == ' ') {
458+ param = find_param(input_buf);
459+ if (!param) {
460+ fputs("delete command requires a parameter\n", stderr);
461+ break;
462+ }
463+ if (param[0] >= '0' && param[0] <= '9') {
464+ value = atoi(param);
465+ this_bp = find_breakpoint_idx(&zbreakpoints, value);
466+ if (!*this_bp) {
467+ fprintf(stderr, "Breakpoint %d does not exist\n", value);
468+ break;
469+ }
470+ new_bp = *this_bp;
471+ zremove_breakpoint(context, new_bp->address);
472+ *this_bp = new_bp->next;
473+ free(new_bp);
474+ } else if (param[0] == 'd') {
475+ param = find_param(param);
476+ if (!param) {
477+ fputs("delete display command requires a parameter\n", stderr);
478+ break;
479+ }
480+ remove_display(&zdisplays, atoi(param));
481+ }
482+ }
483+ break;
484+ case 'n':
485+ //TODO: Handle conditional branch instructions
486+ if (inst.op == Z80_JP) {
487+ if (inst.addr_mode == Z80_IMMED) {
488+ after = inst.immed;
489+ } else if (inst.ea_reg == Z80_HL) {
490+ after = context->regs[Z80_H] << 8 | context->regs[Z80_L];
491+ } else if (inst.ea_reg == Z80_IX) {
492+ after = context->regs[Z80_IXH] << 8 | context->regs[Z80_IXL];
493+ } else if (inst.ea_reg == Z80_IY) {
494+ after = context->regs[Z80_IYH] << 8 | context->regs[Z80_IYL];
495+ }
496+ } else if(inst.op == Z80_JR) {
497+ after += inst.immed;
498+ } else if(inst.op == Z80_RET) {
499+ uint8_t *sp = get_native_pointer(context->sp, (void **)context->mem_pointers, &context->Z80_OPTS->gen);
500+ if (sp) {
501+ after = *sp;
502+ sp = get_native_pointer((context->sp + 1) & 0xFFFF, (void **)context->mem_pointers, &context->Z80_OPTS->gen);
503+ if (sp) {
504+ after |= *sp << 8;
505+ }
506+ }
507+ }
508+ zinsert_breakpoint(context, after, (uint8_t *)zdebugger);
509+ debugging = 0;
510+ break;
511+ case 'p':
512+ param = find_param(input_buf);
513+ if (!param) {
514+ fputs("p command requires a parameter\n", stderr);
515+ break;
516+ }
517+ zdebugger_print(context, input_buf[1] == '/' ? input_buf[2] : 0, param);
518+ break;
519+ case 'q':
520+ puts("Quitting");
521+ exit(0);
522+ break;
523+ case 's': {
524+ param = find_param(input_buf);
525+ if (!param) {
526+ fputs("s command requires a file name\n", stderr);
527+ break;
528+ }
529+ memmap_chunk const *ram_chunk = NULL;
530+ for (int i = 0; i < context->Z80_OPTS->gen.memmap_chunks; i++)
531+ {
532+ memmap_chunk const *cur = context->Z80_OPTS->gen.memmap + i;
533+ if (cur->flags & MMAP_WRITE) {
534+ ram_chunk = cur;
535+ break;
536+ }
537+ }
538+ if (ram_chunk) {
539+ uint32_t size = ram_chunk->end - ram_chunk->start;
540+ if (size > ram_chunk->mask) {
541+ size = ram_chunk->mask+1;
542+ }
543+ uint8_t *buf = get_native_pointer(ram_chunk->start, (void **)context->mem_pointers, &context->Z80_OPTS->gen);
544+ FILE * f = fopen(param, "wb");
545+ if (f) {
546+ if(fwrite(buf, 1, size, f) != size) {
547+ fputs("Error writing file\n", stderr);
548+ }
549+ fclose(f);
550+ printf("Wrote %d bytes to %s\n", size, param);
551+ } else {
552+ fprintf(stderr, "Could not open %s for writing\n", param);
553+ }
554+ } else {
555+ fputs("Failed to find a RAM memory chunk\n", stderr);
556+ }
557+ break;
558+ }
559+ default:
560+ if (
561+ !context->Z80_OPTS->gen.debug_cmd_handler
562+ || !context->Z80_OPTS->gen.debug_cmd_handler(&system->header, input_buf)
563+ ) {
564+ fprintf(stderr, "Unrecognized debugger command %s\n", input_buf);
565+ }
566+ break;
567+ }
568+ }
569+ return context;
570+}
571+
572+static uint32_t branch_t;
573+static uint32_t branch_f;
574+
575+int run_debugger_command(m68k_context *context, char *input_buf, m68kinst inst, uint32_t after)
576+{
577+ char * param;
578+ char format_char;
579+ genesis_context *system = context->system;
580+ uint32_t value;
581+ bp_def *new_bp, **this_bp;
582+ switch(input_buf[0])
583+ {
584+ case 'c':
585+ if (input_buf[1] == 0 || input_buf[1] == 'o' && input_buf[2] == 'n')
586+ {
587+ puts("Continuing");
588+ return 0;
589+ } else if (input_buf[1] == 'o' && input_buf[2] == 'm') {
590+ param = find_param(input_buf);
591+ if (!param) {
592+ fputs("com command requires a parameter\n", stderr);
593+ break;
594+ }
595+ bp_def **target = find_breakpoint_idx(&breakpoints, atoi(param));
596+ if (!target) {
597+ fprintf(stderr, "Breakpoint %s does not exist!\n", param);
598+ break;
599+ }
600+ printf("Enter commands for breakpoing %d, type end when done\n", atoi(param));
601+ char cmd_buf[1024];
602+ char *commands = NULL;
603+ for (;;)
604+ {
605+ fputs(">>", stdout);
606+ fflush(stdout);
607+ fgets(cmd_buf, sizeof(cmd_buf), stdin);
608+ if (strcmp(cmd_buf, "end\n")) {
609+ if (commands) {
610+ char *tmp = commands;
611+ commands = alloc_concat(commands, cmd_buf);
612+ free(tmp);
613+ } else {
614+ commands = strdup(cmd_buf);
615+ }
616+ } else {
617+ break;
618+ }
619+ }
620+ (*target)->commands = commands;
621+ } else {
622+ }
623+ break;
624+ case 'b':
625+ if (input_buf[1] == 't') {
626+ uint32_t stack = context->aregs[7];
627+ if (stack >= 0xE00000) {
628+ stack &= 0xFFFF;
629+ uint8_t non_adr_count = 0;
630+ do {
631+ uint32_t bt_address = system->work_ram[stack/2] << 16 | system->work_ram[stack/2+1];
632+ bt_address = get_instruction_start(context->options, bt_address - 2);
633+ if (bt_address) {
634+ stack += 4;
635+ non_adr_count = 0;
636+ uint16_t *bt_pc = NULL;
637+ if (bt_address < 0x400000) {
638+ bt_pc = system->cart + bt_address/2;
639+ } else if(bt_address > 0xE00000) {
640+ bt_pc = system->work_ram + (bt_address & 0xFFFF)/2;
641+ }
642+ m68k_decode(bt_pc, &inst, bt_address);
643+ m68k_disasm(&inst, input_buf);
644+ printf("%X: %s\n", bt_address, input_buf);
645+ } else {
646+ //non-return address value on stack can be word wide
647+ stack += 2;
648+ non_adr_count++;
649+ }
650+ stack &= 0xFFFF;
651+ } while (stack && non_adr_count < 6);
652+ }
653+ } else {
654+ param = find_param(input_buf);
655+ if (!param) {
656+ fputs("b command requires a parameter\n", stderr);
657+ break;
658+ }
659+ value = strtol(param, NULL, 16);
660+ insert_breakpoint(context, value, debugger);
661+ new_bp = malloc(sizeof(bp_def));
662+ new_bp->next = breakpoints;
663+ new_bp->address = value;
664+ new_bp->index = bp_index++;
665+ new_bp->commands = NULL;
666+ breakpoints = new_bp;
667+ printf("68K Breakpoint %d set at %X\n", new_bp->index, value);
668+ }
669+ break;
670+ case 'a':
671+ param = find_param(input_buf);
672+ if (!param) {
673+ fputs("a command requires a parameter\n", stderr);
674+ break;
675+ }
676+ value = strtol(param, NULL, 16);
677+ insert_breakpoint(context, value, debugger);
678+ return 0;
679+ case 'd':
680+ if (input_buf[1] == 'i') {
681+ format_char = 0;
682+ for(int i = 2; input_buf[i] != 0 && input_buf[i] != ' '; i++) {
683+ if (input_buf[i] == '/') {
684+ format_char = input_buf[i+1];
685+ break;
686+ }
687+ }
688+ param = find_param(input_buf);
689+ if (!param) {
690+ fputs("display command requires a parameter\n", stderr);
691+ break;
692+ }
693+ debugger_print(context, format_char, param);
694+ add_display(&displays, &disp_index, format_char, param);
695+ } else {
696+ param = find_param(input_buf);
697+ if (!param) {
698+ fputs("d command requires a parameter\n", stderr);
699+ break;
700+ }
701+ value = atoi(param);
702+ this_bp = find_breakpoint_idx(&breakpoints, value);
703+ if (!*this_bp) {
704+ fprintf(stderr, "Breakpoint %d does not exist\n", value);
705+ break;
706+ }
707+ new_bp = *this_bp;
708+ *this_bp = (*this_bp)->next;
709+ if (new_bp->commands) {
710+ free(new_bp->commands);
711+ }
712+ free(new_bp);
713+ }
714+ break;
715+ case 'p':
716+ format_char = 0;
717+ for(int i = 1; input_buf[i] != 0 && input_buf[i] != ' '; i++) {
718+ if (input_buf[i] == '/') {
719+ format_char = input_buf[i+1];
720+ break;
721+ }
722+ }
723+ param = find_param(input_buf);
724+ if (!param) {
725+ fputs("p command requires a parameter\n", stderr);
726+ break;
727+ }
728+ debugger_print(context, format_char, param);
729+ break;
730+ case 'n':
731+ if (inst.op == M68K_RTS) {
732+ after = m68k_read_long(context->aregs[7], context);
733+ } else if (inst.op == M68K_RTE || inst.op == M68K_RTR) {
734+ after = m68k_read_long(context->aregs[7] + 2, context);
735+ } else if(m68k_is_noncall_branch(&inst)) {
736+ if (inst.op == M68K_BCC && inst.extra.cond != COND_TRUE) {
737+ branch_f = after;
738+ branch_t = m68k_branch_target(&inst, context->dregs, context->aregs);
739+ insert_breakpoint(context, branch_t, debugger);
740+ } else if(inst.op == M68K_DBCC) {
741+ if ( inst.extra.cond == COND_FALSE) {
742+ if (context->dregs[inst.dst.params.regs.pri] & 0xFFFF) {
743+ after = m68k_branch_target(&inst, context->dregs, context->aregs);
744+ }
745+ } else {
746+ branch_t = after;
747+ branch_f = m68k_branch_target(&inst, context->dregs, context->aregs);
748+ insert_breakpoint(context, branch_f, debugger);
749+ }
750+ } else {
751+ after = m68k_branch_target(&inst, context->dregs, context->aregs);
752+ }
753+ }
754+ insert_breakpoint(context, after, debugger);
755+ return 0;
756+ case 'o':
757+ if (inst.op == M68K_RTS) {
758+ after = m68k_read_long(context->aregs[7], context);
759+ } else if (inst.op == M68K_RTE || inst.op == M68K_RTR) {
760+ after = m68k_read_long(context->aregs[7] + 2, context);
761+ } else if(m68k_is_noncall_branch(&inst)) {
762+ if (inst.op == M68K_BCC && inst.extra.cond != COND_TRUE) {
763+ branch_t = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
764+ if (branch_t < after) {
765+ branch_t = 0;
766+ } else {
767+ branch_f = after;
768+ insert_breakpoint(context, branch_t, debugger);
769+ }
770+ } else if(inst.op == M68K_DBCC) {
771+ uint32_t target = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
772+ if (target > after) {
773+ if (inst.extra.cond == COND_FALSE) {
774+ after = target;
775+ } else {
776+ branch_f = target;
777+ branch_t = after;
778+ insert_breakpoint(context, branch_f, debugger);
779+ }
780+ }
781+ } else {
782+ after = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
783+ }
784+ }
785+ insert_breakpoint(context, after, debugger);
786+ return 0;
787+ case 's':
788+ if (input_buf[1] == 'e') {
789+ param = find_param(input_buf);
790+ if (!param) {
791+ fputs("Missing destination parameter for set\n", stderr);
792+ }
793+ char *val = find_param(param);
794+ if (!val) {
795+ fputs("Missing value parameter for set\n", stderr);
796+ }
797+ long int_val;
798+ int reg_num;
799+ switch (val[0])
800+ {
801+ case 'd':
802+ case 'a':
803+ reg_num = val[1] - '0';
804+ if (reg_num < 0 || reg_num > 8) {
805+ fprintf(stderr, "Invalid register %s\n", val);
806+ return 1;
807+ }
808+ int_val = (val[0] == 'd' ? context->dregs : context->aregs)[reg_num];
809+ break;
810+ case '$':
811+ int_val = strtol(val+1, NULL, 16);
812+ break;
813+ case '0':
814+ if (val[1] == 'x') {
815+ int_val = strtol(val+2, NULL, 16);
816+ break;
817+ }
818+ default:
819+ int_val = strtol(val, NULL, 10);
820+ }
821+ switch(param[0])
822+ {
823+ case 'd':
824+ case 'a':
825+ reg_num = param[1] - '0';
826+ if (reg_num < 0 || reg_num > 8) {
827+ fprintf(stderr, "Invalid register %s\n", param);
828+ return 1;
829+ }
830+ (param[0] == 'd' ? context->dregs : context->aregs)[reg_num] = int_val;
831+ break;
832+ default:
833+ fprintf(stderr, "Invalid destinatino %s\n", param);
834+ }
835+ break;
836+ } else {
837+ if (inst.op == M68K_RTS) {
838+ after = m68k_read_long(context->aregs[7], context);
839+ } else if (inst.op == M68K_RTE || inst.op == M68K_RTR) {
840+ after = m68k_read_long(context->aregs[7] + 2, context);
841+ } else if(m68k_is_branch(&inst)) {
842+ if (inst.op == M68K_BCC && inst.extra.cond != COND_TRUE) {
843+ branch_f = after;
844+ branch_t = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
845+ insert_breakpoint(context, branch_t, debugger);
846+ } else if(inst.op == M68K_DBCC) {
847+ if (inst.extra.cond == COND_FALSE) {
848+ if (context->dregs[inst.dst.params.regs.pri] & 0xFFFF) {
849+ after = m68k_branch_target(&inst, context->dregs, context->aregs);
850+ }
851+ } else {
852+ branch_t = after;
853+ branch_f = m68k_branch_target(&inst, context->dregs, context->aregs);
854+ insert_breakpoint(context, branch_f, debugger);
855+ }
856+ } else {
857+ after = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
858+ }
859+ }
860+ insert_breakpoint(context, after, debugger);
861+ return 0;
862+ }
863+ case 'v': {
864+ genesis_context * gen = context->system;
865+ //VDP debug commands
866+ switch(input_buf[1])
867+ {
868+ case 's':
869+ vdp_print_sprite_table(gen->vdp);
870+ break;
871+ case 'r':
872+ vdp_print_reg_explain(gen->vdp);
873+ break;
874+ }
875+ break;
876+ }
877+ case 'y': {
878+ genesis_context * gen = context->system;
879+ //YM-2612 debug commands
880+ switch(input_buf[1])
881+ {
882+ case 'c':
883+ if (input_buf[2] == ' ') {
884+ int channel = atoi(input_buf+3)-1;
885+ ym_print_channel_info(gen->ym, channel);
886+ } else {
887+ for (int i = 0; i < 6; i++) {
888+ ym_print_channel_info(gen->ym, i);
889+ }
890+ }
891+ break;
892+ case 't':
893+ ym_print_timer_info(gen->ym);
894+ break;
895+ }
896+ break;
897+ }
898+ case 'z': {
899+ genesis_context * gen = context->system;
900+ //Z80 debug commands
901+ switch(input_buf[1])
902+ {
903+ case 'b':
904+ param = find_param(input_buf);
905+ if (!param) {
906+ fputs("zb command requires a parameter\n", stderr);
907+ break;
908+ }
909+ value = strtol(param, NULL, 16);
910+ zinsert_breakpoint(gen->z80, value, (uint8_t *)zdebugger);
911+ new_bp = malloc(sizeof(bp_def));
912+ new_bp->next = zbreakpoints;
913+ new_bp->address = value;
914+ new_bp->index = zbp_index++;
915+ zbreakpoints = new_bp;
916+ printf("Z80 Breakpoint %d set at %X\n", new_bp->index, value);
917+ break;
918+ case 'p':
919+ param = find_param(input_buf);
920+ if (!param) {
921+ fputs("zp command requires a parameter\n", stderr);
922+ break;
923+ }
924+ zdebugger_print(gen->z80, input_buf[2] == '/' ? input_buf[3] : 0, param);
925+ }
926+ break;
927+ }
928+ case 'q':
929+ puts("Quitting");
930+ exit(0);
931+ break;
932+ default:
933+ fprintf(stderr, "Unrecognized debugger command %s\n", input_buf);
934+ break;
935+ }
936+ return 1;
937+}
938+
939+
940+void debugger(m68k_context * context, uint32_t address)
941+{
942+ static char last_cmd[1024];
943+ char input_buf[1024];
944+ m68kinst inst;
945+
946+ init_terminal();
947+
948+ sync_components(context, 0);
949+ genesis_context *gen = context->system;
950+ vdp_force_update_framebuffer(gen->vdp);
951+ //probably not necessary, but let's play it safe
952+ address &= 0xFFFFFF;
953+ if (address == branch_t) {
954+ bp_def ** f_bp = find_breakpoint(&breakpoints, branch_f);
955+ if (!*f_bp) {
956+ remove_breakpoint(context, branch_f);
957+ }
958+ branch_t = branch_f = 0;
959+ } else if(address == branch_f) {
960+ bp_def ** t_bp = find_breakpoint(&breakpoints, branch_t);
961+ if (!*t_bp) {
962+ remove_breakpoint(context, branch_t);
963+ }
964+ branch_t = branch_f = 0;
965+ }
966+
967+ uint16_t * pc = get_native_pointer(address, (void **)context->mem_pointers, &context->options->gen);
968+ if (!pc) {
969+ fatal_error("Entered 68K debugger at address %X\n", address);
970+ }
971+ uint16_t * after_pc = m68k_decode(pc, &inst, address);
972+ uint32_t after = address + (after_pc-pc)*2;
973+ int debugging = 1;
974+ //Check if this is a user set breakpoint, or just a temporary one
975+ bp_def ** this_bp = find_breakpoint(&breakpoints, address);
976+ if (*this_bp) {
977+
978+ if ((*this_bp)->commands)
979+ {
980+ char *commands = strdup((*this_bp)->commands);
981+ char *copy = commands;
982+
983+ while (debugging && *commands)
984+ {
985+ char *cmd = commands;
986+ strip_nl(cmd);
987+ commands += strlen(cmd) + 1;
988+ debugging = run_debugger_command(context, cmd, inst, after);
989+ }
990+ free(copy);
991+ }
992+ if (debugging) {
993+ printf("68K Breakpoint %d hit\n", (*this_bp)->index);
994+ } else {
995+ return;
996+ }
997+ } else {
998+ remove_breakpoint(context, address);
999+ }
1000+ for (disp_def * cur = displays; cur; cur = cur->next) {
1001+ debugger_print(context, cur->format_char, cur->param);
1002+ }
1003+ m68k_disasm(&inst, input_buf);
1004+ printf("%X: %s\n", address, input_buf);
1005+ int prompt = 1;
1006+ fd_set read_fds;
1007+ FD_ZERO(&read_fds);
1008+ struct timeval timeout;
1009+ while (debugging) {
1010+ if (prompt) {
1011+ fputs(">", stdout);
1012+ fflush(stdout);
1013+ }
1014+ process_events();
1015+ timeout.tv_sec = 0;
1016+ timeout.tv_usec = 16667;
1017+ FD_SET(fileno(stdin), &read_fds);
1018+ if(select(fileno(stdin) + 1, &read_fds, NULL, NULL, &timeout) < 1) {
1019+ prompt = 0;
1020+ continue;
1021+ } else {
1022+ prompt = 1;
1023+ }
1024+ if (!fgets(input_buf, sizeof(input_buf), stdin)) {
1025+ fputs("fgets failed", stderr);
1026+ break;
1027+ }
1028+ strip_nl(input_buf);
1029+ //hitting enter repeats last command
1030+ if (input_buf[0]) {
1031+ strcpy(last_cmd, input_buf);
1032+ } else {
1033+ strcpy(input_buf, last_cmd);
1034+ }
1035+ debugging = run_debugger_command(context, input_buf, inst, after);
1036+ }
1037+ return;
1038+}
A
debug.h
+29,
-0
1@@ -0,0 +1,29 @@
2+#ifndef DEBUG_H_
3+#define DEBUG_H_
4+
5+#include <stdint.h>
6+#include "m68k_core.h"
7+#include "z80_to_x86.h"
8+
9+typedef struct disp_def {
10+ struct disp_def * next;
11+ char * param;
12+ uint32_t index;
13+ char format_char;
14+} disp_def;
15+
16+typedef struct bp_def {
17+ struct bp_def *next;
18+ char *commands;
19+ uint32_t address;
20+ uint32_t index;
21+} bp_def;
22+
23+bp_def ** find_breakpoint(bp_def ** cur, uint32_t address);
24+bp_def ** find_breakpoint_idx(bp_def ** cur, uint32_t index);
25+void add_display(disp_def ** head, uint32_t *index, char format_char, char * param);
26+void remove_display(disp_def ** head, uint32_t index);
27+void debugger(m68k_context * context, uint32_t address);
28+z80_context * zdebugger(z80_context * context, uint16_t address);
29+
30+#endif //DEBUG_H_
+376,
-0
1@@ -0,0 +1,376 @@
2+
3+bindings {
4+ keys {
5+ up gamepads.1.up
6+ down gamepads.1.down
7+ left gamepads.1.left
8+ right gamepads.1.right
9+ a gamepads.1.a
10+ s gamepads.1.b
11+ d gamepads.1.c
12+ q gamepads.1.x
13+ w gamepads.1.y
14+ e gamepads.1.z
15+ f gamepads.1.mode
16+ enter gamepads.1.start
17+
18+ r ui.release_mouse
19+ [ ui.vdp_debug_mode
20+ u ui.enter_debugger
21+ p ui.screenshot
22+ b ui.plane_debug
23+ v ui.vram_debug
24+ c ui.cram_debug
25+ n ui.compositing_debug
26+ esc ui.exit
27+ ` ui.save_state
28+ 0 ui.set_speed.0
29+ 1 ui.set_speed.1
30+ 2 ui.set_speed.2
31+ 3 ui.set_speed.3
32+ 4 ui.set_speed.4
33+ 5 ui.set_speed.5
34+ 6 ui.set_speed.6
35+ 7 ui.set_speed.7
36+ = ui.next_speed
37+ - ui.prev_speed
38+ tab ui.soft_reset
39+ f5 ui.reload
40+ z ui.sms_pause
41+ rctrl ui.toggle_keyboard_captured
42+ }
43+ pads {
44+ default {
45+ dpads {
46+ 0 {
47+ up gamepads.n.up
48+ down gamepads.n.down
49+ left gamepads.n.left
50+ right gamepads.n.right
51+ }
52+ }
53+ buttons {
54+ a gamepads.n.a
55+ b gamepads.n.b
56+ rightshoulder gamepads.n.c
57+ x gamepads.n.x
58+ y gamepads.n.y
59+ leftshoulder gamepads.n.z
60+ back gamepads.n.mode
61+ start gamepads.n.start
62+ guide ui.exit
63+ leftstick ui.save_state
64+ }
65+ axes {
66+ lefty.positive gamepads.n.down
67+ lefty.negative gamepads.n.up
68+ leftx.positive gamepads.n.right
69+ leftx.negative gamepads.n.left
70+ lefttrigger ui.prev_speed
71+ righttrigger ui.next_speed
72+ }
73+ }
74+ ps4_6b_right {
75+ axes {
76+ lefttrigger ui.next_speed
77+ leftx.negative gamepads.n.up
78+ leftx.positive gamepads.n.down
79+ lefty.negative gamepads.n.left
80+ lefty.positive gamepads.n.right
81+ righttrigger gamepads.n.c
82+ }
83+ buttons {
84+ a gamepads.n.a
85+ b gamepads.n.b
86+ back ui.sms_pause
87+ guide ui.exit
88+ leftshoulder gamepads.n.mode
89+ leftstick ui.save_state
90+ rightshoulder gamepads.n.z
91+ rightstick ui.prev_speed
92+ start gamepads.n.start
93+ x gamepads.n.x
94+ y gamepads.n.y
95+ }
96+ dpads {
97+ 0 {
98+ down gamepads.n.down
99+ left gamepads.n.left
100+ right gamepads.n.right
101+ up gamepads.n.up
102+ }
103+ }
104+ }
105+ ps3_6b_right {
106+ axes {
107+ lefttrigger ui.next_speed
108+ leftx.negative gamepads.n.up
109+ leftx.positive gamepads.n.down
110+ lefty.negative gamepads.n.left
111+ lefty.positive gamepads.n.right
112+ righttrigger gamepads.n.c
113+ }
114+ buttons {
115+ a gamepads.n.a
116+ b gamepads.n.b
117+ back ui.sms_pause
118+ guide ui.exit
119+ leftshoulder gamepads.n.mode
120+ leftstick ui.save_state
121+ rightshoulder gamepads.n.z
122+ rightstick ui.prev_speed
123+ start gamepads.n.start
124+ x gamepads.n.x
125+ y gamepads.n.y
126+ }
127+ dpads {
128+ 0 {
129+ down gamepads.n.down
130+ left gamepads.n.left
131+ right gamepads.n.right
132+ up gamepads.n.up
133+ }
134+ }
135+ }
136+ xbox_360_6b_right {
137+ axes {
138+ lefttrigger ui.next_speed
139+ leftx.negative gamepads.n.up
140+ leftx.positive gamepads.n.down
141+ lefty.negative gamepads.n.left
142+ lefty.positive gamepads.n.right
143+ righttrigger gamepads.n.c
144+ }
145+ buttons {
146+ a gamepads.n.a
147+ b gamepads.n.b
148+ back ui.sms_pause
149+ guide ui.exit
150+ leftshoulder gamepads.n.mode
151+ leftstick ui.save_state
152+ rightshoulder gamepads.n.z
153+ rightstick ui.prev_speed
154+ start gamepads.n.start
155+ x gamepads.n.x
156+ y gamepads.n.y
157+ }
158+ dpads {
159+ 0 {
160+ down gamepads.n.down
161+ left gamepads.n.left
162+ right gamepads.n.right
163+ up gamepads.n.up
164+ }
165+ }
166+ }
167+ xbone_6b_right {
168+ axes {
169+ lefttrigger ui.next_speed
170+ leftx.negative gamepads.n.up
171+ leftx.positive gamepads.n.down
172+ lefty.negative gamepads.n.left
173+ lefty.positive gamepads.n.right
174+ righttrigger gamepads.n.c
175+ }
176+ buttons {
177+ a gamepads.n.a
178+ b gamepads.n.b
179+ back ui.sms_pause
180+ guide ui.exit
181+ leftshoulder gamepads.n.mode
182+ leftstick ui.save_state
183+ rightshoulder gamepads.n.z
184+ rightstick ui.prev_speed
185+ start gamepads.n.start
186+ x gamepads.n.x
187+ y gamepads.n.y
188+ }
189+ dpads {
190+ 0 {
191+ down gamepads.n.down
192+ left gamepads.n.left
193+ right gamepads.n.right
194+ up gamepads.n.up
195+ }
196+ }
197+ }
198+ genesis_6b_bumpers {
199+ axes {
200+ lefttrigger ui.exit
201+ righttrigger gamepads.n.mode
202+ }
203+ buttons {
204+ a gamepads.n.a
205+ b gamepads.n.b
206+ back ui.sms_pause
207+ guide ui.exit
208+ leftshoulder gamepads.n.z
209+ rightshoulder gamepads.n.c
210+ start gamepads.n.start
211+ x gamepads.n.x
212+ y gamepads.n.y
213+ }
214+ dpads {
215+ 0 {
216+ down gamepads.n.down
217+ left gamepads.n.left
218+ right gamepads.n.right
219+ up gamepads.n.up
220+ }
221+ }
222+ }
223+ saturn_6b_bumpers {
224+ axes {
225+ lefttrigger ui.exit
226+ righttrigger gamepads.n.mode
227+ }
228+ buttons {
229+ a gamepads.n.a
230+ b gamepads.n.b
231+ back ui.sms_pause
232+ guide ui.exit
233+ leftshoulder gamepads.n.z
234+ rightshoulder gamepads.n.c
235+ start gamepads.n.start
236+ x gamepads.n.x
237+ y gamepads.n.y
238+ }
239+ dpads {
240+ 0 {
241+ down gamepads.n.down
242+ left gamepads.n.left
243+ right gamepads.n.right
244+ up gamepads.n.up
245+ }
246+ }
247+ }
248+ }
249+ mice {
250+ 0 {
251+ motion mouse.1.motion
252+ buttons {
253+ 1 mouse.1.left
254+ 2 mouse.1.middle
255+ 3 mouse.1.right
256+ 4 mouse.1.start
257+ }
258+ }
259+ #having the second host mouse also mapped to the first emulated
260+ #mouse is useful for laptop users with an external mouse
261+ 1 {
262+ motion mouse.1.motion
263+ buttons {
264+ 1 mouse.1.left
265+ 2 mouse.1.middle
266+ 3 mouse.1.right
267+ 4 mouse.1.start
268+ }
269+ }
270+ }
271+}
272+
273+io {
274+ devices {
275+ 1 gamepad6.1
276+ 2 gamepad6.2
277+ }
278+}
279+
280+video {
281+ #special value "stretch" will cause aspect to match window aspect ratio
282+ aspect 4:3
283+ width 640
284+ #height is normally calculated automatically from width using the aspect setting
285+ #if you would like to set it explicitly, uncomment the line below
286+ #height 480
287+ ntsc {
288+ overscan {
289+ #these values will result in square pixels in H40 mode
290+ top 2
291+ bottom 1
292+ #if you want to completely hide the border instead
293+ #comment out those two lines and uncomment these
294+ #top 11
295+ #bottom 8
296+
297+ #these values will completely hide the horizontal border
298+ left 13
299+ right 14
300+ }
301+ }
302+ pal {
303+ overscan {
304+ #these values will produce the same size border in V30 mode
305+ #as the default NTSC settings will produce in V24 mode
306+ #this results in a slightly vertically squished picture
307+ #which is probably approximately correct on a properly calibrated TV
308+ top 21
309+ bottom 17
310+ #for square pixels and zero border in V30 mode
311+ #coment out those two lines and uncomment these
312+ #top 30
313+ #bottom 24
314+
315+ #these values will completely hide the horizontal border
316+ left 13
317+ right 14
318+ }
319+ }
320+}
321+
322+audio {
323+ rate 48000
324+ buffer 512
325+ lowpass_cutoff 3390
326+}
327+
328+clocks {
329+ m68k_divider 7
330+ max_cycles 3420
331+ speeds {
332+ 0 100
333+ 1 150
334+ 2 200
335+ 3 300
336+ 4 400
337+ 5 25
338+ 6 50
339+ 7 75
340+ }
341+}
342+
343+ui {
344+ #specifies the ROM that implements the Menu UI
345+ rom menu.bin
346+ #starting path for ROM browsing, accepts special variables $HOME, $EXEDIR
347+ #and variables defined in the OS environment
348+ initial_path $HOME
349+ #if this is set to on, then the menu will remember the last path when visited
350+ #if it's set to off, initial_path will always be used on startup
351+ remember_path on
352+ #path for storing internal screenshots, accepts the same variables as initial_path
353+ screenshot_path $HOME
354+ #see strftime for the format specifiers valid in screenshot_template
355+ screenshot_template blastem_%Y%m%d_%H%M%S.png
356+ #path template for saving SRAM, EEPROM and savestates
357+ #accepts special variables $HOME, $EXEDIR, $USERDATA, $ROMNAME
358+ save_path $USERDATA/blastem/$ROMNAME
359+ #space delimited list of file extensions to filter against in menu
360+ extensions bin gen md smd sms gg zip gz
361+ #specifies the preferred save-state format, set to gst for Genecyst compatible states
362+ state_format native
363+}
364+
365+system {
366+ #controls how the emulated system is synced to the host
367+ #video provides the smoothest experience when the host and emulated system have similar refresh rates
368+ #audio provides lower audio latency, especially when there is a refresh rate mismatch
369+ sync_source audio
370+ #set this to random to debug initialization bugs
371+ ram_init zero
372+ default_region U
373+ #controls whether MegaWiFi support is enabled or not
374+ #MegaWiFi allows ROMs to make connections to the internet
375+ #so it should only be enabled for ROMs you trust
376+ megawifi off
377+}
A
dis.c
+407,
-0
1@@ -0,0 +1,407 @@
2+/*
3+ Copyright 2013 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#include "68kinst.h"
8+#include <stdio.h>
9+#include <stdlib.h>
10+#include <string.h>
11+#include <stdarg.h>
12+#include <ctype.h>
13+#include "vos_program_module.h"
14+#include "tern.h"
15+#include "util.h"
16+
17+uint8_t visited[(16*1024*1024)/16];
18+uint16_t label[(16*1024*1024)/8];
19+
20+void fatal_error(char *format, ...)
21+{
22+ va_list args;
23+ va_start(args, format);
24+ vfprintf(stderr, format, args);
25+ va_end(args);
26+ exit(1);
27+}
28+
29+
30+void visit(uint32_t address)
31+{
32+ address &= 0xFFFFFF;
33+ visited[address/16] |= 1 << ((address / 2) % 8);
34+}
35+
36+void reference(uint32_t address)
37+{
38+ address &= 0xFFFFFF;
39+ //printf("referenced: %X\n", address);
40+ label[address/16] |= 1 << (address % 16);
41+}
42+
43+uint8_t is_visited(uint32_t address)
44+{
45+ address &= 0xFFFFFF;
46+ return visited[address/16] & (1 << ((address / 2) % 8));
47+}
48+
49+uint16_t is_label(uint32_t address)
50+{
51+ address &= 0xFFFFFF;
52+ return label[address/16] & (1 << (address % 16));
53+}
54+
55+typedef struct {
56+ uint32_t num_labels;
57+ uint32_t storage;
58+ char *labels[];
59+} label_names;
60+
61+tern_node * add_label(tern_node * head, char * name, uint32_t address)
62+{
63+ char key[MAX_INT_KEY_SIZE];
64+ address &= 0xFFFFFF;
65+ reference(address);
66+ tern_int_key(address, key);
67+ label_names * names = tern_find_ptr(head, key);
68+ if (names)
69+ {
70+ if (names->num_labels == names->storage)
71+ {
72+ names->storage = names->storage + (names->storage >> 1);
73+ names = realloc(names, sizeof(label_names) + names->storage * sizeof(char *));
74+ }
75+ } else {
76+ names = malloc(sizeof(label_names) + 4 * sizeof(char *));
77+ names->num_labels = 0;
78+ names->storage = 4;
79+ head = tern_insert_ptr(head, key, names);
80+ }
81+ names->labels[names->num_labels++] = strdup(name);
82+ return head;
83+}
84+
85+typedef struct deferred {
86+ uint32_t address;
87+ struct deferred *next;
88+} deferred;
89+
90+deferred * defer(uint32_t address, deferred * next)
91+{
92+ if (is_visited(address) || address & 1) {
93+ return next;
94+ }
95+ //printf("deferring %X\n", address);
96+ deferred * d = malloc(sizeof(deferred));
97+ d->address = address;
98+ d->next = next;
99+ return d;
100+}
101+
102+void check_reference(m68kinst * inst, m68k_op_info * op)
103+{
104+ switch(op->addr_mode)
105+ {
106+ case MODE_PC_DISPLACE:
107+ reference(inst->address + 2 + op->params.regs.displacement);
108+ break;
109+ case MODE_ABSOLUTE:
110+ case MODE_ABSOLUTE_SHORT:
111+ reference(op->params.immed);
112+ break;
113+ }
114+}
115+
116+int label_fun(char *dst, uint32_t address, void * data)
117+{
118+ tern_node * labels = data;
119+ char key[MAX_INT_KEY_SIZE];
120+ label_names * names = tern_find_ptr(labels, tern_int_key(address & 0xFFFFFF, key));
121+ if (names)
122+ {
123+ return sprintf(dst, "%s", names->labels[0]);
124+ } else {
125+ return m68k_default_label_fun(dst, address, NULL);
126+ }
127+}
128+
129+char * strip_ws(char * text)
130+{
131+ while (*text && (!isprint(*text) || isblank(*text)))
132+ {
133+ text++;
134+ }
135+ char * ret = text;
136+ text = ret + strlen(ret) - 1;
137+ while (text > ret && (!isprint(*text) || isblank(*text)))
138+ {
139+ *text = 0;
140+ text--;
141+ }
142+ return ret;
143+}
144+
145+int main(int argc, char ** argv)
146+{
147+ long filesize;
148+ unsigned short *filebuf;
149+ char disbuf[1024];
150+ m68kinst instbuf;
151+ unsigned short * cur;
152+ deferred *def = NULL, *tmpd;
153+
154+ uint8_t labels = 0, addr = 0, only = 0, vos = 0, reset = 0;
155+ tern_node * named_labels = NULL;
156+
157+ uint32_t address_off = 0, address_end;
158+ for(uint8_t opt = 2; opt < argc; ++opt) {
159+ if (argv[opt][0] == '-') {
160+ FILE * address_log;
161+ switch (argv[opt][1])
162+ {
163+ case 'l':
164+ labels = 1;
165+ break;
166+ case 'a':
167+ addr = 1;
168+ break;
169+ case 'o':
170+ only = 1;
171+ break;
172+ case 'v':
173+ vos = 1;
174+ break;
175+ case 'r':
176+ reset = 1;
177+ break;
178+ case 's':
179+ opt++;
180+ if (opt >= argc) {
181+ fputs("-s must be followed by an offset\n", stderr);
182+ exit(1);
183+ }
184+ address_off = strtol(argv[opt], NULL, 0);
185+ break;
186+ case 'f':
187+ opt++;
188+ if (opt >= argc) {
189+ fputs("-f must be followed by a filename\n", stderr);
190+ exit(1);
191+ }
192+ address_log = fopen(argv[opt], "r");
193+ if (!address_log) {
194+ fprintf(stderr, "Failed to open %s for reading\n", argv[opt]);
195+ exit(1);
196+ }
197+ while (fgets(disbuf, sizeof(disbuf), address_log)) {
198+ if (disbuf[0]) {
199+ char *end;
200+ uint32_t address = strtol(disbuf, &end, 16);
201+ if (address) {
202+ def = defer(address, def);
203+ reference(address);
204+ if (*end == '=') {
205+ named_labels = add_label(named_labels, strip_ws(end+1), address);
206+ }
207+ }
208+ }
209+ }
210+ fclose(address_log);
211+ }
212+ } else {
213+ char *end;
214+ uint32_t address = strtol(argv[opt], &end, 16);
215+ def = defer(address, def);
216+ reference(address);
217+ if (*end == '=') {
218+ named_labels = add_label(named_labels, end+1, address);
219+ }
220+ }
221+ }
222+ FILE * f = fopen(argv[1], "rb");
223+ fseek(f, 0, SEEK_END);
224+ filesize = ftell(f);
225+ fseek(f, 0, SEEK_SET);
226+
227+ char int_key[MAX_INT_KEY_SIZE];
228+ if (vos)
229+ {
230+ vos_program_module header;
231+ vos_read_header(f, &header);
232+ vos_read_alloc_module_map(f, &header);
233+ address_off = header.user_boundary;
234+ address_end = address_off + filesize - 0x1000;
235+ def = defer(header.main_entry_link.code_address, def);
236+ named_labels = add_label(named_labels, "main_entry_link", header.main_entry_link.code_address);
237+ for (int i = 0; i < header.n_modules; i++)
238+ {
239+ if (!reset || header.module_map_entries[i].code_address != header.user_boundary)
240+ {
241+ def = defer(header.module_map_entries[i].code_address, def);
242+ }
243+ named_labels = add_label(named_labels, header.module_map_entries[i].name.str, header.module_map_entries[i].code_address);
244+ }
245+ fseek(f, 0x1000, SEEK_SET);
246+ filebuf = malloc(filesize - 0x1000);
247+ if (fread(filebuf, 2, (filesize - 0x1000)/2, f) != (filesize - 0x1000)/2)
248+ {
249+ fprintf(stderr, "Failure while reading file %s\n", argv[1]);
250+ }
251+ fclose(f);
252+ for(cur = filebuf; cur - filebuf < ((filesize - 0x1000)/2); ++cur)
253+ {
254+ *cur = (*cur >> 8) | (*cur << 8);
255+ }
256+ if (reset)
257+ {
258+ def = defer(filebuf[2] << 16 | filebuf[3], def);
259+ named_labels = add_label(named_labels, "reset", filebuf[2] << 16 | filebuf[3]);
260+ }
261+ } else {
262+ address_end = address_off + filesize;
263+ filebuf = malloc(filesize);
264+ if (fread(filebuf, 2, filesize/2, f) != filesize/2)
265+ {
266+ fprintf(stderr, "Failure while reading file %s\n", argv[1]);
267+ }
268+ fclose(f);
269+ for(cur = filebuf; cur - filebuf < (filesize/2); ++cur)
270+ {
271+ *cur = (*cur >> 8) | (*cur << 8);
272+ }
273+ uint32_t start = filebuf[2] << 16 | filebuf[3];
274+ uint32_t int_2 = filebuf[0x68/2] << 16 | filebuf[0x6A/2];
275+ uint32_t int_4 = filebuf[0x70/2] << 16 | filebuf[0x72/2];
276+ uint32_t int_6 = filebuf[0x78/2] << 16 | filebuf[0x7A/2];
277+ named_labels = add_label(named_labels, "start", start);
278+ named_labels = add_label(named_labels, "int_2", int_2);
279+ named_labels = add_label(named_labels, "int_4", int_4);
280+ named_labels = add_label(named_labels, "int_6", int_6);
281+ if (!def || !only) {
282+ def = defer(start, def);
283+ def = defer(int_2, def);
284+ def = defer(int_4, def);
285+ def = defer(int_6, def);
286+ }
287+ }
288+ uint16_t *encoded, *next;
289+ uint32_t size, tmp_addr;
290+ uint32_t address;
291+ while(def) {
292+ do {
293+ encoded = NULL;
294+ address = def->address;
295+ if (!is_visited(address)) {
296+ encoded = filebuf + (address - address_off)/2;
297+ }
298+ tmpd = def;
299+ def = def->next;
300+ free(tmpd);
301+ } while(def && encoded == NULL);
302+ if (!encoded) {
303+ break;
304+ }
305+ for(;;) {
306+ if (address > address_end || address < address_off) {
307+ break;
308+ }
309+ visit(address);
310+ next = m68k_decode(encoded, &instbuf, address);
311+ address += (next-encoded)*2;
312+ encoded = next;
313+ //m68k_disasm(&instbuf, disbuf);
314+ //printf("%X: %s\n", instbuf.address, disbuf);
315+ check_reference(&instbuf, &(instbuf.src));
316+ check_reference(&instbuf, &(instbuf.dst));
317+ if (instbuf.op == M68K_ILLEGAL || instbuf.op == M68K_RTS || instbuf.op == M68K_RTE || instbuf.op == M68K_INVALID) {
318+ break;
319+ }
320+ if (instbuf.op == M68K_BCC || instbuf.op == M68K_DBCC || instbuf.op == M68K_BSR) {
321+ if (instbuf.op == M68K_BCC && instbuf.extra.cond == COND_TRUE) {
322+ address = instbuf.address + 2 + instbuf.src.params.immed;
323+ encoded = filebuf + (address - address_off)/2;
324+ reference(address);
325+ if (is_visited(address)) {
326+ break;
327+ }
328+ } else {
329+ tmp_addr = instbuf.address + 2 + instbuf.src.params.immed;
330+ reference(tmp_addr);
331+ def = defer(tmp_addr, def);
332+ }
333+ } else if(instbuf.op == M68K_JMP) {
334+ if (instbuf.src.addr_mode == MODE_ABSOLUTE || instbuf.src.addr_mode == MODE_ABSOLUTE_SHORT) {
335+ address = instbuf.src.params.immed;
336+ encoded = filebuf + (address - address_off)/2;
337+ if (is_visited(address)) {
338+ break;
339+ }
340+ } else if (instbuf.src.addr_mode == MODE_PC_DISPLACE) {
341+ address = instbuf.src.params.regs.displacement + instbuf.address + 2;
342+ encoded = filebuf + (address - address_off)/2;
343+ if (is_visited(address)) {
344+ break;
345+ }
346+ } else {
347+ break;
348+ }
349+ } else if(instbuf.op == M68K_JSR) {
350+ if (instbuf.src.addr_mode == MODE_ABSOLUTE || instbuf.src.addr_mode == MODE_ABSOLUTE_SHORT) {
351+ def = defer(instbuf.src.params.immed, def);
352+ } else if (instbuf.src.addr_mode == MODE_PC_DISPLACE) {
353+ def = defer(instbuf.src.params.regs.displacement + instbuf.address + 2, def);
354+ }
355+ }
356+ }
357+ }
358+ if (labels) {
359+ for (address = 0; address < address_off; address++) {
360+ if (is_label(address)) {
361+ printf("ADR_%X equ $%X\n", address, address);
362+ }
363+ }
364+ for (address = filesize; address < (16*1024*1024); address++) {
365+ char key[MAX_INT_KEY_SIZE];
366+ tern_int_key(address, key);
367+ label_names *names = tern_find_ptr(named_labels, key);
368+ if (names) {
369+ for (int i = 0; i < names->num_labels; i++)
370+ {
371+ printf("%s equ $%X\n", names->labels[i], address);
372+ }
373+ } else if (is_label(address)) {
374+ printf("ADR_%X equ $%X\n", address, address);
375+ }
376+ }
377+ puts("");
378+ }
379+ for (address = address_off; address < address_end; address+=2) {
380+ if (is_visited(address)) {
381+ encoded = filebuf + (address-address_off)/2;
382+ m68k_decode(encoded, &instbuf, address);
383+ if (labels) {
384+ m68k_disasm_labels(&instbuf, disbuf, label_fun, named_labels);
385+ char keybuf[MAX_INT_KEY_SIZE];
386+ label_names * names = tern_find_ptr(named_labels, tern_int_key(address, keybuf));
387+ if (names)
388+ {
389+ for (int i = 0; i < names->num_labels; i++)
390+ {
391+ printf("%s:\n", names->labels[i]);
392+ }
393+ } else if (is_label(instbuf.address)) {
394+ printf("ADR_%X:\n", instbuf.address);
395+ }
396+ if (addr) {
397+ printf("\t%s\t;%X\n", disbuf, instbuf.address);
398+ } else {
399+ printf("\t%s\n", disbuf);
400+ }
401+ } else {
402+ m68k_disasm(&instbuf, disbuf);
403+ printf("%X: %s\n", instbuf.address, disbuf);
404+ }
405+ }
406+ }
407+ return 0;
408+}
+105,
-0
1@@ -0,0 +1,105 @@
2+CONSOLE_PORT equ 0
3+STATUS_PORT equ 1
4+EXIT_PORT equ 2
5+ org $E400
6+ jp handle_call
7+ ld a, (should_exit)
8+ dec a
9+ jr z, do_exit
10+ ld a, 1
11+ ld (should_exit), a
12+ jp $100
13+do_exit:
14+no_impl
15+ out (EXIT_PORT), a
16+should_exit:
17+ dc.b 0
18+
19+console_in:
20+ in a, (CONSOLE_PORT)
21+ ld l, a
22+ ret
23+console_out:
24+ ld a, e
25+ out (CONSOLE_PORT), a
26+ ret
27+get_iobyte:
28+ ld a, (3)
29+ ld l, a
30+ ret
31+set_iobyte:
32+ ld a, e
33+ ld (3), a
34+ ret
35+write_string:
36+ ld c, '$'
37+ jp .start
38+.continue
39+ out (CONSOLE_PORT), a
40+ inc de
41+.start
42+ ld a, (de)
43+ cp c
44+ jr nz, .continue
45+ ;flush output
46+ out (STATUS_PORT),a
47+ ret
48+read_string:
49+ ld a, (de)
50+ ld c, a
51+ ld b, $A ;newline
52+ inc c
53+ inc de
54+ push de
55+ inc de
56+ jp .start
57+.continue
58+ in a, (CONSOLE_PORT)
59+ cp b
60+ jr z, .end
61+ ld (de), a
62+ inc de
63+.start
64+ dec c
65+ jr nz, .continue
66+ ;todo: consume excess characters
67+.end
68+ pop hl
69+ ex de, hl
70+ sbc hl, de
71+ ld a, l
72+ ld (de), a
73+ ret
74+
75+console_status:
76+ in a, (STATUS_PORT)
77+ ld l, a
78+ ret
79+
80+handle_call:
81+ ld a, c
82+ or a
83+ jr z, do_exit
84+ dec a
85+ jr z, console_in
86+ dec a
87+ jr z, console_out
88+ dec a
89+ jr z, no_impl ;aux reader input
90+ dec a
91+ jr z, no_impl ;aux punch output
92+ dec a
93+ jr z, no_impl ;printer output
94+ dec a
95+ jr z, no_impl ;direct console IO
96+ dec a
97+ jr z, get_iobyte
98+ dec a
99+ jr z, set_iobyte
100+ dec a
101+ jr z, write_string
102+ dec a
103+ jr z, read_string
104+ dec a
105+ jr z, console_status
106+ jp no_impl
A
fib.s68
+22,
-0
1@@ -0,0 +1,22 @@
2+ dc.l $0, start
3+start:
4+ moveq #42, d0
5+ bsr fib
6+ reset
7+fib:
8+ cmp.l #2, d0
9+ blt base
10+ subq.l #1, d0
11+ move.l d0, -(a7)
12+ bsr fib
13+ move.l (a7), d1
14+ exg d0, d1
15+ move.l d1, (a7)
16+ subq.l #1, d0
17+ bsr fib
18+ move.l (a7)+, d1
19+ add.l d1, d0
20+ rts
21+base:
22+ moveq #1, d0
23+ rts
+1,
-0
1@@ -0,0 +1 @@
2+font.png,16,0,raw,nopal
A
font.xcf
+0,
-0
+1,
-0
1@@ -0,0 +1 @@
2+font_interlace_variable.png,16,0,raw,nopal,interlace
+0,
-0
+553,
-0
1@@ -0,0 +1,553 @@
2+/*
3+ Copyright 2013 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#define GDB_IN_FD STDIN_FILENO
8+#define GDB_OUT_FD STDOUT_FILENO
9+#define GDB_READ read
10+#define GDB_WRITE write
11+
12+#include "gdb_remote.h"
13+#include "68kinst.h"
14+#include "debug.h"
15+#include "util.h"
16+#include <unistd.h>
17+#include <fcntl.h>
18+#include <stddef.h>
19+#include <stdlib.h>
20+#include <stdio.h>
21+#include <string.h>
22+
23+
24+
25+#define INITIAL_BUFFER_SIZE (16*1024)
26+
27+#ifdef DO_DEBUG_PRINT
28+#define dfprintf fprintf
29+#else
30+#define dfprintf
31+#endif
32+
33+char * buf = NULL;
34+char * curbuf = NULL;
35+char * end = NULL;
36+size_t bufsize;
37+int cont = 0;
38+int expect_break_response=0;
39+uint32_t resume_pc;
40+
41+
42+static uint16_t branch_t;
43+static uint16_t branch_f;
44+
45+static bp_def * breakpoints = NULL;
46+static uint32_t bp_index = 0;
47+
48+
49+void hex_32(uint32_t num, char * out)
50+{
51+ for (int32_t shift = 28; shift >= 0; shift -= 4)
52+ {
53+ uint8_t nibble = num >> shift & 0xF;
54+ *(out++) = nibble > 9 ? nibble - 0xA + 'A' : nibble + '0';
55+ }
56+}
57+
58+void hex_16(uint16_t num, char * out)
59+{
60+ for (int16_t shift = 14; shift >= 0; shift -= 4)
61+ {
62+ uint8_t nibble = num >> shift & 0xF;
63+ *(out++) = nibble > 9 ? nibble - 0xA + 'A' : nibble + '0';
64+ }
65+}
66+
67+void hex_8(uint8_t num, char * out)
68+{
69+ uint8_t nibble = num >> 4;
70+ *(out++) = nibble > 9 ? nibble - 0xA + 'A' : nibble + '0';
71+ nibble = num & 0xF;
72+ *out = nibble > 9 ? nibble - 0xA + 'A' : nibble + '0';
73+}
74+
75+void gdb_calc_checksum(char * command, char *out)
76+{
77+ uint8_t checksum = 0;
78+ while (*command)
79+ {
80+ checksum += *(command++);
81+ }
82+ hex_8(checksum, out);
83+}
84+
85+void write_or_die(int fd, const void *buf, size_t count)
86+{
87+ if (GDB_WRITE(fd, buf, count) < count) {
88+ fatal_error("Error writing to stdout\n");
89+ }
90+}
91+
92+void gdb_send_command(char * command)
93+{
94+ char end[3];
95+ write_or_die(GDB_OUT_FD, "$", 1);
96+ write_or_die(GDB_OUT_FD, command, strlen(command));
97+ end[0] = '#';
98+ gdb_calc_checksum(command, end+1);
99+ write_or_die(GDB_OUT_FD, end, 3);
100+ dfprintf(stderr, "Sent $%s#%c%c\n", command, end[1], end[2]);
101+}
102+
103+uint32_t calc_status(m68k_context * context)
104+{
105+ uint32_t status = context->status << 3;
106+ for (int i = 0; i < 5; i++)
107+ {
108+ status <<= 1;
109+ status |= context->flags[i];
110+ }
111+ return status;
112+}
113+
114+void update_status(m68k_context * context, uint16_t value)
115+{
116+ context->status = value >> 8;
117+ for (int i = 4; i >= 0; i--)
118+ {
119+ context->flags[i] = value & 1;
120+ value >>= 1;
121+ }
122+}
123+
124+uint8_t m68k_read_byte(m68k_context * context, uint32_t address)
125+{
126+
127+ genesis_context *gen = context->system;
128+ //TODO: Use generated read/write functions to support access to hardware that is not ROM or RAM
129+ uint16_t * word = get_native_pointer(address & 0xFFFFFFFE, (void **)context->mem_pointers, &context->options->gen);
130+ if (word) {
131+ if (address & 1) {
132+ return *word;
133+ }
134+ return *word >> 8;
135+}
136+ if (address >= 0xA00000 && address < 0xA04000) {
137+ return gen->zram[address & 0x1FFF];
138+ }
139+ return 0;
140+}
141+
142+void m68k_write_byte(m68k_context * context, uint32_t address, uint8_t value)
143+{
144+ genesis_context *gen = context->system;
145+ //TODO: Use generated read/write functions so that memory map is properly respected
146+ uint16_t * word = get_native_pointer(address & 0xFFFFFFFE, (void **)context->mem_pointers, &context->options->gen);
147+ if (word) {
148+ if (address & 1) {
149+ *word = (*word & 0xFF00) | value;
150+ } else {
151+ *word = (*word & 0xFF) | value << 8;
152+ }
153+ //TODO: Deal with this more generally once m68k_handle_code_write can handle it
154+ if (address >= 0xE00000) {
155+ m68k_handle_code_write(address, context);
156+ }
157+ return;
158+ }
159+ if (address >= 0xA00000 && address < 0xA04000) {
160+ gen->zram[address & 0x1FFF] = value;
161+ genesis_context * gen = context->system;
162+ z80_handle_code_write(address & 0x1FFF, gen->z80);
163+ return;
164+ } else {
165+ return;
166+ }
167+}
168+
169+void gdb_run_command(m68k_context * context, uint32_t pc, char * command)
170+{
171+ char send_buf[512];
172+ dfprintf(stderr, "Received command %s\n", command);
173+ switch(*command)
174+ {
175+
176+ case 'c':
177+ if (*(command+1) != 0) {
178+ //TODO: implement resuming at an arbitrary address
179+ goto not_impl;
180+ }
181+ cont = 1;
182+ expect_break_response = 1;
183+ break;
184+ case 's': {
185+ if (*(command+1) != 0) {
186+ //TODO: implement resuming at an arbitrary address
187+ goto not_impl;
188+ }
189+ m68kinst inst;
190+ genesis_context *gen = context->system;
191+ uint16_t * pc_ptr = get_native_pointer(pc, (void **)context->mem_pointers, &context->options->gen);
192+ if (!pc_ptr) {
193+ fatal_error("Entered gdb remote debugger stub at address %X\n", pc);
194+ }
195+ uint16_t * after_pc = m68k_decode(pc_ptr, &inst, pc & 0xFFFFFF);
196+ uint32_t after = pc + (after_pc-pc_ptr)*2;
197+
198+ if (inst.op == M68K_RTS) {
199+ after = (read_dma_value(context->aregs[7]/2) << 16) | read_dma_value(context->aregs[7]/2 + 1);
200+ } else if (inst.op == M68K_RTE || inst.op == M68K_RTR) {
201+ after = (read_dma_value((context->aregs[7]+2)/2) << 16) | read_dma_value((context->aregs[7]+2)/2 + 1);
202+ } else if(m68k_is_branch(&inst)) {
203+ if (inst.op == M68K_BCC && inst.extra.cond != COND_TRUE) {
204+ branch_f = after;
205+ branch_t = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
206+ insert_breakpoint(context, branch_t, gdb_debug_enter);
207+ } else if(inst.op == M68K_DBCC && inst.extra.cond != COND_FALSE) {
208+ branch_t = after;
209+ branch_f = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
210+ insert_breakpoint(context, branch_f, gdb_debug_enter);
211+ } else {
212+ after = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
213+ }
214+ }
215+ insert_breakpoint(context, after, gdb_debug_enter);
216+
217+ cont = 1;
218+ expect_break_response = 1;
219+ break;
220+ }
221+ case 'H':
222+ if (command[1] == 'g' || command[1] == 'c') {;
223+ //no thread suport, just acknowledge
224+ gdb_send_command("OK");
225+ } else {
226+ goto not_impl;
227+ }
228+ break;
229+ case 'Z': {
230+ uint8_t type = command[1];
231+ if (type < '2') {
232+ uint32_t address = strtoul(command+3, NULL, 16);
233+ insert_breakpoint(context, address, gdb_debug_enter);
234+ bp_def *new_bp = malloc(sizeof(bp_def));
235+ new_bp->next = breakpoints;
236+ new_bp->address = address;
237+ new_bp->index = bp_index++;
238+ breakpoints = new_bp;
239+ gdb_send_command("OK");
240+ } else {
241+ //watchpoints are not currently supported
242+ gdb_send_command("");
243+ }
244+ break;
245+ }
246+ case 'z': {
247+ uint8_t type = command[1];
248+ if (type < '2') {
249+ uint32_t address = strtoul(command+3, NULL, 16);
250+ remove_breakpoint(context, address);
251+ bp_def **found = find_breakpoint(&breakpoints, address);
252+ if (*found)
253+ {
254+ bp_def * to_remove = *found;
255+ *found = to_remove->next;
256+ free(to_remove);
257+ }
258+ gdb_send_command("OK");
259+ } else {
260+ //watchpoints are not currently supported
261+ gdb_send_command("");
262+ }
263+ break;
264+ }
265+ case 'g': {
266+ char * cur = send_buf;
267+ for (int i = 0; i < 8; i++)
268+ {
269+ hex_32(context->dregs[i], cur);
270+ cur += 8;
271+ }
272+ for (int i = 0; i < 8; i++)
273+ {
274+ hex_32(context->aregs[i], cur);
275+ cur += 8;
276+ }
277+ hex_32(calc_status(context), cur);
278+ cur += 8;
279+ hex_32(pc, cur);
280+ cur += 8;
281+ *cur = 0;
282+ gdb_send_command(send_buf);
283+ break;
284+ }
285+ case 'm': {
286+ char * rest;
287+ uint32_t address = strtoul(command+1, &rest, 16);
288+ uint32_t size = strtoul(rest+1, NULL, 16);
289+ if (size > (sizeof(send_buf)-1)/2) {
290+ size = (sizeof(send_buf)-1)/2;
291+ }
292+ char *cur = send_buf;
293+ while (size)
294+ {
295+ hex_8(m68k_read_byte(context, address), cur);
296+ cur += 2;
297+ address++;
298+ size--;
299+ }
300+ *cur = 0;
301+ gdb_send_command(send_buf);
302+ break;
303+ }
304+ case 'M': {
305+ char * rest;
306+ uint32_t address = strtoul(command+1, &rest, 16);
307+ uint32_t size = strtoul(rest+1, &rest, 16);
308+
309+ char *cur = rest+1;
310+ while (size)
311+ {
312+ char tmp[3];
313+ tmp[0] = *(cur++);
314+ tmp[1] = *(cur++);
315+ tmp[2] = 0;
316+ m68k_write_byte(context, address, strtoul(tmp, NULL, 16));
317+ address++;
318+ size--;
319+ }
320+ gdb_send_command("OK");
321+ break;
322+ }
323+ case 'X':
324+ //binary transfers aren't supported currently as I don't feel like dealing with the escaping
325+ gdb_send_command("");
326+ break;
327+ case 'p': {
328+ unsigned long reg = strtoul(command+1, NULL, 16);
329+
330+ if (reg < 8) {
331+ hex_32(context->dregs[reg], send_buf);
332+ } else if (reg < 16) {
333+ hex_32(context->aregs[reg-8], send_buf);
334+ } else if (reg == 16) {
335+ hex_32(calc_status(context), send_buf);
336+ } else if (reg == 17) {
337+ hex_32(pc, send_buf);
338+ } else {
339+ send_buf[0] = 0;
340+ }
341+ send_buf[8] = 0;
342+ gdb_send_command(send_buf);
343+ break;
344+ }
345+ case 'P': {
346+ char *after = NULL;
347+ unsigned long reg = strtoul(command+1, &after, 16);
348+ uint32_t value = strtoul(after+1, NULL, 16);
349+
350+ if (reg < 8) {
351+ context->dregs[reg] = value;
352+ } else if (reg < 16) {
353+ context->aregs[reg-8] = value;
354+ } else if (reg == 16) {
355+ update_status(context, value);
356+ } else {
357+ //supporting updates to PC is going to be a pain
358+ gdb_send_command("E01");
359+ break;
360+ }
361+ gdb_send_command("OK");
362+ break;
363+ }
364+ case 'q':
365+ if (!memcmp("Supported", command+1, strlen("Supported"))) {
366+ sprintf(send_buf, "PacketSize=%X", (int)bufsize);
367+ gdb_send_command(send_buf);
368+ } else if (!memcmp("Attached", command+1, strlen("Attached"))) {
369+ //not really meaningful for us, but saying we spawned a new process
370+ //is probably closest to the truth
371+ gdb_send_command("0");
372+ } else if (!memcmp("Offsets", command+1, strlen("Offsets"))) {
373+ //no relocations, so offsets are all 0
374+ gdb_send_command("Text=0;Data=0;Bss=0");
375+ } else if (!memcmp("Symbol", command+1, strlen("Symbol"))) {
376+ gdb_send_command("");
377+ } else if (!memcmp("TStatus", command+1, strlen("TStatus"))) {
378+ //TODO: actual tracepoint support
379+ gdb_send_command("T0;tnotrun:0");
380+ } else if (!memcmp("TfV", command+1, strlen("TfV")) || !memcmp("TfP", command+1, strlen("TfP"))) {
381+ //TODO: actual tracepoint support
382+ gdb_send_command("");
383+ } else if (command[1] == 'C') {
384+ //we only support a single thread currently, so send 1
385+ gdb_send_command("QC1");
386+ } else if (!strcmp("fThreadInfo", command + 1)) {
387+ //we only support a single thread currently, so send 1
388+ gdb_send_command("m1");
389+ } else if (!strcmp("sThreadInfo", command + 1)) {
390+ gdb_send_command("l");
391+ } else {
392+ goto not_impl;
393+ }
394+ break;
395+ case 'v':
396+ if (!memcmp("Cont?", command+1, strlen("Cont?"))) {
397+ gdb_send_command("vCont;c;C;s;S");
398+ } else if (!strcmp("MustReplyEmpty", command + 1)) {
399+ gdb_send_command("");
400+ } else if (!memcmp("Cont;", command+1, strlen("Cont;"))) {
401+ switch (*(command + 1 + strlen("Cont;")))
402+ {
403+ case 'c':
404+ case 'C':
405+ //might be interesting to have continue with signal fire a
406+ //trap exception or something, but for no we'll treat it as
407+ //a normal continue
408+ cont = 1;
409+ expect_break_response = 1;
410+ break;
411+ case 's':
412+ case 'S': {
413+ m68kinst inst;
414+ genesis_context *gen = context->system;
415+ uint16_t * pc_ptr = get_native_pointer(pc, (void **)context->mem_pointers, &context->options->gen);
416+ if (!pc_ptr) {
417+ fatal_error("Entered gdb remote debugger stub at address %X\n", pc);
418+ }
419+ uint16_t * after_pc = m68k_decode(pc_ptr, &inst, pc & 0xFFFFFF);
420+ uint32_t after = pc + (after_pc-pc_ptr)*2;
421+
422+ if (inst.op == M68K_RTS) {
423+ after = (read_dma_value(context->aregs[7]/2) << 16) | read_dma_value(context->aregs[7]/2 + 1);
424+ } else if (inst.op == M68K_RTE || inst.op == M68K_RTR) {
425+ after = (read_dma_value((context->aregs[7]+2)/2) << 16) | read_dma_value((context->aregs[7]+2)/2 + 1);
426+ } else if(m68k_is_branch(&inst)) {
427+ if (inst.op == M68K_BCC && inst.extra.cond != COND_TRUE) {
428+ branch_f = after;
429+ branch_t = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
430+ insert_breakpoint(context, branch_t, gdb_debug_enter);
431+ } else if(inst.op == M68K_DBCC && inst.extra.cond != COND_FALSE) {
432+ branch_t = after;
433+ branch_f = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
434+ insert_breakpoint(context, branch_f, gdb_debug_enter);
435+ } else {
436+ after = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
437+ }
438+ }
439+ insert_breakpoint(context, after, gdb_debug_enter);
440+
441+ cont = 1;
442+ expect_break_response = 1;
443+ break;
444+ }
445+ default:
446+ goto not_impl;
447+ }
448+ } else {
449+ goto not_impl;
450+ }
451+ break;
452+ case '?':
453+ gdb_send_command("S05");
454+ break;
455+ default:
456+ goto not_impl;
457+
458+ }
459+ return;
460+not_impl:
461+ fatal_error("Command %s is not implemented, exiting...\n", command);
462+}
463+
464+void gdb_debug_enter(m68k_context * context, uint32_t pc)
465+{
466+ dfprintf(stderr, "Entered debugger at address %X\n", pc);
467+ if (expect_break_response) {
468+ gdb_send_command("S05");
469+ expect_break_response = 0;
470+ }
471+ if ((pc & 0xFFFFFF) == branch_t) {
472+ bp_def ** f_bp = find_breakpoint(&breakpoints, branch_f);
473+ if (!*f_bp) {
474+ remove_breakpoint(context, branch_f);
475+ }
476+ branch_t = branch_f = 0;
477+ } else if((pc & 0xFFFFFF) == branch_f) {
478+ bp_def ** t_bp = find_breakpoint(&breakpoints, branch_t);
479+ if (!*t_bp) {
480+ remove_breakpoint(context, branch_t);
481+ }
482+ branch_t = branch_f = 0;
483+ }
484+ //Check if this is a user set breakpoint, or just a temporary one
485+ bp_def ** this_bp = find_breakpoint(&breakpoints, pc & 0xFFFFFF);
486+ if (!*this_bp) {
487+ remove_breakpoint(context, pc & 0xFFFFFF);
488+ }
489+ resume_pc = pc;
490+ cont = 0;
491+ uint8_t partial = 0;
492+ while(!cont)
493+ {
494+ if (!curbuf) {
495+ int numread = GDB_READ(GDB_IN_FD, buf, bufsize);
496+ if (numread < 0) {
497+ fatal_error("Failed to read on GDB input file descriptor\n");
498+ }
499+ dfprintf(stderr, "read %d bytes\n", numread);
500+ curbuf = buf;
501+ end = buf + numread;
502+ } else if (partial) {
503+ if (curbuf != buf) {
504+ memmove(curbuf, buf, end-curbuf);
505+ end -= curbuf - buf;
506+ }
507+ int numread = GDB_READ(GDB_IN_FD, end, bufsize - (end-buf));
508+ end += numread;
509+ curbuf = buf;
510+ }
511+ for (; curbuf < end; curbuf++)
512+ {
513+ if (*curbuf == '$')
514+ {
515+ curbuf++;
516+ char * start = curbuf;
517+ while (curbuf < end && *curbuf != '#') {
518+ curbuf++;
519+ }
520+ if (*curbuf == '#') {
521+ //check to make sure we've received the checksum bytes
522+ if (end-curbuf >= 2) {
523+ //TODO: verify checksum
524+ //Null terminate payload
525+ *curbuf = 0;
526+ //send acknowledgement
527+ if (GDB_WRITE(GDB_OUT_FD, "+", 1) < 1) {
528+ fatal_error("Error writing to stdout\n");
529+ }
530+ gdb_run_command(context, pc, start);
531+ curbuf += 2;
532+ }
533+ } else {
534+ curbuf--;
535+ partial = 1;
536+ break;
537+ }
538+ } else {
539+ dfprintf(stderr, "Ignoring character %c\n", *curbuf);
540+ }
541+ }
542+ if (curbuf == end) {
543+ curbuf = NULL;
544+ }
545+ }
546+}
547+
548+void gdb_remote_init(void)
549+{
550+ buf = malloc(INITIAL_BUFFER_SIZE);
551+ curbuf = NULL;
552+ bufsize = INITIAL_BUFFER_SIZE;
553+ disable_stdout_messages();
554+}
+8,
-0
1@@ -0,0 +1,8 @@
2+#ifndef GDB_REMOTE_H_
3+#define GDB_REMOTE_H_
4+#include "genesis.h"
5+
6+void gdb_remote_init(void);
7+void gdb_debug_enter(m68k_context * context, uint32_t pc);
8+
9+#endif //GDB_REMOTE_H_
A
gen.c
+16,
-0
1@@ -0,0 +1,16 @@
2+#include <stdio.h>
3+#include <stdlib.h>
4+#include "gen.h"
5+#include "mem.h"
6+#include "util.h"
7+
8+void init_code_info(code_info *code)
9+{
10+ size_t size = CODE_ALLOC_SIZE;
11+ code->cur = alloc_code(&size);
12+ if (!code->cur) {
13+ fatal_error("Failed to allocate memory for generated code\n");
14+ }
15+ code->last = code->cur + size/sizeof(code_word) - RESERVE_WORDS;
16+ code->stack_off = 0;
17+}
A
gen.h
+47,
-0
1@@ -0,0 +1,47 @@
2+#ifndef GEN_H_
3+#define GEN_H_
4+#include <stdint.h>
5+
6+#if defined(__x86_64__)
7+#define X86_64
8+#elif defined(__i386__)
9+#define X86_32
10+#else
11+#error "The Wayland build requires an x86 host"
12+#endif
13+
14+#if defined(X86_64) || defined(X86_32)
15+typedef uint8_t code_word;
16+#define RESERVE_WORDS 5 //opcode + 4-byte displacement
17+#else
18+typedef uint32_t code_word;
19+#define RESERVE_WORDS 4 //1 push + 1 ldr + 1bx + 1 constant
20+#endif
21+typedef code_word * code_ptr;
22+#define CODE_ALLOC_SIZE (1024*1024)
23+
24+typedef struct {
25+ code_ptr cur;
26+ code_ptr last;
27+ uint32_t stack_off;
28+} code_info;
29+
30+void check_alloc_code(code_info *code, uint32_t inst_size);
31+
32+void init_code_info(code_info *code);
33+void call(code_info *code, code_ptr fun);
34+void jmp(code_info *code, code_ptr dest);
35+void jmp_r(code_info *code, uint8_t dst);
36+//standard return from subroutine instruction
37+void rts(code_info *code);
38+//call a function and put the arguments in the appropriate place according to the host ABI
39+void call_args(code_info *code, code_ptr fun, uint32_t num_args, ...);
40+//like the above, but call a function pointer stored in a register
41+void call_args_r(code_info *code, uint8_t fun_reg, uint32_t num_args, ...);
42+//like the above, but follows other aspects of the ABI like stack alignment
43+//void call_args_abi(code_info *code, code_ptr fun, uint32_t num_args, ...);
44+#define call_args_abi call_args
45+void save_callee_save_regs(code_info *code);
46+void restore_callee_save_regs(code_info *code);
47+
48+#endif //GEN_H_
+585,
-0
1@@ -0,0 +1,585 @@
2+/*
3+ Copyright 2014 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#include "gen_arm.h"
8+#include "mem.h"
9+#include <stdio.h>
10+#include <stdlib.h>
11+
12+#define OP_FIELD_SHIFT 21u
13+
14+//Data processing format instructions
15+#define OP_AND 0x0u
16+#define OP_EOR (0x1u << OP_FIELD_SHIFT)
17+#define OP_SUB (0x2u << OP_FIELD_SHIFT)
18+#define OP_RSB (0x3u << OP_FIELD_SHIFT)
19+#define OP_ADD (0x4u << OP_FIELD_SHIFT)
20+#define OP_ADC (0x5u << OP_FIELD_SHIFT)
21+#define OP_SBC (0x6u << OP_FIELD_SHIFT)
22+#define OP_RSC (0x7u << OP_FIELD_SHIFT)
23+#define OP_TST (0x8u << OP_FIELD_SHIFT)
24+#define OP_TEQ (0x9u << OP_FIELD_SHIFT)
25+#define OP_CMP (0xAu << OP_FIELD_SHIFT)
26+#define OP_CMN (0xBu << OP_FIELD_SHIFT)
27+#define OP_ORR (0xCu << OP_FIELD_SHIFT)
28+#define OP_MOV (0xDu << OP_FIELD_SHIFT)
29+#define OP_BIC (0xEu << OP_FIELD_SHIFT)
30+#define OP_MVN (0xFu << OP_FIELD_SHIFT)
31+
32+//branch instructions
33+#define OP_B 0xA000000u
34+#define OP_BL 0xB000000u
35+#define OP_BX 0x12FFF10u
36+
37+//load/store
38+#define OP_STR 0x4000000u
39+#define OP_LDR 0x4100000u
40+#define OP_STM 0x8000000u
41+#define OP_LDM 0x8100000u
42+#define POST_IND 0u
43+#define PRE_IND 0x1000000u
44+#define DIR_DOWN 0u
45+#define DIR_UP 0x0800000u
46+#define SZ_W 0u
47+#define SZ_B 0x0400000u
48+#define WRITE_B 0x0200000u
49+#define OFF_IMM 0u
50+#define OFF_REG 0x2000000u
51+
52+#define PUSH (OP_STR | PRE_IND | OFF_IMM | SZ_W | WRITE_B | DIR_DOWN | sizeof(uint32_t) | (sp << 16))
53+#define POP (OP_LDR | POST_IND | OFF_IMM | SZ_W | DIR_UP | sizeof(uint32_t) | (sp << 16))
54+#define PUSHM (OP_STM | PRE_IND | SZ_W | WRITE_B | DIR_DOWN | (sp << 16))
55+#define POPM (OP_LDM | POST_IND | SZ_W | WRITE_B | DIR_UP | (sp << 16))
56+
57+#define IMMED 0x2000000u
58+#define REG 0u
59+
60+
61+uint32_t make_immed(uint32_t val)
62+{
63+ uint32_t rot_amount = 0;
64+ for (; rot_amount < 0x20; rot_amount += 2)
65+ {
66+ uint32_t test_mask = ~(0xFF << rot_amount | 0xFF >> (32-rot_amount));
67+ if (!(test_mask & val)) {
68+ return val << rot_amount | val >> (32-rot_amount) | rot_amount << 7;
69+ }
70+ }
71+ return INVALID_IMMED;
72+}
73+
74+void check_alloc_code(code_info *code)
75+{
76+ if (code->cur == code->last) {
77+ size_t size = CODE_ALLOC_SIZE;
78+ uint32_t *next_code = alloc_code(&size);
79+ if (!next_code) {
80+ fatal_error("Failed to allocate memory for generated code\n");
81+ }
82+ if (next_code = code->last + RESERVE_WORDS) {
83+ //new chunk is contiguous with the current one
84+ code->last = next_code + size/sizeof(code_word) - RESERVE_WORDS;
85+ } else {
86+ uint32_t * from = code->cur + 2;
87+ if (next_code - from < 0x400000 || from - next_code <= 0x400000) {
88+ *from = CC_AL | OP_B | ((next_code - from) & 0xFFFFFF);
89+ } else {
90+ //push r0 onto the stack
91+ *(from++) = CC_AL | PUSH;
92+ uint32_t immed = make_immed((uint32_t)next_code);
93+ if (immed == INVALID_IMMED) {
94+ //Load target into r0 from word after next instruction into register 0
95+ *(from++) = CC_AL | OP_LDR | OFF_IMM | DIR_DOWN | PRE_IND | SZ_W | (pc << 16) | 4;
96+ from[1] = (uint32_t)next_code;
97+ } else {
98+ //Load target into r0
99+ *(from++) = CC_AL | OP_MOV | IMMED | NO_COND | immed;
100+ }
101+ //branch to address in r0
102+ *from = CC_AL | OP_BX;
103+ code->last = next_code + size/sizeof(code_word) - RESERVE_WORDS;
104+ //pop r0
105+ *(next_code++) = CC_AL | POP;
106+ code->cur = next_code;
107+ }
108+ }
109+ }
110+}
111+
112+uint32_t data_proc(code_info *code, uint32_t cond, uint32_t op, uint32_t set_cond, uint32_t dst, uint32_t src1, uint32_t src2)
113+{
114+ check_alloc_code(code);
115+ *(code->cur++) = cond | op | set_cond | (src1 << 16) | (dst << 12) | src2;
116+
117+ return CODE_OK;
118+}
119+
120+uint32_t data_proci(code_info *code, uint32_t cond, uint32_t op, uint32_t set_cond, uint32_t dst, uint32_t src1, uint32_t immed)
121+{
122+ immed = make_immed(immed);
123+ if (immed == INVALID_IMMED) {
124+ return immed;
125+ }
126+ return data_proc(code, cond, op | IMMED, set_cond, dst, src1, immed);
127+}
128+
129+//TODO: support shifted register for op2
130+
131+uint32_t and(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond)
132+{
133+ return data_proc(code, CC_AL, OP_AND, set_cond, dst, src1, src2);
134+}
135+
136+uint32_t andi(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond)
137+{
138+ return data_proci(code, CC_AL, OP_AND, set_cond, dst, src1, immed);
139+}
140+
141+uint32_t and_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond)
142+{
143+ return data_proc(code, cc, OP_AND, set_cond, dst, src1, src2);
144+}
145+
146+uint32_t andi_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond)
147+{
148+ return data_proci(code, cc, OP_AND, set_cond, dst, src1, immed);
149+}
150+
151+uint32_t eor(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond)
152+{
153+ return data_proc(code, CC_AL, OP_EOR, set_cond, dst, src1, src2);
154+}
155+
156+uint32_t eori(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond)
157+{
158+ return data_proci(code, CC_AL, OP_EOR, set_cond, dst, src1, immed);
159+}
160+
161+uint32_t eor_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond)
162+{
163+ return data_proc(code, cc, OP_EOR, set_cond, dst, src1, src2);
164+}
165+
166+uint32_t eori_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond)
167+{
168+ return data_proci(code, cc, OP_EOR, set_cond, dst, src1, immed);
169+}
170+
171+uint32_t sub(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond)
172+{
173+ return data_proc(code, CC_AL, OP_SUB, set_cond, dst, src1, src2);
174+}
175+
176+uint32_t subi(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond)
177+{
178+ return data_proci(code, CC_AL, OP_SUB, set_cond, dst, src1, immed);
179+}
180+
181+uint32_t sub_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond)
182+{
183+ return data_proc(code, cc, OP_SUB, set_cond, dst, src1, src2);
184+}
185+
186+uint32_t subi_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond)
187+{
188+ return data_proci(code, cc, OP_SUB, set_cond, dst, src1, immed);
189+}
190+
191+uint32_t rsb(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond)
192+{
193+ return data_proc(code, CC_AL, OP_RSB, set_cond, dst, src1, src2);
194+}
195+
196+uint32_t rsbi(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond)
197+{
198+ return data_proci(code, CC_AL, OP_RSB, set_cond, dst, src1, immed);
199+}
200+
201+uint32_t rsb_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond)
202+{
203+ return data_proc(code, cc, OP_RSB, set_cond, dst, src1, src2);
204+}
205+
206+uint32_t rsbi_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond)
207+{
208+ return data_proci(code, cc, OP_RSB, set_cond, dst, src1, immed);
209+}
210+
211+uint32_t add(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond)
212+{
213+ return data_proc(code, CC_AL, OP_ADD, set_cond, dst, src1, src2);
214+}
215+
216+uint32_t addi(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond)
217+{
218+ return data_proci(code, CC_AL, OP_ADD, set_cond, dst, src1, immed);
219+}
220+
221+uint32_t add_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond)
222+{
223+ return data_proc(code, cc, OP_ADD, set_cond, dst, src1, src2);
224+}
225+
226+uint32_t addi_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond)
227+{
228+ return data_proci(code, cc, OP_ADD, set_cond, dst, src1, immed);
229+}
230+
231+uint32_t adc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond)
232+{
233+ return data_proc(code, CC_AL, OP_ADC, set_cond, dst, src1, src2);
234+}
235+
236+uint32_t adci(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond)
237+{
238+ return data_proci(code, CC_AL, OP_ADC, set_cond, dst, src1, immed);
239+}
240+
241+uint32_t adc_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond)
242+{
243+ return data_proc(code, cc, OP_ADC, set_cond, dst, src1, src2);
244+}
245+
246+uint32_t adci_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond)
247+{
248+ return data_proci(code, cc, OP_ADC, set_cond, dst, src1, immed);
249+}
250+
251+uint32_t sbc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond)
252+{
253+ return data_proc(code, CC_AL, OP_SBC, set_cond, dst, src1, src2);
254+}
255+
256+uint32_t sbci(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond)
257+{
258+ return data_proci(code, CC_AL, OP_SBC, set_cond, dst, src1, immed);
259+}
260+
261+uint32_t sbc_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond)
262+{
263+ return data_proc(code, cc, OP_SBC, set_cond, dst, src1, src2);
264+}
265+
266+uint32_t sbci_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond)
267+{
268+ return data_proci(code, cc, OP_SBC, set_cond, dst, src1, immed);
269+}
270+
271+uint32_t rsc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond)
272+{
273+ return data_proc(code, CC_AL, OP_RSC, set_cond, dst, src1, src2);
274+}
275+
276+uint32_t rsci(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond)
277+{
278+ return data_proci(code, CC_AL, OP_RSC, set_cond, dst, src1, immed);
279+}
280+
281+uint32_t rsc_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond)
282+{
283+ return data_proc(code, cc, OP_RSC, set_cond, dst, src1, src2);
284+}
285+
286+uint32_t rsci_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond)
287+{
288+ return data_proci(code, cc, OP_RSC, set_cond, dst, src1, immed);
289+}
290+
291+uint32_t tst(code_info *code, uint32_t src1, uint32_t src2)
292+{
293+ return data_proc(code, CC_AL, OP_TST, SET_COND, r0, src1, src2);
294+}
295+
296+uint32_t tsti(code_info *code, uint32_t src1, uint32_t immed)
297+{
298+ return data_proci(code, CC_AL, OP_TST, SET_COND, r0, src1, immed);
299+}
300+
301+uint32_t tst_cc(code_info *code, uint32_t src1, uint32_t src2, uint32_t cc)
302+{
303+ return data_proc(code, cc, OP_TST, SET_COND, r0, src1, src2);
304+}
305+
306+uint32_t tsti_cc(code_info *code, uint32_t src1, uint32_t immed, uint32_t cc)
307+{
308+ return data_proci(code, cc, OP_TST, SET_COND, r0, src1, immed);
309+}
310+
311+uint32_t teq(code_info *code, uint32_t src1, uint32_t src2)
312+{
313+ return data_proc(code, CC_AL, OP_TEQ, SET_COND, r0, src1, src2);
314+}
315+
316+uint32_t teqi(code_info *code, uint32_t src1, uint32_t immed)
317+{
318+ return data_proci(code, CC_AL, OP_TEQ, SET_COND, r0, src1, immed);
319+}
320+
321+uint32_t teq_cc(code_info *code, uint32_t src1, uint32_t src2, uint32_t cc)
322+{
323+ return data_proc(code, cc, OP_TEQ, SET_COND, r0, src1, src2);
324+}
325+
326+uint32_t teqi_cc(code_info *code, uint32_t src1, uint32_t immed, uint32_t cc)
327+{
328+ return data_proci(code, cc, OP_TEQ, SET_COND, r0, src1, immed);
329+}
330+
331+uint32_t cmp(code_info *code, uint32_t src1, uint32_t src2)
332+{
333+ return data_proc(code, CC_AL, OP_CMP, SET_COND, r0, src1, src2);
334+}
335+
336+uint32_t cmpi(code_info *code, uint32_t src1, uint32_t immed)
337+{
338+ return data_proci(code, CC_AL, OP_CMP, SET_COND, r0, src1, immed);
339+}
340+
341+uint32_t cmp_cc(code_info *code, uint32_t src1, uint32_t src2, uint32_t cc)
342+{
343+ return data_proc(code, cc, OP_CMP, SET_COND, r0, src1, src2);
344+}
345+
346+uint32_t cmpi_cc(code_info *code, uint32_t src1, uint32_t immed, uint32_t cc)
347+{
348+ return data_proci(code, cc, OP_CMP, SET_COND, r0, src1, immed);
349+}
350+
351+uint32_t cmn(code_info *code, uint32_t src1, uint32_t src2)
352+{
353+ return data_proc(code, CC_AL, OP_CMN, SET_COND, r0, src1, src2);
354+}
355+
356+uint32_t cmni(code_info *code, uint32_t src1, uint32_t immed)
357+{
358+ return data_proci(code, CC_AL, OP_CMN, SET_COND, r0, src1, immed);
359+}
360+
361+uint32_t cmn_cc(code_info *code, uint32_t src1, uint32_t src2, uint32_t cc)
362+{
363+ return data_proc(code, cc, OP_CMN, SET_COND, r0, src1, src2);
364+}
365+
366+uint32_t cmni_cc(code_info *code, uint32_t src1, uint32_t immed, uint32_t cc)
367+{
368+ return data_proci(code, cc, OP_CMN, SET_COND, r0, src1, immed);
369+}
370+
371+uint32_t orr(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond)
372+{
373+ return data_proc(code, CC_AL, OP_ORR, set_cond, dst, src1, src2);
374+}
375+
376+uint32_t orri(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond)
377+{
378+ return data_proci(code, CC_AL, OP_ORR, set_cond, dst, src1, immed);
379+}
380+
381+uint32_t orr_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond)
382+{
383+ return data_proc(code, cc, OP_ORR, set_cond, dst, src1, src2);
384+}
385+
386+uint32_t orri_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond)
387+{
388+ return data_proci(code, cc, OP_ORR, set_cond, dst, src1, immed);
389+}
390+
391+uint32_t mov(code_info *code, uint32_t dst, uint32_t src2, uint32_t set_cond)
392+{
393+ return data_proc(code, CC_AL, OP_MOV, set_cond, dst, 0, src2);
394+}
395+
396+uint32_t movi(code_info *code, uint32_t dst, uint32_t immed, uint32_t set_cond)
397+{
398+ return data_proci(code, CC_AL, OP_MOV, set_cond, dst, 0, immed);
399+}
400+
401+uint32_t mov_cc(code_info *code, uint32_t dst, uint32_t src2, uint32_t cc, uint32_t set_cond)
402+{
403+ return data_proc(code, cc, OP_MOV, set_cond, dst, 0, src2);
404+}
405+
406+uint32_t movi_cc(code_info *code, uint32_t dst, uint32_t immed, uint32_t cc, uint32_t set_cond)
407+{
408+ return data_proci(code, cc, OP_MOV, set_cond, dst, 0, immed);
409+}
410+
411+uint32_t bic(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond)
412+{
413+ return data_proc(code, CC_AL, OP_BIC, set_cond, dst, src1, src2);
414+}
415+
416+uint32_t bici(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond)
417+{
418+ return data_proci(code, CC_AL, OP_BIC, set_cond, dst, src1, immed);
419+}
420+
421+uint32_t bic_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond)
422+{
423+ return data_proc(code, cc, OP_BIC, set_cond, dst, src1, src2);
424+}
425+
426+uint32_t bici_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond)
427+{
428+ return data_proci(code, cc, OP_BIC, set_cond, dst, src1, immed);
429+}
430+
431+uint32_t mvn(code_info *code, uint32_t dst, uint32_t src2, uint32_t set_cond)
432+{
433+ return data_proc(code, CC_AL, OP_MVN, set_cond, dst, 0, src2);
434+}
435+
436+uint32_t mvni(code_info *code, uint32_t dst, uint32_t immed, uint32_t set_cond)
437+{
438+ return data_proci(code, CC_AL, OP_MVN, set_cond, dst, 0, immed);
439+}
440+
441+uint32_t mvn_cc(code_info *code, uint32_t dst, uint32_t src2, uint32_t cc, uint32_t set_cond)
442+{
443+ return data_proc(code, cc, OP_MVN, set_cond, dst, 0, src2);
444+}
445+
446+uint32_t mvni_cc(code_info *code, uint32_t dst, uint32_t immed, uint32_t cc, uint32_t set_cond)
447+{
448+ return data_proci(code, cc, OP_MVN, set_cond, dst, 0, immed);
449+}
450+
451+uint32_t branchi(code_info *code, uint32_t cc, uint32_t op, uint32_t *dst)
452+{
453+ uint32_t * from = code->cur + 2;
454+ if (dst - from >= 0x400000 && from - dst > 0x400000) {
455+ return INVALID_IMMED;
456+ }
457+ check_alloc_code(code);
458+ *(code->cur++) = cc | op | ((dst - from) & 0xFFFFFF);
459+ return CODE_OK;
460+}
461+
462+uint32_t b(code_info *code, uint32_t *dst)
463+{
464+ return branchi(code, CC_AL, OP_B, dst);
465+}
466+
467+uint32_t b_cc(code_info *code, uint32_t *dst, uint32_t cc)
468+{
469+ return branchi(code, cc, OP_B, dst);
470+}
471+
472+uint32_t bl(code_info *code, uint32_t *dst)
473+{
474+ return branchi(code, CC_AL, OP_BL, dst);
475+}
476+
477+uint32_t bl_cc(code_info *code, uint32_t *dst, uint32_t cc)
478+{
479+ return branchi(code, cc, OP_BL, dst);
480+}
481+
482+uint32_t bx(code_info *code, uint32_t dst)
483+{
484+ check_alloc_code(code);
485+ *(code->cur++) = CC_AL | OP_BX | dst;
486+ return CODE_OK;
487+}
488+
489+uint32_t bx_cc(code_info *code, uint32_t dst, uint32_t cc)
490+{
491+ check_alloc_code(code);
492+ *(code->cur++) = cc | OP_BX | dst;
493+ return CODE_OK;
494+}
495+
496+uint32_t push(code_info *code, uint32_t reg)
497+{
498+ check_alloc_code(code);
499+ *(code->cur++) = CC_AL | PUSH | reg << 12;
500+ return CODE_OK;
501+}
502+
503+uint32_t push_cc(code_info *code, uint32_t reg, uint32_t cc)
504+{
505+ check_alloc_code(code);
506+ *(code->cur++) = cc | PUSH | reg << 12;
507+ return CODE_OK;
508+}
509+
510+uint32_t pushm(code_info *code, uint32_t reglist)
511+{
512+ check_alloc_code(code);
513+ *(code->cur++) = CC_AL | PUSHM | reglist;
514+ return CODE_OK;
515+}
516+
517+uint32_t pushm_cc(code_info *code, uint32_t reglist, uint32_t cc)
518+{
519+ check_alloc_code(code);
520+ *(code->cur++) = cc | PUSHM | reglist;
521+ return CODE_OK;
522+}
523+
524+uint32_t pop(code_info *code, uint32_t reg)
525+{
526+ check_alloc_code(code);
527+ *(code->cur++) = CC_AL | POP | reg << 12;
528+ return CODE_OK;
529+}
530+
531+uint32_t pop_cc(code_info *code, uint32_t reg, uint32_t cc)
532+{
533+ check_alloc_code(code);
534+ *(code->cur++) = cc | POP | reg << 12;
535+ return CODE_OK;
536+}
537+
538+uint32_t popm(code_info *code, uint32_t reglist)
539+{
540+ check_alloc_code(code);
541+ *(code->cur++) = CC_AL | POPM | reglist;
542+ return CODE_OK;
543+}
544+
545+uint32_t popm_cc(code_info *code, uint32_t reglist, uint32_t cc)
546+{
547+ check_alloc_code(code);
548+ *(code->cur++) = cc | POPM | reglist;
549+ return CODE_OK;
550+}
551+
552+uint32_t load_store_immoff(code_info *code, uint32_t op, uint32_t dst, uint32_t base, int32_t offset, uint32_t cc)
553+{
554+ if (offset >= 0x1000 || offset <= -0x1000) {
555+ return INVALID_IMMED;
556+ }
557+ check_alloc_code(code);
558+ uint32_t instruction = cc | op | POST_IND | OFF_IMM | SZ_W | base << 16 | dst << 12;
559+ if (offset >= 0) {
560+ instruction |= offset | DIR_UP;
561+ } else {
562+ instruction |= (-offset) | DIR_DOWN;
563+ }
564+ *(code->cur++) = instruction;
565+ return CODE_OK;
566+}
567+
568+uint32_t ldr_cc(code_info *code, uint32_t dst, uint32_t base, int32_t offset, uint32_t cc)
569+{
570+ return load_store_immoff(code, OP_LDR, dst, base, offset, cc);
571+}
572+
573+uint32_t ldr(code_info *code, uint32_t dst, uint32_t base, int32_t offset)
574+{
575+ return ldr_cc(code, dst, base, offset, CC_AL);
576+}
577+
578+uint32_t str_cc(code_info *code, uint32_t src, uint32_t base, int32_t offset, uint32_t cc)
579+{
580+ return load_store_immoff(code, OP_STR, src, base, offset, cc);
581+}
582+
583+uint32_t str(code_info *code, uint32_t src, uint32_t base, int32_t offset)
584+{
585+ return str_cc(code, src, base, offset, CC_AL);
586+}
+157,
-0
1@@ -0,0 +1,157 @@
2+/*
3+ Copyright 2014 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#ifndef GEN_ARM_H_
8+#define GEN_ARM_H_
9+
10+#include <stdint.h>
11+#include "gen.h"
12+
13+#define SET_COND 0x100000u
14+#define NO_COND 0u
15+
16+#define CC_FIELD_SHIFT 28
17+
18+#define CC_EQ 0x0u
19+#define CC_NE (0x1u << CC_FIELD_SHIFT)
20+#define CC_CS (0x2u << CC_FIELD_SHIFT)
21+#define CC_CC (0x3u << CC_FIELD_SHIFT)
22+#define CC_MI (0x4u << CC_FIELD_SHIFT)
23+#define CC_PL (0x5u << CC_FIELD_SHIFT)
24+#define CC_VS (0x6u << CC_FIELD_SHIFT)
25+#define CC_VC (0x7u << CC_FIELD_SHIFT)
26+#define CC_HI (0x8u << CC_FIELD_SHIFT)
27+#define CC_LS (0x9u << CC_FIELD_SHIFT)
28+#define CC_GE (0xAu << CC_FIELD_SHIFT)
29+#define CC_LT (0xBu << CC_FIELD_SHIFT)
30+#define CC_GT (0xCu << CC_FIELD_SHIFT)
31+#define CC_LE (0xDu << CC_FIELD_SHIFT)
32+#define CC_AL (0xEu << CC_FIELD_SHIFT)
33+
34+#define INVALID_IMMED 0xFFFFFFFFu
35+#define CODE_OK 0u
36+
37+enum {
38+ r0,
39+ r1,
40+ r2,
41+ r3,
42+ r4,
43+ r5,
44+ r6,
45+ r7,
46+ r8,
47+ r9,
48+ r10,
49+ r11,
50+ r12,
51+ sp,
52+ lr,
53+ pc
54+};
55+
56+#define R0 0x1
57+#define R1 0x2
58+#define R2 0x4
59+#define R3 0x8
60+#define R4 0x10
61+#define R5 0x20
62+#define R6 0x40
63+#define R7 0x80
64+#define R8 0x100
65+#define R9 0x200
66+#define R10 0x400
67+#define R11 0x800
68+#define R12 0x1000
69+#define SP 0x2000
70+#define LR 0x4000
71+#define PC 0x8000
72+
73+uint32_t and(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond);
74+uint32_t andi(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond);
75+uint32_t and_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond);
76+uint32_t andi_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond);
77+uint32_t eor(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond);
78+uint32_t eori(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond);
79+uint32_t eor_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond);
80+uint32_t eori_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond);
81+uint32_t sub(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond);
82+uint32_t subi(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond);
83+uint32_t sub_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond);
84+uint32_t subi_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond);
85+uint32_t rsb(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond);
86+uint32_t rsbi(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond);
87+uint32_t rsb_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond);
88+uint32_t rsbi_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond);
89+uint32_t add(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond);
90+uint32_t addi(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond);
91+uint32_t add_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond);
92+uint32_t addi_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond);
93+uint32_t adc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond);
94+uint32_t adci(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond);
95+uint32_t adc_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond);
96+uint32_t adci_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond);
97+uint32_t sbc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond);
98+uint32_t sbci(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond);
99+uint32_t sbc_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond);
100+uint32_t sbci_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond);
101+uint32_t rsc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond);
102+uint32_t rsci(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond);
103+uint32_t rsc_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond);
104+uint32_t rsci_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond);
105+uint32_t tst(code_info *code, uint32_t src1, uint32_t src2);
106+uint32_t tsti(code_info *code, uint32_t src1, uint32_t immed);
107+uint32_t tst_cc(code_info *code, uint32_t src1, uint32_t src2, uint32_t cc);
108+uint32_t tsti_cc(code_info *code, uint32_t src1, uint32_t immed, uint32_t cc);
109+uint32_t teq(code_info *code, uint32_t src1, uint32_t src2);
110+uint32_t teqi(code_info *code, uint32_t src1, uint32_t immed);
111+uint32_t teq_cc(code_info *code, uint32_t src1, uint32_t src2, uint32_t cc);
112+uint32_t teqi_cc(code_info *code, uint32_t src1, uint32_t immed, uint32_t cc);
113+uint32_t cmp(code_info *code, uint32_t src1, uint32_t src2);
114+uint32_t cmpi(code_info *code, uint32_t src1, uint32_t immed);
115+uint32_t cmp_cc(code_info *code, uint32_t src1, uint32_t src2, uint32_t cc);
116+uint32_t cmpi_cc(code_info *code, uint32_t src1, uint32_t immed, uint32_t cc);
117+uint32_t cmn(code_info *code, uint32_t src1, uint32_t src2);
118+uint32_t cmni(code_info *code, uint32_t src1, uint32_t immed);
119+uint32_t cmn_cc(code_info *code, uint32_t src1, uint32_t src2, uint32_t cc);
120+uint32_t cmni_cc(code_info *code, uint32_t src1, uint32_t immed, uint32_t cc);
121+uint32_t orr(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond);
122+uint32_t orri(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond);
123+uint32_t orr_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond);
124+uint32_t orri_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond);
125+uint32_t mov(code_info *code, uint32_t dst, uint32_t src2, uint32_t set_cond);
126+uint32_t movi(code_info *code, uint32_t dst, uint32_t immed, uint32_t set_cond);
127+uint32_t mov_cc(code_info *code, uint32_t dst, uint32_t src2, uint32_t cc, uint32_t set_cond);
128+uint32_t movi_cc(code_info *code, uint32_t dst, uint32_t immed, uint32_t cc, uint32_t set_cond);
129+uint32_t bic(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond);
130+uint32_t bici(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond);
131+uint32_t bic_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond);
132+uint32_t bici_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond);
133+uint32_t mvn(code_info *code, uint32_t dst, uint32_t src2, uint32_t set_cond);
134+uint32_t mvni(code_info *code, uint32_t dst, uint32_t immed, uint32_t set_cond);
135+uint32_t mvn_cc(code_info *code, uint32_t dst, uint32_t src2, uint32_t cc, uint32_t set_cond);
136+uint32_t mvni_cc(code_info *code, uint32_t dst, uint32_t immed, uint32_t cc, uint32_t set_cond);
137+
138+uint32_t b(code_info *code, uint32_t *dst);
139+uint32_t b_cc(code_info *code, uint32_t *dst, uint32_t cc);
140+uint32_t bl(code_info *code, uint32_t *dst);
141+uint32_t bl_cc(code_info *code, uint32_t *dst, uint32_t cc);
142+uint32_t bx(code_info *code, uint32_t dst);
143+uint32_t bx_cc(code_info *code, uint32_t dst, uint32_t cc);
144+
145+uint32_t push(code_info *code, uint32_t reg);
146+uint32_t push_cc(code_info *code, uint32_t reg, uint32_t cc);
147+uint32_t pushm(code_info *code, uint32_t reglist);
148+uint32_t pushm_cc(code_info *code, uint32_t reglist, uint32_t cc);
149+uint32_t pop(code_info *code, uint32_t reg);
150+uint32_t pop_cc(code_info *code, uint32_t reg, uint32_t cc);
151+uint32_t popm(code_info *code, uint32_t reglist);
152+uint32_t popm_cc(code_info *code, uint32_t reglist, uint32_t cc);
153+uint32_t ldr_cc(code_info *code, uint32_t dst, uint32_t base, int32_t offset, uint32_t cc);
154+uint32_t ldr(code_info *code, uint32_t rst, uint32_t base, int32_t offset);
155+uint32_t str_cc(code_info *code, uint32_t src, uint32_t base, int32_t offset, uint32_t cc);
156+uint32_t str(code_info *code, uint32_t src, uint32_t base, int32_t offset);
157+
158+#endif //GEN_ARM_H_
+631,
-0
1@@ -0,0 +1,631 @@
2+ dc.l $0, start
3+ dc.l empty_handler
4+ dc.l empty_handler
5+ ;$10
6+ dc.l empty_handler
7+ dc.l empty_handler
8+ dc.l empty_handler
9+ dc.l empty_handler
10+ ;$20
11+ dc.l empty_handler
12+ dc.l empty_handler
13+ dc.l empty_handler
14+ dc.l empty_handler
15+ ;$30
16+ dc.l empty_handler
17+ dc.l empty_handler
18+ dc.l empty_handler
19+ dc.l empty_handler
20+ ;$40
21+ dc.l empty_handler
22+ dc.l empty_handler
23+ dc.l empty_handler
24+ dc.l empty_handler
25+ ;$50
26+ dc.l empty_handler
27+ dc.l empty_handler
28+ dc.l empty_handler
29+ dc.l empty_handler
30+ ;$60
31+ dc.l empty_handler
32+ dc.l empty_handler
33+ dc.l empty_handler
34+ dc.l empty_handler
35+ ;$70
36+ dc.l int_4
37+ dc.l empty_handler
38+ dc.l int_6
39+ dc.l empty_handler
40+ ;$80
41+ dc.l empty_handler
42+ dc.l empty_handler
43+ dc.l empty_handler
44+ dc.l empty_handler
45+ ;$90
46+ dc.l empty_handler
47+ dc.l empty_handler
48+ dc.l empty_handler
49+ dc.l empty_handler
50+ ;$A0
51+ dc.l empty_handler
52+ dc.l empty_handler
53+ dc.l empty_handler
54+ dc.l empty_handler
55+ ;$B0
56+ dc.l empty_handler
57+ dc.l empty_handler
58+ dc.l empty_handler
59+ dc.l empty_handler
60+ ;$C0
61+ dc.l empty_handler
62+ dc.l empty_handler
63+ dc.l empty_handler
64+ dc.l empty_handler
65+ ;$D0
66+ dc.l empty_handler
67+ dc.l empty_handler
68+ dc.l empty_handler
69+ dc.l empty_handler
70+ ;$E0
71+ dc.l empty_handler
72+ dc.l empty_handler
73+ dc.l empty_handler
74+ dc.l empty_handler
75+ ;$F0
76+ dc.l empty_handler
77+ dc.l empty_handler
78+ dc.l empty_handler
79+ dc.l empty_handler
80+ dc.b "SEGA"
81+empty_handler:
82+int_6:
83+ rte
84+int_4:
85+ move.w (a2), d0
86+ ori.w #$8000, d0
87+ move.w d0, (a4)+
88+ rte
89+
90+start:
91+ lea $C00000, a0
92+ lea $C00004, a1
93+ move.w #$8104, (a1) ;Mode 5, everything turned off
94+ move.w #$8004, (a1)
95+ move.w #$8220, (a1) ;Scroll a table $8000
96+ move.w #$8404, (a1) ;Scroll b table $8000
97+ move.w #$8560, (a1) ;SAT table $C000
98+ move.w #$8700, (a1) ;backdrop color 0
99+ move.w #$8B00, (a1) ;full screen scroll
100+ move.w #$8C81, (a1) ;40 cell mode, no interlace
101+ move.w #$8C81, (mode).w
102+ move.w #$8D00, (a1) ;hscroll table at 0
103+ move.w #$8F02, (a1) ;autoinc 2
104+ move.w #$9011, (a1) ;64x64 scroll size
105+ move.l #$C0000000, (a1)
106+ move.w #$000, (a0)
107+ move.w #$EEE, (a0)
108+
109+ ;clear scroll table
110+ move.l #$40000000, (a1)
111+ move.l #0, (a0)
112+
113+ ;load tiles
114+ move.l #$44000000, (a1)
115+ lea font(pc), a2
116+ move.w #((fontend-font)/4 - 1), d0
117+tloop:
118+ move.l (a2)+, (a0)
119+ dbra d0, tloop
120+
121+
122+
123+ ;clear name table
124+ move.l #$40000002, (a1)
125+ moveq #32, d0
126+ move.w #(64*64-1), d1
127+ploop:
128+ move.w d0, (a0)
129+ dbra d1, ploop
130+
131+
132+ lea $FF0000, a4
133+ move.b #$40, (a4, 6)
134+ move.w #$8144, (a1) ;enable display
135+ move #$2300, sr
136+
137+ lea (4, a1), a2 ;hv counter line address
138+ lea (2, a1), a3 ;second contro/status address
139+
140+ move.b #254, d0
141+init_wait:
142+ cmp.b (a2), d0
143+ beq init_wait
144+
145+top:
146+ move.b #254, d0
147+ lea $FF0000, a4
148+ move.w #$8F00, (a1) ;autoinc of 0
149+ move.l #$40040000, (a1) ;unused VRAM address
150+wait_active:
151+ cmp.b (a2), d0
152+ bne.s wait_active
153+
154+ move.l #$8A718014, (a1) ;enable Hints
155+
156+ ;sync to VDP by attempting to fill FIFO
157+ ;being in vblank makes this a bit difficult
158+
159+ rept 8
160+ move.l d0, (a0)
161+ endr
162+
163+ ;sample data for vblank flag off
164+ rept 82 ;two lines worth of move.l
165+ move.l (a3), (a4)+
166+ endr
167+
168+ move.l a4, a5 ;save end of first buffer
169+
170+ move.b (a2), d0
171+wait_new_line:
172+ cmp.b (a2), d0
173+ beq.s wait_new_line
174+
175+ ;sync to VDP by filling FIFO
176+ move.l d0, (a0)
177+ move.l d0, (a0)
178+ move.w d0, (a0)
179+
180+ ;sample data for line change HV value
181+ rept 45 ;one line worth of move.l
182+ move.l (a2), (a4)+
183+ endr
184+
185+ move.l a4, usp ;save end of second buffer
186+
187+ moveq #$70, d0
188+wait_hint_line:
189+ cmp.b (a2), d0
190+ bne.s wait_hint_line
191+
192+ ;sample data for line change HV value
193+ rept 45 ;one line worth of move.l
194+ move.l (a2), (a4)+
195+ endr
196+
197+ move.l a4, a6
198+
199+ move.b #223, d0
200+wait_inactive:
201+ cmp.b (a2), d0
202+ bne.s wait_inactive
203+
204+ ;sync to VDP by filling FIFO
205+ move.l d0, (a0)
206+ move.l d0, (a0)
207+ move.w d0, (a0)
208+
209+ ;sample data for vblank on
210+ rept 82 ;two lines worth of move.l
211+ move.l (a3), (a4)+
212+ endr
213+
214+ move.l #$8AFF8004, (a1) ;disable Hints
215+
216+ rsset $FFFF8000
217+vblank_start_min rs.w 1
218+vblank_start_max rs.w 1
219+vblank_end_min rs.w 1
220+vblank_end_max rs.w 1
221+hblank_start_min rs.w 1
222+hblank_start_max rs.w 1
223+hblank_end_min rs.w 1
224+hblank_end_max rs.w 1
225+line_change_min rs.w 1
226+line_change_max rs.w 1
227+hint_min rs.w 1
228+hint_max rs.w 1
229+mode rs.w 1
230+printed_hv_dump rs.b 1
231+button_state rs.b 1
232+
233+ lea $FF0001, a4
234+.loop:
235+ btst.b #3, (a4)
236+ beq.s found_vblank_off
237+ move.w 1(a4), d6
238+ addq #4, a4
239+ bra.s .loop
240+found_vblank_off:
241+
242+ move.w (vblank_end_max).w, d0
243+ beq .new_max
244+ cmp.w d0, d6
245+ blo .no_new_max
246+.new_max
247+ move.w d6, (vblank_end_max).w
248+.no_new_max:
249+
250+
251+ move.w 1(a4), d6
252+
253+ move.w (vblank_end_min).w, d0
254+ beq .new_min
255+ cmp.w d0, d6
256+ bhi .no_new_min
257+.new_min
258+ move.w d6, (vblank_end_min).w
259+.no_new_min:
260+
261+ lea $FF0001, a4
262+;first find a point where HBLANK is not set
263+ bra.s .start
264+.loop:
265+ addq #4, a4
266+.start
267+ btst.b #2, (a4)
268+ bne.s .loop
269+
270+;then find a point after that where it switches to on
271+.loop2:
272+ btst.b #2, (a4)
273+ bne.s found_hblank_on
274+ move.w 1(a4), d5
275+ addq #4, a4
276+ bra.s .loop2
277+found_hblank_on:
278+
279+ move.w (hblank_start_max).w, d0
280+ beq .new_max
281+ cmp.w d0, d5
282+ blo .no_new_max
283+.new_max
284+ move.w d5, (hblank_start_max).w
285+.no_new_max:
286+
287+
288+ move.w 1(a4), d5
289+
290+ move.w (hblank_start_min).w, d0
291+ beq .new_min
292+ cmp.w d0, d5
293+ bhi .no_new_min
294+.new_min
295+ move.w d5, (hblank_start_min).w
296+.no_new_min:
297+
298+;finally find a point after that where it switches back off
299+.loop2:
300+ btst.b #2, (a4)
301+ beq.s found_hblank_off
302+ move.w 1(a4), d5
303+ addq #4, a4
304+ bra.s .loop2
305+found_hblank_off:
306+
307+ move.w (hblank_end_max).w, d0
308+ beq .new_max
309+ cmp.w d0, d5
310+ blo .no_new_max
311+.new_max
312+ move.w d5, (hblank_end_max).w
313+.no_new_max:
314+
315+
316+ move.w 1(a4), d5
317+
318+ move.w (hblank_end_min).w, d0
319+ beq .new_min
320+ cmp.w d0, d5
321+ bhi .no_new_min
322+.new_min
323+ move.w d5, (hblank_end_min).w
324+.no_new_min:
325+
326+ move.l a5, a4 ;save line change buffer for later
327+ move.b (a5), d0
328+.loop
329+ move.w (a5), d7
330+ addq #2, a5
331+ cmp.b (a5), d0
332+ beq .loop
333+found_line_change:
334+
335+ move.w (line_change_max).w, d0
336+ beq .new_max
337+ cmp.w d0, d7
338+ blo .no_new_max
339+.new_max
340+ move.w d7, (line_change_max).w
341+.no_new_max:
342+
343+ move.w (a5), d7
344+
345+ move.w (line_change_min).w, d0
346+ beq .new_min
347+ cmp.w d0, d7
348+ bhi .no_new_min
349+.new_min
350+ move.w d7, (line_change_min).w
351+.no_new_min:
352+
353+ addq #1, a6
354+.loop:
355+ btst.b #3, (a6)
356+ bne.s found_vblank_on
357+ move.w 1(a6), d5
358+ addq #4, a6
359+ bra.s .loop
360+found_vblank_on:
361+
362+ move.w (vblank_start_max).w, d0
363+ beq .new_max
364+ cmp.w d0, d5
365+ blo .no_new_max
366+.new_max
367+ move.w d5, (vblank_start_max).w
368+.no_new_max:
369+
370+ move.w 1(a6), d5
371+
372+ move.w (vblank_start_min).w, d0
373+ beq .new_min
374+ cmp.b d0, d5
375+ bhi .no_new_min
376+.new_min
377+ move.w d5, (vblank_start_min).w
378+.no_new_min:
379+
380+ move usp, a5
381+.loop:
382+ btst.b #7, (a5)
383+ bne.s found_hint
384+ move.w (a5), d1
385+ addq #2, a5
386+ bra.s .loop
387+found_hint:
388+
389+ move.w (hint_max).w, d0
390+ beq .new_max
391+ cmp.w d0, d1
392+ blo .no_new_max
393+.new_max
394+ move.w d1, (hint_max).w
395+.no_new_max:
396+
397+ move.w (a5), d1
398+ and.w #$7FFF, d1
399+
400+ move.w (hint_min).w, d0
401+ beq .new_min
402+ cmp.b d0, d1
403+ bhi .no_new_min
404+.new_min
405+ move.w d1, (hint_min).w
406+.no_new_min:
407+
408+draw_info:
409+ ;draw data
410+ move.w #$8F02, (a1) ;autoinc of 2
411+ move.l #$40840002, (a1)
412+
413+ moveq #0, d0
414+ lea VBlankStart(pc), a6
415+ bsr print_string
416+
417+
418+ move.w (vblank_start_max), d0
419+ moveq #0, d1
420+ bsr print_hexw
421+
422+ move.w #32, (a0)
423+ move.w d5, d0
424+ bsr print_hexw
425+
426+ move.w #32, (a0)
427+ move.w (vblank_start_min), d0
428+ bsr print_hexw
429+
430+ moveq #0, d0
431+ move.l #$41040002, (a1)
432+ lea VBlankEnd(pc), a6
433+ bsr print_string
434+
435+ ;max value before vblank end
436+ moveq #0, d1
437+ move.w (vblank_end_max), d0
438+ bsr print_hexw
439+
440+ move.w #32, (a0)
441+ move.w d6, d0
442+ bsr print_hexw
443+
444+ ;min value after vblank end
445+ move.w (vblank_end_min), d0
446+ move.w #32, (a0)
447+ bsr print_hexw
448+
449+ moveq #0, d0
450+ move.l #$41840002, (a1)
451+ lea LineChange(pc), a6
452+ bsr print_string
453+
454+ move.w (line_change_max), d0
455+ moveq #0, d1
456+ bsr print_hexw
457+
458+ move.w #32, (a0)
459+ move.w d7, d0
460+ bsr print_hexw
461+
462+ move.w (line_change_min), d0
463+ move.w #32, (a0)
464+ bsr print_hexw
465+
466+ moveq #0, d0
467+ move.l #$42040002, (a1)
468+ lea HBlankStart(pc), a6
469+ bsr print_string
470+
471+ move.w (hblank_start_max), d0
472+ moveq #0, d1
473+ bsr print_hexw
474+
475+ move.w (hblank_start_min), d0
476+ move.w #32, (a0)
477+ bsr print_hexw
478+
479+ moveq #0, d0
480+ move.l #$42840002, (a1)
481+ lea HBlankEnd(pc), a6
482+ bsr print_string
483+
484+ move.w (hblank_end_max), d0
485+ moveq #0, d1
486+ bsr print_hexw
487+
488+ move.w (hblank_end_min), d0
489+ move.w #32, (a0)
490+ bsr print_hexw
491+
492+ moveq #0, d0
493+ move.l #$43040002, (a1)
494+ lea HInterrupt(pc), a6
495+ bsr print_string
496+
497+ move.w (hint_max), d0
498+ moveq #0, d1
499+ bsr print_hexw
500+
501+ move.w (hint_min), d0
502+ move.w #32, (a0)
503+ bsr print_hexw
504+
505+ ;read pad
506+ move.b #$40, $A10003
507+ move.b $A10003, d0
508+ move.b #$00, $A10003
509+ and.b #$3f, d0
510+ move.b $A10003, d1
511+ and.b #$30, d1
512+ lsl.b #2, d1
513+ or.b d1, d0
514+ not.b d0
515+ move.b (button_state).w, d2
516+ eor.b d0, d2
517+ and.b d0, d2
518+ move.b d2, d3 ;d3 contains newly pressed buttons, SACBRLDU
519+ move.b d0, (button_state).w
520+
521+ btst.l #7, d3
522+ beq not_pressed
523+
524+ moveq #0, d0
525+ move.l d0, (vblank_start_min).w
526+ move.l d0, (vblank_end_min).w
527+ move.l d0, (hblank_start_min).w
528+ move.l d0, (hblank_end_min).w
529+ move.l d0, (line_change_min).w
530+ move.l d0, (hint_min).w
531+ move.b d0, (printed_hv_dump).w
532+ move.w (mode).w, d0
533+ eor.w #$81, d0
534+ move.w d0, (mode).w
535+ move.w d0, (a1)
536+ bra top
537+
538+not_pressed
539+
540+ move.b (printed_hv_dump).w, d0
541+ bne top
542+ move.b #1, (printed_hv_dump).w
543+
544+ moveq #0, d1
545+ moveq #89, d4
546+ moveq #6, d5
547+ move.l #$45820002, d6
548+ move.l d6, (a1)
549+
550+print_loop:
551+ dbra d5, .no_line_change
552+ ;#$45820002
553+ add.l #$00800000, d6
554+ move.l d6, (a1)
555+ moveq #5, d5
556+.no_line_change
557+ move.w #32, (a0)
558+ move.w (a4)+, d0
559+ bsr print_hexw
560+ dbra d4, print_loop
561+
562+ add.l #$01020000, d6
563+ move.l d6, (a1)
564+ moveq #0, d0
565+ lea Instructions(pc), a6
566+ bsr print_string
567+
568+ bra top
569+
570+VBlankStart:
571+ dc.b "VBlank Start: ", 0
572+VBlankEnd:
573+ dc.b "VBlank End: ", 0
574+LineChange:
575+ dc.b "Line Change: ", 0
576+HBlankStart:
577+ dc.b "HBlank Start: ", 0
578+HBlankEnd:
579+ dc.b "HBlank End: ", 0
580+HInterrupt:
581+ dc.b "HInterrupt: ", 0
582+Instructions:
583+ dc.b "Press Start to switch modes", 0
584+
585+ align 1
586+;Prints a number in hex format
587+;d0.w - number to print
588+;d1.w - base tile attribute
589+;a0 - VDP data port
590+;
591+;Clobbers: d2.l, d3.l
592+;
593+print_hexw:
594+ moveq #3, d3
595+.digitloop
596+ rol.w #4, d0
597+ moveq #$F, d2
598+ and.b d0, d2
599+ cmp.b #$A, d2
600+ bge .hex
601+ add.w #$30, d2
602+ bra .makeattrib
603+.hex
604+ add.w #($41-$A), d2
605+.makeattrib
606+ add.w d1, d2
607+ move.w d2, (a0)
608+ dbra d3, .digitloop
609+ rts
610+
611+;Prints a null terminated string
612+;a6 - pointer to string
613+;a0 - VDP data port
614+;d0 - base tile attribute
615+;
616+;Clobbers: d1.w
617+print_string:
618+.loop
619+ moveq #0, d1
620+ move.b (a6)+, d1
621+ beq .end
622+ add.w d0, d1
623+ move.w d1, (a0)
624+ bra .loop
625+.end
626+ rts
627+
628+ align 1
629+font:
630+ incbin font.tiles
631+fontend
632+
+2321,
-0
1@@ -0,0 +1,2321 @@
2+/*
3+ Copyright 2013 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#include "gen_x86.h"
8+#include "mem.h"
9+#include "util.h"
10+#include <stddef.h>
11+#include <stdio.h>
12+#include <stdlib.h>
13+#include <stdarg.h>
14+#include <string.h>
15+
16+#define REX_RM_FIELD 0x1
17+#define REX_SIB_FIELD 0x2
18+#define REX_REG_FIELD 0x4
19+#define REX_QUAD 0x8
20+
21+#define OP_ADD 0x00
22+#define OP_OR 0x08
23+#define PRE_2BYTE 0x0F
24+#define OP_ADC 0x10
25+#define OP_SBB 0x18
26+#define OP_AND 0x20
27+#define OP_SUB 0x28
28+#define OP_XOR 0x30
29+#define OP_CMP 0x38
30+#define PRE_REX 0x40
31+#define OP_PUSH 0x50
32+#define OP_POP 0x58
33+#define OP_MOVSXD 0x63
34+#define PRE_SIZE 0x66
35+#define OP_IMUL 0x69
36+#define OP_JCC 0x70
37+#define OP_IMMED_ARITH 0x80
38+#define OP_TEST 0x84
39+#define OP_XCHG 0x86
40+#define OP_MOV 0x88
41+#define PRE_XOP 0x8F
42+#define OP_XCHG_AX 0x90
43+#define OP_CDQ 0x99
44+#define OP_PUSHF 0x9C
45+#define OP_POPF 0x9D
46+#define OP_MOV_I8R 0xB0
47+#define OP_MOV_IR 0xB8
48+#define OP_SHIFTROT_IR 0xC0
49+#define OP_RETN 0xC3
50+#define OP_MOV_IEA 0xC6
51+#define OP_SHIFTROT_1 0xD0
52+#define OP_SHIFTROT_CL 0xD2
53+#define OP_LOOP 0xE2
54+#define OP_CALL 0xE8
55+#define OP_JMP 0xE9
56+#define OP_JMP_BYTE 0xEB
57+#define OP_NOT_NEG 0xF6
58+#define OP_SINGLE_EA 0xFF
59+
60+#define OP2_JCC 0x80
61+#define OP2_SETCC 0x90
62+#define OP2_BT 0xA3
63+#define OP2_BTS 0xAB
64+#define OP2_IMUL 0xAF
65+#define OP2_BTR 0xB3
66+#define OP2_BTX_I 0xBA
67+#define OP2_BTC 0xBB
68+#define OP2_MOVSX 0xBE
69+#define OP2_MOVZX 0xB6
70+
71+#define OP_EX_ADDI 0x0
72+#define OP_EX_ORI 0x1
73+#define OP_EX_ADCI 0x2
74+#define OP_EX_SBBI 0x3
75+#define OP_EX_ANDI 0x4
76+#define OP_EX_SUBI 0x5
77+#define OP_EX_XORI 0x6
78+#define OP_EX_CMPI 0x7
79+
80+#define OP_EX_ROL 0x0
81+#define OP_EX_ROR 0x1
82+#define OP_EX_RCL 0x2
83+#define OP_EX_RCR 0x3
84+#define OP_EX_SHL 0x4
85+#define OP_EX_SHR 0x5
86+#define OP_EX_SAL 0x6 //identical to SHL
87+#define OP_EX_SAR 0x7
88+
89+#define OP_EX_BT 0x4
90+#define OP_EX_BTS 0x5
91+#define OP_EX_BTR 0x6
92+#define OP_EX_BTC 0x7
93+
94+#define OP_EX_TEST_I 0x0
95+#define OP_EX_NOT 0x2
96+#define OP_EX_NEG 0x3
97+#define OP_EX_MUL 0x4
98+#define OP_EX_IMUL 0x5
99+#define OP_EX_DIV 0x6
100+#define OP_EX_IDIV 0x7
101+
102+#define OP_EX_INC 0x0
103+#define OP_EX_DEC 0x1
104+#define OP_EX_CALL_EA 0x2
105+#define OP_EX_JMP_EA 0x4
106+#define OP_EX_PUSH_EA 0x6
107+
108+#define BIT_IMMED_RAX 0x4
109+#define BIT_DIR 0x2
110+#define BIT_SIZE 0x1
111+
112+
113+enum {
114+ X86_RAX = 0,
115+ X86_RCX,
116+ X86_RDX,
117+ X86_RBX,
118+ X86_RSP,
119+ X86_RBP,
120+ X86_RSI,
121+ X86_RDI,
122+ X86_AH=4,
123+ X86_CH,
124+ X86_DH,
125+ X86_BH,
126+ X86_R8=0,
127+ X86_R9,
128+ X86_R10,
129+ X86_R11,
130+ X86_R12,
131+ X86_R13,
132+ X86_R14,
133+ X86_R15
134+} x86_regs_enc;
135+
136+char * x86_reg_names[] = {
137+#ifdef X86_64
138+ "rax",
139+ "rcx",
140+ "rdx",
141+ "rbx",
142+ "rsp",
143+ "rbp",
144+ "rsi",
145+ "rdi",
146+#else
147+ "eax",
148+ "ecx",
149+ "edx",
150+ "ebx",
151+ "esp",
152+ "ebp",
153+ "esi",
154+ "edi",
155+#endif
156+ "ah",
157+ "ch",
158+ "dh",
159+ "bh",
160+ "r8",
161+ "r9",
162+ "r10",
163+ "r11",
164+ "r12",
165+ "r13",
166+ "r14",
167+ "r15",
168+};
169+
170+char * x86_sizes[] = {
171+ "b", "w", "d", "q"
172+};
173+
174+#ifdef X86_64
175+#define CHECK_DISP(disp) (disp <= 0x7FFFFFFF && disp >= -2147483648)
176+#else
177+#define CHECK_DISP(disp) 1
178+#endif
179+
180+void jmp_nocheck(code_info *code, code_ptr dest)
181+{
182+ code_ptr out = code->cur;
183+ ptrdiff_t disp = dest-(out+2);
184+ if (disp <= 0x7F && disp >= -0x80) {
185+ *(out++) = OP_JMP_BYTE;
186+ *(out++) = disp;
187+ } else {
188+ disp = dest-(out+5);
189+ if (CHECK_DISP(disp)) {
190+ *(out++) = OP_JMP;
191+ *(out++) = disp;
192+ disp >>= 8;
193+ *(out++) = disp;
194+ disp >>= 8;
195+ *(out++) = disp;
196+ disp >>= 8;
197+ *(out++) = disp;
198+ } else {
199+ fatal_error("jmp: %p - %p = %l which is out of range of a 32-bit displacementX\n", dest, out + 6, (long)disp);
200+ }
201+ }
202+ code->cur = out;
203+}
204+
205+void check_alloc_code(code_info *code, uint32_t inst_size)
206+{
207+ if (code->cur + inst_size > code->last) {
208+ size_t size = CODE_ALLOC_SIZE;
209+ code_ptr next_code = alloc_code(&size);
210+ if (!next_code) {
211+ fatal_error("Failed to allocate memory for generated code\n");
212+ }
213+ if (next_code != code->last + RESERVE_WORDS) {
214+ //new chunk is not contiguous with the current one
215+ jmp_nocheck(code, next_code);
216+ code->cur = next_code;
217+ }
218+ code->last = next_code + size/sizeof(code_word) - RESERVE_WORDS;
219+ }
220+}
221+
222+void x86_rr_sizedir(code_info *code, uint16_t opcode, uint8_t src, uint8_t dst, uint8_t size)
223+{
224+ check_alloc_code(code, 5);
225+ code_ptr out = code->cur;
226+ uint8_t tmp;
227+ if (size == SZ_W) {
228+ *(out++) = PRE_SIZE;
229+ }
230+ if (size == SZ_B && dst >= RSP && dst <= RDI) {
231+ opcode |= BIT_DIR;
232+ tmp = dst;
233+ dst = src;
234+ src = tmp;
235+ }
236+ if (size == SZ_Q || src >= R8 || dst >= R8 || (size == SZ_B && src >= RSP && src <= RDI)) {
237+#ifdef X86_64
238+ *out = PRE_REX;
239+ if (src >= AH && src <= BH || dst >= AH && dst <= BH) {
240+ fatal_error("attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode);
241+ }
242+ if (size == SZ_Q) {
243+ *out |= REX_QUAD;
244+ }
245+ if (src >= R8) {
246+ *out |= REX_REG_FIELD;
247+ src -= (R8 - X86_R8);
248+ }
249+ if (dst >= R8) {
250+ *out |= REX_RM_FIELD;
251+ dst -= (R8 - X86_R8);
252+ }
253+ out++;
254+#else
255+ fatal_error("Instruction requires REX prefix but this is a 32-bit build | opcode: %X, src: %s, dst: %s, size: %s\n", opcode, x86_reg_names[src], x86_reg_names[dst], x86_sizes[size]);
256+#endif
257+ }
258+ if (size == SZ_B) {
259+ if (src >= AH && src <= BH) {
260+ src -= (AH-X86_AH);
261+ }
262+ if (dst >= AH && dst <= BH) {
263+ dst -= (AH-X86_AH);
264+ }
265+ } else {
266+ opcode |= BIT_SIZE;
267+ }
268+ if (opcode >= 0x100) {
269+ *(out++) = opcode >> 8;
270+ *(out++) = opcode;
271+ } else {
272+ *(out++) = opcode;
273+ }
274+ *(out++) = MODE_REG_DIRECT | dst | (src << 3);
275+ code->cur = out;
276+}
277+
278+void x86_rrdisp_sizedir(code_info *code, uint16_t opcode, uint8_t reg, uint8_t base, int32_t disp, uint8_t size, uint8_t dir)
279+{
280+ check_alloc_code(code, 10);
281+ code_ptr out = code->cur;
282+ //TODO: Deal with the fact that AH, BH, CH and DH can only be in the R/M param when there's a REX prefix
283+ uint8_t tmp;
284+ if (size == SZ_W) {
285+ *(out++) = PRE_SIZE;
286+ }
287+ if (size == SZ_Q || reg >= R8 || base >= R8 || (size == SZ_B && reg >= RSP && reg <= RDI)) {
288+#ifdef X86_64
289+ *out = PRE_REX;
290+ if (reg >= AH && reg <= BH) {
291+ fatal_error("attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode);
292+ }
293+ if (size == SZ_Q) {
294+ *out |= REX_QUAD;
295+ }
296+ if (reg >= R8) {
297+ *out |= REX_REG_FIELD;
298+ reg -= (R8 - X86_R8);
299+ }
300+ if (base >= R8) {
301+ *out |= REX_RM_FIELD;
302+ base -= (R8 - X86_R8);
303+ }
304+ out++;
305+#else
306+ fatal_error("Instruction requires REX prefix but this is a 32-bit build | opcode: %X, reg: %s, base: %s, size: %s\n", opcode, x86_reg_names[reg], x86_reg_names[base], x86_sizes[size]);
307+#endif
308+ }
309+ if (size == SZ_B) {
310+ if (reg >= AH && reg <= BH) {
311+ reg -= (AH-X86_AH);
312+ }
313+ } else {
314+ opcode |= BIT_SIZE;
315+ }
316+ opcode |= dir;
317+ if (opcode >= 0x100) {
318+ *(out++) = opcode >> 8;
319+ *(out++) = opcode;
320+ } else {
321+ *(out++) = opcode;
322+ }
323+ if (disp < 128 && disp >= -128) {
324+ *(out++) = MODE_REG_DISPLACE8 | base | (reg << 3);
325+ } else {
326+ *(out++) = MODE_REG_DISPLACE32 | base | (reg << 3);
327+ }
328+ if (base == RSP) {
329+ //add SIB byte, with no index and RSP as base
330+ *(out++) = (RSP << 3) | RSP;
331+ }
332+ *(out++) = disp;
333+ if (disp >= 128 || disp < -128) {
334+ *(out++) = disp >> 8;
335+ *(out++) = disp >> 16;
336+ *(out++) = disp >> 24;
337+ }
338+ code->cur = out;
339+}
340+
341+void x86_rrind_sizedir(code_info *code, uint8_t opcode, uint8_t reg, uint8_t base, uint8_t size, uint8_t dir)
342+{
343+ check_alloc_code(code, 5);
344+ code_ptr out = code->cur;
345+ //TODO: Deal with the fact that AH, BH, CH and DH can only be in the R/M param when there's a REX prefix
346+ uint8_t tmp;
347+ if (size == SZ_W) {
348+ *(out++) = PRE_SIZE;
349+ }
350+ if (size == SZ_Q || reg >= R8 || base >= R8 || (size == SZ_B && reg >= RSP && reg <= RDI)) {
351+#ifdef X86_64
352+ *out = PRE_REX;
353+ if (reg >= AH && reg <= BH) {
354+ fatal_error("attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode);
355+ }
356+ if (size == SZ_Q) {
357+ *out |= REX_QUAD;
358+ }
359+ if (reg >= R8) {
360+ *out |= REX_REG_FIELD;
361+ reg -= (R8 - X86_R8);
362+ }
363+ if (base >= R8) {
364+ *out |= REX_RM_FIELD;
365+ base -= (R8 - X86_R8);
366+ }
367+ out++;
368+#else
369+ fatal_error("Instruction requires REX prefix but this is a 32-bit build | opcode: %X, reg: %s, base: %s, size: %s\n", opcode, x86_reg_names[reg], x86_reg_names[base], x86_sizes[size]);
370+#endif
371+ }
372+ if (size == SZ_B) {
373+ if (reg >= AH && reg <= BH) {
374+ reg -= (AH-X86_AH);
375+ }
376+ } else {
377+ opcode |= BIT_SIZE;
378+ }
379+ *(out++) = opcode | dir;
380+ if (base == RBP) {
381+ //add a dummy 8-bit displacement since MODE_REG_INDIRECT with
382+ //an R/M field of RBP selects RIP, relative addressing
383+ *(out++) = MODE_REG_DISPLACE8 | base | (reg << 3);
384+ *(out++) = 0;
385+ } else {
386+ *(out++) = MODE_REG_INDIRECT | base | (reg << 3);
387+ if (base == RSP) {
388+ //add SIB byte, with no index and RSP as base
389+ *(out++) = (RSP << 3) | RSP;
390+ }
391+ }
392+ code->cur = out;
393+}
394+
395+void x86_rrindex_sizedir(code_info *code, uint8_t opcode, uint8_t reg, uint8_t base, uint8_t index, uint8_t scale, uint8_t size, uint8_t dir)
396+{
397+ check_alloc_code(code, 5);
398+ code_ptr out = code->cur;
399+ //TODO: Deal with the fact that AH, BH, CH and DH can only be in the R/M param when there's a REX prefix
400+ uint8_t tmp;
401+ if (size == SZ_W) {
402+ *(out++) = PRE_SIZE;
403+ }
404+ if (size == SZ_Q || reg >= R8 || base >= R8 || (size == SZ_B && reg >= RSP && reg <= RDI)) {
405+#ifdef X86_64
406+ *out = PRE_REX;
407+ if (reg >= AH && reg <= BH) {
408+ fatal_error("attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode);
409+ }
410+ if (size == SZ_Q) {
411+ *out |= REX_QUAD;
412+ }
413+ if (reg >= R8) {
414+ *out |= REX_REG_FIELD;
415+ reg -= (R8 - X86_R8);
416+ }
417+ if (base >= R8) {
418+ *out |= REX_RM_FIELD;
419+ base -= (R8 - X86_R8);
420+ }
421+ if (index >= R8) {
422+ *out |= REX_SIB_FIELD;
423+ index -= (R8 - X86_R8);
424+ }
425+ out++;
426+#else
427+ fatal_error("Instruction requires REX prefix but this is a 32-bit build | opcode: %X, reg: %s, base: %s, size: %s\n", opcode, x86_reg_names[reg], x86_reg_names[base], x86_sizes[size]);
428+#endif
429+ }
430+ if (size == SZ_B) {
431+ if (reg >= AH && reg <= BH) {
432+ reg -= (AH-X86_AH);
433+ }
434+ } else {
435+ opcode |= BIT_SIZE;
436+ }
437+ *(out++) = opcode | dir;
438+ *(out++) = MODE_REG_INDIRECT | RSP | (reg << 3);
439+ if (scale == 4) {
440+ scale = 2;
441+ } else if(scale == 8) {
442+ scale = 3;
443+ } else {
444+ scale--;
445+ }
446+ *(out++) = scale << 6 | (index << 3) | base;
447+ code->cur = out;
448+}
449+
450+void x86_r_size(code_info *code, uint8_t opcode, uint8_t opex, uint8_t dst, uint8_t size)
451+{
452+ check_alloc_code(code, 4);
453+ code_ptr out = code->cur;
454+ uint8_t tmp;
455+ if (size == SZ_W) {
456+ *(out++) = PRE_SIZE;
457+ }
458+ if (size == SZ_Q || dst >= R8) {
459+#ifdef X86_64
460+ *out = PRE_REX;
461+ if (dst >= AH && dst <= BH) {
462+ fatal_error("attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode);
463+ }
464+ if (size == SZ_Q) {
465+ *out |= REX_QUAD;
466+ }
467+ if (dst >= R8) {
468+ *out |= REX_RM_FIELD;
469+ dst -= (R8 - X86_R8);
470+ }
471+ out++;
472+#else
473+ fatal_error("Instruction requires REX prefix but this is a 32-bit build | opcode: %X:%X, reg: %s, size: %s\n", opcode, opex, x86_reg_names[dst], x86_sizes[size]);
474+#endif
475+ }
476+ if (size == SZ_B) {
477+ if (dst >= AH && dst <= BH) {
478+ dst -= (AH-X86_AH);
479+ }
480+ } else {
481+ opcode |= BIT_SIZE;
482+ }
483+ *(out++) = opcode;
484+ *(out++) = MODE_REG_DIRECT | dst | (opex << 3);
485+ code->cur = out;
486+}
487+
488+void x86_rdisp_size(code_info *code, uint8_t opcode, uint8_t opex, uint8_t dst, int32_t disp, uint8_t size)
489+{
490+ check_alloc_code(code, 7);
491+ code_ptr out = code->cur;
492+ uint8_t tmp;
493+ if (size == SZ_W) {
494+ *(out++) = PRE_SIZE;
495+ }
496+ if (size == SZ_Q || dst >= R8) {
497+#ifdef X86_64
498+ *out = PRE_REX;
499+ if (size == SZ_Q) {
500+ *out |= REX_QUAD;
501+ }
502+ if (dst >= R8) {
503+ *out |= REX_RM_FIELD;
504+ dst -= (R8 - X86_R8);
505+ }
506+ out++;
507+#else
508+ fatal_error("Instruction requires REX prefix but this is a 32-bit build | opcode: %X:%X, reg: %s, size: %s\n", opcode, opex, x86_reg_names[dst], x86_sizes[size]);
509+#endif
510+ }
511+ if (size != SZ_B) {
512+ opcode |= BIT_SIZE;
513+ }
514+ *(out++) = opcode;
515+ if (disp < 128 && disp >= -128) {
516+ *(out++) = MODE_REG_DISPLACE8 | dst | (opex << 3);
517+ *(out++) = disp;
518+ } else {
519+ *(out++) = MODE_REG_DISPLACE32 | dst | (opex << 3);
520+ *(out++) = disp;
521+ *(out++) = disp >> 8;
522+ *(out++) = disp >> 16;
523+ *(out++) = disp >> 24;
524+ }
525+ code->cur = out;
526+}
527+
528+void x86_ir(code_info *code, uint8_t opcode, uint8_t op_ex, uint8_t al_opcode, int32_t val, uint8_t dst, uint8_t size)
529+{
530+ check_alloc_code(code, 8);
531+ code_ptr out = code->cur;
532+ uint8_t sign_extend = 0;
533+ if (opcode != OP_NOT_NEG && (size == SZ_D || size == SZ_Q) && val <= 0x7F && val >= -0x80) {
534+ sign_extend = 1;
535+ opcode |= BIT_DIR;
536+ }
537+ if (size == SZ_W) {
538+ *(out++) = PRE_SIZE;
539+ }
540+ if (dst == RAX && !sign_extend && al_opcode) {
541+ if (size != SZ_B) {
542+ al_opcode |= BIT_SIZE;
543+ if (size == SZ_Q) {
544+#ifdef X86_64
545+ *out = PRE_REX | REX_QUAD;
546+#else
547+ fatal_error("Instruction requires REX prefix but this is a 32-bit build | opcode: %X, reg: %s, size: %s\n", al_opcode, x86_reg_names[dst], x86_sizes[size]);
548+#endif
549+ }
550+ }
551+ *(out++) = al_opcode | BIT_IMMED_RAX;
552+ } else {
553+ if (size == SZ_Q || dst >= R8 || (size == SZ_B && dst >= RSP && dst <= RDI)) {
554+#ifdef X86_64
555+ *out = PRE_REX;
556+ if (size == SZ_Q) {
557+ *out |= REX_QUAD;
558+ }
559+ if (dst >= R8) {
560+ *out |= REX_RM_FIELD;
561+ dst -= (R8 - X86_R8);
562+ }
563+ out++;
564+#else
565+ fatal_error("Instruction requires REX prefix but this is a 32-bit build | opcode: %X:%X, reg: %s, size: %s\n", opcode, op_ex, x86_reg_names[dst], x86_sizes[size]);
566+#endif
567+ }
568+ if (dst >= AH && dst <= BH) {
569+ dst -= (AH-X86_AH);
570+ }
571+ if (size != SZ_B) {
572+ opcode |= BIT_SIZE;
573+ }
574+ *(out++) = opcode;
575+ *(out++) = MODE_REG_DIRECT | dst | (op_ex << 3);
576+ }
577+ *(out++) = val;
578+ if (size != SZ_B && !sign_extend) {
579+ val >>= 8;
580+ *(out++) = val;
581+ if (size != SZ_W) {
582+ val >>= 8;
583+ *(out++) = val;
584+ val >>= 8;
585+ *(out++) = val;
586+ }
587+ }
588+ code->cur = out;
589+}
590+
591+void x86_irdisp(code_info *code, uint8_t opcode, uint8_t op_ex, int32_t val, uint8_t dst, int32_t disp, uint8_t size)
592+{
593+ check_alloc_code(code, 12);
594+ code_ptr out = code->cur;
595+ uint8_t sign_extend = 0;
596+ if ((size == SZ_D || size == SZ_Q) && val <= 0x7F && val >= -0x80) {
597+ sign_extend = 1;
598+ opcode |= BIT_DIR;
599+ }
600+ if (size == SZ_W) {
601+ *(out++) = PRE_SIZE;
602+ }
603+
604+ if (size == SZ_Q || dst >= R8) {
605+#ifdef X86_64
606+ *out = PRE_REX;
607+ if (size == SZ_Q) {
608+ *out |= REX_QUAD;
609+ }
610+ if (dst >= R8) {
611+ *out |= REX_RM_FIELD;
612+ dst -= (R8 - X86_R8);
613+ }
614+ out++;
615+#else
616+ fatal_error("Instruction requires REX prefix but this is a 32-bit build | opcode: %X:%X, reg: %s, size: %s\n", opcode, op_ex, x86_reg_names[dst], x86_sizes[size]);
617+#endif
618+ }
619+ if (size != SZ_B) {
620+ opcode |= BIT_SIZE;
621+ }
622+ *(out++) = opcode;
623+ if (disp < 128 && disp >= -128) {
624+ *(out++) = MODE_REG_DISPLACE8 | dst | (op_ex << 3);
625+ *(out++) = disp;
626+ } else {
627+ *(out++) = MODE_REG_DISPLACE32 | dst | (op_ex << 3);
628+ *(out++) = disp;
629+ disp >>= 8;
630+ *(out++) = disp;
631+ disp >>= 8;
632+ *(out++) = disp;
633+ disp >>= 8;
634+ *(out++) = disp;
635+ }
636+ *(out++) = val;
637+ if (size != SZ_B && !sign_extend) {
638+ val >>= 8;
639+ *(out++) = val;
640+ if (size != SZ_W) {
641+ val >>= 8;
642+ *(out++) = val;
643+ val >>= 8;
644+ *(out++) = val;
645+ }
646+ }
647+ code->cur = out;
648+}
649+
650+void x86_shiftrot_ir(code_info *code, uint8_t op_ex, uint8_t val, uint8_t dst, uint8_t size)
651+{
652+ check_alloc_code(code, 5);
653+ code_ptr out = code->cur;
654+ if (size == SZ_W) {
655+ *(out++) = PRE_SIZE;
656+ }
657+ if (size == SZ_Q || dst >= R8 || (size == SZ_B && dst >= RSP && dst <= RDI)) {
658+ *out = PRE_REX;
659+ if (size == SZ_Q) {
660+ *out |= REX_QUAD;
661+ }
662+ if (dst >= R8) {
663+ *out |= REX_RM_FIELD;
664+ dst -= (R8 - X86_R8);
665+ }
666+ out++;
667+ }
668+ if (dst >= AH && dst <= BH) {
669+ dst -= (AH-X86_AH);
670+ }
671+
672+ *(out++) = (val == 1 ? OP_SHIFTROT_1: OP_SHIFTROT_IR) | (size == SZ_B ? 0 : BIT_SIZE);
673+ *(out++) = MODE_REG_DIRECT | dst | (op_ex << 3);
674+ if (val != 1) {
675+ *(out++) = val;
676+ }
677+ code->cur = out;
678+}
679+
680+void x86_shiftrot_irdisp(code_info *code, uint8_t op_ex, uint8_t val, uint8_t dst, int32_t disp, uint8_t size)
681+{
682+ check_alloc_code(code, 9);
683+ code_ptr out = code->cur;
684+ if (size == SZ_W) {
685+ *(out++) = PRE_SIZE;
686+ }
687+ if (size == SZ_Q || dst >= R8) {
688+ *out = PRE_REX;
689+ if (size == SZ_Q) {
690+ *out |= REX_QUAD;
691+ }
692+ if (dst >= R8) {
693+ *out |= REX_RM_FIELD;
694+ dst -= (R8 - X86_R8);
695+ }
696+ out++;
697+ }
698+ if (dst >= AH && dst <= BH) {
699+ dst -= (AH-X86_AH);
700+ }
701+
702+ *(out++) = (val == 1 ? OP_SHIFTROT_1: OP_SHIFTROT_IR) | (size == SZ_B ? 0 : BIT_SIZE);
703+ if (disp < 128 && disp >= -128) {
704+ *(out++) = MODE_REG_DISPLACE8 | dst | (op_ex << 3);
705+ *(out++) = disp;
706+ } else {
707+ *(out++) = MODE_REG_DISPLACE32 | dst | (op_ex << 3);
708+ *(out++) = disp;
709+ *(out++) = disp >> 8;
710+ *(out++) = disp >> 16;
711+ *(out++) = disp >> 24;
712+ }
713+ if (val != 1) {
714+ *(out++) = val;
715+ }
716+ code->cur = out;
717+}
718+
719+void x86_shiftrot_clr(code_info *code, uint8_t op_ex, uint8_t dst, uint8_t size)
720+{
721+ check_alloc_code(code, 4);
722+ code_ptr out = code->cur;
723+ if (size == SZ_W) {
724+ *(out++) = PRE_SIZE;
725+ }
726+ if (size == SZ_Q || dst >= R8 || (size == SZ_B && dst >= RSP && dst <= RDI)) {
727+ *out = PRE_REX;
728+ if (size == SZ_Q) {
729+ *out |= REX_QUAD;
730+ }
731+ if (dst >= R8) {
732+ *out |= REX_RM_FIELD;
733+ dst -= (R8 - X86_R8);
734+ }
735+ out++;
736+ }
737+ if (dst >= AH && dst <= BH) {
738+ dst -= (AH-X86_AH);
739+ }
740+
741+ *(out++) = OP_SHIFTROT_CL | (size == SZ_B ? 0 : BIT_SIZE);
742+ *(out++) = MODE_REG_DIRECT | dst | (op_ex << 3);
743+ code->cur = out;
744+}
745+
746+void x86_shiftrot_clrdisp(code_info *code, uint8_t op_ex, uint8_t dst, int32_t disp, uint8_t size)
747+{
748+ check_alloc_code(code, 8);
749+ code_ptr out = code->cur;
750+ if (size == SZ_W) {
751+ *(out++) = PRE_SIZE;
752+ }
753+ if (size == SZ_Q || dst >= R8) {
754+ *out = PRE_REX;
755+ if (size == SZ_Q) {
756+ *out |= REX_QUAD;
757+ }
758+ if (dst >= R8) {
759+ *out |= REX_RM_FIELD;
760+ dst -= (R8 - X86_R8);
761+ }
762+ out++;
763+ }
764+ if (dst >= AH && dst <= BH) {
765+ dst -= (AH-X86_AH);
766+ }
767+
768+ *(out++) = OP_SHIFTROT_CL | (size == SZ_B ? 0 : BIT_SIZE);
769+ if (disp < 128 && disp >= -128) {
770+ *(out++) = MODE_REG_DISPLACE8 | dst | (op_ex << 3);
771+ *(out++) = disp;
772+ } else {
773+ *(out++) = MODE_REG_DISPLACE32 | dst | (op_ex << 3);
774+ *(out++) = disp;
775+ *(out++) = disp >> 8;
776+ *(out++) = disp >> 16;
777+ *(out++) = disp >> 24;
778+}
779+ code->cur = out;
780+}
781+
782+void rol_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size)
783+{
784+ x86_shiftrot_ir(code, OP_EX_ROL, val, dst, size);
785+}
786+
787+void ror_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size)
788+{
789+ x86_shiftrot_ir(code, OP_EX_ROR, val, dst, size);
790+}
791+
792+void rcl_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size)
793+{
794+ x86_shiftrot_ir(code, OP_EX_RCL, val, dst, size);
795+}
796+
797+void rcr_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size)
798+{
799+ x86_shiftrot_ir(code, OP_EX_RCR, val, dst, size);
800+}
801+
802+void shl_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size)
803+{
804+ x86_shiftrot_ir(code, OP_EX_SHL, val, dst, size);
805+}
806+
807+void shr_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size)
808+{
809+ x86_shiftrot_ir(code, OP_EX_SHR, val, dst, size);
810+}
811+
812+void sar_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size)
813+{
814+ x86_shiftrot_ir(code, OP_EX_SAR, val, dst, size);
815+}
816+
817+void rol_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size)
818+{
819+ x86_shiftrot_irdisp(code, OP_EX_ROL, val, dst_base, disp, size);
820+}
821+
822+void ror_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size)
823+{
824+ x86_shiftrot_irdisp(code, OP_EX_ROR, val, dst_base, disp, size);
825+}
826+
827+void rcl_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size)
828+{
829+ x86_shiftrot_irdisp(code, OP_EX_RCL, val, dst_base, disp, size);
830+}
831+
832+void rcr_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size)
833+{
834+ x86_shiftrot_irdisp(code, OP_EX_RCR, val, dst_base, disp, size);
835+}
836+
837+void shl_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size)
838+{
839+ x86_shiftrot_irdisp(code, OP_EX_SHL, val, dst_base, disp, size);
840+}
841+
842+void shr_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size)
843+{
844+ x86_shiftrot_irdisp(code, OP_EX_SHR, val, dst_base, disp, size);
845+}
846+
847+void sar_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size)
848+{
849+ x86_shiftrot_irdisp(code, OP_EX_SAR, val, dst_base, disp, size);
850+}
851+
852+void rol_clr(code_info *code, uint8_t dst, uint8_t size)
853+{
854+ x86_shiftrot_clr(code, OP_EX_ROL, dst, size);
855+}
856+
857+void ror_clr(code_info *code, uint8_t dst, uint8_t size)
858+{
859+ x86_shiftrot_clr(code, OP_EX_ROR, dst, size);
860+}
861+
862+void rcl_clr(code_info *code, uint8_t dst, uint8_t size)
863+{
864+ x86_shiftrot_clr(code, OP_EX_RCL, dst, size);
865+}
866+
867+void rcr_clr(code_info *code, uint8_t dst, uint8_t size)
868+{
869+ x86_shiftrot_clr(code, OP_EX_RCR, dst, size);
870+}
871+
872+void shl_clr(code_info *code, uint8_t dst, uint8_t size)
873+{
874+ x86_shiftrot_clr(code, OP_EX_SHL, dst, size);
875+}
876+
877+void shr_clr(code_info *code, uint8_t dst, uint8_t size)
878+{
879+ x86_shiftrot_clr(code, OP_EX_SHR, dst, size);
880+}
881+
882+void sar_clr(code_info *code, uint8_t dst, uint8_t size)
883+{
884+ x86_shiftrot_clr(code, OP_EX_SAR, dst, size);
885+}
886+
887+void rol_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size)
888+{
889+ x86_shiftrot_clrdisp(code, OP_EX_ROL, dst_base, disp, size);
890+}
891+
892+void ror_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size)
893+{
894+ x86_shiftrot_clrdisp(code, OP_EX_ROR, dst_base, disp, size);
895+}
896+
897+void rcl_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size)
898+{
899+ x86_shiftrot_clrdisp(code, OP_EX_RCL, dst_base, disp, size);
900+}
901+
902+void rcr_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size)
903+{
904+ x86_shiftrot_clrdisp(code, OP_EX_RCR, dst_base, disp, size);
905+}
906+
907+void shl_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size)
908+{
909+ x86_shiftrot_clrdisp(code, OP_EX_SHL, dst_base, disp, size);
910+}
911+
912+void shr_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size)
913+{
914+ x86_shiftrot_clrdisp(code, OP_EX_SHR, dst_base, disp, size);
915+}
916+
917+void sar_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size)
918+{
919+ x86_shiftrot_clrdisp(code, OP_EX_SAR, dst_base, disp, size);
920+}
921+
922+void add_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
923+{
924+ x86_rr_sizedir(code, OP_ADD, src, dst, size);
925+}
926+
927+void add_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size)
928+{
929+ x86_ir(code, OP_IMMED_ARITH, OP_EX_ADDI, OP_ADD, val, dst, size);
930+}
931+
932+void add_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size)
933+{
934+ x86_irdisp(code, OP_IMMED_ARITH, OP_EX_ADDI, val, dst_base, disp, size);
935+}
936+
937+void add_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size)
938+{
939+ x86_rrdisp_sizedir(code, OP_ADD, src, dst_base, disp, size, 0);
940+}
941+
942+void add_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size)
943+{
944+ x86_rrdisp_sizedir(code, OP_ADD, dst, src_base, disp, size, BIT_DIR);
945+}
946+
947+void adc_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
948+{
949+ x86_rr_sizedir(code, OP_ADC, src, dst, size);
950+}
951+
952+void adc_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size)
953+{
954+ x86_ir(code, OP_IMMED_ARITH, OP_EX_ADCI, OP_ADC, val, dst, size);
955+}
956+
957+void adc_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size)
958+{
959+ x86_irdisp(code, OP_IMMED_ARITH, OP_EX_ADCI, val, dst_base, disp, size);
960+}
961+
962+void adc_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size)
963+{
964+ x86_rrdisp_sizedir(code, OP_ADC, src, dst_base, disp, size, 0);
965+}
966+
967+void adc_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size)
968+{
969+ x86_rrdisp_sizedir(code, OP_ADC, dst, src_base, disp, size, BIT_DIR);
970+}
971+
972+void or_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
973+{
974+ x86_rr_sizedir(code, OP_OR, src, dst, size);
975+}
976+void or_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size)
977+{
978+ x86_ir(code, OP_IMMED_ARITH, OP_EX_ORI, OP_OR, val, dst, size);
979+}
980+
981+void or_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size)
982+{
983+ x86_irdisp(code, OP_IMMED_ARITH, OP_EX_ORI, val, dst_base, disp, size);
984+}
985+
986+void or_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size)
987+{
988+ x86_rrdisp_sizedir(code, OP_OR, src, dst_base, disp, size, 0);
989+}
990+
991+void or_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size)
992+{
993+ x86_rrdisp_sizedir(code, OP_OR, dst, src_base, disp, size, BIT_DIR);
994+}
995+
996+void and_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
997+{
998+ x86_rr_sizedir(code, OP_AND, src, dst, size);
999+}
1000+
1001+void and_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size)
1002+{
1003+ x86_ir(code, OP_IMMED_ARITH, OP_EX_ANDI, OP_AND, val, dst, size);
1004+}
1005+
1006+void and_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size)
1007+{
1008+ x86_irdisp(code, OP_IMMED_ARITH, OP_EX_ANDI, val, dst_base, disp, size);
1009+}
1010+
1011+void and_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size)
1012+{
1013+ x86_rrdisp_sizedir(code, OP_AND, src, dst_base, disp, size, 0);
1014+}
1015+
1016+void and_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size)
1017+{
1018+ x86_rrdisp_sizedir(code, OP_AND, dst, src_base, disp, size, BIT_DIR);
1019+}
1020+
1021+void xor_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
1022+{
1023+ x86_rr_sizedir(code, OP_XOR, src, dst, size);
1024+}
1025+
1026+void xor_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size)
1027+{
1028+ x86_ir(code, OP_IMMED_ARITH, OP_EX_XORI, OP_XOR, val, dst, size);
1029+}
1030+
1031+void xor_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size)
1032+{
1033+ x86_irdisp(code, OP_IMMED_ARITH, OP_EX_XORI, val, dst_base, disp, size);
1034+}
1035+
1036+void xor_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size)
1037+{
1038+ x86_rrdisp_sizedir(code, OP_XOR, src, dst_base, disp, size, 0);
1039+}
1040+
1041+void xor_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size)
1042+{
1043+ x86_rrdisp_sizedir(code, OP_XOR, dst, src_base, disp, size, BIT_DIR);
1044+}
1045+
1046+void sub_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
1047+{
1048+ x86_rr_sizedir(code, OP_SUB, src, dst, size);
1049+}
1050+
1051+void sub_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size)
1052+{
1053+ x86_ir(code, OP_IMMED_ARITH, OP_EX_SUBI, OP_SUB, val, dst, size);
1054+}
1055+
1056+void sub_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size)
1057+{
1058+ x86_irdisp(code, OP_IMMED_ARITH, OP_EX_SUBI, val, dst_base, disp, size);
1059+}
1060+
1061+void sub_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size)
1062+{
1063+ x86_rrdisp_sizedir(code, OP_SUB, src, dst_base, disp, size, 0);
1064+}
1065+
1066+void sub_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size)
1067+{
1068+ x86_rrdisp_sizedir(code, OP_SUB, dst, src_base, disp, size, BIT_DIR);
1069+}
1070+
1071+void sbb_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
1072+{
1073+ x86_rr_sizedir(code, OP_SBB, src, dst, size);
1074+}
1075+
1076+void sbb_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size)
1077+{
1078+ x86_ir(code, OP_IMMED_ARITH, OP_EX_SBBI, OP_SBB, val, dst, size);
1079+}
1080+
1081+void sbb_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size)
1082+{
1083+ x86_irdisp(code, OP_IMMED_ARITH, OP_EX_SBBI, val, dst_base, disp, size);
1084+}
1085+
1086+void sbb_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size)
1087+{
1088+ x86_rrdisp_sizedir(code, OP_SBB, src, dst_base, disp, size, 0);
1089+}
1090+
1091+void sbb_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size)
1092+{
1093+ x86_rrdisp_sizedir(code, OP_SBB, dst, src_base, disp, size, BIT_DIR);
1094+}
1095+
1096+void cmp_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
1097+{
1098+ x86_rr_sizedir(code, OP_CMP, src, dst, size);
1099+}
1100+
1101+void cmp_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size)
1102+{
1103+ x86_ir(code, OP_IMMED_ARITH, OP_EX_CMPI, OP_CMP, val, dst, size);
1104+}
1105+
1106+void cmp_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size)
1107+{
1108+ x86_irdisp(code, OP_IMMED_ARITH, OP_EX_CMPI, val, dst_base, disp, size);
1109+}
1110+
1111+void cmp_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size)
1112+{
1113+ x86_rrdisp_sizedir(code, OP_CMP, src, dst_base, disp, size, 0);
1114+}
1115+
1116+void cmp_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size)
1117+{
1118+ x86_rrdisp_sizedir(code, OP_CMP, dst, src_base, disp, size, BIT_DIR);
1119+}
1120+
1121+void test_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
1122+{
1123+ x86_rr_sizedir(code, OP_TEST, src, dst, size);
1124+}
1125+
1126+void test_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size)
1127+{
1128+ x86_ir(code, OP_NOT_NEG, OP_EX_TEST_I, OP_TEST, val, dst, size);
1129+}
1130+
1131+void test_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size)
1132+{
1133+ x86_irdisp(code, OP_NOT_NEG, OP_EX_TEST_I, val, dst_base, disp, size);
1134+}
1135+
1136+void test_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size)
1137+{
1138+ x86_rrdisp_sizedir(code, OP_TEST, src, dst_base, disp, size, 0);
1139+}
1140+
1141+void test_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size)
1142+{
1143+ x86_rrdisp_sizedir(code, OP_TEST, dst, src_base, disp, size, BIT_DIR);
1144+}
1145+
1146+void imul_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
1147+{
1148+ x86_rr_sizedir(code, OP2_IMUL | (PRE_2BYTE << 8), dst, src, size);
1149+}
1150+
1151+void imul_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size)
1152+{
1153+ x86_rrdisp_sizedir(code, OP2_IMUL | (PRE_2BYTE << 8), dst, src_base, disp, size, 0);
1154+}
1155+
1156+void imul_irr(code_info *code, int32_t val, uint8_t src, uint8_t dst, uint8_t size)
1157+{
1158+ if (size == SZ_B) {
1159+ fatal_error("imul immediate only supports 16-bit sizes and up");
1160+ }
1161+
1162+ x86_ir(code, OP_IMUL, dst, 0, val, src, size);
1163+}
1164+
1165+void not_r(code_info *code, uint8_t dst, uint8_t size)
1166+{
1167+ x86_r_size(code, OP_NOT_NEG, OP_EX_NOT, dst, size);
1168+}
1169+
1170+void neg_r(code_info *code, uint8_t dst, uint8_t size)
1171+{
1172+ x86_r_size(code, OP_NOT_NEG, OP_EX_NEG, dst, size);
1173+}
1174+
1175+void not_rdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size)
1176+{
1177+ x86_rdisp_size(code, OP_NOT_NEG, OP_EX_NOT, dst_base, disp, size);
1178+}
1179+
1180+void neg_rdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size)
1181+{
1182+ x86_rdisp_size(code, OP_NOT_NEG, OP_EX_NEG, dst_base, disp, size);
1183+}
1184+
1185+void mul_r(code_info *code, uint8_t dst, uint8_t size)
1186+{
1187+ x86_r_size(code, OP_NOT_NEG, OP_EX_MUL, dst, size);
1188+}
1189+
1190+void imul_r(code_info *code, uint8_t dst, uint8_t size)
1191+{
1192+ x86_r_size(code, OP_NOT_NEG, OP_EX_IMUL, dst, size);
1193+}
1194+
1195+void div_r(code_info *code, uint8_t dst, uint8_t size)
1196+{
1197+ x86_r_size(code, OP_NOT_NEG, OP_EX_DIV, dst, size);
1198+}
1199+
1200+void idiv_r(code_info *code, uint8_t dst, uint8_t size)
1201+{
1202+ x86_r_size(code, OP_NOT_NEG, OP_EX_IDIV, dst, size);
1203+}
1204+
1205+void mul_rdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size)
1206+{
1207+ x86_rdisp_size(code, OP_NOT_NEG, OP_EX_MUL, dst_base, disp, size);
1208+}
1209+
1210+void imul_rdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size)
1211+{
1212+ x86_rdisp_size(code, OP_NOT_NEG, OP_EX_IMUL, dst_base, disp, size);
1213+}
1214+
1215+void div_rdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size)
1216+{
1217+ x86_rdisp_size(code, OP_NOT_NEG, OP_EX_DIV, dst_base, disp, size);
1218+}
1219+
1220+void idiv_rdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size)
1221+{
1222+ x86_rdisp_size(code, OP_NOT_NEG, OP_EX_IDIV, dst_base, disp, size);
1223+}
1224+
1225+void mov_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
1226+{
1227+ x86_rr_sizedir(code, OP_MOV, src, dst, size);
1228+}
1229+
1230+void mov_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size)
1231+{
1232+ x86_rrdisp_sizedir(code, OP_MOV, src, dst_base, disp, size, 0);
1233+}
1234+
1235+void mov_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size)
1236+{
1237+ x86_rrdisp_sizedir(code, OP_MOV, dst, src_base, disp, size, BIT_DIR);
1238+}
1239+
1240+void mov_rrind(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
1241+{
1242+ x86_rrind_sizedir(code, OP_MOV, src, dst, size, 0);
1243+}
1244+
1245+void mov_rindr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
1246+{
1247+ x86_rrind_sizedir(code, OP_MOV, dst, src, size, BIT_DIR);
1248+}
1249+
1250+void mov_rrindex(code_info *code, uint8_t src, uint8_t dst_base, uint8_t dst_index, uint8_t scale, uint8_t size)
1251+{
1252+ x86_rrindex_sizedir(code, OP_MOV, src, dst_base, dst_index, scale, size, 0);
1253+}
1254+
1255+void mov_rindexr(code_info *code, uint8_t src_base, uint8_t src_index, uint8_t scale, uint8_t dst, uint8_t size)
1256+{
1257+ x86_rrindex_sizedir(code, OP_MOV, dst, src_base, src_index, scale, size, BIT_DIR);
1258+}
1259+
1260+void mov_ir(code_info *code, int64_t val, uint8_t dst, uint8_t size)
1261+{
1262+ check_alloc_code(code, 14);
1263+ code_ptr out = code->cur;
1264+ uint8_t sign_extend = 0;
1265+ if (size == SZ_Q && val <= 0x7FFFFFFF && val >= -2147483648) {
1266+ sign_extend = 1;
1267+ }
1268+ if (size == SZ_W) {
1269+ *(out++) = PRE_SIZE;
1270+ }
1271+ if (size == SZ_Q || dst >= R8 || (size == SZ_B && dst >= RSP && dst <= RDI)) {
1272+ *out = PRE_REX;
1273+ if (size == SZ_Q) {
1274+ *out |= REX_QUAD;
1275+ }
1276+ if (dst >= R8) {
1277+ *out |= REX_RM_FIELD;
1278+ dst -= (R8 - X86_R8);
1279+ }
1280+ out++;
1281+ }
1282+ if (dst >= AH && dst <= BH) {
1283+ dst -= (AH-X86_AH);
1284+ }
1285+ if (size == SZ_B) {
1286+ *(out++) = OP_MOV_I8R | dst;
1287+ } else if (size == SZ_Q && sign_extend) {
1288+ *(out++) = OP_MOV_IEA | BIT_SIZE;
1289+ *(out++) = MODE_REG_DIRECT | dst;
1290+ } else {
1291+ *(out++) = OP_MOV_IR | dst;
1292+ }
1293+ *(out++) = val;
1294+ if (size != SZ_B) {
1295+ val >>= 8;
1296+ *(out++) = val;
1297+ if (size != SZ_W) {
1298+ val >>= 8;
1299+ *(out++) = val;
1300+ val >>= 8;
1301+ *(out++) = val;
1302+ if (size == SZ_Q && !sign_extend) {
1303+ val >>= 8;
1304+ *(out++) = val;
1305+ val >>= 8;
1306+ *(out++) = val;
1307+ val >>= 8;
1308+ *(out++) = val;
1309+ val >>= 8;
1310+ *(out++) = val;
1311+ }
1312+ }
1313+ }
1314+ code->cur = out;
1315+}
1316+
1317+uint8_t is_mov_ir(code_ptr inst)
1318+{
1319+ while (*inst == PRE_SIZE || *inst == PRE_REX)
1320+ {
1321+ inst++;
1322+ }
1323+ return (*inst & 0xF8) == OP_MOV_I8R || (*inst & 0xF8) == OP_MOV_IR || (*inst & 0xFE) == OP_MOV_IEA;
1324+}
1325+
1326+void mov_irdisp(code_info *code, int32_t val, uint8_t dst, int32_t disp, uint8_t size)
1327+{
1328+ check_alloc_code(code, 12);
1329+ code_ptr out = code->cur;
1330+ if (size == SZ_W) {
1331+ *(out++) = PRE_SIZE;
1332+ }
1333+ if (size == SZ_Q || dst >= R8) {
1334+ *out = PRE_REX;
1335+ if (size == SZ_Q) {
1336+ *out |= REX_QUAD;
1337+ }
1338+ if (dst >= R8) {
1339+ *out |= REX_RM_FIELD;
1340+ dst -= (R8 - X86_R8);
1341+ }
1342+ out++;
1343+ }
1344+ if (dst >= AH && dst <= BH) {
1345+ dst -= (AH-X86_AH);
1346+ }
1347+ *(out++) = OP_MOV_IEA | (size == SZ_B ? 0 : BIT_SIZE);
1348+ if (disp < 128 && disp >= -128) {
1349+ *(out++) = MODE_REG_DISPLACE8 | dst;
1350+ *(out++) = disp;
1351+ } else {
1352+ *(out++) = MODE_REG_DISPLACE32 | dst;
1353+ *(out++) = disp;
1354+ *(out++) = disp >> 8;
1355+ *(out++) = disp >> 16;
1356+ *(out++) = disp >> 24;
1357+ }
1358+
1359+ *(out++) = val;
1360+ if (size != SZ_B) {
1361+ val >>= 8;
1362+ *(out++) = val;
1363+ if (size != SZ_W) {
1364+ val >>= 8;
1365+ *(out++) = val;
1366+ val >>= 8;
1367+ *(out++) = val;
1368+ }
1369+ }
1370+ code->cur = out;
1371+}
1372+
1373+void mov_irind(code_info *code, int32_t val, uint8_t dst, uint8_t size)
1374+{
1375+ check_alloc_code(code, 8);
1376+ code_ptr out = code->cur;
1377+ if (size == SZ_W) {
1378+ *(out++) = PRE_SIZE;
1379+ }
1380+ if (size == SZ_Q || dst >= R8 || (size == SZ_B && dst >= RSP && dst <= RDI)) {
1381+ *out = PRE_REX;
1382+ if (size == SZ_Q) {
1383+ *out |= REX_QUAD;
1384+ }
1385+ if (dst >= R8) {
1386+ *out |= REX_RM_FIELD;
1387+ dst -= (R8 - X86_R8);
1388+ }
1389+ out++;
1390+ }
1391+ if (dst >= AH && dst <= BH) {
1392+ dst -= (AH-X86_AH);
1393+ }
1394+ *(out++) = OP_MOV_IEA | (size == SZ_B ? 0 : BIT_SIZE);
1395+ *(out++) = MODE_REG_INDIRECT | dst;
1396+
1397+ *(out++) = val;
1398+ if (size != SZ_B) {
1399+ val >>= 8;
1400+ *(out++) = val;
1401+ if (size != SZ_W) {
1402+ val >>= 8;
1403+ *(out++) = val;
1404+ val >>= 8;
1405+ *(out++) = val;
1406+ }
1407+ }
1408+ code->cur = out;
1409+}
1410+
1411+void movsx_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t src_size, uint8_t size)
1412+{
1413+ check_alloc_code(code, 5);
1414+ code_ptr out = code->cur;
1415+ if (size == SZ_W) {
1416+ *(out++) = PRE_SIZE;
1417+ }
1418+ if (size == SZ_Q || dst >= R8 || src >= R8) {
1419+ *out = PRE_REX;
1420+ if (size == SZ_Q) {
1421+ *out |= REX_QUAD;
1422+ }
1423+ if (src >= R8) {
1424+ *out |= REX_RM_FIELD;
1425+ src -= (R8 - X86_R8);
1426+ }
1427+ if (dst >= R8) {
1428+ *out |= REX_REG_FIELD;
1429+ dst -= (R8 - X86_R8);
1430+ }
1431+ out++;
1432+ }
1433+ if (src_size == SZ_D) {
1434+ *(out++) = OP_MOVSXD;
1435+ } else {
1436+ *(out++) = PRE_2BYTE;
1437+ *(out++) = OP2_MOVSX | (src_size == SZ_B ? 0 : BIT_SIZE);
1438+ }
1439+ *(out++) = MODE_REG_DIRECT | src | (dst << 3);
1440+ code->cur = out;
1441+}
1442+
1443+void movsx_rdispr(code_info *code, uint8_t src, int32_t disp, uint8_t dst, uint8_t src_size, uint8_t size)
1444+{
1445+ check_alloc_code(code, 12);
1446+ code_ptr out = code->cur;
1447+ if (size == SZ_W) {
1448+ *(out++) = PRE_SIZE;
1449+ }
1450+ if (size == SZ_Q || dst >= R8 || src >= R8) {
1451+ *out = PRE_REX;
1452+ if (size == SZ_Q) {
1453+ *out |= REX_QUAD;
1454+ }
1455+ if (src >= R8) {
1456+ *out |= REX_RM_FIELD;
1457+ src -= (R8 - X86_R8);
1458+ }
1459+ if (dst >= R8) {
1460+ *out |= REX_REG_FIELD;
1461+ dst -= (R8 - X86_R8);
1462+ }
1463+ out++;
1464+ }
1465+ if (src_size == SZ_D) {
1466+ *(out++) = OP_MOVSXD;
1467+ } else {
1468+ *(out++) = PRE_2BYTE;
1469+ *(out++) = OP2_MOVSX | (src_size == SZ_B ? 0 : BIT_SIZE);
1470+ }
1471+ if (disp < 128 && disp >= -128) {
1472+ *(out++) = MODE_REG_DISPLACE8 | src | (dst << 3);
1473+ *(out++) = disp;
1474+ } else {
1475+ *(out++) = MODE_REG_DISPLACE32 | src | (dst << 3);
1476+ *(out++) = disp;
1477+ *(out++) = disp >> 8;
1478+ *(out++) = disp >> 16;
1479+ *(out++) = disp >> 24;
1480+ }
1481+ code->cur = out;
1482+}
1483+
1484+void movzx_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t src_size, uint8_t size)
1485+{
1486+ check_alloc_code(code, 5);
1487+ code_ptr out = code->cur;
1488+ if (size == SZ_W) {
1489+ *(out++) = PRE_SIZE;
1490+ }
1491+ if (size == SZ_Q || dst >= R8 || src >= R8) {
1492+ *out = PRE_REX;
1493+ if (size == SZ_Q) {
1494+ *out |= REX_QUAD;
1495+ }
1496+ if (src >= R8) {
1497+ *out |= REX_RM_FIELD;
1498+ src -= (R8 - X86_R8);
1499+ }
1500+ if (dst >= R8) {
1501+ *out |= REX_REG_FIELD;
1502+ dst -= (R8 - X86_R8);
1503+ }
1504+ out++;
1505+ }
1506+ *(out++) = PRE_2BYTE;
1507+ *(out++) = OP2_MOVZX | (src_size == SZ_B ? 0 : BIT_SIZE);
1508+ *(out++) = MODE_REG_DIRECT | src | (dst << 3);
1509+ code->cur = out;
1510+}
1511+
1512+void movzx_rdispr(code_info *code, uint8_t src, int32_t disp, uint8_t dst, uint8_t src_size, uint8_t size)
1513+{
1514+ check_alloc_code(code, 9);
1515+ code_ptr out = code->cur;
1516+ if (size == SZ_W) {
1517+ *(out++) = PRE_SIZE;
1518+ }
1519+ if (size == SZ_Q || dst >= R8 || src >= R8) {
1520+ *out = PRE_REX;
1521+ if (size == SZ_Q) {
1522+ *out |= REX_QUAD;
1523+ }
1524+ if (src >= R8) {
1525+ *out |= REX_RM_FIELD;
1526+ src -= (R8 - X86_R8);
1527+ }
1528+ if (dst >= R8) {
1529+ *out |= REX_REG_FIELD;
1530+ dst -= (R8 - X86_R8);
1531+ }
1532+ out++;
1533+ }
1534+ *(out++) = PRE_2BYTE;
1535+ *(out++) = OP2_MOVZX | (src_size == SZ_B ? 0 : BIT_SIZE);
1536+ if (disp < 128 && disp >= -128) {
1537+ *(out++) = MODE_REG_DISPLACE8 | src | (dst << 3);
1538+ *(out++) = disp;
1539+ } else {
1540+ *(out++) = MODE_REG_DISPLACE32 | src | (dst << 3);
1541+ *(out++) = disp;
1542+ *(out++) = disp >> 8;
1543+ *(out++) = disp >> 16;
1544+ *(out++) = disp >> 24;
1545+ }
1546+ code->cur = out;
1547+}
1548+
1549+void xchg_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
1550+{
1551+ check_alloc_code(code, 4);
1552+ code_ptr out = code->cur;
1553+ //TODO: Use OP_XCHG_AX when one of the registers is AX, EAX or RAX
1554+ uint8_t tmp;
1555+ if (size == SZ_W) {
1556+ *(out++) = PRE_SIZE;
1557+ }
1558+ if (size == SZ_B && dst >= RSP && dst <= RDI) {
1559+ tmp = dst;
1560+ dst = src;
1561+ src = tmp;
1562+ }
1563+ if (size == SZ_Q || src >= R8 || dst >= R8 || (size == SZ_B && src >= RSP && src <= RDI)) {
1564+ *out = PRE_REX;
1565+ if (size == SZ_Q) {
1566+ *out |= REX_QUAD;
1567+ }
1568+ if (src >= R8) {
1569+ *out |= REX_REG_FIELD;
1570+ src -= (R8 - X86_R8);
1571+ }
1572+ if (dst >= R8) {
1573+ *out |= REX_RM_FIELD;
1574+ dst -= (R8 - X86_R8);
1575+ }
1576+ out++;
1577+ }
1578+ uint8_t opcode = OP_XCHG;
1579+ if (size == SZ_B) {
1580+ if (src >= AH && src <= BH) {
1581+ src -= (AH-X86_AH);
1582+ }
1583+ if (dst >= AH && dst <= BH) {
1584+ dst -= (AH-X86_AH);
1585+ }
1586+ } else {
1587+ opcode |= BIT_SIZE;
1588+ }
1589+ *(out++) = opcode;
1590+ *(out++) = MODE_REG_DIRECT | dst | (src << 3);
1591+ code->cur = out;
1592+}
1593+
1594+void pushf(code_info *code)
1595+{
1596+ check_alloc_code(code, 1);
1597+ code_ptr out = code->cur;
1598+ *(out++) = OP_PUSHF;
1599+ code->cur = out;
1600+}
1601+
1602+void popf(code_info *code)
1603+{
1604+ check_alloc_code(code, 1);
1605+ code_ptr out = code->cur;
1606+ *(out++) = OP_POPF;
1607+ code->cur = out;
1608+}
1609+
1610+void push_r(code_info *code, uint8_t reg)
1611+{
1612+ check_alloc_code(code, 2);
1613+ code_ptr out = code->cur;
1614+ if (reg >= R8) {
1615+ *(out++) = PRE_REX | REX_RM_FIELD;
1616+ reg -= R8 - X86_R8;
1617+ }
1618+ *(out++) = OP_PUSH | reg;
1619+ code->cur = out;
1620+ code->stack_off += sizeof(void *);
1621+}
1622+
1623+void push_rdisp(code_info *code, uint8_t base, int32_t disp)
1624+{
1625+ //This instruction has no explicit size, so we pass SZ_B
1626+ //to avoid any prefixes or bits being set
1627+ x86_rdisp_size(code, OP_SINGLE_EA, OP_EX_PUSH_EA, base, disp, SZ_B);
1628+ code->stack_off += sizeof(void *);
1629+}
1630+
1631+void pop_r(code_info *code, uint8_t reg)
1632+{
1633+ check_alloc_code(code, 2);
1634+ code_ptr out = code->cur;
1635+ if (reg >= R8) {
1636+ *(out++) = PRE_REX | REX_RM_FIELD;
1637+ reg -= R8 - X86_R8;
1638+ }
1639+ *(out++) = OP_POP | reg;
1640+ code->cur = out;
1641+ code->stack_off -= sizeof(void *);
1642+}
1643+
1644+void pop_rind(code_info *code, uint8_t reg)
1645+{
1646+ check_alloc_code(code, 3);
1647+ code_ptr out = code->cur;
1648+ if (reg >= R8) {
1649+ *(out++) = PRE_REX | REX_RM_FIELD;
1650+ reg -= R8 - X86_R8;
1651+ }
1652+ *(out++) = PRE_XOP;
1653+ *(out++) = MODE_REG_INDIRECT | reg;
1654+ code->cur = out;
1655+ code->stack_off -= sizeof(void *);
1656+}
1657+
1658+void setcc_r(code_info *code, uint8_t cc, uint8_t dst)
1659+{
1660+ check_alloc_code(code, 4);
1661+ code_ptr out = code->cur;
1662+ if (dst >= R8) {
1663+ *(out++) = PRE_REX | REX_RM_FIELD;
1664+ dst -= R8 - X86_R8;
1665+ } else if (dst >= RSP && dst <= RDI) {
1666+ *(out++) = PRE_REX;
1667+ } else if (dst >= AH && dst <= BH) {
1668+ dst -= AH - X86_AH;
1669+ }
1670+ *(out++) = PRE_2BYTE;
1671+ *(out++) = OP2_SETCC | cc;
1672+ *(out++) = MODE_REG_DIRECT | dst;
1673+ code->cur = out;
1674+}
1675+
1676+void setcc_rind(code_info *code, uint8_t cc, uint8_t dst)
1677+{
1678+ check_alloc_code(code, 4);
1679+ code_ptr out = code->cur;
1680+ if (dst >= R8) {
1681+ *(out++) = PRE_REX | REX_RM_FIELD;
1682+ dst -= R8 - X86_R8;
1683+ }
1684+ *(out++) = PRE_2BYTE;
1685+ *(out++) = OP2_SETCC | cc;
1686+ *(out++) = MODE_REG_INDIRECT | dst;
1687+ code->cur = out;
1688+}
1689+
1690+void setcc_rdisp(code_info *code, uint8_t cc, uint8_t dst, int32_t disp)
1691+{
1692+ check_alloc_code(code, 8);
1693+ code_ptr out = code->cur;
1694+ if (dst >= R8) {
1695+ *(out++) = PRE_REX | REX_RM_FIELD;
1696+ dst -= R8 - X86_R8;
1697+ }
1698+ *(out++) = PRE_2BYTE;
1699+ *(out++) = OP2_SETCC | cc;
1700+ if (disp < 128 && disp >= -128) {
1701+ *(out++) = MODE_REG_DISPLACE8 | dst;
1702+ *(out++) = disp;
1703+ } else {
1704+ *(out++) = MODE_REG_DISPLACE32 | dst;
1705+ *(out++) = disp;
1706+ *(out++) = disp >> 8;
1707+ *(out++) = disp >> 16;
1708+ *(out++) = disp >> 24;
1709+ }
1710+ code->cur = out;
1711+}
1712+
1713+void bit_rr(code_info *code, uint8_t op2, uint8_t src, uint8_t dst, uint8_t size)
1714+{
1715+ check_alloc_code(code, 5);
1716+ code_ptr out = code->cur;
1717+ if (size == SZ_W) {
1718+ *(out++) = PRE_SIZE;
1719+ }
1720+ if (size == SZ_Q || src >= R8 || dst >= R8) {
1721+ *out = PRE_REX;
1722+ if (size == SZ_Q) {
1723+ *out |= REX_QUAD;
1724+ }
1725+ if (src >= R8) {
1726+ *out |= REX_REG_FIELD;
1727+ src -= (R8 - X86_R8);
1728+ }
1729+ if (dst >= R8) {
1730+ *out |= REX_RM_FIELD;
1731+ dst -= (R8 - X86_R8);
1732+ }
1733+ out++;
1734+ }
1735+ *(out++) = PRE_2BYTE;
1736+ *(out++) = op2;
1737+ *(out++) = MODE_REG_DIRECT | dst | (src << 3);
1738+ code->cur = out;
1739+}
1740+
1741+void bit_rrdisp(code_info *code, uint8_t op2, uint8_t src, uint8_t dst_base, int32_t dst_disp, uint8_t size)
1742+{
1743+ check_alloc_code(code, 9);
1744+ code_ptr out = code->cur;
1745+ if (size == SZ_W) {
1746+ *(out++) = PRE_SIZE;
1747+ }
1748+ if (size == SZ_Q || src >= R8 || dst_base >= R8) {
1749+ *out = PRE_REX;
1750+ if (size == SZ_Q) {
1751+ *out |= REX_QUAD;
1752+ }
1753+ if (src >= R8) {
1754+ *out |= REX_REG_FIELD;
1755+ src -= (R8 - X86_R8);
1756+ }
1757+ if (dst_base >= R8) {
1758+ *out |= REX_RM_FIELD;
1759+ dst_base -= (R8 - X86_R8);
1760+ }
1761+ out++;
1762+ }
1763+ *(out++) = PRE_2BYTE;
1764+ *(out++) = op2;
1765+ if (dst_disp < 128 && dst_disp >= -128) {
1766+ *(out++) = MODE_REG_DISPLACE8 | dst_base | (src << 3);
1767+ *(out++) = dst_disp;
1768+ } else {
1769+ *(out++) = MODE_REG_DISPLACE32 | dst_base | (src << 3);
1770+ *(out++) = dst_disp;
1771+ *(out++) = dst_disp >> 8;
1772+ *(out++) = dst_disp >> 16;
1773+ *(out++) = dst_disp >> 24;
1774+ }
1775+ code->cur = out;
1776+}
1777+
1778+void bit_ir(code_info *code, uint8_t op_ex, uint8_t val, uint8_t dst, uint8_t size)
1779+{
1780+ check_alloc_code(code, 6);
1781+ code_ptr out = code->cur;
1782+ if (size == SZ_W) {
1783+ *(out++) = PRE_SIZE;
1784+ }
1785+ if (size == SZ_Q || dst >= R8) {
1786+ *out = PRE_REX;
1787+ if (size == SZ_Q) {
1788+ *out |= REX_QUAD;
1789+ }
1790+ if (dst >= R8) {
1791+ *out |= REX_RM_FIELD;
1792+ dst -= (R8 - X86_R8);
1793+ }
1794+ out++;
1795+ }
1796+ *(out++) = PRE_2BYTE;
1797+ *(out++) = OP2_BTX_I;
1798+ *(out++) = MODE_REG_DIRECT | dst | (op_ex << 3);
1799+ *(out++) = val;
1800+ code->cur = out;
1801+}
1802+
1803+void bit_irdisp(code_info *code, uint8_t op_ex, uint8_t val, uint8_t dst_base, int32_t dst_disp, uint8_t size)
1804+{
1805+ check_alloc_code(code, 10);
1806+ code_ptr out = code->cur;
1807+ if (size == SZ_W) {
1808+ *(out++) = PRE_SIZE;
1809+ }
1810+ if (size == SZ_Q || dst_base >= R8) {
1811+ *out = PRE_REX;
1812+ if (size == SZ_Q) {
1813+ *out |= REX_QUAD;
1814+ }
1815+ if (dst_base >= R8) {
1816+ *out |= REX_RM_FIELD;
1817+ dst_base -= (R8 - X86_R8);
1818+ }
1819+ out++;
1820+ }
1821+ *(out++) = PRE_2BYTE;
1822+ *(out++) = OP2_BTX_I;
1823+ if (dst_disp < 128 && dst_disp >= -128) {
1824+ *(out++) = MODE_REG_DISPLACE8 | dst_base | (op_ex << 3);
1825+ *(out++) = dst_disp;
1826+ } else {
1827+ *(out++) = MODE_REG_DISPLACE32 | dst_base | (op_ex << 3);
1828+ *(out++) = dst_disp;
1829+ *(out++) = dst_disp >> 8;
1830+ *(out++) = dst_disp >> 16;
1831+ *(out++) = dst_disp >> 24;
1832+ }
1833+ *(out++) = val;
1834+ code->cur = out;
1835+}
1836+
1837+void bt_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
1838+{
1839+ return bit_rr(code, OP2_BT, src, dst, size);
1840+}
1841+
1842+void bt_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t dst_disp, uint8_t size)
1843+{
1844+ return bit_rrdisp(code, OP2_BT, src, dst_base, dst_disp, size);
1845+}
1846+
1847+void bt_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size)
1848+{
1849+ return bit_ir(code, OP_EX_BT, val, dst, size);
1850+}
1851+
1852+void bt_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t dst_disp, uint8_t size)
1853+{
1854+ return bit_irdisp(code, OP_EX_BT, val, dst_base, dst_disp, size);
1855+}
1856+
1857+void bts_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
1858+{
1859+ return bit_rr(code, OP2_BTS, src, dst, size);
1860+}
1861+
1862+void bts_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t dst_disp, uint8_t size)
1863+{
1864+ return bit_rrdisp(code, OP2_BTS, src, dst_base, dst_disp, size);
1865+}
1866+
1867+void bts_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size)
1868+{
1869+ return bit_ir(code, OP_EX_BTS, val, dst, size);
1870+}
1871+
1872+void bts_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t dst_disp, uint8_t size)
1873+{
1874+ return bit_irdisp(code, OP_EX_BTS, val, dst_base, dst_disp, size);
1875+}
1876+
1877+void btr_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
1878+{
1879+ return bit_rr(code, OP2_BTR, src, dst, size);
1880+}
1881+
1882+void btr_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t dst_disp, uint8_t size)
1883+{
1884+ return bit_rrdisp(code, OP2_BTR, src, dst_base, dst_disp, size);
1885+}
1886+
1887+void btr_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size)
1888+{
1889+ return bit_ir(code, OP_EX_BTR, val, dst, size);
1890+}
1891+
1892+void btr_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t dst_disp, uint8_t size)
1893+{
1894+ return bit_irdisp(code, OP_EX_BTR, val, dst_base, dst_disp, size);
1895+}
1896+
1897+void btc_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size)
1898+{
1899+ return bit_rr(code, OP2_BTC, src, dst, size);
1900+}
1901+
1902+void btc_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t dst_disp, uint8_t size)
1903+{
1904+ return bit_rrdisp(code, OP2_BTC, src, dst_base, dst_disp, size);
1905+}
1906+
1907+void btc_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size)
1908+{
1909+ return bit_ir(code, OP_EX_BTC, val, dst, size);
1910+}
1911+
1912+void btc_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t dst_disp, uint8_t size)
1913+{
1914+ return bit_irdisp(code, OP_EX_BTC, val, dst_base, dst_disp, size);
1915+}
1916+
1917+void jcc(code_info *code, uint8_t cc, code_ptr dest)
1918+{
1919+ check_alloc_code(code, 6);
1920+ code_ptr out = code->cur;
1921+ ptrdiff_t disp = dest-(out+2);
1922+ if (disp <= 0x7F && disp >= -0x80) {
1923+ *(out++) = OP_JCC | cc;
1924+ *(out++) = disp;
1925+ } else {
1926+ disp = dest-(out+6);
1927+ if (CHECK_DISP(disp)) {
1928+ *(out++) = PRE_2BYTE;
1929+ *(out++) = OP2_JCC | cc;
1930+ *(out++) = disp;
1931+ disp >>= 8;
1932+ *(out++) = disp;
1933+ disp >>= 8;
1934+ *(out++) = disp;
1935+ disp >>= 8;
1936+ *(out++) = disp;
1937+ } else {
1938+ fatal_error("jcc: %p - %p = %lX which is out of range for a 32-bit displacement\n", dest, out + 6, (long)disp);
1939+ }
1940+ }
1941+ code->cur = out;
1942+}
1943+
1944+void jmp(code_info *code, code_ptr dest)
1945+{
1946+ check_alloc_code(code, 5);
1947+ code_ptr out = code->cur;
1948+ ptrdiff_t disp = dest-(out+2);
1949+ if (disp <= 0x7F && disp >= -0x80) {
1950+ *(out++) = OP_JMP_BYTE;
1951+ *(out++) = disp;
1952+ } else {
1953+ disp = dest-(out+5);
1954+ if (CHECK_DISP(disp)) {
1955+ *(out++) = OP_JMP;
1956+ *(out++) = disp;
1957+ disp >>= 8;
1958+ *(out++) = disp;
1959+ disp >>= 8;
1960+ *(out++) = disp;
1961+ disp >>= 8;
1962+ *(out++) = disp;
1963+ } else {
1964+ fatal_error("jmp: %p - %p = %lX which is out of range for a 32-bit displacement\n", dest, out + 6, (long)disp);
1965+ }
1966+ }
1967+ code->cur = out;
1968+}
1969+
1970+void jmp_r(code_info *code, uint8_t dst)
1971+{
1972+ check_alloc_code(code, 3);
1973+ code_ptr out = code->cur;
1974+ if (dst >= R8) {
1975+ dst -= R8 - X86_R8;
1976+ *(out++) = PRE_REX | REX_RM_FIELD;
1977+ }
1978+ *(out++) = OP_SINGLE_EA;
1979+ *(out++) = MODE_REG_DIRECT | dst | (OP_EX_JMP_EA << 3);
1980+ code->cur = out;
1981+}
1982+
1983+void jmp_rind(code_info *code, uint8_t dst)
1984+{
1985+ check_alloc_code(code, 3);
1986+ code_ptr out = code->cur;
1987+ if (dst >= R8) {
1988+ dst -= R8 - X86_R8;
1989+ *(out++) = PRE_REX | REX_RM_FIELD;
1990+ }
1991+ *(out++) = OP_SINGLE_EA;
1992+ *(out++) = MODE_REG_INDIRECT | dst | (OP_EX_JMP_EA << 3);
1993+ code->cur = out;
1994+}
1995+
1996+void call_noalign(code_info *code, code_ptr fun)
1997+{
1998+ check_alloc_code(code, 5);
1999+ code_ptr out = code->cur;
2000+ ptrdiff_t disp = fun-(out+5);
2001+ if (CHECK_DISP(disp)) {
2002+ *(out++) = OP_CALL;
2003+ *(out++) = disp;
2004+ disp >>= 8;
2005+ *(out++) = disp;
2006+ disp >>= 8;
2007+ *(out++) = disp;
2008+ disp >>= 8;
2009+ *(out++) = disp;
2010+ } else {
2011+ //TODO: Implement far call???
2012+ fatal_error("call: %p - %p = %lX which is out of range for a 32-bit displacement\n", fun, out + 5, (long)disp);
2013+ }
2014+ code->cur = out;
2015+}
2016+
2017+volatile int foo;
2018+void call(code_info *code, code_ptr fun)
2019+{
2020+ foo = *fun;
2021+ code->stack_off += sizeof(void *);
2022+ int32_t adjust = 0;
2023+ if (code->stack_off & 0xF) {
2024+ adjust = 16 - (code->stack_off & 0xF);
2025+ code->stack_off += adjust;
2026+ sub_ir(code, adjust, RSP, SZ_PTR);
2027+ }
2028+ call_noalign(code, fun);
2029+ if (adjust) {
2030+ add_ir(code, adjust, RSP, SZ_PTR);
2031+ }
2032+ code->stack_off -= sizeof(void *) + adjust;
2033+}
2034+void call_raxfallback(code_info *code, code_ptr fun)
2035+{
2036+ check_alloc_code(code, 5);
2037+ code_ptr out = code->cur;
2038+ ptrdiff_t disp = fun-(out+5);
2039+ if (CHECK_DISP(disp)) {
2040+ *(out++) = OP_CALL;
2041+ *(out++) = disp;
2042+ disp >>= 8;
2043+ *(out++) = disp;
2044+ disp >>= 8;
2045+ *(out++) = disp;
2046+ disp >>= 8;
2047+ *(out++) = disp;
2048+ code->cur = out;
2049+ } else {
2050+ mov_ir(code, (int64_t)fun, RAX, SZ_PTR);
2051+ call_r(code, RAX);
2052+ }
2053+}
2054+
2055+void call_r(code_info *code, uint8_t dst)
2056+{
2057+ code->stack_off += sizeof(void *);
2058+ int32_t adjust = 0;
2059+ if (code->stack_off & 0xF) {
2060+ adjust = 16 - (code->stack_off & 0xF);
2061+ code->stack_off += adjust;
2062+ sub_ir(code, adjust, RSP, SZ_PTR);
2063+ }
2064+ check_alloc_code(code, 2);
2065+ code_ptr out = code->cur;
2066+ *(out++) = OP_SINGLE_EA;
2067+ *(out++) = MODE_REG_DIRECT | dst | (OP_EX_CALL_EA << 3);
2068+ code->cur = out;
2069+ if (adjust) {
2070+ add_ir(code, adjust, RSP, SZ_PTR);
2071+ }
2072+ code->stack_off -= sizeof(void *) + adjust;
2073+}
2074+
2075+void retn(code_info *code)
2076+{
2077+ check_alloc_code(code, 1);
2078+ code_ptr out = code->cur;
2079+ *(out++) = OP_RETN;
2080+ code->cur = out;
2081+}
2082+
2083+void rts(code_info *code)
2084+{
2085+ retn(code);
2086+}
2087+
2088+void cdq(code_info *code)
2089+{
2090+ check_alloc_code(code, 1);
2091+ code_ptr out = code->cur;
2092+ *(out++) = OP_CDQ;
2093+ code->cur = out;
2094+}
2095+
2096+void loop(code_info *code, code_ptr dst)
2097+{
2098+ check_alloc_code(code, 2);
2099+ code_ptr out = code->cur;
2100+ ptrdiff_t disp = dst-(out+2);
2101+ *(out++) = OP_LOOP;
2102+ *(out++) = disp;
2103+ code->cur = out;
2104+}
2105+
2106+uint32_t prep_args(code_info *code, uint32_t num_args, va_list args)
2107+{
2108+ uint8_t *arg_arr = malloc(num_args);
2109+ for (int i = 0; i < num_args; i ++)
2110+ {
2111+ arg_arr[i] = va_arg(args, int);
2112+ }
2113+#ifdef X86_64
2114+ uint32_t stack_args = 0;
2115+ uint8_t abi_regs[] = {RDI, RSI, RDX, RCX, R8, R9};
2116+ int8_t reg_swap[R15+1];
2117+ uint32_t usage = 0;
2118+ memset(reg_swap, -1, sizeof(reg_swap));
2119+ for (int i = 0; i < num_args; i ++)
2120+ {
2121+ usage |= 1 << arg_arr[i];
2122+ }
2123+ for (int i = 0; i < num_args; i ++)
2124+ {
2125+ uint8_t reg_arg = arg_arr[i];
2126+ if (i < sizeof(abi_regs)) {
2127+ if (reg_swap[reg_arg] >= 0) {
2128+ reg_arg = reg_swap[reg_arg];
2129+ }
2130+ if (reg_arg != abi_regs[i]) {
2131+ if (usage & (1 << abi_regs[i])) {
2132+ xchg_rr(code, reg_arg, abi_regs[i], SZ_PTR);
2133+ reg_swap[abi_regs[i]] = reg_arg;
2134+ } else {
2135+ mov_rr(code, reg_arg, abi_regs[i], SZ_PTR);
2136+ }
2137+ }
2138+ } else {
2139+ arg_arr[stack_args++] = reg_arg;
2140+ }
2141+ }
2142+#else
2143+#define stack_args num_args
2144+#endif
2145+ uint32_t stack_off_call = code->stack_off + sizeof(void *) * (stack_args + 1);
2146+ uint32_t adjust = 0;
2147+ if (stack_off_call & 0xF) {
2148+ adjust = 16 - (stack_off_call & 0xF);
2149+ sub_ir(code, adjust, RSP, SZ_PTR);
2150+ code->stack_off += adjust;
2151+ }
2152+ for (int i = stack_args -1; i >= 0; i--)
2153+ {
2154+ push_r(code, arg_arr[i]);
2155+ }
2156+ free(arg_arr);
2157+
2158+ return stack_args * sizeof(void *) + adjust;
2159+}
2160+
2161+void call_args(code_info *code, code_ptr fun, uint32_t num_args, ...)
2162+{
2163+ va_list args;
2164+ va_start(args, num_args);
2165+ uint32_t adjust = prep_args(code, num_args, args);
2166+ va_end(args);
2167+ call_raxfallback(code, fun);
2168+ if (adjust) {
2169+ add_ir(code, adjust, RSP, SZ_PTR);
2170+ code->stack_off -= adjust;
2171+ }
2172+}
2173+
2174+void call_args_r(code_info *code, uint8_t fun_reg, uint32_t num_args, ...)
2175+{
2176+ va_list args;
2177+ va_start(args, num_args);
2178+ uint32_t adjust = prep_args(code, num_args, args);
2179+ va_end(args);
2180+ call_r(code, fun_reg);
2181+ if (adjust) {
2182+ add_ir(code, adjust, RSP, SZ_PTR);
2183+ code->stack_off -= adjust;
2184+ }
2185+}
2186+/*
2187+void call_args_abi(code_info *code, code_ptr fun, uint32_t num_args, ...)
2188+{
2189+ va_list args;
2190+ va_start(args, num_args);
2191+ uint32_t adjust = prep_args(code, num_args, args);
2192+ va_end(args);
2193+#ifdef X86_64
2194+ test_ir(code, 8, RSP, SZ_PTR); //check stack alignment
2195+ code_ptr do_adjust_rsp = code->cur + 1;
2196+ jcc(code, CC_NZ, code->cur + 2);
2197+#endif
2198+ call_raxfallback(code, fun);
2199+ if (adjust) {
2200+ add_ir(code, adjust, RSP, SZ_PTR);
2201+ }
2202+#ifdef X86_64
2203+ code_ptr no_adjust_rsp = code->cur + 1;
2204+ jmp(code, code->cur + 2);
2205+ *do_adjust_rsp = code->cur - (do_adjust_rsp+1);
2206+ sub_ir(code, 8, RSP, SZ_PTR);
2207+ call_raxfallback(code, fun);
2208+ add_ir(code, adjust + 8 , RSP, SZ_PTR);
2209+ *no_adjust_rsp = code->cur - (no_adjust_rsp+1);
2210+#endif
2211+}
2212+*/
2213+void save_callee_save_regs(code_info *code)
2214+{
2215+ push_r(code, RBX);
2216+ push_r(code, RBP);
2217+#ifdef X86_64
2218+ push_r(code, R12);
2219+ push_r(code, R13);
2220+ push_r(code, R14);
2221+ push_r(code, R15);
2222+#else
2223+ push_r(code, RDI);
2224+ push_r(code, RSI);
2225+#endif
2226+}
2227+
2228+void restore_callee_save_regs(code_info *code)
2229+{
2230+#ifdef X86_64
2231+ pop_r(code, R15);
2232+ pop_r(code, R14);
2233+ pop_r(code, R13);
2234+ pop_r(code, R12);
2235+#else
2236+ pop_r(code, RSI);
2237+ pop_r(code, RDI);
2238+#endif
2239+ pop_r(code, RBP);
2240+ pop_r(code, RBX);
2241+}
2242+
2243+uint8_t has_modrm(uint8_t prefix, uint8_t opcode)
2244+{
2245+ if (!prefix) {
2246+ switch (opcode)
2247+ {
2248+ case OP_JMP:
2249+ case OP_JMP_BYTE:
2250+ case OP_JCC:
2251+ case OP_CALL:
2252+ case OP_RETN:
2253+ case OP_LOOP:
2254+ case OP_MOV_I8R:
2255+ case OP_MOV_IR:
2256+ case OP_PUSHF:
2257+ case OP_POPF:
2258+ case OP_PUSH:
2259+ case OP_POP:
2260+ case OP_CDQ:
2261+ return 0;
2262+ }
2263+ } else if (prefix == PRE_2BYTE) {
2264+ switch (opcode)
2265+ {
2266+ case OP2_JCC:
2267+ return 0;
2268+ }
2269+ }
2270+ return 1;
2271+}
2272+
2273+uint8_t has_sib(uint8_t mod_rm)
2274+{
2275+ uint8_t mode = mod_rm & 0xC0;
2276+ uint8_t rm = mod_rm & 3;
2277+
2278+ return mode != MODE_REG_DIRECT && rm == RSP;
2279+}
2280+
2281+uint32_t x86_inst_size(code_ptr start)
2282+{
2283+ code_ptr code = start;
2284+ uint8_t cont = 1;
2285+ uint8_t prefix = 0;
2286+ uint8_t op_size = SZ_B;
2287+ uint8_t main_op;
2288+
2289+ while (cont)
2290+ {
2291+ if (*code == PRE_SIZE) {
2292+ op_size = SZ_W;
2293+ } else if (*code == PRE_REX) {
2294+ if (*code & REX_QUAD) {
2295+ op_size = SZ_Q;
2296+ }
2297+ } else if(*code == PRE_2BYTE || *code == PRE_XOP) {
2298+ prefix = *code;
2299+ } else {
2300+ main_op = *code;
2301+ cont = 0;
2302+ }
2303+ code++;
2304+ }
2305+ if (has_modrm(prefix, main_op)) {
2306+ uint8_t mod_rm = *(code++);
2307+ if (has_sib(mod_rm)) {
2308+ //sib takes up a byte, but can't add any additional ones beyond that
2309+ code++;
2310+ }
2311+ uint8_t mode = mod_rm & 0xC0;
2312+ uint8_t rm = mod_rm & 3;
2313+ if (mode == MODE_REG_DISPLACE8) {
2314+ code++;
2315+ } else if (mode == MODE_REG_DISPLACE32 || (mode == MODE_REG_INDIRECT && rm == RBP)) {
2316+ code += 4;
2317+ }
2318+ } else {
2319+ }
2320+
2321+ return code-start;
2322+}
+221,
-0
1@@ -0,0 +1,221 @@
2+/*
3+ Copyright 2013 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#ifndef GEN_X86_H_
8+#define GEN_X86_H_
9+
10+#include <stdint.h>
11+#include "gen.h"
12+
13+enum {
14+ RAX = 0,
15+ RCX,
16+ RDX,
17+ RBX,
18+ RSP,
19+ RBP,
20+ RSI,
21+ RDI,
22+ AH,
23+ CH,
24+ DH,
25+ BH,
26+ R8,
27+ R9,
28+ R10,
29+ R11,
30+ R12,
31+ R13,
32+ R14,
33+ R15
34+};
35+
36+enum {
37+ CC_O = 0,
38+ CC_NO,
39+ CC_C,
40+ CC_B = CC_C,
41+ CC_NC,
42+ CC_NB = CC_NC,
43+ CC_Z,
44+ CC_NZ,
45+ CC_BE,
46+ CC_A,
47+ CC_S,
48+ CC_NS,
49+ CC_P,
50+ CC_NP,
51+ CC_L,
52+ CC_GE,
53+ CC_LE,
54+ CC_G
55+};
56+
57+enum {
58+ SZ_B = 0,
59+ SZ_W,
60+ SZ_D,
61+ SZ_Q
62+};
63+
64+#ifdef X86_64
65+#define SZ_PTR SZ_Q
66+#define MAX_INST_LEN 14
67+#else
68+#define SZ_PTR SZ_D
69+#define MAX_INST_LEN 11
70+#endif
71+
72+enum {
73+ MODE_REG_INDIRECT = 0,
74+ MODE_REG_INDEXED = 4,
75+ MODE_REG_DISPLACE8 = 0x40,
76+ MODE_REG_INDEXED_DISPLACE8 = 0x44,
77+ MODE_REG_DISPLACE32 = 0x80,
78+ MODE_REG_INDEXED_DIPSLACE32 = 0x84,
79+ MODE_REG_DIRECT = 0xC0,
80+//"phony" mode
81+ MODE_IMMED = 0xFF
82+};
83+
84+void rol_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size);
85+void ror_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size);
86+void rcl_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size);
87+void rcr_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size);
88+void shl_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size);
89+void shr_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size);
90+void sar_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size);
91+void rol_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size);
92+void ror_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size);
93+void rcl_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size);
94+void rcr_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size);
95+void shl_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size);
96+void shr_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size);
97+void sar_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size);
98+void rol_clr(code_info *code, uint8_t dst, uint8_t size);
99+void ror_clr(code_info *code, uint8_t dst, uint8_t size);
100+void rcl_clr(code_info *code, uint8_t dst, uint8_t size);
101+void rcr_clr(code_info *code, uint8_t dst, uint8_t size);
102+void shl_clr(code_info *code, uint8_t dst, uint8_t size);
103+void shr_clr(code_info *code, uint8_t dst, uint8_t size);
104+void sar_clr(code_info *code, uint8_t dst, uint8_t size);
105+void rol_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size);
106+void ror_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size);
107+void rcl_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size);
108+void rcr_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size);
109+void shl_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size);
110+void shr_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size);
111+void sar_clrdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size);
112+void add_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size);
113+void adc_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size);
114+void or_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size);
115+void xor_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size);
116+void and_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size);
117+void sub_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size);
118+void sbb_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size);
119+void cmp_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size);
120+void add_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size);
121+void adc_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size);
122+void or_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size);
123+void xor_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size);
124+void and_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size);
125+void sub_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size);
126+void sbb_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size);
127+void cmp_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size);
128+void add_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size);
129+void adc_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size);
130+void or_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size);
131+void xor_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size);
132+void and_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size);
133+void sub_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size);
134+void sbb_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size);
135+void cmp_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size);
136+void add_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size);
137+void adc_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size);
138+void add_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size);
139+void adc_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size);
140+void or_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size);
141+void or_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size);
142+void xor_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size);
143+void xor_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size);
144+void and_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size);
145+void and_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size);
146+void sub_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size);
147+void sub_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size);
148+void sbb_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size);
149+void sbb_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size);
150+void cmp_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size);
151+void cmp_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size);
152+void imul_irr(code_info *code, int32_t val, uint8_t src, uint8_t dst, uint8_t size);
153+void imul_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size);
154+void imul_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size);
155+void imul_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size);
156+void not_r(code_info *code, uint8_t dst, uint8_t size);
157+void neg_r(code_info *code, uint8_t dst, uint8_t size);
158+void not_rdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size);
159+void neg_rdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size);
160+void mul_r(code_info *code, uint8_t dst, uint8_t size);
161+void imul_r(code_info *code, uint8_t dst, uint8_t size);
162+void div_r(code_info *code, uint8_t dst, uint8_t size);
163+void idiv_r(code_info *code, uint8_t dst, uint8_t size);
164+void mul_rdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size);
165+void imul_rdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size);
166+void div_rdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size);
167+void idiv_rdisp(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size);
168+void test_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size);
169+void test_ir(code_info *code, int32_t val, uint8_t dst, uint8_t size);
170+void test_irdisp(code_info *code, int32_t val, uint8_t dst_base, int32_t disp, uint8_t size);
171+void test_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size);
172+void test_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size);
173+void mov_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size);
174+void mov_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t disp, uint8_t size);
175+void mov_rdispr(code_info *code, uint8_t src_base, int32_t disp, uint8_t dst, uint8_t size);
176+void mov_rrindex(code_info *code, uint8_t src, uint8_t dst_base, uint8_t dst_index, uint8_t scale, uint8_t size);
177+void mov_rindexr(code_info *code, uint8_t src_base, uint8_t src_index, uint8_t scale, uint8_t dst, uint8_t size);
178+void mov_rrind(code_info *code, uint8_t src, uint8_t dst, uint8_t size);
179+void mov_rindr(code_info *code, uint8_t src, uint8_t dst, uint8_t size);
180+void mov_ir(code_info *code, int64_t val, uint8_t dst, uint8_t size);
181+void mov_irdisp(code_info *code, int32_t val, uint8_t dst, int32_t disp, uint8_t size);
182+void mov_irind(code_info *code, int32_t val, uint8_t dst, uint8_t size);
183+void movsx_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t src_size, uint8_t size);
184+void movsx_rdispr(code_info *code, uint8_t src, int32_t disp, uint8_t dst, uint8_t src_size, uint8_t size);
185+void movzx_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t src_size, uint8_t size);
186+void movzx_rdispr(code_info *code, uint8_t src, int32_t disp, uint8_t dst, uint8_t src_size, uint8_t size);
187+void xchg_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size);
188+void pushf(code_info *code);
189+void popf(code_info *code);
190+void push_r(code_info *code, uint8_t reg);
191+void push_rdisp(code_info *code, uint8_t base, int32_t disp);
192+void pop_r(code_info *code, uint8_t reg);
193+void pop_rind(code_info *code, uint8_t reg);
194+void setcc_r(code_info *code, uint8_t cc, uint8_t dst);
195+void setcc_rind(code_info *code, uint8_t cc, uint8_t dst);
196+void setcc_rdisp(code_info *code, uint8_t cc, uint8_t dst, int32_t disp);
197+void bt_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size);
198+void bt_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t dst_disp, uint8_t size);
199+void bt_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size);
200+void bt_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t dst_disp, uint8_t size);
201+void bts_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size);
202+void bts_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t dst_disp, uint8_t size);
203+void bts_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size);
204+void bts_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t dst_disp, uint8_t size);
205+void btr_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size);
206+void btr_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t dst_disp, uint8_t size);
207+void btr_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size);
208+void btr_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t dst_disp, uint8_t size);
209+void btc_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size);
210+void btc_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t dst_disp, uint8_t size);
211+void btc_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size);
212+void btc_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t dst_disp, uint8_t size);
213+void jcc(code_info *code, uint8_t cc, code_ptr dest);
214+void jmp_rind(code_info *code, uint8_t dst);
215+void call_noalign(code_info *code, code_ptr fun);
216+void call_r(code_info *code, uint8_t dst);
217+void retn(code_info *code);
218+void cdq(code_info *code);
219+void loop(code_info *code, code_ptr dst);
220+uint8_t is_mov_ir(code_ptr inst);
221+
222+#endif //GEN_X86_H_
+1507,
-0
1@@ -0,0 +1,1507 @@
2+/*
3+ Copyright 2013-2016 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#include "genesis.h"
8+#include "blastem.h"
9+#include "nor.h"
10+#include <stdlib.h>
11+#include <ctype.h>
12+#include <time.h>
13+#include <string.h>
14+#include "render.h"
15+#include "gst.h"
16+#include "util.h"
17+#include "debug.h"
18+#include "gdb_remote.h"
19+#include "saves.h"
20+#include "bindings.h"
21+#include "jcart.h"
22+#define MCLKS_NTSC 53693175
23+#define MCLKS_PAL 53203395
24+
25+uint32_t MCLKS_PER_68K;
26+#define MCLKS_PER_YM 7
27+#define MCLKS_PER_Z80 15
28+#define MCLKS_PER_PSG (MCLKS_PER_Z80*16)
29+#define Z80_INT_PULSE_MCLKS 2573 //measured value is ~171.5 Z80 clocks
30+#define DEFAULT_SYNC_INTERVAL MCLKS_LINE
31+#define DEFAULT_LOWPASS_CUTOFF 3390
32+
33+//TODO: Figure out the exact value for this
34+#define LINES_NTSC 262
35+#define LINES_PAL 313
36+
37+#define MAX_SOUND_CYCLES 100000
38+
39+#define Z80_CYCLE current_cycle
40+#define Z80_OPTS options
41+
42+void genesis_serialize(genesis_context *gen, serialize_buffer *buf, uint32_t m68k_pc)
43+{
44+ start_section(buf, SECTION_68000);
45+ m68k_serialize(gen->m68k, m68k_pc, buf);
46+ end_section(buf);
47+
48+ start_section(buf, SECTION_Z80);
49+ z80_serialize(gen->z80, buf);
50+ end_section(buf);
51+
52+ start_section(buf, SECTION_VDP);
53+ vdp_serialize(gen->vdp, buf);
54+ end_section(buf);
55+
56+ start_section(buf, SECTION_YM2612);
57+ ym_serialize(gen->ym, buf);
58+ end_section(buf);
59+
60+ start_section(buf, SECTION_PSG);
61+ psg_serialize(gen->psg, buf);
62+ end_section(buf);
63+
64+ start_section(buf, SECTION_GEN_BUS_ARBITER);
65+ save_int8(buf, gen->z80->reset);
66+ save_int8(buf, gen->z80->busreq);
67+ save_int16(buf, gen->z80_bank_reg);
68+ end_section(buf);
69+
70+ start_section(buf, SECTION_SEGA_IO_1);
71+ io_serialize(gen->io.ports, buf);
72+ end_section(buf);
73+
74+ start_section(buf, SECTION_SEGA_IO_2);
75+ io_serialize(gen->io.ports + 1, buf);
76+ end_section(buf);
77+
78+ start_section(buf, SECTION_SEGA_IO_EXT);
79+ io_serialize(gen->io.ports + 2, buf);
80+ end_section(buf);
81+
82+ start_section(buf, SECTION_MAIN_RAM);
83+ save_int8(buf, RAM_WORDS * 2 / 1024);
84+ save_buffer16(buf, gen->work_ram, RAM_WORDS);
85+ end_section(buf);
86+
87+ start_section(buf, SECTION_SOUND_RAM);
88+ save_int8(buf, Z80_RAM_BYTES / 1024);
89+ save_buffer8(buf, gen->zram, Z80_RAM_BYTES);
90+ end_section(buf);
91+
92+ cart_serialize(&gen->header, buf);
93+}
94+
95+static uint8_t *serialize(system_header *sys, size_t *size_out)
96+{
97+ genesis_context *gen = (genesis_context *)sys;
98+ uint32_t address;
99+ if (gen->m68k->resume_pc) {
100+ gen->m68k->target_cycle = gen->m68k->current_cycle;
101+ gen->header.save_state = SERIALIZE_SLOT+1;
102+ resume_68k(gen->m68k);
103+ if (size_out) {
104+ *size_out = gen->serialize_size;
105+ }
106+ return gen->serialize_tmp;
107+ } else {
108+ serialize_buffer state;
109+ init_serialize(&state);
110+ uint32_t address = read_word(4, (void **)gen->m68k->mem_pointers, &gen->m68k->options->gen, gen->m68k) << 16;
111+ address |= read_word(6, (void **)gen->m68k->mem_pointers, &gen->m68k->options->gen, gen->m68k);
112+ genesis_serialize(gen, &state, address);
113+ if (size_out) {
114+ *size_out = state.size;
115+ }
116+ return state.data;
117+ }
118+}
119+
120+static void ram_deserialize(deserialize_buffer *buf, void *vgen)
121+{
122+ genesis_context *gen = vgen;
123+ uint32_t ram_size = load_int8(buf) * 1024 / 2;
124+ if (ram_size > RAM_WORDS) {
125+ fatal_error("State has a RAM size of %d bytes", ram_size * 2);
126+ }
127+ load_buffer16(buf, gen->work_ram, ram_size);
128+ m68k_invalidate_code_range(gen->m68k, 0xE00000, 0x1000000);
129+}
130+
131+static void zram_deserialize(deserialize_buffer *buf, void *vgen)
132+{
133+ genesis_context *gen = vgen;
134+ uint32_t ram_size = load_int8(buf) * 1024;
135+ if (ram_size > Z80_RAM_BYTES) {
136+ fatal_error("State has a Z80 RAM size of %d bytes", ram_size);
137+ }
138+ load_buffer8(buf, gen->zram, ram_size);
139+ z80_invalidate_code_range(gen->z80, 0, 0x4000);
140+}
141+
142+static void update_z80_bank_pointer(genesis_context *gen)
143+{
144+ if (gen->z80_bank_reg < 0x140) {
145+ gen->z80->mem_pointers[1] = get_native_pointer(gen->z80_bank_reg << 15, (void **)gen->m68k->mem_pointers, &gen->m68k->options->gen);
146+ } else {
147+ gen->z80->mem_pointers[1] = NULL;
148+ }
149+ z80_invalidate_code_range(gen->z80, 0x8000, 0xFFFF);
150+}
151+
152+static void bus_arbiter_deserialize(deserialize_buffer *buf, void *vgen)
153+{
154+ genesis_context *gen = vgen;
155+ gen->z80->reset = load_int8(buf);
156+ gen->z80->busreq = load_int8(buf);
157+ gen->z80_bank_reg = load_int16(buf) & 0x1FF;
158+}
159+
160+static void adjust_int_cycle(m68k_context * context, vdp_context * v_context);
161+void genesis_deserialize(deserialize_buffer *buf, genesis_context *gen)
162+{
163+ register_section_handler(buf, (section_handler){.fun = m68k_deserialize, .data = gen->m68k}, SECTION_68000);
164+ register_section_handler(buf, (section_handler){.fun = z80_deserialize, .data = gen->z80}, SECTION_Z80);
165+ register_section_handler(buf, (section_handler){.fun = vdp_deserialize, .data = gen->vdp}, SECTION_VDP);
166+ register_section_handler(buf, (section_handler){.fun = ym_deserialize, .data = gen->ym}, SECTION_YM2612);
167+ register_section_handler(buf, (section_handler){.fun = psg_deserialize, .data = gen->psg}, SECTION_PSG);
168+ register_section_handler(buf, (section_handler){.fun = bus_arbiter_deserialize, .data = gen}, SECTION_GEN_BUS_ARBITER);
169+ register_section_handler(buf, (section_handler){.fun = io_deserialize, .data = gen->io.ports}, SECTION_SEGA_IO_1);
170+ register_section_handler(buf, (section_handler){.fun = io_deserialize, .data = gen->io.ports + 1}, SECTION_SEGA_IO_2);
171+ register_section_handler(buf, (section_handler){.fun = io_deserialize, .data = gen->io.ports + 2}, SECTION_SEGA_IO_EXT);
172+ register_section_handler(buf, (section_handler){.fun = ram_deserialize, .data = gen}, SECTION_MAIN_RAM);
173+ register_section_handler(buf, (section_handler){.fun = zram_deserialize, .data = gen}, SECTION_SOUND_RAM);
174+ register_section_handler(buf, (section_handler){.fun = cart_deserialize, .data = gen}, SECTION_MAPPER);
175+ while (buf->cur_pos < buf->size)
176+ {
177+ load_section(buf);
178+ }
179+ update_z80_bank_pointer(gen);
180+ adjust_int_cycle(gen->m68k, gen->vdp);
181+ free(buf->handlers);
182+ buf->handlers = NULL;
183+}
184+
185+#include "m68k_internal.h" //needed for get_native_address_trans, should be eliminated once handling of PC is cleaned up
186+static void deserialize(system_header *sys, uint8_t *data, size_t size)
187+{
188+ genesis_context *gen = (genesis_context *)sys;
189+ deserialize_buffer buffer;
190+ init_deserialize(&buffer, data, size);
191+ genesis_deserialize(&buffer, gen);
192+ //HACK: Fix this once PC/IR is represented in a better way in 68K core
193+ gen->m68k->resume_pc = get_native_address_trans(gen->m68k, gen->m68k->last_prefetch_address);
194+}
195+
196+uint16_t read_dma_value(uint32_t address)
197+{
198+ genesis_context *genesis = (genesis_context *)current_system;
199+ //TODO: Figure out what happens when you try to DMA from weird adresses like IO or banked Z80 area
200+ if ((address >= 0xA00000 && address < 0xB00000) || (address >= 0xC00000 && address <= 0xE00000)) {
201+ return 0;
202+ }
203+
204+ //addresses here are word addresses (i.e. bit 0 corresponds to A1), so no need to do multiply by 2
205+ return read_word(address * 2, (void **)genesis->m68k->mem_pointers, &genesis->m68k->options->gen, genesis->m68k);
206+}
207+
208+static uint16_t get_open_bus_value(system_header *system)
209+{
210+ genesis_context *genesis = (genesis_context *)system;
211+ return read_dma_value(genesis->m68k->last_prefetch_address/2);
212+}
213+
214+static void adjust_int_cycle(m68k_context * context, vdp_context * v_context)
215+{
216+ //static int old_int_cycle = CYCLE_NEVER;
217+ genesis_context *gen = context->system;
218+ if (context->sync_cycle - context->current_cycle > gen->max_cycles) {
219+ context->sync_cycle = context->current_cycle + gen->max_cycles;
220+ }
221+ context->int_cycle = CYCLE_NEVER;
222+ if ((context->status & 0x7) < 6) {
223+ uint32_t next_vint = vdp_next_vint(v_context);
224+ if (next_vint != CYCLE_NEVER) {
225+ context->int_cycle = next_vint;
226+ context->int_num = 6;
227+ }
228+ if ((context->status & 0x7) < 4) {
229+ uint32_t next_hint = vdp_next_hint(v_context);
230+ if (next_hint != CYCLE_NEVER) {
231+ next_hint = next_hint < context->current_cycle ? context->current_cycle : next_hint;
232+ if (next_hint < context->int_cycle) {
233+ context->int_cycle = next_hint;
234+ context->int_num = 4;
235+
236+ }
237+ }
238+ }
239+ }
240+ if (context->int_cycle > context->current_cycle && context->int_pending == INT_PENDING_SR_CHANGE) {
241+ context->int_pending = INT_PENDING_NONE;
242+ }
243+ /*if (context->int_cycle != old_int_cycle) {
244+ printf("int cycle changed to: %d, level: %d @ %d(%d), frame: %d, vcounter: %d, hslot: %d, mask: %d, hint_counter: %d\n", context->int_cycle, context->int_num, v_context->cycles, context->current_cycle, v_context->frame, v_context->vcounter, v_context->hslot, context->status & 0x7, v_context->hint_counter);
245+ old_int_cycle = context->int_cycle;
246+ }*/
247+
248+ if (context->status & M68K_STATUS_TRACE || context->trace_pending) {
249+ context->target_cycle = context->current_cycle;
250+ return;
251+ }
252+
253+ context->target_cycle = context->int_cycle < context->sync_cycle ? context->int_cycle : context->sync_cycle;
254+ if (context->should_return) {
255+ context->target_cycle = context->current_cycle;
256+ } else if (context->target_cycle < context->current_cycle) {
257+ //Changes to SR can result in an interrupt cycle that's in the past
258+ //This can cause issues with the implementation of STOP though
259+ context->target_cycle = context->current_cycle;
260+ }
261+ if (context->target_cycle == context->int_cycle) {
262+ //Currently delays from Z80 access and refresh are applied only when we sync
263+ //this can cause extra latency when it comes to interrupts
264+ //to prevent this code forces some extra synchronization in the period immediately before an interrupt
265+ if ((context->target_cycle - context->current_cycle) > gen->int_latency_prev1) {
266+ context->target_cycle = context->sync_cycle = context->int_cycle - gen->int_latency_prev1;
267+ } else if ((context->target_cycle - context->current_cycle) > gen->int_latency_prev2) {
268+ context->target_cycle = context->sync_cycle = context->int_cycle - gen->int_latency_prev2;
269+ } else {
270+ context->target_cycle = context->sync_cycle = context->current_cycle;
271+ }
272+
273+ }
274+ /*printf("Cyc: %d, Trgt: %d, Int Cyc: %d, Int: %d, Mask: %X, V: %d, H: %d, HICount: %d, HReg: %d, Line: %d\n",
275+ context->current_cycle, context->target_cycle, context->int_cycle, context->int_num, (context->status & 0x7),
276+ v_context->regs[REG_MODE_2] & 0x20, v_context->regs[REG_MODE_1] & 0x10, v_context->hint_counter, v_context->regs[REG_HINT], v_context->cycles / MCLKS_LINE);*/
277+}
278+
279+//#define DO_DEBUG_PRINT
280+#ifdef DO_DEBUG_PRINT
281+#define dprintf printf
282+#define dputs puts
283+#else
284+#define dprintf
285+#define dputs
286+#endif
287+
288+static void z80_next_int_pulse(z80_context * z_context)
289+{
290+ genesis_context * gen = z_context->system;
291+ z_context->int_pulse_start = vdp_next_vint_z80(gen->vdp);
292+ z_context->int_pulse_end = z_context->int_pulse_start + Z80_INT_PULSE_MCLKS;
293+ z_context->im2_vector = 0xFF;
294+}
295+
296+static void sync_z80(z80_context * z_context, uint32_t mclks)
297+{
298+ if (z80_enabled) {
299+ z80_run(z_context, mclks);
300+ } else
301+ {
302+ z_context->Z80_CYCLE = mclks;
303+ }
304+}
305+
306+static void sync_sound(genesis_context * gen, uint32_t target)
307+{
308+ //printf("YM | Cycle: %d, bpos: %d, PSG | Cycle: %d, bpos: %d\n", gen->ym->current_cycle, gen->ym->buffer_pos, gen->psg->cycles, gen->psg->buffer_pos * 2);
309+ while (target > gen->psg->cycles && target - gen->psg->cycles > MAX_SOUND_CYCLES) {
310+ uint32_t cur_target = gen->psg->cycles + MAX_SOUND_CYCLES;
311+ //printf("Running PSG to cycle %d\n", cur_target);
312+ psg_run(gen->psg, cur_target);
313+ //printf("Running YM-2612 to cycle %d\n", cur_target);
314+ ym_run(gen->ym, cur_target);
315+ }
316+ psg_run(gen->psg, target);
317+ ym_run(gen->ym, target);
318+
319+ //printf("Target: %d, YM bufferpos: %d, PSG bufferpos: %d\n", target, gen->ym->buffer_pos, gen->psg->buffer_pos * 2);
320+}
321+
322+//TODO: move this inside the system context
323+static uint32_t last_frame_num;
324+
325+//My refresh emulation isn't currently good enough and causes more problems than it solves
326+#define REFRESH_EMULATION
327+#ifdef REFRESH_EMULATION
328+#define REFRESH_INTERVAL 128
329+#define REFRESH_DELAY 2
330+uint32_t last_sync_cycle;
331+uint32_t refresh_counter;
332+#endif
333+
334+#include <limits.h>
335+#define ADJUST_BUFFER (8*MCLKS_LINE*313)
336+#define MAX_NO_ADJUST (UINT_MAX-ADJUST_BUFFER)
337+
338+m68k_context * sync_components(m68k_context * context, uint32_t address)
339+{
340+ genesis_context * gen = context->system;
341+ vdp_context * v_context = gen->vdp;
342+ z80_context * z_context = gen->z80;
343+#ifdef REFRESH_EMULATION
344+ //lame estimation of refresh cycle delay
345+ refresh_counter += context->current_cycle - last_sync_cycle;
346+ if (!gen->bus_busy) {
347+ context->current_cycle += REFRESH_DELAY * MCLKS_PER_68K * (refresh_counter / (MCLKS_PER_68K * REFRESH_INTERVAL));
348+ }
349+ refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL);
350+#endif
351+
352+ uint32_t mclks = context->current_cycle;
353+ sync_z80(z_context, mclks);
354+ sync_sound(gen, mclks);
355+ vdp_run_context(v_context, mclks);
356+ if (mclks >= gen->reset_cycle) {
357+ gen->reset_requested = 1;
358+ context->should_return = 1;
359+ gen->reset_cycle = CYCLE_NEVER;
360+ }
361+ if (v_context->frame != last_frame_num) {
362+ //printf("reached frame end %d | MCLK Cycles: %d, Target: %d, VDP cycles: %d, vcounter: %d, hslot: %d\n", last_frame_num, mclks, gen->frame_end, v_context->cycles, v_context->vcounter, v_context->hslot);
363+ last_frame_num = v_context->frame;
364+
365+ if(exit_after){
366+ --exit_after;
367+ if (!exit_after) {
368+ exit(0);
369+ }
370+ }
371+ if (context->current_cycle > MAX_NO_ADJUST) {
372+ uint32_t deduction = mclks - ADJUST_BUFFER;
373+ vdp_adjust_cycles(v_context, deduction);
374+ io_adjust_cycles(gen->io.ports, context->current_cycle, deduction);
375+ io_adjust_cycles(gen->io.ports+1, context->current_cycle, deduction);
376+ io_adjust_cycles(gen->io.ports+2, context->current_cycle, deduction);
377+ if (gen->mapper_type == MAPPER_JCART) {
378+ jcart_adjust_cycles(gen, deduction);
379+ }
380+ context->current_cycle -= deduction;
381+ z80_adjust_cycles(z_context, deduction);
382+ gen->ym->current_cycle -= deduction;
383+ gen->psg->cycles -= deduction;
384+ if (gen->ym->write_cycle != CYCLE_NEVER) {
385+ gen->ym->write_cycle = gen->ym->write_cycle >= deduction ? gen->ym->write_cycle - deduction : 0;
386+ }
387+ if (gen->reset_cycle != CYCLE_NEVER) {
388+ gen->reset_cycle -= deduction;
389+ }
390+ }
391+ }
392+ gen->frame_end = vdp_cycles_to_frame_end(v_context);
393+ context->sync_cycle = gen->frame_end;
394+ //printf("Set sync cycle to: %d @ %d, vcounter: %d, hslot: %d\n", context->sync_cycle, context->current_cycle, v_context->vcounter, v_context->hslot);
395+ if (context->int_ack) {
396+ //printf("acknowledging %d @ %d:%d, vcounter: %d, hslot: %d\n", context->int_ack, context->current_cycle, v_context->cycles, v_context->vcounter, v_context->hslot);
397+ vdp_int_ack(v_context);
398+ context->int_ack = 0;
399+ }
400+ if (!address && (gen->header.enter_debugger || gen->header.save_state)) {
401+ context->sync_cycle = context->current_cycle + 1;
402+ }
403+ adjust_int_cycle(context, v_context);
404+ if (gen->reset_cycle < context->target_cycle) {
405+ context->target_cycle = gen->reset_cycle;
406+ }
407+ if (address) {
408+ if (gen->header.enter_debugger) {
409+ gen->header.enter_debugger = 0;
410+ debugger(context, address);
411+ }
412+ if (gen->header.save_state && (z_context->pc || !z_context->native_pc || z_context->reset || !z_context->busreq)) {
413+ uint8_t slot = gen->header.save_state - 1;
414+ gen->header.save_state = 0;
415+ if (z_context->native_pc && !z_context->reset) {
416+ //advance Z80 core to the start of an instruction
417+ while (!z_context->pc)
418+ {
419+ sync_z80(z_context, z_context->current_cycle + MCLKS_PER_Z80);
420+ }
421+ }
422+ char *save_path = slot == SERIALIZE_SLOT ? NULL : get_slot_name(&gen->header, slot, use_native_states ? "state" : "gst");
423+ if (use_native_states || slot == SERIALIZE_SLOT) {
424+ serialize_buffer state;
425+ init_serialize(&state);
426+ genesis_serialize(gen, &state, address);
427+ if (slot == SERIALIZE_SLOT) {
428+ gen->serialize_tmp = state.data;
429+ gen->serialize_size = state.size;
430+ context->sync_cycle = context->current_cycle;
431+ context->should_return = 1;
432+ } else {
433+ save_to_file(&state, save_path);
434+ free(state.data);
435+ }
436+ } else {
437+ save_gst(gen, save_path, address);
438+ }
439+ printf("Saved state to %s\n", save_path);
440+ free(save_path);
441+ } else if(gen->header.save_state) {
442+ context->sync_cycle = context->current_cycle + 1;
443+ }
444+ }
445+#ifdef REFRESH_EMULATION
446+ last_sync_cycle = context->current_cycle;
447+#endif
448+ return context;
449+}
450+
451+static m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_t value)
452+{
453+ if (vdp_port & 0x2700E0) {
454+ fatal_error("machine freeze due to write to address %X\n", 0xC00000 | vdp_port);
455+ }
456+ vdp_port &= 0x1F;
457+ //printf("vdp_port write: %X, value: %X, cycle: %d\n", vdp_port, value, context->current_cycle);
458+#ifdef REFRESH_EMULATION
459+ //do refresh check here so we can avoid adding a penalty for a refresh that happens during a VDP access
460+ refresh_counter += context->current_cycle - 4*MCLKS_PER_68K - last_sync_cycle;
461+ context->current_cycle += REFRESH_DELAY * MCLKS_PER_68K * (refresh_counter / (MCLKS_PER_68K * REFRESH_INTERVAL));
462+ refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL);
463+ last_sync_cycle = context->current_cycle;
464+#endif
465+ sync_components(context, 0);
466+ genesis_context * gen = context->system;
467+ vdp_context *v_context = gen->vdp;
468+ uint32_t before_cycle = v_context->cycles;
469+ if (vdp_port < 0x10) {
470+ int blocked;
471+ if (vdp_port < 4) {
472+ while (vdp_data_port_write(v_context, value) < 0) {
473+ while(v_context->flags & FLAG_DMA_RUN) {
474+ vdp_run_dma_done(v_context, gen->frame_end);
475+ if (v_context->cycles >= gen->frame_end) {
476+ uint32_t cycle_diff = v_context->cycles - context->current_cycle;
477+ uint32_t m68k_cycle_diff = (cycle_diff / MCLKS_PER_68K) * MCLKS_PER_68K;
478+ if (m68k_cycle_diff < cycle_diff) {
479+ m68k_cycle_diff += MCLKS_PER_68K;
480+ }
481+ context->current_cycle += m68k_cycle_diff;
482+ gen->bus_busy = 1;
483+ sync_components(context, 0);
484+ gen->bus_busy = 0;
485+ }
486+ }
487+ //context->current_cycle = v_context->cycles;
488+ }
489+ } else if(vdp_port < 8) {
490+ vdp_run_context_full(v_context, context->current_cycle);
491+ before_cycle = v_context->cycles;
492+ blocked = vdp_control_port_write(v_context, value);
493+ if (blocked) {
494+ while (blocked) {
495+ while(v_context->flags & FLAG_DMA_RUN) {
496+ vdp_run_dma_done(v_context, gen->frame_end);
497+ if (v_context->cycles >= gen->frame_end) {
498+ uint32_t cycle_diff = v_context->cycles - context->current_cycle;
499+ uint32_t m68k_cycle_diff = (cycle_diff / MCLKS_PER_68K) * MCLKS_PER_68K;
500+ if (m68k_cycle_diff < cycle_diff) {
501+ m68k_cycle_diff += MCLKS_PER_68K;
502+ }
503+ context->current_cycle += m68k_cycle_diff;
504+ gen->bus_busy = 1;
505+ sync_components(context, 0);
506+ gen->bus_busy = 0;
507+ }
508+ }
509+
510+ if (blocked < 0) {
511+ blocked = vdp_control_port_write(v_context, value);
512+ } else {
513+ blocked = 0;
514+ }
515+ }
516+ } else {
517+ context->sync_cycle = gen->frame_end = vdp_cycles_to_frame_end(v_context);
518+ //printf("Set sync cycle to: %d @ %d, vcounter: %d, hslot: %d\n", context->sync_cycle, context->current_cycle, v_context->vcounter, v_context->hslot);
519+ adjust_int_cycle(context, v_context);
520+ }
521+ } else {
522+ fatal_error("Illegal write to HV Counter port %X\n", vdp_port);
523+ }
524+ if (v_context->cycles != before_cycle) {
525+ //printf("68K paused for %d (%d) cycles at cycle %d (%d) for write\n", v_context->cycles - context->current_cycle, v_context->cycles - before_cycle, context->current_cycle, before_cycle);
526+ uint32_t cycle_diff = v_context->cycles - context->current_cycle;
527+ uint32_t m68k_cycle_diff = (cycle_diff / MCLKS_PER_68K) * MCLKS_PER_68K;
528+ if (m68k_cycle_diff < cycle_diff) {
529+ m68k_cycle_diff += MCLKS_PER_68K;
530+ }
531+ context->current_cycle += m68k_cycle_diff;
532+ //Lock the Z80 out of the bus until the VDP access is complete
533+ gen->bus_busy = 1;
534+ sync_z80(gen->z80, v_context->cycles);
535+ gen->bus_busy = 0;
536+ }
537+ } else if (vdp_port < 0x18) {
538+ psg_write(gen->psg, value);
539+ } else {
540+ vdp_test_port_write(gen->vdp, value);
541+ }
542+#ifdef REFRESH_EMULATION
543+ last_sync_cycle -= 4;
544+ //refresh may have happened while we were waiting on the VDP,
545+ //so advance refresh_counter but don't add any delays
546+ if (vdp_port >= 4 && vdp_port < 8 && v_context->cycles != before_cycle) {
547+ refresh_counter = 0;
548+ } else {
549+ refresh_counter += (context->current_cycle - last_sync_cycle);
550+ refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL);
551+ }
552+ last_sync_cycle = context->current_cycle;
553+#endif
554+ return context;
555+}
556+
557+static m68k_context * vdp_port_write_b(uint32_t vdp_port, m68k_context * context, uint8_t value)
558+{
559+ return vdp_port_write(vdp_port, context, vdp_port < 0x10 ? value | value << 8 : ((vdp_port & 1) ? value : 0));
560+}
561+
562+static void * z80_vdp_port_write(uint32_t vdp_port, void * vcontext, uint8_t value)
563+{
564+ z80_context * context = vcontext;
565+ genesis_context * gen = context->system;
566+ vdp_port &= 0xFF;
567+ if (vdp_port & 0xE0) {
568+ fatal_error("machine freeze due to write to Z80 address %X\n", 0x7F00 | vdp_port);
569+ }
570+ if (vdp_port < 0x10) {
571+ //These probably won't currently interact well with the 68K accessing the VDP
572+ if (vdp_port < 4) {
573+ vdp_run_context(gen->vdp, context->Z80_CYCLE);
574+ vdp_data_port_write(gen->vdp, value << 8 | value);
575+ } else if (vdp_port < 8) {
576+ vdp_run_context_full(gen->vdp, context->Z80_CYCLE);
577+ vdp_control_port_write(gen->vdp, value << 8 | value);
578+ } else {
579+ fatal_error("Illegal write to HV Counter port %X\n", vdp_port);
580+ }
581+ } else if (vdp_port < 0x18) {
582+ sync_sound(gen, context->Z80_CYCLE);
583+ psg_write(gen->psg, value);
584+ } else {
585+ vdp_test_port_write(gen->vdp, value);
586+ }
587+ return context;
588+}
589+
590+static uint16_t vdp_port_read(uint32_t vdp_port, m68k_context * context)
591+{
592+ if (vdp_port & 0x2700E0) {
593+ fatal_error("machine freeze due to read from address %X\n", 0xC00000 | vdp_port);
594+ }
595+ vdp_port &= 0x1F;
596+ uint16_t value;
597+#ifdef REFRESH_EMULATION
598+ //do refresh check here so we can avoid adding a penalty for a refresh that happens during a VDP access
599+ refresh_counter += context->current_cycle - 4*MCLKS_PER_68K - last_sync_cycle;
600+ context->current_cycle += REFRESH_DELAY * MCLKS_PER_68K * (refresh_counter / (MCLKS_PER_68K * REFRESH_INTERVAL));
601+ refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL);
602+ last_sync_cycle = context->current_cycle;
603+#endif
604+ sync_components(context, 0);
605+ genesis_context *gen = context->system;
606+ vdp_context * v_context = gen->vdp;
607+ uint32_t before_cycle = v_context->cycles;
608+ if (vdp_port < 0x10) {
609+ if (vdp_port < 4) {
610+ value = vdp_data_port_read(v_context);
611+ } else if(vdp_port < 8) {
612+ value = vdp_control_port_read(v_context);
613+ } else {
614+ value = vdp_hv_counter_read(v_context);
615+ //printf("HV Counter: %X at cycle %d\n", value, v_context->cycles);
616+ }
617+ } else if (vdp_port < 0x18){
618+ fatal_error("Illegal read from PSG port %X\n", vdp_port);
619+ } else {
620+ value = vdp_test_port_read(v_context);
621+ }
622+ if (v_context->cycles != before_cycle) {
623+ //printf("68K paused for %d (%d) cycles at cycle %d (%d) for read\n", v_context->cycles - context->current_cycle, v_context->cycles - before_cycle, context->current_cycle, before_cycle);
624+ context->current_cycle = v_context->cycles;
625+ //Lock the Z80 out of the bus until the VDP access is complete
626+ genesis_context *gen = context->system;
627+ gen->bus_busy = 1;
628+ sync_z80(gen->z80, v_context->cycles);
629+ gen->bus_busy = 0;
630+ }
631+#ifdef REFRESH_EMULATION
632+ last_sync_cycle -= 4;
633+ //refresh may have happened while we were waiting on the VDP,
634+ //so advance refresh_counter but don't add any delays
635+ refresh_counter += (context->current_cycle - last_sync_cycle);
636+ refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL);
637+ last_sync_cycle = context->current_cycle;
638+#endif
639+ return value;
640+}
641+
642+static uint8_t vdp_port_read_b(uint32_t vdp_port, m68k_context * context)
643+{
644+ uint16_t value = vdp_port_read(vdp_port, context);
645+ if (vdp_port & 1) {
646+ return value;
647+ } else {
648+ return value >> 8;
649+ }
650+}
651+
652+static uint8_t z80_vdp_port_read(uint32_t vdp_port, void * vcontext)
653+{
654+ z80_context * context = vcontext;
655+ if (vdp_port & 0xE0) {
656+ fatal_error("machine freeze due to read from Z80 address %X\n", 0x7F00 | vdp_port);
657+ }
658+ genesis_context * gen = context->system;
659+ //VDP access goes over the 68K bus like a bank area access
660+ //typical delay from bus arbitration
661+ context->Z80_CYCLE += 3 * MCLKS_PER_Z80;
662+ //TODO: add cycle for an access right after a previous one
663+ //TODO: Below cycle time is an estimate based on the time between 68K !BG goes low and Z80 !MREQ goes high
664+ // Needs a new logic analyzer capture to get the actual delay on the 68K side
665+ gen->m68k->current_cycle += 8 * MCLKS_PER_68K;
666+
667+
668+ vdp_port &= 0x1F;
669+ uint16_t ret;
670+ if (vdp_port < 0x10) {
671+ //These probably won't currently interact well with the 68K accessing the VDP
672+ vdp_run_context(gen->vdp, context->Z80_CYCLE);
673+ if (vdp_port < 4) {
674+ ret = vdp_data_port_read(gen->vdp);
675+ } else if (vdp_port < 8) {
676+ ret = vdp_control_port_read(gen->vdp);
677+ } else {
678+ ret = vdp_hv_counter_read(gen->vdp);
679+ }
680+ } else {
681+ //TODO: Figure out the correct value today
682+ ret = 0xFFFF;
683+ }
684+ return vdp_port & 1 ? ret : ret >> 8;
685+}
686+
687+//TODO: Move this inside the system context
688+static uint32_t zram_counter = 0;
689+
690+static m68k_context * io_write(uint32_t location, m68k_context * context, uint8_t value)
691+{
692+ genesis_context * gen = context->system;
693+ if (location < 0x10000) {
694+ //Access to Z80 memory incurs a one 68K cycle wait state
695+ context->current_cycle += MCLKS_PER_68K;
696+ if (!z80_enabled || z80_get_busack(gen->z80, context->current_cycle)) {
697+ location &= 0x7FFF;
698+ if (location < 0x4000) {
699+ gen->zram[location & 0x1FFF] = value;
700+ z80_handle_code_write(location & 0x1FFF, gen->z80);
701+ } else if (location < 0x6000) {
702+ sync_sound(gen, context->current_cycle);
703+ if (location & 1) {
704+ ym_data_write(gen->ym, value);
705+ } else if(location & 2) {
706+ ym_address_write_part2(gen->ym, value);
707+ } else {
708+ ym_address_write_part1(gen->ym, value);
709+ }
710+ } else if (location == 0x6000) {
711+ gen->z80_bank_reg = (gen->z80_bank_reg >> 1 | value << 8) & 0x1FF;
712+ if (gen->z80_bank_reg < 0x80) {
713+ gen->z80->mem_pointers[1] = (gen->z80_bank_reg << 15) + ((char *)gen->z80->mem_pointers[2]);
714+ } else {
715+ gen->z80->mem_pointers[1] = NULL;
716+ }
717+ } else {
718+ fatal_error("68K write to unhandled Z80 address %X\n", location);
719+ }
720+ }
721+ } else {
722+ location &= 0x1FFF;
723+ if (location < 0x100) {
724+ switch(location/2)
725+ {
726+ case 0x1:
727+ io_data_write(gen->io.ports, value, context->current_cycle);
728+ break;
729+ case 0x2:
730+ io_data_write(gen->io.ports+1, value, context->current_cycle);
731+ break;
732+ case 0x3:
733+ io_data_write(gen->io.ports+2, value, context->current_cycle);
734+ break;
735+ case 0x4:
736+ io_control_write(gen->io.ports, value, context->current_cycle);
737+ break;
738+ case 0x5:
739+ io_control_write(gen->io.ports+1, value, context->current_cycle);
740+ break;
741+ case 0x6:
742+ io_control_write(gen->io.ports+2, value, context->current_cycle);
743+ break;
744+ case 0x7:
745+ gen->io.ports[0].serial_out = value;
746+ break;
747+ case 0x8:
748+ case 0xB:
749+ case 0xE:
750+ //serial input port is not writeable
751+ break;
752+ case 0x9:
753+ gen->io.ports[0].serial_ctrl = value;
754+ break;
755+ case 0xA:
756+ gen->io.ports[1].serial_out = value;
757+ break;
758+ case 0xC:
759+ gen->io.ports[1].serial_ctrl = value;
760+ break;
761+ case 0xD:
762+ gen->io.ports[2].serial_out = value;
763+ break;
764+ case 0xF:
765+ gen->io.ports[2].serial_ctrl = value;
766+ break;
767+ }
768+ } else {
769+ if (location == 0x1100) {
770+ if (value & 1) {
771+ dputs("bus requesting Z80");
772+ if (z80_enabled) {
773+ z80_assert_busreq(gen->z80, context->current_cycle);
774+ } else {
775+ gen->z80->busack = 1;
776+ }
777+ } else {
778+ if (gen->z80->busreq) {
779+ dputs("releasing z80 bus");
780+ #ifdef DO_DEBUG_PRINT
781+ char fname[20];
782+ sprintf(fname, "zram-%d", zram_counter++);
783+ FILE * f = fopen(fname, "wb");
784+ fwrite(z80_ram, 1, sizeof(z80_ram), f);
785+ fclose(f);
786+ #endif
787+ }
788+ if (z80_enabled) {
789+ z80_clear_busreq(gen->z80, context->current_cycle);
790+ } else {
791+ gen->z80->busack = 0;
792+ }
793+ }
794+ } else if (location == 0x1200) {
795+ sync_z80(gen->z80, context->current_cycle);
796+ if (value & 1) {
797+ if (z80_enabled) {
798+ z80_clear_reset(gen->z80, context->current_cycle);
799+ } else {
800+ gen->z80->reset = 0;
801+ }
802+ } else {
803+ if (z80_enabled) {
804+ z80_assert_reset(gen->z80, context->current_cycle);
805+ } else {
806+ gen->z80->reset = 1;
807+ }
808+ ym_reset(gen->ym);
809+ }
810+ }
811+ }
812+ }
813+ return context;
814+}
815+
816+static m68k_context * io_write_w(uint32_t location, m68k_context * context, uint16_t value)
817+{
818+ if (location < 0x10000 || (location & 0x1FFF) >= 0x100) {
819+ return io_write(location, context, value >> 8);
820+ } else {
821+ return io_write(location, context, value);
822+ }
823+}
824+
825+#define FOREIGN 0x80
826+#define HZ50 0x40
827+#define USA FOREIGN
828+#define JAP 0x00
829+#define EUR (HZ50|FOREIGN)
830+#define NO_DISK 0x20
831+
832+static uint8_t io_read(uint32_t location, m68k_context * context)
833+{
834+ uint8_t value;
835+ genesis_context *gen = context->system;
836+ if (location < 0x10000) {
837+ //Access to Z80 memory incurs a one 68K cycle wait state
838+ context->current_cycle += MCLKS_PER_68K;
839+ if (!z80_enabled || z80_get_busack(gen->z80, context->current_cycle)) {
840+ location &= 0x7FFF;
841+ if (location < 0x4000) {
842+ value = gen->zram[location & 0x1FFF];
843+ } else if (location < 0x6000) {
844+ sync_sound(gen, context->current_cycle);
845+ value = ym_read_status(gen->ym);
846+ } else {
847+ value = 0xFF;
848+ }
849+ } else {
850+ value = 0xFF;
851+ }
852+ } else {
853+ location &= 0x1FFF;
854+ if (location < 0x100) {
855+ switch(location/2)
856+ {
857+ case 0x0:
858+ //version bits should be 0 for now since we're not emulating TMSS
859+ value = gen->version_reg;
860+ break;
861+ case 0x1:
862+ value = io_data_read(gen->io.ports, context->current_cycle);
863+ break;
864+ case 0x2:
865+ value = io_data_read(gen->io.ports+1, context->current_cycle);
866+ break;
867+ case 0x3:
868+ value = io_data_read(gen->io.ports+2, context->current_cycle);
869+ break;
870+ case 0x4:
871+ value = gen->io.ports[0].control;
872+ break;
873+ case 0x5:
874+ value = gen->io.ports[1].control;
875+ break;
876+ case 0x6:
877+ value = gen->io.ports[2].control;
878+ break;
879+ case 0x7:
880+ value = gen->io.ports[0].serial_out;
881+ break;
882+ case 0x8:
883+ value = gen->io.ports[0].serial_in;
884+ break;
885+ case 0x9:
886+ value = gen->io.ports[0].serial_ctrl;
887+ break;
888+ case 0xA:
889+ value = gen->io.ports[1].serial_out;
890+ break;
891+ case 0xB:
892+ value = gen->io.ports[1].serial_in;
893+ break;
894+ case 0xC:
895+ value = gen->io.ports[1].serial_ctrl;
896+ break;
897+ case 0xD:
898+ value = gen->io.ports[2].serial_out;
899+ break;
900+ case 0xE:
901+ value = gen->io.ports[2].serial_in;
902+ break;
903+ case 0xF:
904+ value = gen->io.ports[2].serial_ctrl;
905+ break;
906+ default:
907+ value = 0xFF;
908+ }
909+ } else {
910+ if (location == 0x1100) {
911+ value = z80_enabled ? !z80_get_busack(gen->z80, context->current_cycle) : !gen->z80->busack;
912+ value |= (get_open_bus_value(&gen->header) >> 8) & 0xFE;
913+ dprintf("Byte read of BUSREQ returned %d @ %d (reset: %d)\n", value, context->current_cycle, gen->z80->reset);
914+ } else if (location == 0x1200) {
915+ value = !gen->z80->reset;
916+ } else {
917+ value = 0xFF;
918+ printf("Byte read of unknown IO location: %X\n", location);
919+ }
920+ }
921+ }
922+ return value;
923+}
924+
925+static uint16_t io_read_w(uint32_t location, m68k_context * context)
926+{
927+ genesis_context *gen = context->system;
928+ uint16_t value = io_read(location, context);
929+ if (location < 0x10000 || (location & 0x1FFF) < 0x100) {
930+ value = value | (value << 8);
931+ } else {
932+ value <<= 8;
933+ value |= get_open_bus_value(&gen->header) & 0xFF;
934+ }
935+ return value;
936+}
937+
938+static void * z80_write_ym(uint32_t location, void * vcontext, uint8_t value)
939+{
940+ z80_context * context = vcontext;
941+ genesis_context * gen = context->system;
942+ sync_sound(gen, context->Z80_CYCLE);
943+ if (location & 1) {
944+ ym_data_write(gen->ym, value);
945+ } else if (location & 2) {
946+ ym_address_write_part2(gen->ym, value);
947+ } else {
948+ ym_address_write_part1(gen->ym, value);
949+ }
950+ return context;
951+}
952+
953+static uint8_t z80_read_ym(uint32_t location, void * vcontext)
954+{
955+ z80_context * context = vcontext;
956+ genesis_context * gen = context->system;
957+ sync_sound(gen, context->Z80_CYCLE);
958+ return ym_read_status(gen->ym);
959+}
960+
961+static uint8_t z80_read_bank(uint32_t location, void * vcontext)
962+{
963+ z80_context * context = vcontext;
964+ genesis_context *gen = context->system;
965+ if (gen->bus_busy) {
966+ context->Z80_CYCLE = gen->m68k->current_cycle;
967+ }
968+ //typical delay from bus arbitration
969+ context->Z80_CYCLE += 3 * MCLKS_PER_Z80;
970+ //TODO: add cycle for an access right after a previous one
971+ //TODO: Below cycle time is an estimate based on the time between 68K !BG goes low and Z80 !MREQ goes high
972+ // Needs a new logic analyzer capture to get the actual delay on the 68K side
973+ gen->m68k->current_cycle += 8 * MCLKS_PER_68K;
974+
975+ location &= 0x7FFF;
976+ if (context->mem_pointers[1]) {
977+ return context->mem_pointers[1][location ^ 1];
978+ }
979+ uint32_t address = gen->z80_bank_reg << 15 | location;
980+ if (address >= 0xC00000 && address < 0xE00000) {
981+ return z80_vdp_port_read(location & 0xFF, context);
982+ } else {
983+ fprintf(stderr, "Unhandled read by Z80 from address %X through banked memory area (%X)\n", address, gen->z80_bank_reg << 15);
984+ }
985+ return 0;
986+}
987+
988+static void *z80_write_bank(uint32_t location, void * vcontext, uint8_t value)
989+{
990+ z80_context * context = vcontext;
991+ genesis_context *gen = context->system;
992+ if (gen->bus_busy) {
993+ context->Z80_CYCLE = gen->m68k->current_cycle;
994+ }
995+ //typical delay from bus arbitration
996+ context->Z80_CYCLE += 3 * MCLKS_PER_Z80;
997+ //TODO: add cycle for an access right after a previous one
998+ //TODO: Below cycle time is an estimate based on the time between 68K !BG goes low and Z80 !MREQ goes high
999+ // Needs a new logic analyzer capture to get the actual delay on the 68K side
1000+ gen->m68k->current_cycle += 8 * MCLKS_PER_68K;
1001+
1002+ location &= 0x7FFF;
1003+ uint32_t address = gen->z80_bank_reg << 15 | location;
1004+ if (address >= 0xE00000) {
1005+ address &= 0xFFFF;
1006+ ((uint8_t *)gen->work_ram)[address ^ 1] = value;
1007+ } else if (address >= 0xC00000) {
1008+ z80_vdp_port_write(location & 0xFF, context, value);
1009+ } else {
1010+ fprintf(stderr, "Unhandled write by Z80 to address %X through banked memory area\n", address);
1011+ }
1012+ return context;
1013+}
1014+
1015+static void *z80_write_bank_reg(uint32_t location, void * vcontext, uint8_t value)
1016+{
1017+ z80_context * context = vcontext;
1018+ genesis_context *gen = context->system;
1019+
1020+ gen->z80_bank_reg = (gen->z80_bank_reg >> 1 | value << 8) & 0x1FF;
1021+ update_z80_bank_pointer(context->system);
1022+
1023+ return context;
1024+}
1025+
1026+static void set_speed_percent(system_header * system, uint32_t percent)
1027+{
1028+ genesis_context *context = (genesis_context *)system;
1029+ uint32_t old_clock = context->master_clock;
1030+ context->master_clock = ((uint64_t)context->normal_clock * (uint64_t)percent) / 100;
1031+ while (context->ym->current_cycle != context->psg->cycles) {
1032+ sync_sound(context, context->psg->cycles + MCLKS_PER_PSG);
1033+ }
1034+ ym_adjust_master_clock(context->ym, context->master_clock);
1035+ psg_adjust_master_clock(context->psg, context->master_clock);
1036+}
1037+
1038+void set_region(genesis_context *gen, rom_info *info, uint8_t region)
1039+{
1040+ if (!region) {
1041+ char * def_region = tern_find_path_default(config, "system\0default_region\0", (tern_val){.ptrval = "U"}, TVAL_PTR).ptrval;
1042+ if (!info->regions || (info->regions & translate_region_char(toupper(*def_region)))) {
1043+ region = translate_region_char(toupper(*def_region));
1044+ } else {
1045+ region = info->regions;
1046+ }
1047+ }
1048+ if (region & REGION_E) {
1049+ gen->version_reg = NO_DISK | EUR;
1050+ } else if (region & REGION_J) {
1051+ gen->version_reg = NO_DISK | JAP;
1052+ } else {
1053+ gen->version_reg = NO_DISK | USA;
1054+ }
1055+
1056+ if (region & HZ50) {
1057+ gen->normal_clock = MCLKS_PAL;
1058+ } else {
1059+ gen->normal_clock = MCLKS_NTSC;
1060+ }
1061+ gen->master_clock = gen->normal_clock;
1062+}
1063+
1064+static uint8_t load_state(system_header *system, uint8_t slot)
1065+{
1066+ genesis_context *gen = (genesis_context *)system;
1067+ char *statepath = get_slot_name(system, slot, "state");
1068+ deserialize_buffer state;
1069+ uint32_t pc = 0;
1070+ uint8_t ret;
1071+ if (!gen->m68k->resume_pc) {
1072+ system->delayed_load_slot = slot + 1;
1073+ gen->m68k->should_return = 1;
1074+ ret = get_modification_time(statepath) != 0;
1075+ if (!ret) {
1076+ strcpy(statepath + strlen(statepath)-strlen("state"), "gst");
1077+ ret = get_modification_time(statepath) != 0;
1078+ }
1079+ goto done;
1080+ }
1081+ if (load_from_file(&state, statepath)) {
1082+ genesis_deserialize(&state, gen);
1083+ free(state.data);
1084+ //HACK
1085+ pc = gen->m68k->last_prefetch_address;
1086+ ret = 1;
1087+ } else {
1088+ strcpy(statepath + strlen(statepath)-strlen("state"), "gst");
1089+ pc = load_gst(gen, statepath);
1090+ ret = pc != 0;
1091+ }
1092+ if (ret) {
1093+ gen->m68k->resume_pc = get_native_address_trans(gen->m68k, pc);
1094+ }
1095+done:
1096+ free(statepath);
1097+ return ret;
1098+}
1099+
1100+static void handle_reset_requests(genesis_context *gen)
1101+{
1102+ while (gen->reset_requested || gen->header.delayed_load_slot)
1103+ {
1104+ if (gen->reset_requested) {
1105+ gen->reset_requested = 0;
1106+ gen->m68k->should_return = 0;
1107+ z80_assert_reset(gen->z80, gen->m68k->current_cycle);
1108+ z80_clear_busreq(gen->z80, gen->m68k->current_cycle);
1109+ ym_reset(gen->ym);
1110+ //Is there any sort of VDP reset?
1111+ m68k_reset(gen->m68k);
1112+ }
1113+ if (gen->header.delayed_load_slot) {
1114+ load_state(&gen->header, gen->header.delayed_load_slot - 1);
1115+ gen->header.delayed_load_slot = 0;
1116+ resume_68k(gen->m68k);
1117+ }
1118+ }
1119+ bindings_release_capture();
1120+ vdp_release_framebuffer(gen->vdp);
1121+ render_pause_source(gen->ym->audio);
1122+ render_pause_source(gen->psg->audio);
1123+}
1124+
1125+static void start_genesis(system_header *system, char *statefile)
1126+{
1127+ genesis_context *gen = (genesis_context *)system;
1128+ if (statefile) {
1129+ //first try loading as a native format savestate
1130+ deserialize_buffer state;
1131+ uint32_t pc;
1132+ if (load_from_file(&state, statefile)) {
1133+ genesis_deserialize(&state, gen);
1134+ free(state.data);
1135+ //HACK
1136+ pc = gen->m68k->last_prefetch_address;
1137+ } else {
1138+ pc = load_gst(gen, statefile);
1139+ if (!pc) {
1140+ fatal_error("Failed to load save state %s\n", statefile);
1141+ }
1142+ }
1143+ printf("Loaded %s\n", statefile);
1144+ if (gen->header.enter_debugger) {
1145+ gen->header.enter_debugger = 0;
1146+ insert_breakpoint(gen->m68k, pc, gen->header.debugger_type == DEBUGGER_NATIVE ? debugger : gdb_debug_enter);
1147+ }
1148+ adjust_int_cycle(gen->m68k, gen->vdp);
1149+ start_68k_context(gen->m68k, pc);
1150+ } else {
1151+ if (gen->header.enter_debugger) {
1152+ gen->header.enter_debugger = 0;
1153+ uint32_t address = gen->cart[2] << 16 | gen->cart[3];
1154+ insert_breakpoint(gen->m68k, address, gen->header.debugger_type == DEBUGGER_NATIVE ? debugger : gdb_debug_enter);
1155+ }
1156+ m68k_reset(gen->m68k);
1157+ }
1158+ handle_reset_requests(gen);
1159+ return;
1160+}
1161+
1162+static void resume_genesis(system_header *system)
1163+{
1164+ genesis_context *gen = (genesis_context *)system;
1165+ render_set_video_standard((gen->version_reg & HZ50) ? VID_PAL : VID_NTSC);
1166+ bindings_reacquire_capture();
1167+ vdp_reacquire_framebuffer(gen->vdp);
1168+ render_resume_source(gen->ym->audio);
1169+ render_resume_source(gen->psg->audio);
1170+ resume_68k(gen->m68k);
1171+ handle_reset_requests(gen);
1172+}
1173+
1174+static void inc_debug_mode(system_header *system)
1175+{
1176+ genesis_context *gen = (genesis_context *)system;
1177+ vdp_inc_debug_mode(gen->vdp);
1178+}
1179+
1180+static void request_exit(system_header *system)
1181+{
1182+ genesis_context *gen = (genesis_context *)system;
1183+ gen->m68k->target_cycle = gen->m68k->current_cycle;
1184+ gen->m68k->should_return = 1;
1185+}
1186+
1187+static void persist_save(system_header *system)
1188+{
1189+ genesis_context *gen = (genesis_context *)system;
1190+ if (gen->save_type == SAVE_NONE) {
1191+ return;
1192+ }
1193+ FILE * f = fopen(save_filename, "wb");
1194+ if (!f) {
1195+ fprintf(stderr, "Failed to open %s file %s for writing\n", save_type_name(gen->save_type), save_filename);
1196+ return;
1197+ }
1198+ fwrite(gen->save_storage, 1, gen->save_size, f);
1199+ fclose(f);
1200+ printf("Saved %s to %s\n", save_type_name(gen->save_type), save_filename);
1201+}
1202+
1203+static void load_save(system_header *system)
1204+{
1205+ genesis_context *gen = (genesis_context *)system;
1206+ FILE * f = fopen(save_filename, "rb");
1207+ if (f) {
1208+ uint32_t read = fread(gen->save_storage, 1, gen->save_size, f);
1209+ fclose(f);
1210+ if (read > 0) {
1211+ printf("Loaded %s from %s\n", save_type_name(gen->save_type), save_filename);
1212+ }
1213+ }
1214+}
1215+
1216+static void soft_reset(system_header *system)
1217+{
1218+ genesis_context *gen = (genesis_context *)system;
1219+ if (gen->reset_cycle == CYCLE_NEVER) {
1220+ double random = (double)rand()/(double)RAND_MAX;
1221+ gen->reset_cycle = gen->m68k->current_cycle + random * MCLKS_LINE * (gen->version_reg & HZ50 ? LINES_PAL : LINES_NTSC);
1222+ if (gen->reset_cycle < gen->m68k->target_cycle) {
1223+ gen->m68k->target_cycle = gen->reset_cycle;
1224+ }
1225+ }
1226+}
1227+
1228+static void free_genesis(system_header *system)
1229+{
1230+ genesis_context *gen = (genesis_context *)system;
1231+ vdp_free(gen->vdp);
1232+ memmap_chunk *map = (memmap_chunk *)gen->m68k->options->gen.memmap;
1233+ m68k_options_free(gen->m68k->options);
1234+ free(gen->cart);
1235+ free(gen->m68k);
1236+ free(gen->work_ram);
1237+ z80_options_free(gen->z80->Z80_OPTS);
1238+ free(gen->z80);
1239+ free(gen->zram);
1240+ ym_free(gen->ym);
1241+ psg_free(gen->psg);
1242+ free(gen->header.save_dir);
1243+ free_rom_info(&gen->header.info);
1244+ free(gen->lock_on);
1245+ free(gen);
1246+}
1247+
1248+static void gamepad_down(system_header *system, uint8_t gamepad_num, uint8_t button)
1249+{
1250+ genesis_context *gen = (genesis_context *)system;
1251+ io_gamepad_down(&gen->io, gamepad_num, button);
1252+ if (gen->mapper_type == MAPPER_JCART) {
1253+ jcart_gamepad_down(gen, gamepad_num, button);
1254+ }
1255+}
1256+
1257+static void gamepad_up(system_header *system, uint8_t gamepad_num, uint8_t button)
1258+{
1259+ genesis_context *gen = (genesis_context *)system;
1260+ io_gamepad_up(&gen->io, gamepad_num, button);
1261+ if (gen->mapper_type == MAPPER_JCART) {
1262+ jcart_gamepad_up(gen, gamepad_num, button);
1263+ }
1264+}
1265+
1266+static void mouse_down(system_header *system, uint8_t mouse_num, uint8_t button)
1267+{
1268+ genesis_context *gen = (genesis_context *)system;
1269+ io_mouse_down(&gen->io, mouse_num, button);
1270+}
1271+
1272+static void mouse_up(system_header *system, uint8_t mouse_num, uint8_t button)
1273+{
1274+ genesis_context *gen = (genesis_context *)system;
1275+ io_mouse_up(&gen->io, mouse_num, button);
1276+}
1277+
1278+static void mouse_motion_absolute(system_header *system, uint8_t mouse_num, uint16_t x, uint16_t y)
1279+{
1280+ genesis_context *gen = (genesis_context *)system;
1281+ io_mouse_motion_absolute(&gen->io, mouse_num, x, y);
1282+}
1283+
1284+static void mouse_motion_relative(system_header *system, uint8_t mouse_num, int32_t x, int32_t y)
1285+{
1286+ genesis_context *gen = (genesis_context *)system;
1287+ io_mouse_motion_relative(&gen->io, mouse_num, x, y);
1288+}
1289+
1290+static void keyboard_down(system_header *system, uint8_t scancode)
1291+{
1292+ genesis_context *gen = (genesis_context *)system;
1293+ io_keyboard_down(&gen->io, scancode);
1294+}
1295+
1296+static void keyboard_up(system_header *system, uint8_t scancode)
1297+{
1298+ genesis_context *gen = (genesis_context *)system;
1299+ io_keyboard_up(&gen->io, scancode);
1300+}
1301+
1302+static void set_audio_config(genesis_context *gen)
1303+{
1304+ char *config_gain;
1305+ config_gain = tern_find_path(config, "audio\0psg_gain\0", TVAL_PTR).ptrval;
1306+ render_audio_source_gaindb(gen->psg->audio, config_gain ? atof(config_gain) : 0.0f);
1307+ config_gain = tern_find_path(config, "audio\0fm_gain\0", TVAL_PTR).ptrval;
1308+ render_audio_source_gaindb(gen->ym->audio, config_gain ? atof(config_gain) : 0.0f);
1309+
1310+ char *config_dac = tern_find_path_default(config, "audio\0fm_dac\0", (tern_val){.ptrval="zero_offset"}, TVAL_PTR).ptrval;
1311+ ym_enable_zero_offset(gen->ym, !strcmp(config_dac, "zero_offset"));
1312+}
1313+
1314+static void config_updated(system_header *system)
1315+{
1316+ genesis_context *gen = (genesis_context *)system;
1317+ setup_io_devices(config, &system->info, &gen->io);
1318+ set_audio_config(gen);
1319+}
1320+
1321+genesis_context *alloc_init_genesis(rom_info *rom, void *main_rom, void *lock_on, uint32_t system_opts, uint8_t force_region)
1322+{
1323+ static memmap_chunk z80_map[] = {
1324+ { 0x0000, 0x4000, 0x1FFF, 0, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, NULL, NULL, NULL, NULL, NULL },
1325+ { 0x8000, 0x10000, 0x7FFF, 0, 0, 0, NULL, NULL, NULL, z80_read_bank, z80_write_bank},
1326+ { 0x4000, 0x6000, 0x0003, 0, 0, 0, NULL, NULL, NULL, z80_read_ym, z80_write_ym},
1327+ { 0x6000, 0x6100, 0xFFFF, 0, 0, 0, NULL, NULL, NULL, NULL, z80_write_bank_reg},
1328+ { 0x7F00, 0x8000, 0x00FF, 0, 0, 0, NULL, NULL, NULL, z80_vdp_port_read, z80_vdp_port_write}
1329+ };
1330+ genesis_context *gen = calloc(1, sizeof(genesis_context));
1331+ gen->header.set_speed_percent = set_speed_percent;
1332+ gen->header.start_context = start_genesis;
1333+ gen->header.resume_context = resume_genesis;
1334+ gen->header.load_save = load_save;
1335+ gen->header.persist_save = persist_save;
1336+ gen->header.load_state = load_state;
1337+ gen->header.soft_reset = soft_reset;
1338+ gen->header.free_context = free_genesis;
1339+ gen->header.get_open_bus_value = get_open_bus_value;
1340+ gen->header.request_exit = request_exit;
1341+ gen->header.inc_debug_mode = inc_debug_mode;
1342+ gen->header.gamepad_down = gamepad_down;
1343+ gen->header.gamepad_up = gamepad_up;
1344+ gen->header.mouse_down = mouse_down;
1345+ gen->header.mouse_up = mouse_up;
1346+ gen->header.mouse_motion_absolute = mouse_motion_absolute;
1347+ gen->header.mouse_motion_relative = mouse_motion_relative;
1348+ gen->header.keyboard_down = keyboard_down;
1349+ gen->header.keyboard_up = keyboard_up;
1350+ gen->header.config_updated = config_updated;
1351+ gen->header.serialize = serialize;
1352+ gen->header.deserialize = deserialize;
1353+ gen->header.type = SYSTEM_GENESIS;
1354+ gen->header.info = *rom;
1355+ set_region(gen, rom, force_region);
1356+
1357+ gen->vdp = init_vdp_context(gen->version_reg & 0x40);
1358+ gen->vdp->system = &gen->header;
1359+ gen->frame_end = vdp_cycles_to_frame_end(gen->vdp);
1360+ char * config_cycles = tern_find_path(config, "clocks\0max_cycles\0", TVAL_PTR).ptrval;
1361+ gen->max_cycles = config_cycles ? atoi(config_cycles) : DEFAULT_SYNC_INTERVAL;
1362+ gen->int_latency_prev1 = MCLKS_PER_68K * 32;
1363+ gen->int_latency_prev2 = MCLKS_PER_68K * 16;
1364+
1365+ render_set_video_standard((gen->version_reg & HZ50) ? VID_PAL : VID_NTSC);
1366+
1367+ gen->ym = malloc(sizeof(ym2612_context));
1368+ ym_init(gen->ym, gen->master_clock, MCLKS_PER_YM, system_opts);
1369+
1370+ gen->psg = malloc(sizeof(psg_context));
1371+ psg_init(gen->psg, gen->master_clock, MCLKS_PER_PSG);
1372+
1373+ set_audio_config(gen);
1374+
1375+ z80_map[0].buffer = gen->zram = calloc(1, Z80_RAM_BYTES);
1376+ z80_options *z_opts = malloc(sizeof(z80_options));
1377+ init_z80_opts(z_opts, z80_map, 5, NULL, 0, MCLKS_PER_Z80, 0xFFFF);
1378+ gen->z80 = init_z80_context(z_opts);
1379+ gen->z80->next_int_pulse = z80_next_int_pulse;
1380+ z80_assert_reset(gen->z80, 0);
1381+
1382+ gen->z80->system = gen;
1383+ gen->z80->mem_pointers[0] = gen->zram;
1384+ gen->z80->mem_pointers[1] = gen->z80->mem_pointers[2] = (uint8_t *)main_rom;
1385+
1386+ gen->cart = main_rom;
1387+ gen->lock_on = lock_on;
1388+ gen->work_ram = calloc(2, RAM_WORDS);
1389+ if (!strcmp("random", tern_find_path_default(config, "system\0ram_init\0", (tern_val){.ptrval = "zero"}, TVAL_PTR).ptrval))
1390+ {
1391+ srand(time(NULL));
1392+ for (int i = 0; i < RAM_WORDS; i++)
1393+ {
1394+ gen->work_ram[i] = rand();
1395+ }
1396+ for (int i = 0; i < Z80_RAM_BYTES; i++)
1397+ {
1398+ gen->zram[i] = rand();
1399+ }
1400+ for (int i = 0; i < VRAM_SIZE; i++)
1401+ {
1402+ gen->vdp->vdpmem[i] = rand();
1403+ }
1404+ for (int i = 0; i < SAT_CACHE_SIZE; i++)
1405+ {
1406+ gen->vdp->sat_cache[i] = rand();
1407+ }
1408+ for (int i = 0; i < CRAM_SIZE; i++)
1409+ {
1410+ write_cram_internal(gen->vdp, i, rand());
1411+ }
1412+ for (int i = 0; i < VSRAM_SIZE; i++)
1413+ {
1414+ gen->vdp->vsram[i] = rand();
1415+ }
1416+ }
1417+ setup_io_devices(config, rom, &gen->io);
1418+ gen->header.has_keyboard = io_has_keyboard(&gen->io);
1419+
1420+ gen->mapper_type = rom->mapper_type;
1421+ gen->save_type = rom->save_type;
1422+ if (gen->save_type != SAVE_NONE) {
1423+ gen->save_ram_mask = rom->save_mask;
1424+ gen->save_size = rom->save_size;
1425+ gen->save_storage = rom->save_buffer;
1426+ gen->eeprom_map = rom->eeprom_map;
1427+ gen->num_eeprom = rom->num_eeprom;
1428+ if (gen->save_type == SAVE_I2C) {
1429+ eeprom_init(&gen->eeprom, gen->save_storage, gen->save_size);
1430+ } else if (gen->save_type == SAVE_NOR) {
1431+ memcpy(&gen->nor, rom->nor, sizeof(gen->nor));
1432+ //nor_flash_init(&gen->nor, gen->save_storage, gen->save_size, rom->save_page_size, rom->save_product_id, rom->save_bus);
1433+ }
1434+ } else {
1435+ gen->save_storage = NULL;
1436+ }
1437+
1438+ //This must happen before we generate memory access functions in init_m68k_opts
1439+ for (int i = 0; i < rom->map_chunks; i++)
1440+ {
1441+ if (rom->map[i].start == 0xE00000) {
1442+ rom->map[i].buffer = gen->work_ram;
1443+ break;
1444+ }
1445+ }
1446+
1447+ m68k_options *opts = malloc(sizeof(m68k_options));
1448+ init_m68k_opts(opts, rom->map, rom->map_chunks, MCLKS_PER_68K);
1449+ //TODO: make this configurable
1450+ opts->gen.flags |= M68K_OPT_BROKEN_READ_MODIFY;
1451+ gen->m68k = init_68k_context(opts, NULL);
1452+ gen->m68k->system = gen;
1453+ opts->address_log = (system_opts & OPT_ADDRESS_LOG) ? fopen("address.log", "w") : NULL;
1454+
1455+ //This must happen after the 68K context has been allocated
1456+ for (int i = 0; i < rom->map_chunks; i++)
1457+ {
1458+ if (rom->map[i].flags & MMAP_PTR_IDX) {
1459+ gen->m68k->mem_pointers[rom->map[i].ptr_index] = rom->map[i].buffer;
1460+ }
1461+ }
1462+
1463+ if (gen->mapper_type == MAPPER_SEGA) {
1464+ //initialize bank registers
1465+ for (int i = 1; i < sizeof(gen->bank_regs); i++)
1466+ {
1467+ gen->bank_regs[i] = i;
1468+ }
1469+ }
1470+
1471+ return gen;
1472+}
1473+
1474+genesis_context *alloc_config_genesis(void *rom, uint32_t rom_size, void *lock_on, uint32_t lock_on_size, uint32_t ym_opts, uint8_t force_region)
1475+{
1476+ static memmap_chunk base_map[] = {
1477+ {0xE00000, 0x1000000, 0xFFFF, 0, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, NULL,
1478+ NULL, NULL, NULL, NULL},
1479+ {0xC00000, 0xE00000, 0x1FFFFF, 0, 0, 0, NULL,
1480+ (read_16_fun)vdp_port_read, (write_16_fun)vdp_port_write,
1481+ (read_8_fun)vdp_port_read_b, (write_8_fun)vdp_port_write_b},
1482+ {0xA00000, 0xA12000, 0x1FFFF, 0, 0, 0, NULL,
1483+ (read_16_fun)io_read_w, (write_16_fun)io_write_w,
1484+ (read_8_fun)io_read, (write_8_fun)io_write}
1485+ };
1486+ static tern_node *rom_db;
1487+ if (!rom_db) {
1488+ rom_db = load_rom_db();
1489+ }
1490+ rom_info info = configure_rom(rom_db, rom, rom_size, lock_on, lock_on_size, base_map, sizeof(base_map)/sizeof(base_map[0]));
1491+ rom = info.rom;
1492+ rom_size = info.rom_size;
1493+#ifndef BLASTEM_BIG_ENDIAN
1494+ byteswap_rom(rom_size, rom);
1495+ if (lock_on) {
1496+ byteswap_rom(lock_on_size, lock_on);
1497+ }
1498+#endif
1499+ char *m68k_divider = tern_find_path(config, "clocks\0m68k_divider\0", TVAL_PTR).ptrval;
1500+ if (!m68k_divider) {
1501+ m68k_divider = "7";
1502+ }
1503+ MCLKS_PER_68K = atoi(m68k_divider);
1504+ if (!MCLKS_PER_68K) {
1505+ MCLKS_PER_68K = 7;
1506+ }
1507+ return alloc_init_genesis(&info, rom, lock_on, ym_opts, force_region);
1508+}
+71,
-0
1@@ -0,0 +1,71 @@
2+/*
3+ Copyright 2013 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#ifndef GENESIS_H_
8+#define GENESIS_H_
9+
10+#include <stdint.h>
11+#include "system.h"
12+#include "m68k_core.h"
13+#include "z80_to_x86.h"
14+#include "ym2612.h"
15+#include "vdp.h"
16+#include "psg.h"
17+#include "io.h"
18+#include "romdb.h"
19+#include "arena.h"
20+#include "i2c.h"
21+
22+typedef struct genesis_context genesis_context;
23+
24+struct genesis_context {
25+ system_header header;
26+ m68k_context *m68k;
27+ z80_context *z80;
28+ vdp_context *vdp;
29+ ym2612_context *ym;
30+ psg_context *psg;
31+ uint16_t *cart;
32+ uint16_t *lock_on;
33+ uint16_t *work_ram;
34+ uint8_t *zram;
35+ void *extra;
36+ uint8_t *save_storage;
37+ void *mapper_temp;
38+ eeprom_map *eeprom_map;
39+ uint8_t *serialize_tmp;
40+ size_t serialize_size;
41+ uint32_t num_eeprom;
42+ uint32_t save_size;
43+ uint32_t save_ram_mask;
44+ uint32_t master_clock; //Current master clock value
45+ uint32_t normal_clock; //Normal master clock (used to restore master clock after turbo mode)
46+ uint32_t frame_end;
47+ uint32_t max_cycles;
48+ uint32_t int_latency_prev1;
49+ uint32_t int_latency_prev2;
50+ uint32_t reset_cycle;
51+ uint8_t bank_regs[8];
52+ uint16_t z80_bank_reg;
53+ uint16_t mapper_start_index;
54+ uint8_t mapper_type;
55+ uint8_t save_type;
56+ sega_io io;
57+ uint8_t version_reg;
58+ uint8_t bus_busy;
59+ uint8_t reset_requested;
60+ eeprom_state eeprom;
61+ nor_state nor;
62+};
63+
64+#define RAM_WORDS 32 * 1024
65+#define Z80_RAM_BYTES 8 * 1024
66+
67+m68k_context * sync_components(m68k_context *context, uint32_t address);
68+genesis_context *alloc_config_genesis(void *rom, uint32_t rom_size, void *lock_on, uint32_t lock_on_size, uint32_t system_opts, uint8_t force_region);
69+void genesis_serialize(genesis_context *gen, serialize_buffer *buf, uint32_t m68k_pc);
70+void genesis_deserialize(deserialize_buffer *buf, genesis_context *gen);
71+
72+#endif //GENESIS_H_
+532,
-0
1@@ -0,0 +1,532 @@
2+#!/usr/bin/env python
3+
4+def split_fields(line):
5+ parts = []
6+ while line:
7+ field,_,line = line.partition('\t')
8+ parts.append(field.strip())
9+ while line.startswith('\t'):
10+ line = line[1:]
11+ return parts
12+
13+class Program(object):
14+ def __init__(self, instruction):
15+ self.avail_dregs = {0,1,2,3,4,5,6,7}
16+ self.avail_aregs = {0,1,2,3,4,5,6,7}
17+ instruction.consume_regs(self)
18+ self.inst = instruction
19+
20+ def dirname(self):
21+ return self.inst.name + '_' + self.inst.size
22+ def name(self):
23+ return str(self.inst).replace('.', '_').replace('#', '_').replace(',', '_').replace(' ', '_').replace('(', '[').replace(')', ']')
24+
25+ def write_rom_test(self, outfile):
26+ outfile.write('\tdc.l $0, start\n')
27+ needdivzero = self.inst.name.startswith('div')
28+ needchk = self.inst.name.startswith('chk')
29+ for i in xrange(0x8, 0x100, 0x4):
30+ if needdivzero and i == 0x14:
31+ outfile.write('\tdc.l div_zero_handler\n')
32+ elif needchk and i == 0x18:
33+ outfile.write('\tdc.l chk_handler\n')
34+ else:
35+ outfile.write('\tdc.l empty_handler\n')
36+ outfile.write('\tdc.b "SEGA"\nempty_handler:\n\trte\n')
37+ if needdivzero:
38+ outfile.write('div_zero_handler:\n')
39+ div_zero_count = self.get_dreg()
40+ outfile.write('\taddq #1, ' + str(div_zero_count) + '\n')
41+ outfile.write('\trte\n')
42+ if needchk:
43+ outfile.write('chk_handler:\n')
44+ chk_count = self.get_dreg()
45+ outfile.write('\taddq #1, ' + str(chk_count) + '\n')
46+ outfile.write('\trte\n')
47+ outfile.write('start:\n\tmove #0, CCR\n')
48+ if needdivzero:
49+ outfile.write('\tmoveq #0, ' + str(div_zero_count) + '\n')
50+ already = {}
51+ self.inst.write_init(outfile, already)
52+ if 'label' in already:
53+ outfile.write('lbl_' + str(already['label']) + ':\n')
54+ outfile.write('\t'+str(self.inst)+'\n')
55+ outfile.write('\t'+self.inst.save_result(self.get_dreg(), True) + '\n')
56+ save_ccr = self.get_dreg()
57+ outfile.write('\tmove SR, ' + str(save_ccr) + '\n')
58+ outfile.write('\tmove #$1F, CCR\n')
59+ self.inst.invalidate_dest(already)
60+ self.inst.write_init(outfile, already)
61+ if 'label' in already:
62+ outfile.write('lbl_' + str(already['label']) + ':\n')
63+ outfile.write('\t'+str(self.inst)+'\n')
64+ outfile.write('\t'+self.inst.save_result(self.get_dreg(), False) + '\n')
65+ outfile.write('\treset\nforever:\n\tbra.s forever\n')
66+
67+ def consume_dreg(self, num):
68+ self.avail_dregs.discard(num)
69+
70+ def consume_areg(self, num):
71+ self.avail_aregs.discard(num)
72+
73+ def get_dreg(self):
74+ return Register('d', self.avail_dregs.pop())
75+
76+class Dummy(object):
77+ def __str__(self):
78+ return ''
79+ def write_init(self, outfile, size, already):
80+ pass
81+ def consume_regs(self, program):
82+ pass
83+
84+dummy_op = Dummy()
85+
86+class Register(object):
87+ def __init__(self, kind, num):
88+ self.kind = kind
89+ self.num = num
90+
91+ def __str__(self):
92+ if self.kind == 'd' or self.kind == 'a':
93+ return self.kind + str(self.num)
94+ return self.kind
95+
96+ def write_init(self, outfile, size, already):
97+ if not str(self) in already:
98+ minv,maxv = get_size_range(size)
99+ val = randint(minv,maxv)
100+ already[str(self)] = val
101+ outfile.write('\tmove.'+size+' #'+str(val)+', ' + str(self) + '\n')
102+
103+ def consume_regs(self, program):
104+ if self.kind == 'd':
105+ program.consume_dreg(self.num)
106+ elif self.kind == 'a':
107+ program.consume_areg(self.num)
108+
109+def valid_ram_address(address, size='b'):
110+ return address >= 0xE00000 and address <= 0xFFFFFFFC and (address & 0xE00000) == 0xE00000 and (size == 'b' or not address & 1)
111+
112+def random_ram_address(mina=0xE00000, maxa=0xFFFFFFFC):
113+ return randint(mina/2, maxa/2)*2 | 0xE00000
114+
115+class Indexed(object):
116+ def __init__(self, base, index, index_size, disp):
117+ self.base = base
118+ self.index = index
119+ self.index_size = index_size
120+ self.disp = disp
121+
122+ def write_init(self, outfile, size, already):
123+ if self.base.kind == 'pc':
124+ if str(self.index) in already:
125+ index = already[str(self.index)]
126+ if self.index_size == 'w':
127+ index = index & 0xFFFF
128+ #sign extend index
129+ if index & 0x8000:
130+ index -= 65536
131+ if index > -1024:
132+ index = already[str(self.index)] = 2 * randint(-16384, -512)
133+ outfile.write('\tmove.l #' + str(index) + ', ' + str(self.index) + '\n')
134+ else:
135+ index = already[str(self.index)] = 2 * randint(-16384, -512)
136+ outfile.write('\tmove.l #' + str(index) + ', ' + str(self.index) + '\n')
137+ num = already.get('label', 0)+1
138+ already['label'] = num
139+ if (already[str(self.index)] + self.disp) & 1:
140+ self.disp += 1
141+ address = 'lbl_' + str(num) + ' + 2 + ' + str(self.disp) + ' + ' + str(index)
142+ else:
143+ if self.base == self.index:
144+ if str(self.base) in already:
145+ if not valid_ram_address(already[str(self.base)]*2):
146+ del already[str(self.base)]
147+ self.write_init(outfile, size, already)
148+ return
149+ else:
150+ base = index = already[str(self.base)]
151+ else:
152+ base = index = already[str(self.base)] = random_ram_address()/2
153+ outfile.write('\tmove.l #' + str(base) + ', ' + str(self.base) + '\n')
154+ else:
155+ if str(self.base) in already:
156+ if not valid_ram_address(already[str(self.base)]):
157+ del already[str(self.base)]
158+ self.write_init(outfile, size, already)
159+ return
160+ else:
161+ base = already[str(self.base)]
162+ else:
163+ base = already[str(self.base)] = random_ram_address()
164+ outfile.write('\tmove.l #' + str(base) + ', ' + str(self.base) + '\n')
165+ if str(self.index) in already:
166+ index = already[str(self.index)]
167+ if self.index_size == 'w':
168+ index = index & 0xFFFF
169+ #sign extend index
170+ if index & 0x8000:
171+ index -= 65536
172+ if not valid_ram_address(base + index):
173+ index = already[str(self.index)] = randint(-64, 63)
174+ outfile.write('\tmove.l #' + str(index) + ', ' + str(self.index) + '\n')
175+ else:
176+ index = already[str(self.index)] = randint(-64, 63)
177+ outfile.write('\tmove.l #' + str(index) + ', ' + str(self.index) + '\n')
178+ address = base + index + self.disp
179+ if (address & 0xFFFFFF) < 0xE00000:
180+ if (address & 0xFFFFFF) < 128:
181+ self.disp -= (address & 0xFFFFFF)
182+ else:
183+ self.disp += 0xE00000-(address & 0xFFFFFF)
184+ if self.disp > 127:
185+ self.disp = 127
186+ elif self.disp < -128:
187+ self.disp = -128
188+ address = base + index + self.disp
189+ elif (address & 0xFFFFFF) > 0xFFFFFC:
190+ self.disp -= (address & 0xFFFFFF) - 0xFFFFFC
191+ if self.disp > 127:
192+ self.disp = 127
193+ elif self.disp < -128:
194+ self.disp = -128
195+ address = base + index + self.disp
196+ if size != 'b' and address & 1:
197+ self.disp = self.disp ^ 1
198+ address = base + index + self.disp
199+ minv,maxv = get_size_range(size)
200+ outfile.write('\tmove.' + size + ' #' + str(randint(minv, maxv)) + ', (' + str(address) + ').l\n')
201+
202+ def __str__(self):
203+ return '(' + str(self.disp) + ', ' + str(self.base) + ', ' + str(self.index) + '.' + self.index_size + ')'
204+
205+ def consume_regs(self, program):
206+ self.base.consume_regs(program)
207+ self.index.consume_regs(program)
208+
209+class Displacement(object):
210+ def __init__(self, base, disp):
211+ self.base = base
212+ if disp & 1:
213+ disp += 1
214+ self.disp = disp
215+
216+ def write_init(self, outfile, size, already):
217+ if self.base.kind == 'pc':
218+ num = already.get('label', 0)+1
219+ already['label'] = num
220+ address = 'lbl_' + str(num) + ' + 2 + ' + str(self.disp)
221+ else:
222+ if str(self.base) in already:
223+ if not valid_ram_address(already[str(self.base)]):
224+ del already[str(self.base)]
225+ self.write_init(outfile, size, already)
226+ return
227+ else:
228+ base = already[str(self.base)]
229+ else:
230+ base = already[str(self.base)] = random_ram_address()
231+ outfile.write('\tmove.l #' + str(base) + ', ' + str(self.base) + '\n')
232+ address = base + self.disp
233+ if (address & 0xFFFFFF) < 0xE00000:
234+ if (address & 0xFFFFFF) < 0x10000:
235+ self.disp -= (address & 0xFFFFFF)
236+ else:
237+ self.disp += 0xE00000-(address & 0xFFFFFF)
238+ address = base + self.disp
239+ elif (address & 0xFFFFFF) > 0xFFFFFC:
240+ self.disp -= (address & 0xFFFFFF) - 0xFFFFFC
241+ address = base + self.disp
242+ if size != 'b' and address & 1:
243+ self.disp = self.disp ^ 1
244+ address = base + self.disp
245+ minv,maxv = get_size_range(size)
246+ outfile.write('\tmove.' + size + ' #' + str(randint(minv, maxv)) + ', (' + str(address) + ').l\n')
247+
248+ def __str__(self):
249+ return '(' + str(self.disp) + ', ' + str(self.base) + ')'
250+
251+ def consume_regs(self, program):
252+ self.base.consume_regs(program)
253+
254+class Indirect(object):
255+ def __init__(self, reg):
256+ self.reg = reg
257+
258+ def __str__(self):
259+ return '(' + str(self.reg) + ')'
260+
261+ def write_init(self, outfile, size, already):
262+ if str(self.reg) in already:
263+ if not valid_ram_address(already[str(self.reg)], size):
264+ del already[str(self.reg)]
265+ self.write_init(outfile, size, already)
266+ return
267+ else:
268+ address = already[str(self.reg)]
269+ else:
270+ address = random_ram_address()
271+ if size != 'b':
272+ address = address & 0xFFFFFFFE
273+ outfile.write('\tmove.l #' + str(address) + ', ' + str(self.reg) + '\n')
274+ already[str(self.reg)] = address
275+ minv,maxv = get_size_range(size)
276+ outfile.write('\tmove.' + size + ' #' + str(randint(minv, maxv)) + ', (' + str(address) + ').l\n')
277+
278+ def consume_regs(self, program):
279+ self.reg.consume_regs(program)
280+
281+class Increment(object):
282+ def __init__(self, reg):
283+ self.reg = reg
284+
285+ def __str__(self):
286+ return '(' + str(self.reg) + ')+'
287+
288+ def write_init(self, outfile, size, already):
289+ if str(self.reg) in already:
290+ if not valid_ram_address(already[str(self.reg)], size):
291+ del already[str(self.reg)]
292+ self.write_init(outfile, size, already)
293+ return
294+ else:
295+ address = already[str(self.reg)]
296+ else:
297+ address = random_ram_address()
298+ if size != 'b':
299+ address = address & 0xFFFFFFFE
300+ outfile.write('\tmove.l #' + str(address) + ', ' + str(self.reg) + '\n')
301+ already[str(self.reg)] = address
302+ minv,maxv = get_size_range(size)
303+ outfile.write('\tmove.' + size + ' #' + str(randint(minv, maxv)) + ', (' + str(address) + ').l\n')
304+
305+ def consume_regs(self, program):
306+ self.reg.consume_regs(program)
307+
308+class Decrement(object):
309+ def __init__(self, reg):
310+ self.reg = reg
311+
312+ def __str__(self):
313+ return '-(' + str(self.reg) + ')'
314+
315+ def write_init(self, outfile, size, already):
316+ if str(self.reg) in already:
317+ if not valid_ram_address(already[str(self.reg)]- 4 if size == 'l' else 2 if size == 'w' else 1, size):
318+ del already[str(self.reg)]
319+ self.write_init(outfile, size, already)
320+ return
321+ else:
322+ address = already[str(self.reg)]
323+ else:
324+ address = random_ram_address(mina=0xE00004)
325+ if size != 'b':
326+ address = address & 0xFFFFFFFE
327+ outfile.write('\tmove.l #' + str(address) + ', ' + str(self.reg) + '\n')
328+ already[str(self.reg)] = address
329+ minv,maxv = get_size_range(size)
330+ outfile.write('\tmove.' + size + ' #' + str(randint(minv, maxv)) + ', (' + str(address) + ').l\n')
331+
332+ def consume_regs(self, program):
333+ self.reg.consume_regs(program)
334+
335+class Absolute(object):
336+ def __init__(self, address, size):
337+ self.address = address
338+ self.size = size
339+
340+ def __str__(self):
341+ return '(' + str(self.address) + ').' + self.size
342+
343+ def write_init(self, outfile, size, already):
344+ minv,maxv = get_size_range(size)
345+ outfile.write('\tmove.' + size + ' #' + str(randint(minv, maxv)) + ', '+str(self)+'\n')
346+
347+ def consume_regs(self, program):
348+ pass
349+
350+class Immediate(object):
351+ def __init__(self, value):
352+ self.value = value
353+
354+ def __str__(self):
355+ return '#' + str(self.value)
356+
357+ def write_init(self, outfile, size, already):
358+ pass
359+
360+ def consume_regs(self, program):
361+ pass
362+
363+all_dregs = [Register('d', i) for i in range(0, 8)]
364+all_aregs = [Register('a', i) for i in range(0, 8)]
365+all_indirect = [Indirect(reg) for reg in all_aregs]
366+all_predec = [Decrement(reg) for reg in all_aregs]
367+all_postinc = [Increment(reg) for reg in all_aregs]
368+from random import randint
369+def all_indexed():
370+ return [Indexed(base, index, index_size, randint(-128, 127)) for base in all_aregs for index in all_dregs + all_aregs for index_size in ('w','l')]
371+
372+def all_disp():
373+ return [Displacement(base, randint(-32768, 32767)) for base in all_aregs]
374+
375+def rand_pc_disp():
376+ return [Displacement(Register('pc', 0), randint(-32768, -1024)) for x in xrange(0, 8)]
377+
378+def all_pc_indexed():
379+ return [Indexed(Register('pc', 0), index, index_size, randint(-128, 127)) for index in all_dregs + all_aregs for index_size in ('w','l')]
380+
381+def rand_abs_short():
382+ return [Absolute(random_ram_address(0xFFFF8000), 'w') for x in xrange(0, 8)]
383+
384+def rand_abs_long():
385+ return [Absolute(random_ram_address(), 'l') for x in xrange(0, 8)]
386+
387+def get_size_range(size):
388+ if size == 'b':
389+ return (-128, 127)
390+ elif size == 'w':
391+ return (-32768, 32767)
392+ else:
393+ return (-2147483648, 2147483647)
394+
395+def rand_immediate(size):
396+ minv,maxv = get_size_range(size)
397+
398+ return [Immediate(randint(minv, maxv)) for x in xrange(0,8)]
399+
400+def get_variations(mode, size):
401+ mapping = {
402+ 'd':all_dregs,
403+ 'a':all_aregs,
404+ '(a)':all_indirect,
405+ '-(a)':all_predec,
406+ '(a)+':all_postinc,
407+ '(n,a)':all_disp,
408+ '(n,a,x)':all_indexed,
409+ '(n,pc)':rand_pc_disp,
410+ '(n,pc,x)':all_pc_indexed,
411+ '(n).w':rand_abs_short,
412+ '(n).l':rand_abs_long
413+ }
414+ if mode in mapping:
415+ ret = mapping[mode]
416+ if type(ret) != list:
417+ ret = ret()
418+ return ret
419+ elif mode == '#n':
420+ return rand_immediate(size)
421+ elif mode.startswith('#(') and mode.endswith(')'):
422+ inner = mode[2:-1]
423+ start,sep,end = inner.rpartition('-')
424+ start,end = int(start),int(end)
425+ if end-start > 16:
426+ return [Immediate(randint(start, end)) for x in range(0,8)]
427+ else:
428+ return [Immediate(num) for num in range(start, end+1)]
429+ else:
430+ print "Don't know what to do with source type", mode
431+ return None
432+
433+class Inst2Op(object):
434+ def __init__(self, name, size, src, dst):
435+ self.name = name
436+ self.size = size
437+ self.src = src
438+ self.dst = dst
439+
440+ def __str__(self):
441+ return self.name + '.' + self.size + ' ' + str(self.src) + ', ' + str(self.dst)
442+
443+ def write_init(self, outfile, already):
444+ self.src.write_init(outfile, self.size, already)
445+ self.dst.write_init(outfile, self.size, already)
446+
447+ def invalidate_dest(self, already):
448+ if type(self.dst) == Register:
449+ del already[str(self.dst)]
450+
451+ def save_result(self, reg, always):
452+ if always or type(self.dst) != Register:
453+ if type(self.dst) == Decrement:
454+ src = Increment(self.dst.reg)
455+ elif type(self.dst) == Increment:
456+ src = Decrement(self.dst.reg)
457+ else:
458+ src = self.dst
459+ return 'move.' + self.size + ' ' + str(src) + ', ' + str(reg)
460+ else:
461+ return ''
462+
463+ def consume_regs(self, program):
464+ self.src.consume_regs(program)
465+ self.dst.consume_regs(program)
466+
467+class Inst1Op(Inst2Op):
468+ def __init__(self, name, size, dst):
469+ super(Inst1Op, self).__init__(name, size, dummy_op, dst)
470+
471+ def __str__(self):
472+ return self.name + '.' + self.size + ' ' + str(self.dst)
473+
474+class Entry(object):
475+ def __init__(self, line):
476+ fields = split_fields(line)
477+ self.name = fields[0]
478+ sizes = fields[1]
479+ sources = fields[2].split(';')
480+ if len(fields) > 3:
481+ dests = fields[3].split(';')
482+ else:
483+ dests = None
484+ combos = []
485+ for size in sizes:
486+ for source in sources:
487+ if size != 'b' or source != 'a':
488+ if dests:
489+ for dest in dests:
490+ if size != 'b' or dest != 'a':
491+ combos.append((size, source, dest))
492+ else:
493+ combos.append((size, None, source))
494+ self.cases = combos
495+
496+ def programs(self):
497+ res = []
498+ for (size, src, dst) in self.cases:
499+ dests = get_variations(dst, size)
500+ if src:
501+ sources = get_variations(src, size)
502+ for source in sources:
503+ for dest in dests:
504+ res.append(Program(Inst2Op(self.name, size, source, dest)))
505+ else:
506+ for dest in dests:
507+ res.append(Program(Inst1Op(self.name, size, dest)))
508+ return res
509+
510+def process_entries(f):
511+ entries = []
512+ for line in f:
513+ if not line.startswith('Name') and not line.startswith('#') and len(line.strip()) > 0:
514+ entries.append(Entry(line))
515+ return entries
516+
517+from os import path, mkdir
518+def main(args):
519+ entries = process_entries(open('testcases.txt'))
520+ for entry in entries:
521+ programs = entry.programs()
522+ for program in programs:
523+ dname = program.dirname()
524+ if not path.exists('generated_tests/' + dname):
525+ mkdir('generated_tests/' + dname)
526+ f = open('generated_tests/' + dname + '/' + program.name() + '.s68', 'w')
527+ program.write_rom_test(f)
528+ f.close()
529+
530+if __name__ == '__main__':
531+ import sys
532+ main(sys.argv)
533+
A
gst.c
+505,
-0
1@@ -0,0 +1,505 @@
2+/*
3+ Copyright 2013 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#include "genesis.h"
8+#include "gst.h"
9+#include <string.h>
10+#include <stdio.h>
11+
12+#define GST_68K_REGS 0x80
13+#define GST_68K_REG_SIZE (0xDA-GST_68K_REGS)
14+#define GST_68K_PC_OFFSET (0xC8-GST_68K_REGS)
15+#define GST_68K_SR_OFFSET (0xD0-GST_68K_REGS)
16+#define GST_68K_USP_OFFSET (0xD2-GST_68K_REGS)
17+#define GST_68K_SSP_OFFSET (0xD6-GST_68K_REGS)
18+#define GST_68K_RAM 0x2478
19+#define GST_Z80_REGS 0x404
20+#define GST_Z80_REG_SIZE (0x440-GST_Z80_REGS)
21+#define GST_Z80_RAM 0x474
22+#define GST_VDP_REGS 0xFA
23+#define GST_VDP_MEM 0x12478
24+#define GST_YM_OFFSET 0x1E4
25+#define GST_YM_SIZE (0x3E4-GST_YM_OFFSET)
26+
27+uint32_t read_le_32(uint8_t * data)
28+{
29+ return data[3] << 24 | data[2] << 16 | data[1] << 8 | data[0];
30+}
31+
32+uint16_t read_le_16(uint8_t * data)
33+{
34+ return data[1] << 8 | data[0];
35+}
36+
37+uint16_t read_be_16(uint8_t * data)
38+{
39+ return data[0] << 8 | data[1];
40+}
41+
42+void write_le_32(uint8_t * dst, uint32_t val)
43+{
44+ dst[0] = val;
45+ dst[1] = val >> 8;
46+ dst[2] = val >> 16;
47+ dst[3] = val >> 24;
48+}
49+
50+void write_le_16(uint8_t * dst, uint16_t val)
51+{
52+ dst[0] = val;
53+ dst[1] = val >> 8;
54+}
55+
56+void write_be_32(uint8_t * dst, uint32_t val)
57+{
58+ dst[0] = val >> 24;
59+ dst[1] = val >> 16;
60+ dst[2] = val >> 8;
61+ dst[3] = val;
62+}
63+
64+void write_be_16(uint8_t * dst, uint16_t val)
65+{
66+ dst[0] = val >> 8;
67+ dst[1] = val;
68+}
69+
70+uint32_t m68k_load_gst(m68k_context * context, FILE * gstfile)
71+{
72+ uint8_t buffer[GST_68K_REG_SIZE];
73+ fseek(gstfile, GST_68K_REGS, SEEK_SET);
74+ if (fread(buffer, 1, GST_68K_REG_SIZE, gstfile) != GST_68K_REG_SIZE) {
75+ fputs("Failed to read 68K registers from savestate\n", stderr);
76+ return 0;
77+ }
78+ uint8_t * curpos = buffer;
79+ for (int i = 0; i < 8; i++) {
80+ context->dregs[i] = read_le_32(curpos);
81+ curpos += sizeof(uint32_t);
82+ }
83+ for (int i = 0; i < 8; i++) {
84+ context->aregs[i] = read_le_32(curpos);
85+ curpos += sizeof(uint32_t);
86+ }
87+ uint32_t pc = read_le_32(buffer + GST_68K_PC_OFFSET);
88+ uint16_t sr = read_le_16(buffer + GST_68K_SR_OFFSET);
89+ context->status = sr >> 8;
90+ for (int flag = 4; flag >= 0; flag--) {
91+ context->flags[flag] = sr & 1;
92+ sr >>= 1;
93+ }
94+ if (context->status & (1 << 5)) {
95+ context->aregs[8] = read_le_32(buffer + GST_68K_USP_OFFSET);
96+ } else {
97+ context->aregs[8] = read_le_32(buffer + GST_68K_SSP_OFFSET);
98+ }
99+
100+ return pc;
101+}
102+
103+uint8_t m68k_save_gst(m68k_context * context, uint32_t pc, FILE * gstfile)
104+{
105+ uint8_t buffer[GST_68K_REG_SIZE];
106+ uint8_t * curpos = buffer;
107+ for (int i = 0; i < 8; i++) {
108+ write_le_32(curpos, context->dregs[i]);
109+ curpos += sizeof(uint32_t);
110+ }
111+ for (int i = 0; i < 8; i++) {
112+ write_le_32(curpos, context->aregs[i]);
113+ curpos += sizeof(uint32_t);
114+ }
115+ write_le_32(buffer + GST_68K_PC_OFFSET, pc);
116+ uint16_t sr = context->status << 3;
117+ for (int flag = 4; flag >= 0; flag--) {
118+ sr <<= 1;
119+ sr |= context->flags[flag];
120+ }
121+ write_le_16(buffer + GST_68K_SR_OFFSET, sr);
122+ if (context->status & (1 << 5)) {
123+ write_le_32(buffer + GST_68K_USP_OFFSET, context->aregs[8]);
124+ write_le_32(buffer + GST_68K_SSP_OFFSET, context->aregs[7]);
125+ } else {
126+ write_le_32(buffer + GST_68K_USP_OFFSET, context->aregs[7]);
127+ write_le_32(buffer + GST_68K_SSP_OFFSET, context->aregs[8]);
128+ }
129+ fseek(gstfile, GST_68K_REGS, SEEK_SET);
130+ if (fwrite(buffer, 1, GST_68K_REG_SIZE, gstfile) != GST_68K_REG_SIZE) {
131+ fputs("Failed to write 68K registers to savestate\n", stderr);
132+ return 0;
133+ }
134+
135+ return 1;
136+}
137+
138+uint8_t z80_load_gst(z80_context * context, FILE * gstfile)
139+{
140+ uint8_t regdata[GST_Z80_REG_SIZE];
141+ fseek(gstfile, GST_Z80_REGS, SEEK_SET);
142+ if (fread(regdata, 1, sizeof(regdata), gstfile) != sizeof(regdata)) {
143+ fputs("Failed to read Z80 registers from savestate\n", stderr);
144+ return 0;
145+ }
146+ uint8_t * curpos = regdata;
147+ uint8_t f = *(curpos++);
148+ context->flags[ZF_C] = f & 1;
149+ f >>= 1;
150+ context->flags[ZF_N] = f & 1;
151+ f >>= 1;
152+ context->flags[ZF_PV] = f & 1;
153+ f >>= 2;
154+ context->flags[ZF_H] = f & 1;
155+ f >>= 2;
156+ context->flags[ZF_Z] = f & 1;
157+ f >>= 1;
158+ context->flags[ZF_S] = f;
159+
160+ context->regs[Z80_A] = *curpos;
161+ curpos += 3;
162+ for (int reg = Z80_C; reg <= Z80_IYH; reg++) {
163+ context->regs[reg++] = *(curpos++);
164+ context->regs[reg] = *curpos;
165+ curpos += 3;
166+ }
167+ context->pc = read_le_16(curpos);
168+ curpos += 4;
169+ context->sp = read_le_16(curpos);
170+ curpos += 4;
171+ f = *(curpos++);
172+ context->alt_flags[ZF_C] = f & 1;
173+ f >>= 1;
174+ context->alt_flags[ZF_N] = f & 1;
175+ f >>= 1;
176+ context->alt_flags[ZF_PV] = f & 1;
177+ f >>= 2;
178+ context->alt_flags[ZF_H] = f & 1;
179+ f >>= 2;
180+ context->alt_flags[ZF_Z] = f & 1;
181+ f >>= 1;
182+ context->alt_flags[ZF_S] = f;
183+ context->alt_regs[Z80_A] = *curpos;
184+ curpos += 3;
185+ for (int reg = Z80_C; reg <= Z80_H; reg++) {
186+ context->alt_regs[reg++] = *(curpos++);
187+ context->alt_regs[reg] = *curpos;
188+ curpos += 3;
189+ }
190+ context->regs[Z80_I] = *curpos;
191+ curpos += 2;
192+ context->iff1 = context->iff2 = *curpos;
193+ curpos += 2;
194+ context->reset = !*(curpos++);
195+ context->busreq = *curpos;
196+ curpos += 3;
197+ uint32_t bank = read_le_32(curpos);
198+ if (bank < 0x400000) {
199+ context->mem_pointers[1] = context->mem_pointers[2] + bank;
200+ } else {
201+ context->mem_pointers[1] = NULL;
202+ }
203+ context->bank_reg = bank >> 15;
204+ uint8_t buffer[Z80_RAM_BYTES];
205+ fseek(gstfile, GST_Z80_RAM, SEEK_SET);
206+ if(fread(buffer, 1, sizeof(buffer), gstfile) != (8*1024)) {
207+ fputs("Failed to read Z80 RAM from savestate\n", stderr);
208+ return 0;
209+ }
210+ for (int i = 0; i < Z80_RAM_BYTES; i++)
211+ {
212+ if (context->mem_pointers[0][i] != buffer[i]) {
213+ context->mem_pointers[0][i] = buffer[i];
214+ z80_handle_code_write(i, context);
215+ }
216+ }
217+ context->native_pc = NULL;
218+ context->extra_pc = NULL;
219+ return 1;
220+}
221+
222+uint8_t vdp_load_gst(vdp_context * context, FILE * state_file)
223+{
224+ uint8_t tmp_buf[VRAM_SIZE];
225+ fseek(state_file, GST_VDP_REGS, SEEK_SET);
226+ if (fread(tmp_buf, 1, VDP_REGS, state_file) != VDP_REGS) {
227+ fputs("Failed to read VDP registers from savestate\n", stderr);
228+ return 0;
229+ }
230+ for (uint16_t i = 0; i < VDP_REGS; i++)
231+ {
232+ vdp_control_port_write(context, 0x8000 | (i << 8) | tmp_buf[i]);
233+ }
234+ if (fread(tmp_buf, 1, CRAM_SIZE*2, state_file) != CRAM_SIZE*2) {
235+ fputs("Failed to read CRAM from savestate\n", stderr);
236+ return 0;
237+ }
238+ for (int i = 0; i < CRAM_SIZE; i++) {
239+ uint16_t value;
240+ write_cram_internal(context, i, (tmp_buf[i*2+1] << 8) | tmp_buf[i*2]);
241+ }
242+ if (fread(tmp_buf, 2, VSRAM_SIZE, state_file) != VSRAM_SIZE) {
243+ fputs("Failed to read VSRAM from savestate\n", stderr);
244+ return 0;
245+ }
246+ for (int i = 0; i < VSRAM_SIZE; i++) {
247+ context->vsram[i] = (tmp_buf[i*2+1] << 8) | tmp_buf[i*2];
248+ }
249+ fseek(state_file, GST_VDP_MEM, SEEK_SET);
250+ if (fread(tmp_buf, 1, VRAM_SIZE, state_file) != VRAM_SIZE) {
251+ fputs("Failed to read VRAM from savestate\n", stderr);
252+ return 0;
253+ }
254+ for (int i = 0; i < VRAM_SIZE; i++) {
255+ context->vdpmem[i] = tmp_buf[i];
256+ vdp_check_update_sat_byte(context, i, tmp_buf[i]);
257+ }
258+ return 1;
259+}
260+
261+uint8_t vdp_save_gst(vdp_context * context, FILE * outfile)
262+{
263+ uint8_t tmp_buf[CRAM_SIZE*2];
264+ fseek(outfile, GST_VDP_REGS, SEEK_SET);
265+ if(fwrite(context->regs, 1, VDP_REGS, outfile) != VDP_REGS) {
266+ fputs("Error writing VDP regs to savestate\n", stderr);
267+ return 0;
268+ }
269+ for (int i = 0; i < CRAM_SIZE; i++)
270+ {
271+ tmp_buf[i*2] = context->cram[i];
272+ tmp_buf[i*2+1] = context->cram[i] >> 8;
273+ }
274+ if (fwrite(tmp_buf, 1, sizeof(tmp_buf), outfile) != sizeof(tmp_buf)) {
275+ fputs("Error writing CRAM to savestate\n", stderr);
276+ return 0;
277+ }
278+ for (int i = 0; i < VSRAM_SIZE; i++)
279+ {
280+ tmp_buf[i*2] = context->vsram[i];
281+ tmp_buf[i*2+1] = context->vsram[i] >> 8;
282+ }
283+ if (fwrite(tmp_buf, 2, VSRAM_SIZE, outfile) != VSRAM_SIZE) {
284+ fputs("Error writing VSRAM to savestate\n", stderr);
285+ return 0;
286+ }
287+ fseek(outfile, GST_VDP_MEM, SEEK_SET);
288+ if (fwrite(context->vdpmem, 1, VRAM_SIZE, outfile) != VRAM_SIZE) {
289+ fputs("Error writing VRAM to savestate\n", stderr);
290+ return 0;
291+ }
292+ return 1;
293+}
294+
295+uint8_t z80_save_gst(z80_context * context, FILE * gstfile)
296+{
297+ uint8_t regdata[GST_Z80_REG_SIZE];
298+ uint8_t * curpos = regdata;
299+ memset(regdata, 0, sizeof(regdata));
300+ uint8_t f = context->flags[ZF_S];
301+ f <<= 1;
302+ f |= context->flags[ZF_Z] ;
303+ f <<= 2;
304+ f |= context->flags[ZF_H];
305+ f <<= 2;
306+ f |= context->flags[ZF_PV];
307+ f <<= 1;
308+ f |= context->flags[ZF_N];
309+ f <<= 1;
310+ f |= context->flags[ZF_C];
311+ *(curpos++) = f;
312+ *curpos = context->regs[Z80_A];
313+
314+ curpos += 3;
315+ for (int reg = Z80_C; reg <= Z80_IYH; reg++) {
316+ *(curpos++) = context->regs[reg++];
317+ *curpos = context->regs[reg];
318+ curpos += 3;
319+ }
320+ write_le_16(curpos, context->pc);
321+ curpos += 4;
322+ write_le_16(curpos, context->sp);
323+ curpos += 4;
324+ f = context->alt_flags[ZF_S];
325+ f <<= 1;
326+ f |= context->alt_flags[ZF_Z] ;
327+ f <<= 2;
328+ f |= context->alt_flags[ZF_H];
329+ f <<= 2;
330+ f |= context->alt_flags[ZF_PV];
331+ f <<= 1;
332+ f |= context->alt_flags[ZF_N];
333+ f <<= 1;
334+ f |= context->alt_flags[ZF_C];
335+ *(curpos++) = f;
336+ *curpos = context->alt_regs[Z80_A];
337+ curpos += 3;
338+ for (int reg = Z80_C; reg <= Z80_H; reg++) {
339+ *(curpos++) = context->alt_regs[reg++];
340+ *curpos = context->alt_regs[reg];
341+ curpos += 3;
342+ }
343+ *curpos = context->regs[Z80_I];
344+ curpos += 2;
345+ *curpos = context->iff1;
346+ curpos += 2;
347+ *(curpos++) = !context->reset;
348+ *curpos = context->busreq;
349+ curpos += 3;
350+ uint32_t bank = context->bank_reg << 15;
351+ write_le_32(curpos, bank);
352+ fseek(gstfile, GST_Z80_REGS, SEEK_SET);
353+ if (fwrite(regdata, 1, sizeof(regdata), gstfile) != sizeof(regdata)) {
354+ return 0;
355+ }
356+ fseek(gstfile, GST_Z80_RAM, SEEK_SET);
357+ if(fwrite(context->mem_pointers[0], 1, 8*1024, gstfile) != (8*1024)) {
358+ fputs("Failed to write Z80 RAM to savestate\n", stderr);
359+ return 0;
360+ }
361+ return 1;
362+}
363+
364+uint8_t ym_load_gst(ym2612_context * context, FILE * gstfile)
365+{
366+ uint8_t regdata[GST_YM_SIZE];
367+ fseek(gstfile, GST_YM_OFFSET, SEEK_SET);
368+ if (fread(regdata, 1, sizeof(regdata), gstfile) != sizeof(regdata)) {
369+ return 0;
370+ }
371+ for (int i = 0; i < sizeof(regdata); i++) {
372+ if (i & 0x100) {
373+ ym_address_write_part2(context, i & 0xFF);
374+ } else {
375+ ym_address_write_part1(context, i);
376+ }
377+ ym_data_write(context, regdata[i]);
378+ }
379+ return 1;
380+}
381+
382+uint8_t ym_save_gst(ym2612_context * context, FILE * gstfile)
383+{
384+ uint8_t regdata[GST_YM_SIZE];
385+ for (int i = 0; i < sizeof(regdata); i++) {
386+ if (i & 0x100) {
387+ int reg = (i & 0xFF);
388+ if (reg >= YM_PART2_START && reg < YM_REG_END) {
389+ regdata[i] = context->part2_regs[reg-YM_PART2_START];
390+ } else {
391+ regdata[i] = 0xFF;
392+ }
393+ } else {
394+ if (i >= YM_PART1_START && i < YM_REG_END) {
395+ regdata[i] = context->part1_regs[i-YM_PART1_START];
396+ } else {
397+ regdata[i] = 0xFF;
398+ }
399+ }
400+ }
401+ fseek(gstfile, GST_YM_OFFSET, SEEK_SET);
402+ if (fwrite(regdata, 1, sizeof(regdata), gstfile) != sizeof(regdata)) {
403+ return 0;
404+ }
405+ return 1;
406+}
407+
408+uint32_t load_gst(genesis_context * gen, char * fname)
409+{
410+ char buffer[4096];
411+ FILE * gstfile = fopen(fname, "rb");
412+ if (!gstfile) {
413+ fprintf(stderr, "Could not open file %s for reading\n", fname);
414+ goto error;
415+ }
416+ char ident[5];
417+ if (fread(ident, 1, sizeof(ident), gstfile) != sizeof(ident)) {
418+ fprintf(stderr, "Could not read ident code from %s\n", fname);
419+ goto error_close;
420+ }
421+ if (memcmp(ident, "GST\x40\xE0", 3) != 0) {
422+ fprintf(stderr, "%s doesn't appear to be a GST savestate. The ident code is %c%c%c\\x%X\\x%X instead of GST\\x40\\xE0.\n", fname, ident[0], ident[1], ident[2], ident[3], ident[4]);
423+ goto error_close;
424+ }
425+ uint32_t pc = m68k_load_gst(gen->m68k, gstfile);
426+ if (!pc) {
427+ goto error_close;
428+ }
429+
430+ if (!vdp_load_gst(gen->vdp, gstfile)) {
431+ goto error_close;
432+ }
433+ if (!ym_load_gst(gen->ym, gstfile)) {
434+ goto error_close;
435+ }
436+ if (!z80_load_gst(gen->z80, gstfile)) {
437+ goto error_close;
438+ }
439+ gen->io.ports[0].control = 0x40;
440+ gen->io.ports[1].control = 0x40;
441+
442+ fseek(gstfile, GST_68K_RAM, SEEK_SET);
443+ for (int i = 0; i < (32*1024);) {
444+ if (fread(buffer, 1, sizeof(buffer), gstfile) != sizeof(buffer)) {
445+ fputs("Failed to read 68K RAM from savestate\n", stderr);
446+ return 0;
447+ }
448+ for(char *curpos = buffer; curpos < (buffer + sizeof(buffer)); curpos += sizeof(uint16_t)) {
449+ uint16_t word = read_be_16(curpos);
450+ if (word != gen->work_ram[i]) {
451+ gen->work_ram[i] = word;
452+ m68k_handle_code_write(0xFF0000 | (i << 1), gen->m68k);
453+ }
454+ i++;
455+ }
456+ }
457+ fclose(gstfile);
458+ return pc;
459+
460+error_close:
461+ fclose(gstfile);
462+error:
463+ return 0;
464+}
465+
466+uint8_t save_gst(genesis_context * gen, char *fname, uint32_t m68k_pc)
467+{
468+ char buffer[4096];
469+ FILE * gstfile = fopen(fname, "wb");
470+ if (!gstfile) {
471+ fprintf(stderr, "Could not open %s for writing\n", fname);
472+ goto error;
473+ }
474+ if (fwrite("GST\x40\xE0", 1, 5, gstfile) != 5) {
475+ fputs("Error writing signature to savestate\n", stderr);
476+ goto error_close;
477+ }
478+ if (!m68k_save_gst(gen->m68k, m68k_pc, gstfile)) {
479+ goto error_close;
480+ }
481+ if (!z80_save_gst(gen->z80, gstfile)) {
482+ goto error_close;
483+ }
484+ if (!vdp_save_gst(gen->vdp, gstfile)) {
485+ goto error_close;
486+ }
487+ if (!ym_save_gst(gen->ym, gstfile)) {
488+ goto error_close;
489+ }
490+ fseek(gstfile, GST_68K_RAM, SEEK_SET);
491+ for (int i = 0; i < (32*1024);) {
492+ for(char *curpos = buffer; curpos < (buffer + sizeof(buffer)); curpos += sizeof(uint16_t)) {
493+ write_be_16(curpos, gen->work_ram[i++]);
494+ }
495+ if (fwrite(buffer, 1, sizeof(buffer), gstfile) != sizeof(buffer)) {
496+ fputs("Failed to write 68K RAM to savestate\n", stderr);
497+ return 0;
498+ }
499+ }
500+ return 1;
501+
502+error_close:
503+ fclose(gstfile);
504+error:
505+ return 0;
506+}
A
gst.h
+13,
-0
1@@ -0,0 +1,13 @@
2+/*
3+ Copyright 2013 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#ifndef GST_H_
8+#define GST_H_
9+#include "blastem.h"
10+
11+uint8_t save_gst(genesis_context * gen, char *fname, uint32_t m68k_pc);
12+uint32_t load_gst(genesis_context * gen, char * fname);
13+
14+#endif //GST_H_
A
hash.c
+101,
-0
1@@ -0,0 +1,101 @@
2+#include <stdint.h>
3+#include <string.h>
4+
5+//NOTE: This is only intended for use in file identification
6+//Please do not use this in a cryptographic setting as no attempts have been
7+//made at avoiding side channel attacks
8+
9+static uint32_t rotleft(uint32_t val, uint32_t shift)
10+{
11+ return val << shift | val >> (32-shift);
12+}
13+
14+static void sha1_step(uint32_t *state, uint32_t f, uint32_t k, uint32_t w)
15+{
16+ uint32_t tmp = rotleft(state[0], 5) + f + state[4] + k + w;
17+ state[4] = state[3];
18+ state[3] = state[2];
19+ state[2] = rotleft(state[1], 30);
20+ state[1] = state[0];
21+ state[0] = tmp;
22+}
23+
24+static void sha1_chunk(uint8_t *chunk, uint32_t *hash)
25+{
26+ uint32_t state[5], w[80];
27+ memcpy(state, hash, sizeof(state));
28+ for (uint32_t src = 0; src < 64; src += 4)
29+ {
30+ w[src >> 2] = chunk[src] << 24 | chunk[src+1] << 16 | chunk[src+2] << 8 | chunk[src+3];
31+ }
32+ for (uint32_t cur = 16; cur < 80; cur++)
33+ {
34+ w[cur] = rotleft(w[cur-3] ^ w[cur-8] ^ w[cur-14] ^ w[cur-16], 1);
35+ }
36+ for (uint32_t cur = 0; cur < 20; cur++)
37+ {
38+ sha1_step(state, (state[1] & state[2]) | ((~state[1]) & state[3]), 0x5A827999, w[cur]);
39+ }
40+ for (uint32_t cur = 20; cur < 40; cur++)
41+ {
42+ sha1_step(state, state[1] ^ state[2] ^ state[3], 0x6ED9EBA1, w[cur]);
43+ }
44+ for (uint32_t cur = 40; cur < 60; cur++)
45+ {
46+ sha1_step(state, (state[1] & state[2]) | (state[1] & state[3]) | (state[2] & state[3]), 0x8F1BBCDC, w[cur]);
47+ }
48+ for (uint32_t cur = 60; cur < 80; cur++)
49+ {
50+ sha1_step(state, state[1] ^ state[2] ^ state[3], 0xCA62C1D6, w[cur]);
51+ }
52+ for (uint32_t i = 0; i < 5; i++)
53+ {
54+ hash[i] += state[i];
55+ }
56+}
57+
58+void sha1(uint8_t *data, uint64_t size, uint8_t *out)
59+{
60+ uint32_t hash[5] = {0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0};
61+ uint8_t last[128];
62+ uint32_t last_size = 0;
63+ if ((size & 63) != 0) {
64+ for (uint32_t src = size - (size & 63); src < size; src++)
65+ {
66+ last[last_size++] = data[src];
67+ }
68+ }
69+ uint64_t bitsize = size * 8;
70+ size -= last_size;
71+ last[last_size++] = 0x80;
72+ while ((last_size & 63) != 56)
73+ {
74+ last[last_size++] = 0;
75+ }
76+
77+ last[last_size++] = bitsize >> 56;
78+ last[last_size++] = bitsize >> 48;
79+ last[last_size++] = bitsize >> 40;
80+ last[last_size++] = bitsize >> 32;
81+ last[last_size++] = bitsize >> 24;
82+ last[last_size++] = bitsize >> 16;
83+ last[last_size++] = bitsize >> 8;
84+ last[last_size++] = bitsize;
85+
86+ for (uint64_t cur = 0; cur < size; cur += 64)
87+ {
88+ sha1_chunk(data + cur, hash);
89+ }
90+ for (uint64_t cur = 0; cur < last_size; cur += 64)
91+ {
92+ sha1_chunk(last + cur, hash);
93+ }
94+ for (uint32_t cur = 0; cur < 20; cur += 4)
95+ {
96+ uint32_t val = hash[cur >> 2];
97+ out[cur] = val >> 24;
98+ out[cur+1] = val >> 16;
99+ out[cur+2] = val >> 8;
100+ out[cur+3] = val;
101+ }
102+}
A
hash.h
+12,
-0
1@@ -0,0 +1,12 @@
2+#ifndef HASH_H_
3+#define HASH_H_
4+
5+#include <stdint.h>
6+
7+//NOTE: This is only intended for use in file identification
8+//Please do not use this in a cryptographic setting as no attempts have been
9+//made at avoiding side channel attacks
10+
11+void sha1(uint8_t *data, uint64_t size, uint8_t *out);
12+
13+#endif //HASH_H_
A
i2c.c
+250,
-0
1@@ -0,0 +1,250 @@
2+#include "genesis.h"
3+#include "util.h"
4+
5+enum {
6+ I2C_IDLE,
7+ I2C_START,
8+ I2C_DEVICE_ACK,
9+ I2C_ADDRESS_HI,
10+ I2C_ADDRESS_HI_ACK,
11+ I2C_ADDRESS,
12+ I2C_ADDRESS_ACK,
13+ I2C_READ,
14+ I2C_READ_ACK,
15+ I2C_WRITE,
16+ I2C_WRITE_ACK
17+};
18+
19+char * i2c_states[] = {
20+ "idle",
21+ "start",
22+ "device ack",
23+ "address hi",
24+ "address hi ack",
25+ "address",
26+ "address ack",
27+ "read",
28+ "read_ack",
29+ "write",
30+ "write_ack"
31+};
32+
33+void eeprom_init(eeprom_state *state, uint8_t *buffer, uint32_t size)
34+{
35+ state->slave_sda = 1;
36+ state->host_sda = state->scl = 0;
37+ state->buffer = buffer;
38+ state->size = size;
39+ state->state = I2C_IDLE;
40+}
41+
42+void set_host_sda(eeprom_state *state, uint8_t val)
43+{
44+ if (state->scl) {
45+ if (val & ~state->host_sda) {
46+ //low to high, stop condition
47+ state->state = I2C_IDLE;
48+ state->slave_sda = 1;
49+ } else if (~val & state->host_sda) {
50+ //high to low, start condition
51+ state->state = I2C_START;
52+ state->slave_sda = 1;
53+ state->counter = 8;
54+ }
55+ }
56+ state->host_sda = val;
57+}
58+
59+void set_scl(eeprom_state *state, uint8_t val)
60+{
61+ if (val & ~state->scl) {
62+ //low to high transition
63+ switch (state->state)
64+ {
65+ case I2C_START:
66+ case I2C_ADDRESS_HI:
67+ case I2C_ADDRESS:
68+ case I2C_WRITE:
69+ state->latch = state->host_sda | state->latch << 1;
70+ state->counter--;
71+ if (!state->counter) {
72+ switch (state->state & 0x7F)
73+ {
74+ case I2C_START:
75+ state->state = I2C_DEVICE_ACK;
76+ break;
77+ case I2C_ADDRESS_HI:
78+ state->address = state->latch << 8;
79+ state->state = I2C_ADDRESS_HI_ACK;
80+ break;
81+ case I2C_ADDRESS:
82+ state->address |= state->latch;
83+ state->state = I2C_ADDRESS_ACK;
84+ break;
85+ case I2C_WRITE:
86+ state->buffer[state->address] = state->latch;
87+ state->state = I2C_WRITE_ACK;
88+ break;
89+ }
90+ }
91+ break;
92+ case I2C_DEVICE_ACK:
93+ if (state->latch & 1) {
94+ state->state = I2C_READ;
95+ state->counter = 8;
96+ if (state->size < 256) {
97+ state->address = state->latch >> 1;
98+ }
99+ state->latch = state->buffer[state->address];
100+ } else {
101+ if (state->size < 256) {
102+ state->address = state->latch >> 1;
103+ state->state = I2C_WRITE;
104+ } else if (state->size < 4096) {
105+ state->address = (state->latch & 0xE) << 7;
106+ state->state = I2C_ADDRESS;
107+ } else {
108+ state->state = I2C_ADDRESS_HI;
109+ }
110+ state->counter = 8;
111+ }
112+ break;
113+ case I2C_ADDRESS_HI_ACK:
114+ state->state = I2C_ADDRESS;
115+ state->counter = 8;
116+ break;
117+ case I2C_ADDRESS_ACK:
118+ state->state = I2C_WRITE;
119+ state->address &= state->size-1;
120+ state->counter = 8;
121+ break;
122+ case I2C_READ:
123+ state->counter--;
124+ if (!state->counter) {
125+ state->state = I2C_READ_ACK;
126+ }
127+ break;
128+ case I2C_READ_ACK:
129+ state->state = I2C_READ;
130+ state->counter = 8;
131+ state->address++;
132+ //TODO: page mask
133+ state->address &= state->size-1;
134+ state->latch = state->buffer[state->address];
135+ break;
136+ case I2C_WRITE_ACK:
137+ state->state = I2C_WRITE;
138+ state->counter = 8;
139+ state->address++;
140+ //TODO: page mask
141+ state->address &= state->size-1;
142+ break;
143+ }
144+ } else if (~val & state->scl) {
145+ //high to low transition
146+ switch (state->state & 0x7F)
147+ {
148+ case I2C_DEVICE_ACK:
149+ case I2C_ADDRESS_HI_ACK:
150+ case I2C_ADDRESS_ACK:
151+ case I2C_READ_ACK:
152+ case I2C_WRITE_ACK:
153+ state->slave_sda = 0;
154+ break;
155+ case I2C_READ:
156+ state->slave_sda = state->latch >> 7;
157+ state->latch = state->latch << 1;
158+ break;
159+ default:
160+ state->slave_sda = 1;
161+ break;
162+ }
163+ }
164+ state->scl = val;
165+}
166+
167+uint8_t get_sda(eeprom_state *state)
168+{
169+ return state->host_sda & state->slave_sda;
170+}
171+
172+eeprom_map *find_eeprom_map(uint32_t address, genesis_context *gen)
173+{
174+ for (int i = 0; i < gen->num_eeprom; i++)
175+ {
176+ if (address >= gen->eeprom_map[i].start && address <= gen->eeprom_map[i].end) {
177+ return gen->eeprom_map + i;
178+ }
179+ }
180+ return NULL;
181+}
182+
183+void * write_eeprom_i2c_w(uint32_t address, void * context, uint16_t value)
184+{
185+ genesis_context *gen = ((m68k_context *)context)->system;
186+ eeprom_map *map = find_eeprom_map(address, gen);
187+ if (!map) {
188+ fatal_error("Could not find EEPROM map for address %X\n", address);
189+ }
190+ if (map->scl_mask) {
191+ set_scl(&gen->eeprom, (value & map->scl_mask) != 0);
192+ }
193+ if (map->sda_write_mask) {
194+ set_host_sda(&gen->eeprom, (value & map->sda_write_mask) != 0);
195+ }
196+ return context;
197+}
198+
199+void * write_eeprom_i2c_b(uint32_t address, void * context, uint8_t value)
200+{
201+ genesis_context *gen = ((m68k_context *)context)->system;
202+ eeprom_map *map = find_eeprom_map(address, gen);
203+ if (!map) {
204+ fatal_error("Could not find EEPROM map for address %X\n", address);
205+ }
206+
207+ uint16_t expanded, mask;
208+ if (address & 1) {
209+ expanded = value;
210+ mask = 0xFF;
211+ } else {
212+ expanded = value << 8;
213+ mask = 0xFF00;
214+ }
215+ if (map->scl_mask & mask) {
216+ set_scl(&gen->eeprom, (expanded & map->scl_mask) != 0);
217+ }
218+ if (map->sda_write_mask & mask) {
219+ set_host_sda(&gen->eeprom, (expanded & map->sda_write_mask) != 0);
220+ }
221+ return context;
222+}
223+
224+uint16_t read_eeprom_i2c_w(uint32_t address, void * context)
225+{
226+ genesis_context *gen = ((m68k_context *)context)->system;
227+ eeprom_map *map = find_eeprom_map(address, gen);
228+ if (!map) {
229+ fatal_error("Could not find EEPROM map for address %X\n", address);
230+ }
231+ uint16_t ret = 0;
232+ if (map->sda_read_bit < 16) {
233+ ret = get_sda(&gen->eeprom) << map->sda_read_bit;
234+ }
235+ return ret;
236+}
237+
238+uint8_t read_eeprom_i2c_b(uint32_t address, void * context)
239+{
240+ genesis_context *gen = ((m68k_context *)context)->system;
241+ eeprom_map *map = find_eeprom_map(address, gen);
242+ if (!map) {
243+ fatal_error("Could not find EEPROM map for address %X\n", address);
244+ }
245+ uint8_t bit = address & 1 ? map->sda_read_bit : map->sda_read_bit - 8;
246+ uint8_t ret = 0;
247+ if (bit < 8) {
248+ ret = get_sda(&gen->eeprom) << bit;
249+ }
250+ return ret;
251+}
A
i2c.h
+22,
-0
1@@ -0,0 +1,22 @@
2+#ifndef I2C_H_
3+#define I2C_H_
4+
5+typedef struct {
6+ char *buffer;
7+ uint32_t size;
8+ uint16_t address;
9+ uint8_t host_sda;
10+ uint8_t slave_sda;
11+ uint8_t scl;
12+ uint8_t state;
13+ uint8_t counter;
14+ uint8_t latch;
15+} eeprom_state;
16+
17+void eeprom_init(eeprom_state *state, uint8_t *buffer, uint32_t size);
18+void * write_eeprom_i2c_w(uint32_t address, void * context, uint16_t value);
19+void * write_eeprom_i2c_b(uint32_t address, void * context, uint8_t value);
20+uint16_t read_eeprom_i2c_w(uint32_t address, void * context);
21+uint8_t read_eeprom_i2c_b(uint32_t address, void * context);
22+
23+#endif //I2C_H_
+316,
-0
1@@ -0,0 +1,316 @@
2+#!/usr/bin/env python
3+from PIL import Image
4+
5+def gchannel(Val):
6+ return (Val >> 4) & 0xE
7+
8+threshold = 127
9+
10+def get_rgba(im, pixels=None, idx=None, color=None):
11+ A = 255
12+ if color is None:
13+ color = pixels[idx]
14+ if type(color) == int:
15+ R, G, B = im.getpalette()[color*3:color*3+3]
16+ else:
17+ if len(color) == 4:
18+ R, G, B, A = color
19+ elif len(color) == 3:
20+ R, G, B = color
21+ else:
22+ L, A = color
23+ R = G = B = L
24+ return (R, G, B, A)
25+
26+def get_gcolor(im, threshold, pixels=None, idx=None, color=None):
27+ R,G,B,A = get_rgba(im, pixels, idx, color)
28+ if A > threshold:
29+ return (gchannel(R), gchannel(G), gchannel(B))
30+ return 0
31+
32+def get_color_info(im, pixels, rng, threshold, exclude={}):
33+ gencolors = {}
34+ A = 255
35+ pal = None
36+ transparent = False
37+ for idx in rng:
38+ gcolor = get_gcolor(im, threshold, pixels, idx)
39+ if type(gcolor) == tuple:
40+ if not gcolor in exclude:
41+ if gcolor in gencolors:
42+ gencolors[gcolor] += 1
43+ else:
44+ gencolors[gcolor] = 1
45+ else:
46+ transparent = True
47+ glist = [(gencolors[color], color) for color in gencolors]
48+ glist.sort()
49+ glist.reverse()
50+ return glist
51+
52+def get_color_info_both(im, pixels, rng, threshold, exclude={}):
53+ gencolors = {}
54+ A = 255
55+ pal = None
56+ transparent = False
57+ for idx in rng:
58+ gcolor = get_gcolor(im, threshold, pixels, idx)
59+ if type(gcolor) == tuple:
60+ if not gcolor in exclude:
61+ if not gcolor in gencolors:
62+ _,best = best_match(gcolor, (exclude,))
63+ gencolors[gcolor] = (color_dist(gcolor, best), 1)
64+ else:
65+ (dist, count) = gencolors[gcolor]
66+ gencolors[gcolor] = (dist, count+1)
67+ else:
68+ transparent = True
69+ glist = [(gencolors[color][0] * gencolors[color][1], color) for color in gencolors]
70+ glist.sort()
71+ glist.reverse()
72+
73+ return glist
74+
75+def make_palette(im, trans_thresh, max_global, max_line):
76+ pixels = im.getdata()
77+ (width, height) = im.size
78+ colors = get_color_info(im, pixels, xrange(0, height * width), trans_thresh)
79+ print len(colors), 'distinct 9-bit colors in image'
80+ glob_pal = {}
81+ print 'Static Palette:'
82+ while len(glob_pal) < max_global and len(colors):
83+ idx = len(glob_pal)
84+ (count, color) = colors[0]
85+ print str(idx) + ':', color
86+ glob_pal[color] = idx
87+ colors = get_color_info_both(im, pixels, xrange(0, height * width), trans_thresh, glob_pal)
88+ line_pals = []
89+ if max_global < len(colors):
90+ for line in xrange(0, height):
91+ linestart = line * width
92+ if len(glob_pal):
93+ linecolors = get_color_info_both(im, pixels, xrange(linestart, linestart+width), trans_thresh, glob_pal)
94+ else:
95+ linecolors = get_color_info(im, pixels, xrange(linestart, linestart+width), trans_thresh)
96+ line_pal = {}
97+ while len(line_pal) < max_line and len(linecolors):
98+ (score, color) = linecolors[0]
99+ line_pal[color] = len(line_pal) + max_global
100+ if len(line_pal) < max_line:
101+ combo = dict(glob_pal)
102+ for color in line_pal:
103+ combo[color] = line_pal[color]
104+ linecolors = get_color_info_both(im, pixels, xrange(linestart, linestart+width), trans_thresh, combo)
105+ #for idx in xrange(0, min(max_line, len(linecolors))):
106+ # (count, color) = linecolors[idx]
107+ # line_pal[color] = idx + max_global
108+ line_pals.append(line_pal)
109+ return (glob_pal, line_pals, max_global, max_line)
110+
111+def color_dist(a, b):
112+ (ra, ga, ba) = a
113+ (rb, gb, bb) = b
114+ return (ra-rb)**2 + (ga-gb)**2 + (ba-bb)**2
115+
116+def best_match(gpixel, pals):
117+ bestdist = color_dist((0,0,0), (15, 15, 15))
118+ bestpalidx = 0
119+ bestcolor = (0,0,0)
120+ for i in xrange(0, len(pals)):
121+ pal = pals[i]
122+ for cur in pal:
123+ curdist = color_dist(gpixel, cur)
124+ if curdist < bestdist:
125+ bestdist = curdist
126+ bestpalidx = pal[cur]
127+ bestcolor = cur
128+ return (bestpalidx, bestcolor)
129+
130+def trans_image(im, trans_thresh, pal, chunky):
131+ (global_pal, line_pals, _, _) = pal
132+ pixels = im.getdata()
133+ (width, height) = im.size
134+ gpixels = []
135+ A = 255
136+ pal = None
137+ x = 0
138+ y = 0
139+ numchannels = len(im.getbands())
140+ offset = 1 if numchannels == 4 or numchannels == 2 else 0
141+ for pixel in pixels:
142+ if x == width:
143+ x = 0
144+ y += 1
145+ if width % 8 and not chunky:
146+ for i in xrange(0, 8-(width%8)):
147+ gpixels.append(0)
148+ gpixel = get_gcolor(im, trans_thresh, color=pixel)
149+ if type(gpixel) == tuple:
150+ if gpixel in global_pal:
151+ val = global_pal[gpixel]
152+ elif gpixel in line_pals[y]:
153+ val = line_pals[y][gpixel]
154+ else:
155+ bestpal,color = best_match(gpixel, (global_pal, line_pals[y]))
156+ val = bestpal
157+ gpixels.append(offset+val)
158+ else:
159+ gpixels.append(gpixel)
160+ x += 1
161+ if width % 8 and not chunky:
162+ for i in xrange(0, 8-(width%8)):
163+ gpixels.append(0)
164+ width += 8-(width%8)
165+ if height % 8 and not chunky:
166+ for y in xrange(0, 8-(height%8)):
167+ for x in xrange(0, width):
168+ gpixels.append(0)
169+ height += 8-(height%8)
170+
171+ return (width, height, gpixels)
172+
173+def appendword(b, word):
174+ b.append(word >> 8)
175+ b.append(word & 0xff)
176+
177+def to_tiles(palpix, raw=False, chunky=False, tile_height=8, sprite_order = False):
178+ (width, height, pixels) = palpix
179+ b = bytearray()
180+ if chunky:
181+ if not raw:
182+ appendword(b, width)
183+ appendword(b, height)
184+ for pixel in pixels:
185+ b.append(pixel)
186+ else:
187+ cwidth = width/8
188+ cheight = height/tile_height
189+ words = len(pixels)/4
190+ if not raw:
191+ appendword(b, words)
192+ appendword(b, cwidth)
193+ appendword(b, cheight)
194+
195+ if sprite_order:
196+ for cx in xrange(0, cwidth):
197+ xstart = cx * 8
198+ for cy in xrange(0, cheight):
199+ startoff = cy*tile_height*width + xstart
200+ for row in xrange(0, tile_height):
201+ rowoff = startoff + row*width
202+ for bytecol in xrange(0, 4):
203+ boff = bytecol * 2 + rowoff
204+ #print 'boff:', boff, 'len(pixels)', len(pixels), 'cx', cx, 'cy', cy, 'cwidth', cwidth, 'cheight', cheight
205+ #print 'pixels[boff]:', pixels[boff]
206+ b.append(pixels[boff] << 4 | pixels[boff+1])
207+ else:
208+ for cy in xrange(0, cheight):
209+ ystart = cy*tile_height*width
210+ for cx in xrange(0, cwidth):
211+ startoff = (cx*8) + ystart
212+ for row in xrange(0, tile_height):
213+ rowoff = startoff + row*width
214+ for bytecol in xrange(0, 4):
215+ boff = bytecol * 2 + rowoff
216+ #print 'boff:', boff, 'len(pixels)', len(pixels), 'cx', cx, 'cy', cy, 'cwidth', cwidth, 'cheight', cheight
217+ #print 'pixels[boff]:', pixels[boff]
218+ b.append(pixels[boff] << 4 | pixels[boff+1])
219+ return b
220+
221+def add_pal_entries(tiles, pal):
222+ (global_pal, line_pals, max_global, max_line) = pal
223+ tiles.append(max_global)
224+ tiles.append(max_line)
225+ pal_list = [(0, 0, 0)] * max_global
226+ for entry in global_pal:
227+ pal_list[global_pal[entry]] = entry
228+ for entry in pal_list:
229+ (R, G, B) = entry
230+ tiles.append(B)
231+ tiles.append(G << 4 | R)
232+ for line in line_pals:
233+ pal_list = [(0, 0, 0)] * max_line
234+ for entry in line:
235+ pal_list[line[entry]-max_global] = entry
236+ for entry in pal_list:
237+ (R, G, B) = entry
238+ tiles.append(B)
239+ tiles.append(G << 4 | R)
240+
241+
242+
243+def main(argv):
244+
245+ posargs = []
246+ omit_pal = raw = chunky = False
247+ expect_option = None
248+ options = {}
249+ tile_height = 8
250+ sprite_order = False
251+ for i in xrange(1, len(argv)):
252+ if argv[i].startswith('-'):
253+ if argv[i] == '-r':
254+ raw = True
255+ elif argv[i] == '-p':
256+ omit_pal = True
257+ elif argv[i] == '-o':
258+ sprite_order = True
259+ elif argv[i] == '-c':
260+ chunky = True
261+ elif argv[i] == '-i':
262+ tile_height = 16
263+ elif argv[i] == '-s' or argv[i] == '--spec':
264+ expect_option = 'specfile'
265+ else:
266+ print 'Unrecognized switch', argv[i]
267+ return
268+ elif not expect_option is None:
269+ options[expect_option] = argv[i]
270+ expect_option = None
271+ else:
272+ posargs.append(argv[i])
273+ if len(posargs) < 2 and not ('specfile' in options and len(posargs) >= 1):
274+ print "Usage: img2tiles.py [OPTIONS] infile outfile [STATIC_COLORS [DYNAMIC_COLORS]]"
275+ return
276+ if 'specfile' in options:
277+ props = open(options['specfile']).read().strip().split(',')
278+ fname,static_colors,dynamic_colors = props[0:3]
279+ for prop in props[3:]:
280+ if prop == 'chunky':
281+ chunky = True
282+ elif prop == 'raw':
283+ raw = True
284+ elif prop == 'nopal':
285+ omit_pal = True
286+ elif prop == 'interlace':
287+ tile_height = 16
288+ elif prop == 'sprite':
289+ sprite_order = True
290+ static_colors = int(static_colors)
291+ dynamic_colors = int(dynamic_colors)
292+ outfile = posargs[0]
293+ else:
294+ fname = posargs[0]
295+ outfile = posargs[1]
296+ static_colors = 8
297+ dynamic_colors = 8
298+ if len(posargs) > 2:
299+ static_colors = int(posargs[2])
300+ dynamic_colors = 16-static_colors
301+ if len(posargs) > 3:
302+ dynamic_colors = int(posargs[3])
303+ if dynamic_colors + static_colors > 16:
304+ print "No more than 16 combined dynamic and static colors are allowed"
305+ return
306+ im = Image.open(fname)
307+ pal = make_palette(im, threshold, static_colors, dynamic_colors)
308+ palpix = trans_image(im, threshold, pal, chunky)
309+ tiles = to_tiles(palpix, raw, chunky, tile_height, sprite_order)
310+ if not omit_pal:
311+ bits = add_pal_entries(tiles, pal)
312+ out = open(outfile, 'wb')
313+ out.write(tiles)
314+
315+if __name__ == '__main__':
316+ import sys
317+ main(sys.argv)
A
io.c
+1107,
-0
1@@ -0,0 +1,1107 @@
2+/*
3+ Copyright 2013 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#include <unistd.h>
8+#include <fcntl.h>
9+#include <sys/socket.h>
10+#include <sys/un.h>
11+#include <sys/types.h>
12+#include <sys/stat.h>
13+#include <errno.h>
14+#include <string.h>
15+#include <stdlib.h>
16+
17+#include "serialize.h"
18+#include "io.h"
19+#include "blastem.h"
20+#include "render.h"
21+#include "util.h"
22+#include "bindings.h"
23+
24+#define CYCLE_NEVER 0xFFFFFFFF
25+#define MIN_POLL_INTERVAL 6840
26+
27+const char * device_type_names[] = {
28+ "None",
29+ "SMS gamepad",
30+ "3-button gamepad",
31+ "6-button gamepad",
32+ "Mega Mouse",
33+ "Saturn Keyboard",
34+ "XBAND Keyboard",
35+ "Menacer",
36+ "Justifier",
37+ "Sega multi-tap",
38+ "EA 4-way Play cable A",
39+ "EA 4-way Play cable B",
40+ "Sega Parallel Transfer Board",
41+ "Generic Device"
42+};
43+
44+#define GAMEPAD_TH0 0
45+#define GAMEPAD_TH1 1
46+#define GAMEPAD_EXTRA 2
47+#define GAMEPAD_NONE 0xF
48+
49+#define IO_TH0 0
50+#define IO_TH1 1
51+#define IO_STATE 2
52+
53+enum {
54+ IO_WRITE_PENDING,
55+ IO_WRITTEN,
56+ IO_READ_PENDING,
57+ IO_READ
58+};
59+
60+typedef struct {
61+ uint8_t states[2], value;
62+} gp_button_def;
63+
64+
65+static gp_button_def button_defs[NUM_GAMEPAD_BUTTONS] = {
66+ [DPAD_UP] = {.states = {GAMEPAD_TH0, GAMEPAD_TH1}, .value = 0x1},
67+ [DPAD_DOWN] = {.states = {GAMEPAD_TH0, GAMEPAD_TH1}, .value = 0x2},
68+ [DPAD_LEFT] = {.states = {GAMEPAD_TH1, GAMEPAD_NONE}, .value = 0x4},
69+ [DPAD_RIGHT] = {.states = {GAMEPAD_TH1, GAMEPAD_NONE}, .value = 0x8},
70+ [BUTTON_A] = {.states = {GAMEPAD_TH0, GAMEPAD_NONE}, .value = 0x10},
71+ [BUTTON_B] = {.states = {GAMEPAD_TH1, GAMEPAD_NONE}, .value = 0x10},
72+ [BUTTON_C] = {.states = {GAMEPAD_TH1, GAMEPAD_NONE}, .value = 0x20},
73+ [BUTTON_START] = {.states = {GAMEPAD_TH0, GAMEPAD_NONE}, .value = 0x20},
74+ [BUTTON_X] = {.states = {GAMEPAD_EXTRA, GAMEPAD_NONE}, .value = 0x4},
75+ [BUTTON_Y] = {.states = {GAMEPAD_EXTRA, GAMEPAD_NONE}, .value = 0x2},
76+ [BUTTON_Z] = {.states = {GAMEPAD_EXTRA, GAMEPAD_NONE}, .value = 0x1},
77+ [BUTTON_MODE] = {.states = {GAMEPAD_EXTRA, GAMEPAD_NONE}, .value = 0x8},
78+};
79+
80+static io_port *find_gamepad(sega_io *io, uint8_t gamepad_num)
81+{
82+ for (int i = 0; i < 3; i++)
83+ {
84+ io_port *port = io->ports + i;
85+ if (port->device_type < IO_MOUSE && port->device.pad.gamepad_num == gamepad_num) {
86+ return port;
87+ }
88+ }
89+ return NULL;
90+}
91+
92+static io_port *find_mouse(sega_io *io, uint8_t mouse_num)
93+{
94+ for (int i = 0; i < 3; i++)
95+ {
96+ io_port *port = io->ports + i;
97+ if (port->device_type == IO_MOUSE && port->device.mouse.mouse_num == mouse_num) {
98+ return port;
99+ }
100+ }
101+ return NULL;
102+}
103+
104+static io_port *find_keyboard(sega_io *io)
105+{
106+ for (int i = 0; i < 3; i++)
107+ {
108+ io_port *port = io->ports + i;
109+ if (port->device_type == IO_SATURN_KEYBOARD || port->device_type == IO_XBAND_KEYBOARD) {
110+ return port;
111+ }
112+ }
113+ return NULL;
114+}
115+
116+void io_port_gamepad_down(io_port *port, uint8_t button)
117+{
118+ gp_button_def *def = button_defs + button;
119+ port->input[def->states[0]] |= def->value;
120+ if (def->states[1] != GAMEPAD_NONE) {
121+ port->input[def->states[1]] |= def->value;
122+ }
123+}
124+
125+void io_port_gamepad_up(io_port *port, uint8_t button)
126+{
127+ gp_button_def *def = button_defs + button;
128+ port->input[def->states[0]] &= ~def->value;
129+ if (def->states[1] != GAMEPAD_NONE) {
130+ port->input[def->states[1]] &= ~def->value;
131+ }
132+}
133+
134+void io_gamepad_down(sega_io *io, uint8_t gamepad_num, uint8_t button)
135+{
136+ io_port *port = find_gamepad(io, gamepad_num);
137+ if (port) {
138+ io_port_gamepad_down(port, button);
139+ }
140+}
141+
142+void io_gamepad_up(sega_io *io, uint8_t gamepad_num, uint8_t button)
143+{
144+ io_port *port = find_gamepad(io, gamepad_num);
145+ if (port) {
146+ io_port_gamepad_up(port, button);
147+ }
148+}
149+
150+void io_mouse_down(sega_io *io, uint8_t mouse_num, uint8_t button)
151+{
152+ io_port *port = find_mouse(io, mouse_num);
153+ if (port) {
154+ port->input[0] |= button;
155+ }
156+}
157+
158+void io_mouse_up(sega_io *io, uint8_t mouse_num, uint8_t button)
159+{
160+ io_port *port = find_mouse(io, mouse_num);
161+ if (port) {
162+ port->input[0] &= ~button;
163+ }
164+}
165+
166+void io_mouse_motion_absolute(sega_io *io, uint8_t mouse_num, uint16_t x, uint16_t y)
167+{
168+ io_port *port = find_mouse(io, mouse_num);
169+ if (port) {
170+ port->device.mouse.cur_x = x;
171+ port->device.mouse.cur_y = y;
172+ }
173+}
174+
175+void io_mouse_motion_relative(sega_io *io, uint8_t mouse_num, int32_t x, int32_t y)
176+{
177+ io_port *port = find_mouse(io, mouse_num);
178+ if (port) {
179+ port->device.mouse.cur_x += x;
180+ port->device.mouse.cur_y += y;
181+ }
182+}
183+
184+void store_key_event(io_port *keyboard_port, uint16_t code)
185+{
186+ if (keyboard_port && keyboard_port->device.keyboard.write_pos != keyboard_port->device.keyboard.read_pos) {
187+ //there's room in the buffer, record this event
188+ keyboard_port->device.keyboard.events[keyboard_port->device.keyboard.write_pos] = code;
189+ if (keyboard_port->device.keyboard.read_pos == 0xFF) {
190+ //ring buffer was empty, update read_pos to indicate there is now data
191+ keyboard_port->device.keyboard.read_pos = keyboard_port->device.keyboard.write_pos;
192+ }
193+ keyboard_port->device.keyboard.write_pos = (keyboard_port->device.keyboard.write_pos + 1) & 7;
194+ }
195+}
196+
197+void io_keyboard_down(sega_io *io, uint8_t scancode)
198+{
199+ store_key_event(find_keyboard(io), scancode);
200+}
201+
202+void io_keyboard_up(sega_io *io, uint8_t scancode)
203+{
204+ store_key_event(find_keyboard(io), 0xF000 | scancode);
205+}
206+
207+uint8_t io_has_keyboard(sega_io *io)
208+{
209+ return find_keyboard(io) != NULL;
210+}
211+
212+void process_device(char * device_type, io_port * port)
213+{
214+ //assuming that the io_port struct has been zeroed if this is the first time this has been called
215+ if (!device_type)
216+ {
217+ return;
218+ }
219+
220+ const int gamepad_len = strlen("gamepad");
221+ if (startswith(device_type, "gamepad"))
222+ {
223+ if (
224+ (device_type[gamepad_len] != '3' && device_type[gamepad_len] != '6' && device_type[gamepad_len] != '2')
225+ || device_type[gamepad_len+1] != '.' || device_type[gamepad_len+2] < '1'
226+ || device_type[gamepad_len+2] > '8' || device_type[gamepad_len+3] != 0
227+ ) {
228+ warning("%s is not a valid gamepad type\n", device_type);
229+ } else if (device_type[gamepad_len] == '3') {
230+ port->device_type = IO_GAMEPAD3;
231+ } else if (device_type[gamepad_len] == '2') {
232+ port->device_type = IO_GAMEPAD2;
233+ } else {
234+ port->device_type = IO_GAMEPAD6;
235+ }
236+ port->device.pad.gamepad_num = device_type[gamepad_len+2] - '0';
237+ } else if(startswith(device_type, "mouse")) {
238+ if (port->device_type != IO_MOUSE) {
239+ port->device_type = IO_MOUSE;
240+ port->device.mouse.mouse_num = device_type[strlen("mouse")+1] - '0';
241+ port->device.mouse.last_read_x = 0;
242+ port->device.mouse.last_read_y = 0;
243+ port->device.mouse.cur_x = 0;
244+ port->device.mouse.cur_y = 0;
245+ port->device.mouse.latched_x = 0;
246+ port->device.mouse.latched_y = 0;
247+ port->device.mouse.ready_cycle = CYCLE_NEVER;
248+ port->device.mouse.tr_counter = 0;
249+ }
250+ } else if(!strcmp(device_type, "saturn keyboard")) {
251+ if (port->device_type != IO_SATURN_KEYBOARD) {
252+ port->device_type = IO_SATURN_KEYBOARD;
253+ port->device.keyboard.read_pos = 0xFF;
254+ port->device.keyboard.write_pos = 0;
255+ }
256+ } else if(!strcmp(device_type, "xband keyboard")) {
257+ if (port->device_type != IO_XBAND_KEYBOARD) {
258+ port->device_type = IO_XBAND_KEYBOARD;
259+ port->device.keyboard.read_pos = 0xFF;
260+ port->device.keyboard.write_pos = 0;
261+ }
262+ } else if(!strcmp(device_type, "sega_parallel")) {
263+ if (port->device_type != IO_SEGA_PARALLEL) {
264+ port->device_type = IO_SEGA_PARALLEL;
265+ port->device.stream.data_fd = -1;
266+ port->device.stream.listen_fd = -1;
267+ }
268+ } else if(!strcmp(device_type, "generic")) {
269+ if (port->device_type != IO_GENERIC) {
270+ port->device_type = IO_GENERIC;
271+ port->device.stream.data_fd = -1;
272+ port->device.stream.listen_fd = -1;
273+ }
274+ }
275+}
276+
277+char * io_name(int i)
278+{
279+ switch (i)
280+ {
281+ case 0:
282+ return "1";
283+ case 1:
284+ return "2";
285+ case 2:
286+ return "EXT";
287+ default:
288+ return "invalid";
289+ }
290+}
291+
292+static char * sockfile_name;
293+static void cleanup_sockfile()
294+{
295+ unlink(sockfile_name);
296+}
297+
298+void setup_io_devices(tern_node * config, rom_info *rom, sega_io *io)
299+{
300+ io_port * ports = io->ports;
301+ tern_node *io_nodes = tern_find_path(config, "io\0devices\0", TVAL_NODE).ptrval;
302+ char * io_1 = rom->port1_override ? rom->port1_override : tern_find_ptr_default(io_nodes, "1", "gamepad6.1");
303+ char * io_2 = rom->port2_override ? rom->port2_override : tern_find_ptr_default(io_nodes, "2", "gamepad6.2");
304+ char * io_ext = rom->ext_override ? rom->ext_override : tern_find_ptr(io_nodes, "ext");
305+
306+ process_device(io_1, ports);
307+ process_device(io_2, ports+1);
308+ process_device(io_ext, ports+2);
309+
310+ uint8_t mouse_mode;
311+ if (ports[0].device_type == IO_MOUSE || ports[1].device_type == IO_MOUSE || ports[2].device_type == IO_MOUSE) {
312+ if (rom->mouse_mode && !strcmp(rom->mouse_mode, "absolute")) {
313+ mouse_mode = MOUSE_ABSOLUTE;
314+ } else {
315+ mouse_mode = MOUSE_CAPTURE;
316+ }
317+ } else {
318+ mouse_mode = MOUSE_NONE;
319+ }
320+ bindings_set_mouse_mode(mouse_mode);
321+
322+ for (int i = 0; i < 3; i++)
323+ {
324+ if (ports[i].device_type == IO_SEGA_PARALLEL && ports[i].device.stream.data_fd == -1)
325+ {
326+ char *pipe_name = tern_find_path(config, "io\0parallel_pipe\0", TVAL_PTR).ptrval;
327+ if (!pipe_name)
328+ {
329+ warning("IO port %s is configured to use the sega parallel board, but no paralell_pipe is set!\n", io_name(i));
330+ ports[i].device_type = IO_NONE;
331+ } else {
332+ debug_message("IO port: %s connected to device '%s' with pipe name: %s\n", io_name(i), device_type_names[ports[i].device_type], pipe_name);
333+ if (!strcmp("stdin", pipe_name))
334+ {
335+ ports[i].device.stream.data_fd = STDIN_FILENO;
336+ } else {
337+ if (mkfifo(pipe_name, 0666) && errno != EEXIST)
338+ {
339+ warning("Failed to create fifo %s for Sega parallel board emulation: %d %s\n", pipe_name, errno, strerror(errno));
340+ ports[i].device_type = IO_NONE;
341+ } else {
342+ ports[i].device.stream.data_fd = open(pipe_name, O_NONBLOCK | O_RDONLY);
343+ if (ports[i].device.stream.data_fd == -1)
344+ {
345+ warning("Failed to open fifo %s for Sega parallel board emulation: %d %s\n", pipe_name, errno, strerror(errno));
346+ ports[i].device_type = IO_NONE;
347+ }
348+ }
349+ }
350+ }
351+ } else if (ports[i].device_type == IO_GENERIC && ports[i].device.stream.data_fd == -1) {
352+ char *sock_name = tern_find_path(config, "io\0socket\0", TVAL_PTR).ptrval;
353+ if (!sock_name)
354+ {
355+ warning("IO port %s is configured to use generic IO, but no socket is set!\n", io_name(i));
356+ ports[i].device_type = IO_NONE;
357+ } else {
358+ debug_message("IO port: %s connected to device '%s' with socket name: %s\n", io_name(i), device_type_names[ports[i].device_type], sock_name);
359+ ports[i].device.stream.data_fd = -1;
360+ ports[i].device.stream.listen_fd = socket(AF_UNIX, SOCK_STREAM, 0);
361+ size_t pathlen = strlen(sock_name);
362+ size_t addrlen = offsetof(struct sockaddr_un, sun_path) + pathlen + 1;
363+ struct sockaddr_un *saddr = malloc(addrlen);
364+ saddr->sun_family = AF_UNIX;
365+ memcpy(saddr->sun_path, sock_name, pathlen+1);
366+ if (bind(ports[i].device.stream.listen_fd, (struct sockaddr *)saddr, addrlen))
367+ {
368+ warning("Failed to bind socket for IO Port %s to path %s: %d %s\n", io_name(i), sock_name, errno, strerror(errno));
369+ goto cleanup_sock;
370+ }
371+ if (listen(ports[i].device.stream.listen_fd, 1))
372+ {
373+ warning("Failed to listen on socket for IO Port %s: %d %s\n", io_name(i), errno, strerror(errno));
374+ goto cleanup_sockfile;
375+ }
376+ sockfile_name = sock_name;
377+ atexit(cleanup_sockfile);
378+ continue;
379+cleanup_sockfile:
380+ unlink(sock_name);
381+cleanup_sock:
382+ close(ports[i].device.stream.listen_fd);
383+ ports[i].device_type = IO_NONE;
384+ }
385+ } else
386+ if (ports[i].device_type == IO_GAMEPAD3 || ports[i].device_type == IO_GAMEPAD6 || ports[i].device_type == IO_GAMEPAD2) {
387+ debug_message("IO port %s connected to gamepad #%d with type '%s'\n", io_name(i), ports[i].device.pad.gamepad_num, device_type_names[ports[i].device_type]);
388+ } else {
389+ debug_message("IO port %s connected to device '%s'\n", io_name(i), device_type_names[ports[i].device_type]);
390+ }
391+ }
392+}
393+
394+
395+#define TH 0x40
396+#define TR 0x20
397+#define TH_TIMEOUT 56000
398+
399+void mouse_check_ready(io_port *port, uint32_t current_cycle)
400+{
401+ if (current_cycle >= port->device.mouse.ready_cycle) {
402+ port->device.mouse.tr_counter++;
403+ port->device.mouse.ready_cycle = CYCLE_NEVER;
404+ if (port->device.mouse.tr_counter == 3) {
405+ port->device.mouse.latched_x = port->device.mouse.cur_x;
406+ port->device.mouse.latched_y = port->device.mouse.cur_y;
407+ /* FIXME mouse mode owned by bindings now
408+ if (current_io->mouse_mode == MOUSE_ABSOLUTE) {
409+ //avoid overflow in absolute mode
410+ int deltax = port->device.mouse.latched_x - port->device.mouse.last_read_x;
411+ if (abs(deltax) > 255) {
412+ port->device.mouse.latched_x = port->device.mouse.last_read_x + (deltax > 0 ? 255 : -255);
413+ }
414+ int deltay = port->device.mouse.latched_y - port->device.mouse.last_read_y;
415+ if (abs(deltay) > 255) {
416+ port->device.mouse.latched_y = port->device.mouse.last_read_y + (deltay > 0 ? 255 : -255);
417+ }
418+ }*/
419+ }
420+ }
421+}
422+
423+uint32_t last_poll_cycle;
424+void io_adjust_cycles(io_port * port, uint32_t current_cycle, uint32_t deduction)
425+{
426+ /*uint8_t control = pad->control | 0x80;
427+ uint8_t th = control & pad->output;
428+ if (pad->input[GAMEPAD_TH0] || pad->input[GAMEPAD_TH1]) {
429+ printf("adjust_cycles | control: %X, TH: %X, GAMEPAD_TH0: %X, GAMEPAD_TH1: %X, TH Counter: %d, Timeout: %d, Cycle: %d\n", control, th, pad->input[GAMEPAD_TH0], pad->input[GAMEPAD_TH1], pad->th_counter,pad->timeout_cycle, current_cycle);
430+ }*/
431+ if (port->device_type == IO_GAMEPAD6)
432+ {
433+ if (current_cycle >= port->device.pad.timeout_cycle)
434+ {
435+ port->device.pad.th_counter = 0;
436+ } else {
437+ port->device.pad.timeout_cycle -= deduction;
438+ }
439+ } else if (port->device_type == IO_MOUSE) {
440+ mouse_check_ready(port, current_cycle);
441+ if (port->device.mouse.ready_cycle != CYCLE_NEVER) {
442+ port->device.mouse.ready_cycle -= deduction;
443+ }
444+ }
445+ for (int i = 0; i < 8; i++)
446+ {
447+ if (port->slow_rise_start[i] != CYCLE_NEVER) {
448+ if (port->slow_rise_start[i] >= deduction) {
449+ port->slow_rise_start[i] -= deduction;
450+ } else {
451+ port->slow_rise_start[i] = CYCLE_NEVER;
452+ }
453+ }
454+ }
455+ if (last_poll_cycle >= deduction) {
456+ last_poll_cycle -= deduction;
457+ } else {
458+ last_poll_cycle = 0;
459+ }
460+}
461+
462+static void wait_for_connection(io_port * port)
463+{
464+ if (port->device.stream.data_fd == -1)
465+ {
466+ debug_message("Waiting for socket connection...");
467+ port->device.stream.data_fd = accept(port->device.stream.listen_fd, NULL, NULL);
468+ fcntl(port->device.stream.data_fd, F_SETFL, O_NONBLOCK | O_RDWR);
469+ }
470+}
471+
472+static void service_pipe(io_port * port)
473+{
474+ uint8_t value;
475+ int numRead = read(port->device.stream.data_fd, &value, sizeof(value));
476+ if (numRead > 0)
477+ {
478+ port->input[IO_TH0] = (value & 0xF) | 0x10;
479+ port->input[IO_TH1] = (value >> 4) | 0x10;
480+ } else if(numRead == -1 && errno != EAGAIN && errno != EWOULDBLOCK) {
481+ warning("Error reading pipe for IO port: %d %s\n", errno, strerror(errno));
482+ }
483+}
484+
485+static void service_socket(io_port *port)
486+{
487+ uint8_t buf[32];
488+ uint8_t blocking = 0;
489+ int numRead = 0;
490+ while (numRead <= 0)
491+ {
492+ numRead = recv(port->device.stream.data_fd, buf, sizeof(buf), 0);
493+ if (numRead > 0)
494+ {
495+ port->input[IO_TH0] = buf[numRead-1];
496+ if (port->input[IO_STATE] == IO_READ_PENDING)
497+ {
498+ port->input[IO_STATE] = IO_READ;
499+ if (blocking)
500+ {
501+ //pending read satisfied, back to non-blocking mode
502+ fcntl(port->device.stream.data_fd, F_SETFL, O_RDWR | O_NONBLOCK);
503+ }
504+ } else if (port->input[IO_STATE] == IO_WRITTEN) {
505+ port->input[IO_STATE] = IO_READ;
506+ }
507+ } else if (numRead == 0) {
508+ port->device.stream.data_fd = -1;
509+ wait_for_connection(port);
510+ } else if (errno != EAGAIN && errno != EWOULDBLOCK) {
511+ warning("Error reading from socket for IO port: %d %s\n", errno, strerror(errno));
512+ close(port->device.stream.data_fd);
513+ wait_for_connection(port);
514+ } else if (port->input[IO_STATE] == IO_READ_PENDING) {
515+ //clear the nonblocking flag so the next read will block
516+ if (!blocking)
517+ {
518+ fcntl(port->device.stream.data_fd, F_SETFL, O_RDWR);
519+ blocking = 1;
520+ }
521+ } else {
522+ //no new data, but that's ok
523+ break;
524+ }
525+ }
526+
527+ if (port->input[IO_STATE] == IO_WRITE_PENDING)
528+ {
529+ uint8_t value = port->output & port->control;
530+ int written = 0;
531+ blocking = 0;
532+ while (written <= 0)
533+ {
534+ send(port->device.stream.data_fd, &value, sizeof(value), 0);
535+ if (written > 0)
536+ {
537+ port->input[IO_STATE] = IO_WRITTEN;
538+ if (blocking)
539+ {
540+ //pending write satisfied, back to non-blocking mode
541+ fcntl(port->device.stream.data_fd, F_SETFL, O_RDWR | O_NONBLOCK);
542+ }
543+ } else if (written == 0) {
544+ port->device.stream.data_fd = -1;
545+ wait_for_connection(port);
546+ } else if (errno != EAGAIN && errno != EWOULDBLOCK) {
547+ warning("Error writing to socket for IO port: %d %s\n", errno, strerror(errno));
548+ close(port->device.stream.data_fd);
549+ wait_for_connection(port);
550+ } else {
551+ //clear the nonblocking flag so the next write will block
552+ if (!blocking)
553+ {
554+ fcntl(port->device.stream.data_fd, F_SETFL, O_RDWR);
555+ blocking = 1;
556+ }
557+ }
558+ }
559+ }
560+}
561+
562+const int mouse_delays[] = {112*7, 120*7, 96*7, 132*7, 104*7, 96*7, 112*7, 96*7};
563+
564+enum {
565+ KB_SETUP,
566+ KB_READ,
567+ KB_WRITE
568+};
569+
570+void io_control_write(io_port *port, uint8_t value, uint32_t current_cycle)
571+{
572+ uint8_t changes = value ^ port->control;
573+ if (changes) {
574+ for (int i = 0; i < 8; i++)
575+ {
576+ if (!(value & 1 << i) && !(port->output & 1 << i)) {
577+ //port switched from output to input and the output value was 0
578+ //since there is a weak pull-up on input pins, this will lead
579+ //to a slow rise from 0 to 1 if the pin isn't being externally driven
580+ port->slow_rise_start[i] = current_cycle;
581+ } else {
582+ port->slow_rise_start[i] = CYCLE_NEVER;
583+ }
584+ }
585+ port->control = value;
586+ }
587+}
588+
589+void io_data_write(io_port * port, uint8_t value, uint32_t current_cycle)
590+{
591+ uint8_t old_output = (port->control & port->output) | (~port->control & 0xFF);
592+ uint8_t output = (port->control & value) | (~port->control & 0xFF);
593+ switch (port->device_type)
594+ {
595+ case IO_GAMEPAD6:
596+ //check if TH has changed
597+ if ((old_output & TH) ^ (output & TH)) {
598+ if (current_cycle >= port->device.pad.timeout_cycle) {
599+ port->device.pad.th_counter = 0;
600+ }
601+ if ((output & TH)) {
602+ port->device.pad.th_counter++;
603+ }
604+ port->device.pad.timeout_cycle = current_cycle + TH_TIMEOUT;
605+ }
606+ break;
607+ case IO_MOUSE:
608+ mouse_check_ready(port, current_cycle);
609+ if (output & TH) {
610+ //request is over or mouse is being reset
611+ if (port->device.mouse.tr_counter) {
612+ //request is over
613+ port->device.mouse.last_read_x = port->device.mouse.latched_x;
614+ port->device.mouse.last_read_y = port->device.mouse.latched_y;
615+ }
616+ port->device.mouse.tr_counter = 0;
617+ port->device.mouse.ready_cycle = CYCLE_NEVER;
618+ } else {
619+ if ((output & TR) != (old_output & TR)) {
620+ int delay_index = port->device.mouse.tr_counter >= sizeof(mouse_delays) ? sizeof(mouse_delays)-1 : port->device.mouse.tr_counter;
621+ port->device.mouse.ready_cycle = current_cycle + mouse_delays[delay_index];
622+ }
623+ }
624+ break;
625+ case IO_SATURN_KEYBOARD:
626+ if (output & TH) {
627+ //request is over
628+ if (port->device.keyboard.tr_counter >= 10 && port->device.keyboard.read_pos != 0xFF) {
629+ //remove scan code from buffer
630+ port->device.keyboard.read_pos++;
631+ port->device.keyboard.read_pos &= 7;
632+ if (port->device.keyboard.read_pos == port->device.keyboard.write_pos) {
633+ port->device.keyboard.read_pos = 0xFF;
634+ }
635+ }
636+ port->device.keyboard.tr_counter = 0;
637+ } else {
638+ if ((output & TR) != (old_output & TR)) {
639+ port->device.keyboard.tr_counter++;
640+ }
641+ }
642+ break;
643+ case IO_XBAND_KEYBOARD:
644+ if (output & TH) {
645+ //request is over
646+ if (
647+ port->device.keyboard.mode == KB_READ && port->device.keyboard.tr_counter > 6
648+ && (port->device.keyboard.tr_counter & 1)
649+ ) {
650+ if (port->device.keyboard.events[port->device.keyboard.read_pos] & 0xFF00) {
651+ port->device.keyboard.events[port->device.keyboard.read_pos] &= 0xFF;
652+ } else {
653+ port->device.keyboard.read_pos++;
654+ port->device.keyboard.read_pos &= 7;
655+ if (port->device.keyboard.read_pos == port->device.keyboard.write_pos) {
656+ port->device.keyboard.read_pos = 0xFF;
657+ }
658+ }
659+ }
660+ port->device.keyboard.tr_counter = 0;
661+ port->device.keyboard.mode = KB_SETUP;
662+ } else {
663+ if ((output & TR) != (old_output & TR)) {
664+ port->device.keyboard.tr_counter++;
665+ if (port->device.keyboard.tr_counter == 2) {
666+ port->device.keyboard.mode = (output & 0xF) ? KB_READ : KB_WRITE;
667+ } else if (port->device.keyboard.mode == KB_WRITE) {
668+ switch (port->device.keyboard.tr_counter)
669+ {
670+ case 3:
671+ //host writes 0b0001
672+ break;
673+ case 4:
674+ //host writes 0b0000
675+ break;
676+ case 5:
677+ //host writes 0b0000
678+ break;
679+ case 6:
680+ port->device.keyboard.cmd = output << 4;
681+ break;
682+ case 7:
683+ port->device.keyboard.cmd |= output & 0xF;
684+ //TODO: actually do something with the command
685+ break;
686+ }
687+ } else if (
688+ port->device.keyboard.mode == KB_READ && port->device.keyboard.tr_counter > 7
689+ && !(port->device.keyboard.tr_counter & 1)
690+ ) {
691+
692+ if (port->device.keyboard.events[port->device.keyboard.read_pos] & 0xFF00) {
693+ port->device.keyboard.events[port->device.keyboard.read_pos] &= 0xFF;
694+ } else {
695+ port->device.keyboard.read_pos++;
696+ port->device.keyboard.read_pos &= 7;
697+ if (port->device.keyboard.read_pos == port->device.keyboard.write_pos) {
698+ port->device.keyboard.read_pos = 0xFF;
699+ }
700+ }
701+ }
702+ }
703+ }
704+ break;
705+ case IO_GENERIC:
706+ wait_for_connection(port);
707+ port->input[IO_STATE] = IO_WRITE_PENDING;
708+ service_socket(port);
709+ break;
710+ }
711+ port->output = value;
712+
713+}
714+
715+uint8_t get_scancode_bytes(io_port *port)
716+{
717+ if (port->device.keyboard.read_pos == 0xFF) {
718+ return 0;
719+ }
720+ uint8_t bytes = 0, read_pos = port->device.keyboard.read_pos;
721+ do {
722+ bytes += port->device.keyboard.events[read_pos] & 0xFF00 ? 2 : 1;
723+ read_pos++;
724+ read_pos &= 7;
725+ } while (read_pos != port->device.keyboard.write_pos);
726+
727+ return bytes;
728+}
729+
730+#define SLOW_RISE_DEVICE (30*7)
731+#define SLOW_RISE_INPUT (12*7)
732+
733+static uint8_t get_output_value(io_port *port, uint32_t current_cycle, uint32_t slow_rise_delay)
734+{
735+ uint8_t output = (port->control | 0x80) & port->output;
736+ for (int i = 0; i < 8; i++)
737+ {
738+ if (!(port->control & 1 << i)) {
739+ if (port->slow_rise_start[i] != CYCLE_NEVER) {
740+ if (current_cycle - port->slow_rise_start[i] >= slow_rise_delay) {
741+ output |= 1 << i;
742+ }
743+ } else {
744+ output |= 1 << i;
745+ }
746+ }
747+ }
748+ return output;
749+}
750+
751+uint8_t io_data_read(io_port * port, uint32_t current_cycle)
752+{
753+ uint8_t output = get_output_value(port, current_cycle, SLOW_RISE_DEVICE);
754+ uint8_t control = port->control | 0x80;
755+ uint8_t th = output & 0x40;
756+ uint8_t input;
757+ uint8_t device_driven;
758+ if (current_cycle - last_poll_cycle > MIN_POLL_INTERVAL) {
759+ process_events();
760+ last_poll_cycle = current_cycle;
761+ }
762+ switch (port->device_type)
763+ {
764+ case IO_GAMEPAD2:
765+ input = ~port->input[GAMEPAD_TH1];
766+ device_driven = 0x3F;
767+ break;
768+ case IO_GAMEPAD3:
769+ {
770+ input = port->input[th ? GAMEPAD_TH1 : GAMEPAD_TH0];
771+ if (!th) {
772+ input |= 0xC;
773+ }
774+ //controller output is logically inverted
775+ input = ~input;
776+ device_driven = 0x3F;
777+ break;
778+ }
779+ case IO_GAMEPAD6:
780+ {
781+ if (current_cycle >= port->device.pad.timeout_cycle) {
782+ port->device.pad.th_counter = 0;
783+ }
784+ /*if (port->input[GAMEPAD_TH0] || port->input[GAMEPAD_TH1]) {
785+ printf("io_data_read | control: %X, TH: %X, GAMEPAD_TH0: %X, GAMEPAD_TH1: %X, TH Counter: %d, Timeout: %d, Cycle: %d\n", control, th, port->input[GAMEPAD_TH0], port->input[GAMEPAD_TH1], port->th_counter,port->timeout_cycle, context->current_cycle);
786+ }*/
787+ if (th) {
788+ if (port->device.pad.th_counter == 3) {
789+ input = port->input[GAMEPAD_EXTRA];
790+ } else {
791+ input = port->input[GAMEPAD_TH1];
792+ }
793+ } else {
794+ if (port->device.pad.th_counter == 2) {
795+ input = port->input[GAMEPAD_TH0] | 0xF;
796+ } else if(port->device.pad.th_counter == 3) {
797+ input = port->input[GAMEPAD_TH0] & 0x30;
798+ } else {
799+ input = port->input[GAMEPAD_TH0] | 0xC;
800+ }
801+ }
802+ //controller output is logically inverted
803+ input = ~input;
804+ device_driven = 0x3F;
805+ break;
806+ }
807+ case IO_MOUSE:
808+ {
809+ mouse_check_ready(port, current_cycle);
810+ uint8_t tr = output & TR;
811+ if (th) {
812+ if (tr) {
813+ input = 0x10;
814+ } else {
815+ input = 0;
816+ }
817+ } else {
818+
819+ int16_t delta_x = port->device.mouse.latched_x - port->device.mouse.last_read_x;
820+ int16_t delta_y = port->device.mouse.last_read_y - port->device.mouse.latched_y;
821+ switch (port->device.mouse.tr_counter)
822+ {
823+ case 0:
824+ input = 0xB;
825+ break;
826+ case 1:
827+ case 2:
828+ input = 0xF;
829+ break;
830+ case 3:
831+ input = 0;
832+ if (delta_y > 255 || delta_y < -255) {
833+ input |= 8;
834+ }
835+ if (delta_x > 255 || delta_x < -255) {
836+ input |= 4;
837+ }
838+ if (delta_y < 0) {
839+ input |= 2;
840+ }
841+ if (delta_x < 0) {
842+ input |= 1;
843+ }
844+ break;
845+ case 4:
846+ input = port->input[0];
847+ break;
848+ case 5:
849+ input = delta_x >> 4 & 0xF;
850+ break;
851+ case 6:
852+ input = delta_x & 0xF;
853+ break;
854+ case 7:
855+ input = delta_y >> 4 & 0xF;
856+ break;
857+ case 8:
858+ default:
859+ input = delta_y & 0xF;
860+ break;
861+ }
862+ input |= ((port->device.mouse.tr_counter & 1) == 0) << 4;
863+ }
864+ device_driven = 0x1F;
865+ break;
866+ }
867+ case IO_SATURN_KEYBOARD:
868+ {
869+ if (th) {
870+ input = 0x11;
871+ } else {
872+ uint16_t code = port->device.keyboard.read_pos == 0xFF ? 0
873+ : port->device.keyboard.events[port->device.keyboard.read_pos];
874+ switch (port->device.keyboard.tr_counter)
875+ {
876+ case 0:
877+ input = 1;
878+ break;
879+ case 1:
880+ //Saturn peripheral ID
881+ input = 3;
882+ break;
883+ case 2:
884+ //data size
885+ input = 4;
886+ break;
887+ case 3:
888+ //d-pad
889+ //TODO: set these based on keyboard state
890+ input = 0xF;
891+ break;
892+ case 4:
893+ //Start ABC
894+ //TODO: set these based on keyboard state
895+ input = 0xF;
896+ break;
897+ case 5:
898+ //R XYZ
899+ //TODO: set these based on keyboard state
900+ input = 0xF;
901+ break;
902+ case 6:
903+ //L and KBID
904+ //TODO: set L based on keyboard state
905+ input = 0x8;
906+ break;
907+ case 7:
908+ //Capslock, Numlock, Scrolllock
909+ //TODO: set these based on keyboard state
910+ input = 0;
911+ break;
912+ case 8:
913+ input = 6;
914+ if (code & 0xFF00) {
915+ //break
916+ input |= 1;
917+ } else if (code) {
918+ input |= 8;
919+ }
920+ break;
921+ case 9:
922+ input = code >> 4 & 0xF;
923+ break;
924+ case 10:
925+ input = code & 0xF;
926+ break;
927+ case 11:
928+ input = 0;
929+ break;
930+ default:
931+ input = 1;
932+ break;
933+ }
934+ input |= ((port->device.keyboard.tr_counter & 1) == 0) << 4;
935+ }
936+ device_driven = 0x1F;
937+ break;
938+ }
939+ case IO_XBAND_KEYBOARD:
940+ {
941+ if (th) {
942+ input = 0x1C;
943+ } else {
944+ uint8_t size;
945+ if (port->device.keyboard.mode == KB_SETUP || port->device.keyboard.mode == KB_READ) {
946+ switch (port->device.keyboard.tr_counter)
947+ {
948+ case 0:
949+ input = 0x3;
950+ break;
951+ case 1:
952+ input = 0x6;
953+ break;
954+ case 2:
955+ //This is where thoe host indicates a read or write
956+ //presumably, the keyboard only outputs this if the host
957+ //is not already driving the data bus low
958+ input = 0x9;
959+ break;
960+ case 3:
961+ size = get_scancode_bytes(port);
962+ if (size) {
963+ ++size;
964+ }
965+ if (size > 15) {
966+ size = 15;
967+ }
968+ input = size;
969+ break;
970+ case 4:
971+ case 5:
972+ //always send packet type 0 for now
973+ input = 0;
974+ break;
975+ default:
976+ if (port->device.keyboard.read_pos == 0xFF) {
977+ //we've run out of bytes
978+ input = 0;
979+ } else if (port->device.keyboard.events[port->device.keyboard.read_pos] & 0xFF00) {
980+ if (port->device.keyboard.tr_counter & 1) {
981+ input = port->device.keyboard.events[port->device.keyboard.read_pos] >> 8 & 0xF;
982+ } else {
983+ input = port->device.keyboard.events[port->device.keyboard.read_pos] >> 12;
984+ }
985+ } else {
986+ if (port->device.keyboard.tr_counter & 1) {
987+ input = port->device.keyboard.events[port->device.keyboard.read_pos] & 0xF;
988+ } else {
989+ input = port->device.keyboard.events[port->device.keyboard.read_pos] >> 4;
990+ }
991+ }
992+ break;
993+ }
994+ } else {
995+ input = 0xF;
996+ }
997+ input |= ((port->device.keyboard.tr_counter & 1) == 0) << 4;
998+ }
999+ //this is not strictly correct at all times, but good enough for now
1000+ device_driven = 0x1F;
1001+ break;
1002+ }
1003+ case IO_SEGA_PARALLEL:
1004+ if (!th)
1005+ {
1006+ service_pipe(port);
1007+ }
1008+ input = port->input[th ? IO_TH1 : IO_TH0];
1009+ device_driven = 0x3F;
1010+ break;
1011+ case IO_GENERIC:
1012+ if (port->input[IO_TH0] & 0x80 && port->input[IO_STATE] == IO_WRITTEN)
1013+ {
1014+ //device requested a blocking read after writes
1015+ port->input[IO_STATE] = IO_READ_PENDING;
1016+ }
1017+ service_socket(port);
1018+ input = port->input[IO_TH0];
1019+ device_driven = 0x7F;
1020+ break;
1021+ default:
1022+ input = 0;
1023+ device_driven = 0;
1024+ break;
1025+ }
1026+ uint8_t value = (input & (~control) & device_driven) | (port->output & control);
1027+ //deal with pins that are configured as inputs, but not being actively driven by the device
1028+ uint8_t floating = (~device_driven) & (~control);
1029+ if (floating) {
1030+ value |= get_output_value(port, current_cycle, SLOW_RISE_INPUT) & floating;
1031+ }
1032+ /*if (port->input[GAMEPAD_TH0] || port->input[GAMEPAD_TH1]) {
1033+ printf ("value: %X\n", value);
1034+ }*/
1035+ return value;
1036+}
1037+
1038+void io_serialize(io_port *port, serialize_buffer *buf)
1039+{
1040+ save_int8(buf, port->output);
1041+ save_int8(buf, port->control);
1042+ save_int8(buf, port->serial_out);
1043+ save_int8(buf, port->serial_in);
1044+ save_int8(buf, port->serial_ctrl);
1045+ save_int8(buf, port->device_type);
1046+ save_buffer32(buf, port->slow_rise_start, 8);
1047+ switch (port->device_type)
1048+ {
1049+ case IO_GAMEPAD6:
1050+ save_int32(buf, port->device.pad.timeout_cycle);
1051+ save_int16(buf, port->device.pad.th_counter);
1052+ break;
1053+ case IO_MOUSE:
1054+ save_int32(buf, port->device.mouse.ready_cycle);
1055+ save_int16(buf, port->device.mouse.last_read_x);
1056+ save_int16(buf, port->device.mouse.last_read_y);
1057+ save_int16(buf, port->device.mouse.latched_x);
1058+ save_int16(buf, port->device.mouse.latched_y);
1059+ save_int8(buf, port->device.mouse.tr_counter);
1060+ break;
1061+ case IO_SATURN_KEYBOARD:
1062+ case IO_XBAND_KEYBOARD:
1063+ save_int8(buf, port->device.keyboard.tr_counter);
1064+ if (port->device_type == IO_XBAND_KEYBOARD) {
1065+ save_int8(buf, port->device.keyboard.mode);
1066+ save_int8(buf, port->device.keyboard.cmd);
1067+ }
1068+ break;
1069+ }
1070+}
1071+
1072+void io_deserialize(deserialize_buffer *buf, void *vport)
1073+{
1074+ io_port *port = vport;
1075+ port->output = load_int8(buf);
1076+ port->control = load_int8(buf);
1077+ port->serial_out = load_int8(buf);
1078+ port->serial_in = load_int8(buf);
1079+ port->serial_ctrl = load_int8(buf);
1080+ uint8_t device_type = load_int8(buf);
1081+ if (device_type != port->device_type) {
1082+ warning("Loaded save state has a different device type from the current configuration");
1083+ return;
1084+ }
1085+ switch (port->device_type)
1086+ {
1087+ case IO_GAMEPAD6:
1088+ port->device.pad.timeout_cycle = load_int32(buf);
1089+ port->device.pad.th_counter = load_int16(buf);
1090+ break;
1091+ case IO_MOUSE:
1092+ port->device.mouse.ready_cycle = load_int32(buf);
1093+ port->device.mouse.last_read_x = load_int16(buf);
1094+ port->device.mouse.last_read_y = load_int16(buf);
1095+ port->device.mouse.latched_x = load_int16(buf);
1096+ port->device.mouse.latched_y = load_int16(buf);
1097+ port->device.mouse.tr_counter = load_int8(buf);
1098+ break;
1099+ case IO_SATURN_KEYBOARD:
1100+ case IO_XBAND_KEYBOARD:
1101+ port->device.keyboard.tr_counter = load_int8(buf);
1102+ if (port->device_type == IO_XBAND_KEYBOARD) {
1103+ port->device.keyboard.mode = load_int8(buf);
1104+ port->device.keyboard.cmd = load_int8(buf);
1105+ }
1106+ break;
1107+ }
1108+}
A
io.h
+130,
-0
1@@ -0,0 +1,130 @@
2+/*
3+ Copyright 2013 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#ifndef IO_H_
8+#define IO_H_
9+#include <stdint.h>
10+#include "tern.h"
11+#include "romdb.h"
12+#include "serialize.h"
13+
14+enum {
15+ IO_NONE,
16+ IO_GAMEPAD2,
17+ IO_GAMEPAD3,
18+ IO_GAMEPAD6,
19+ IO_MOUSE,
20+ IO_SATURN_KEYBOARD,
21+ IO_XBAND_KEYBOARD,
22+ IO_MENACER,
23+ IO_JUSTIFIER,
24+ IO_SEGA_MULTI,
25+ IO_EA_MULTI_A,
26+ IO_EA_MULTI_B,
27+ IO_SEGA_PARALLEL,
28+ IO_GENERIC
29+};
30+
31+typedef struct {
32+ union {
33+ struct {
34+ uint32_t timeout_cycle;
35+ uint16_t th_counter;
36+ uint16_t gamepad_num;
37+ } pad;
38+ struct {
39+ int data_fd;
40+ int listen_fd;
41+ } stream;
42+ struct {
43+ uint32_t ready_cycle;
44+ uint16_t last_read_x;
45+ uint16_t last_read_y;
46+ uint16_t cur_x;
47+ uint16_t cur_y;
48+ uint16_t latched_x;
49+ uint16_t latched_y;
50+ uint8_t tr_counter;
51+ uint8_t mouse_num;
52+ } mouse;
53+ struct {
54+ uint16_t events[8];
55+ uint8_t read_pos;
56+ uint8_t write_pos;
57+ uint8_t tr_counter;
58+ uint8_t mode;
59+ uint8_t cmd;
60+ } keyboard;
61+ } device;
62+ uint8_t output;
63+ uint8_t control;
64+ uint8_t input[3];
65+ uint32_t slow_rise_start[8];
66+ uint8_t serial_out;
67+ uint8_t serial_in;
68+ uint8_t serial_ctrl;
69+ uint8_t device_type;
70+} io_port;
71+
72+typedef struct {
73+ io_port ports[3];
74+} sega_io;
75+
76+//pseudo gamepad for buttons on main console unit
77+#define GAMEPAD_MAIN_UNIT 255
78+
79+enum {
80+ BUTTON_INVALID,
81+ DPAD_UP,
82+ DPAD_DOWN,
83+ DPAD_LEFT,
84+ DPAD_RIGHT,
85+ BUTTON_A,
86+ BUTTON_B,
87+ BUTTON_C,
88+ BUTTON_START,
89+ BUTTON_X,
90+ BUTTON_Y,
91+ BUTTON_Z,
92+ BUTTON_MODE,
93+ NUM_GAMEPAD_BUTTONS
94+};
95+
96+enum {
97+ MAIN_UNIT_PAUSE
98+};
99+
100+enum {
101+ MOUSE_LEFT = 1,
102+ MOUSE_RIGHT = 2,
103+ MOUSE_MIDDLE = 4,
104+ MOUSE_START = 8,
105+ PSEUDO_BUTTON_MOTION=0xFF
106+};
107+
108+void setup_io_devices(tern_node * config, rom_info *rom, sega_io *io);
109+void io_adjust_cycles(io_port * pad, uint32_t current_cycle, uint32_t deduction);
110+void io_control_write(io_port *port, uint8_t value, uint32_t current_cycle);
111+void io_data_write(io_port * pad, uint8_t value, uint32_t current_cycle);
112+uint8_t io_data_read(io_port * pad, uint32_t current_cycle);
113+void io_serialize(io_port *port, serialize_buffer *buf);
114+void io_deserialize(deserialize_buffer *buf, void *vport);
115+
116+void io_port_gamepad_down(io_port *port, uint8_t button);
117+void io_port_gamepad_up(io_port *port, uint8_t button);
118+void io_gamepad_down(sega_io *io, uint8_t gamepad_num, uint8_t button);
119+void io_gamepad_up(sega_io *io, uint8_t gamepad_num, uint8_t button);
120+void io_mouse_down(sega_io *io, uint8_t mouse_num, uint8_t button);
121+void io_mouse_up(sega_io *io, uint8_t mouse_num, uint8_t button);
122+void io_mouse_motion_absolute(sega_io *io, uint8_t mouse_num, uint16_t x, uint16_t y);
123+void io_mouse_motion_relative(sega_io *io, uint8_t mouse_num, int32_t x, int32_t y);
124+void io_keyboard_down(sega_io *io, uint8_t scancode);
125+void io_keyboard_up(sega_io *io, uint8_t scancode);
126+uint8_t io_has_keyboard(sega_io *io);
127+
128+extern const char * device_type_names[];
129+
130+#endif //IO_H_
131+
A
jcart.c
+88,
-0
1@@ -0,0 +1,88 @@
2+#include <stdlib.h>
3+#include "genesis.h"
4+
5+static io_port *get_ports(m68k_context *m68k)
6+{
7+ genesis_context *gen = m68k->system;
8+ if (!gen->extra) {
9+ io_port *ports = calloc(2, sizeof(io_port));
10+ ports[0].device_type = IO_GAMEPAD3;
11+ ports[0].device.pad.gamepad_num = 3;
12+ ports[1].device_type = IO_GAMEPAD3;
13+ ports[1].device.pad.gamepad_num = 4;
14+ io_control_write(ports, 0x40, 0);
15+ io_control_write(ports + 1, 0x40, 0);
16+ gen->extra = ports;
17+ }
18+
19+ return gen->extra;
20+}
21+
22+void *jcart_write_w(uint32_t address, void *context, uint16_t value)
23+{
24+ m68k_context *m68k= context;
25+ io_port *ports = get_ports(m68k);
26+ value = value << 6 & 0x40;
27+ io_data_write(ports, value, m68k->current_cycle);
28+ io_data_write(ports + 1, value, m68k->current_cycle);
29+ return context;
30+}
31+
32+void *jcart_write_b(uint32_t address, void *context, uint8_t value)
33+{
34+ if (address & 1) {
35+ return jcart_write_w(address, context, value);
36+ }
37+ return context;
38+}
39+
40+uint16_t jcart_read_w(uint32_t address, void *context)
41+{
42+ m68k_context *m68k= context;
43+ io_port *ports = get_ports(m68k);
44+ //according to Eke, bit 14 is forced low, at least on the Micro Machines 2 cart
45+ //TODO: Test behavior of actual cart
46+ uint16_t value = io_data_read(ports, m68k->current_cycle) << 8;
47+ value |= io_data_read(ports + 1, m68k->current_cycle);
48+ return value;
49+}
50+
51+uint8_t jcart_read_b(uint32_t address, void *context)
52+{
53+ m68k_context *m68k= context;
54+ io_port *ports = get_ports(m68k);
55+ return io_data_read(ports + (address & 1), m68k->current_cycle);
56+}
57+
58+void jcart_adjust_cycles(genesis_context *context, uint32_t deduction)
59+{
60+ io_port *ports = get_ports(context->m68k);
61+ io_adjust_cycles(ports, context->m68k->current_cycle, deduction);
62+ io_adjust_cycles(ports + 1, context->m68k->current_cycle, deduction);
63+}
64+
65+void jcart_gamepad_down(genesis_context *context, uint8_t gamepad_num, uint8_t button)
66+{
67+ io_port *ports = get_ports(context->m68k);
68+ if (gamepad_num == ports[1].device.pad.gamepad_num) {
69+ ports++;
70+ } else if (gamepad_num != ports[0].device.pad.gamepad_num) {
71+ ports = NULL;
72+ }
73+ if (ports) {
74+ io_port_gamepad_down(ports, button);
75+ }
76+}
77+
78+void jcart_gamepad_up(genesis_context *context, uint8_t gamepad_num, uint8_t button)
79+{
80+ io_port *ports = get_ports(context->m68k);
81+ if (gamepad_num == ports[1].device.pad.gamepad_num) {
82+ ports++;
83+ } else if (gamepad_num != ports[0].device.pad.gamepad_num) {
84+ ports = NULL;
85+ }
86+ if (ports) {
87+ io_port_gamepad_up(ports, button);
88+ }
89+}
A
jcart.h
+12,
-0
1@@ -0,0 +1,12 @@
2+#ifndef JCART_H_
3+#define JCART_H_
4+
5+void *jcart_write_w(uint32_t address, void *context, uint16_t value);
6+void *jcart_write_b(uint32_t address, void *context, uint8_t value);
7+uint16_t jcart_read_w(uint32_t address, void *context);
8+uint8_t jcart_read_b(uint32_t address, void *context);
9+void jcart_adjust_cycles(genesis_context *context, uint32_t deduction);
10+void jcart_gamepad_down(genesis_context *context, uint8_t gamepad_num, uint8_t button);
11+void jcart_gamepad_up(genesis_context *context, uint8_t gamepad_num, uint8_t button);
12+
13+#endif //JCART_H_
+1276,
-0
1@@ -0,0 +1,1276 @@
2+/*
3+ Copyright 2014 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#include "m68k_core.h"
8+#include "m68k_internal.h"
9+#include "68kinst.h"
10+#include "backend.h"
11+#include "gen.h"
12+#include "util.h"
13+#include "serialize.h"
14+#include <stdio.h>
15+#include <stddef.h>
16+#include <stdlib.h>
17+#include <string.h>
18+
19+char disasm_buf[1024];
20+
21+int8_t native_reg(m68k_op_info * op, m68k_options * opts)
22+{
23+ if (op->addr_mode == MODE_REG) {
24+ return opts->dregs[op->params.regs.pri];
25+ }
26+ if (op->addr_mode == MODE_AREG) {
27+ return opts->aregs[op->params.regs.pri];
28+ }
29+ return -1;
30+}
31+
32+size_t dreg_offset(uint8_t reg)
33+{
34+ return offsetof(m68k_context, dregs) + sizeof(uint32_t) * reg;
35+}
36+
37+size_t areg_offset(uint8_t reg)
38+{
39+ return offsetof(m68k_context, aregs) + sizeof(uint32_t) * reg;
40+}
41+
42+//must be called with an m68k_op_info that uses a register
43+size_t reg_offset(m68k_op_info *op)
44+{
45+ return op->addr_mode == MODE_REG ? dreg_offset(op->params.regs.pri) : areg_offset(op->params.regs.pri);
46+}
47+
48+void m68k_print_regs(m68k_context * context)
49+{
50+ printf("XNZVC\n%d%d%d%d%d\n", context->flags[0], context->flags[1], context->flags[2], context->flags[3], context->flags[4]);
51+ for (int i = 0; i < 8; i++) {
52+ printf("d%d: %X\n", i, context->dregs[i]);
53+ }
54+ for (int i = 0; i < 8; i++) {
55+ printf("a%d: %X\n", i, context->aregs[i]);
56+ }
57+}
58+
59+void m68k_read_size(m68k_options *opts, uint8_t size)
60+{
61+ switch (size)
62+ {
63+ case OPSIZE_BYTE:
64+ call(&opts->gen.code, opts->read_8);
65+ break;
66+ case OPSIZE_WORD:
67+ call(&opts->gen.code, opts->read_16);
68+ break;
69+ case OPSIZE_LONG:
70+ call(&opts->gen.code, opts->read_32);
71+ break;
72+ }
73+}
74+
75+void m68k_write_size(m68k_options *opts, uint8_t size, uint8_t lowfirst)
76+{
77+ switch (size)
78+ {
79+ case OPSIZE_BYTE:
80+ call(&opts->gen.code, opts->write_8);
81+ break;
82+ case OPSIZE_WORD:
83+ call(&opts->gen.code, opts->write_16);
84+ break;
85+ case OPSIZE_LONG:
86+ if (lowfirst) {
87+ call(&opts->gen.code, opts->write_32_lowfirst);
88+ } else {
89+ call(&opts->gen.code, opts->write_32_highfirst);
90+ }
91+ break;
92+ }
93+}
94+
95+void m68k_save_result(m68kinst * inst, m68k_options * opts)
96+{
97+ if (inst->dst.addr_mode != MODE_REG && inst->dst.addr_mode != MODE_AREG && inst->dst.addr_mode != MODE_UNUSED) {
98+ if (inst->dst.addr_mode == MODE_AREG_PREDEC &&
99+ ((inst->src.addr_mode == MODE_AREG_PREDEC && inst->op != M68K_MOVE) || (inst->op == M68K_NBCD))
100+ ) {
101+ areg_to_native(opts, inst->dst.params.regs.pri, opts->gen.scratch2);
102+ }
103+ m68k_write_size(opts, inst->extra.size, 1);
104+ }
105+}
106+
107+static void translate_m68k_lea_pea(m68k_options * opts, m68kinst * inst)
108+{
109+ code_info *code = &opts->gen.code;
110+ int8_t dst_reg = inst->op == M68K_PEA ? opts->gen.scratch1 : native_reg(&(inst->dst), opts);
111+ switch(inst->src.addr_mode)
112+ {
113+ case MODE_AREG_INDIRECT:
114+ cycles(&opts->gen, BUS);
115+ if (dst_reg >= 0) {
116+ areg_to_native(opts, inst->src.params.regs.pri, dst_reg);
117+ } else {
118+ if (opts->aregs[inst->src.params.regs.pri] >= 0) {
119+ native_to_areg(opts, opts->aregs[inst->src.params.regs.pri], inst->dst.params.regs.pri);
120+ } else {
121+ areg_to_native(opts, inst->src.params.regs.pri, opts->gen.scratch1);
122+ native_to_areg(opts, opts->gen.scratch1, inst->dst.params.regs.pri);
123+ }
124+ }
125+ break;
126+ case MODE_AREG_DISPLACE:
127+ cycles(&opts->gen, 8);
128+ calc_areg_displace(opts, &inst->src, dst_reg >= 0 ? dst_reg : opts->gen.scratch1);
129+ if (dst_reg < 0) {
130+ native_to_areg(opts, opts->gen.scratch1, inst->dst.params.regs.pri);
131+ }
132+ break;
133+ case MODE_AREG_INDEX_DISP8:
134+ cycles(&opts->gen, 12);
135+ if (dst_reg < 0 || inst->dst.params.regs.pri == inst->src.params.regs.pri || inst->dst.params.regs.pri == (inst->src.params.regs.sec >> 1 & 0x7)) {
136+ dst_reg = opts->gen.scratch1;
137+ }
138+ calc_areg_index_disp8(opts, &inst->src, dst_reg);
139+ if (dst_reg == opts->gen.scratch1 && inst->op != M68K_PEA) {
140+ native_to_areg(opts, opts->gen.scratch1, inst->dst.params.regs.pri);
141+ }
142+ break;
143+ case MODE_PC_DISPLACE:
144+ cycles(&opts->gen, 8);
145+ if (inst->op == M68K_PEA) {
146+ ldi_native(opts, inst->src.params.regs.displacement + inst->address+2, dst_reg);
147+ } else {
148+ ldi_areg(opts, inst->src.params.regs.displacement + inst->address+2, inst->dst.params.regs.pri);
149+ }
150+ break;
151+ case MODE_PC_INDEX_DISP8:
152+ cycles(&opts->gen, BUS*3);
153+ if (dst_reg < 0 || inst->dst.params.regs.pri == (inst->src.params.regs.sec >> 1 & 0x7)) {
154+ dst_reg = opts->gen.scratch1;
155+ }
156+ ldi_native(opts, inst->address+2, dst_reg);
157+ calc_index_disp8(opts, &inst->src, dst_reg);
158+ if (dst_reg == opts->gen.scratch1 && inst->op != M68K_PEA) {
159+ native_to_areg(opts, opts->gen.scratch1, inst->dst.params.regs.pri);
160+ }
161+ break;
162+ case MODE_ABSOLUTE:
163+ case MODE_ABSOLUTE_SHORT:
164+ cycles(&opts->gen, (inst->src.addr_mode == MODE_ABSOLUTE) ? BUS * 3 : BUS * 2);
165+ if (inst->op == M68K_PEA) {
166+ ldi_native(opts, inst->src.params.immed, dst_reg);
167+ } else {
168+ ldi_areg(opts, inst->src.params.immed, inst->dst.params.regs.pri);
169+ }
170+ break;
171+ default:
172+ m68k_disasm(inst, disasm_buf);
173+ fatal_error("%X: %s\naddress mode %d not implemented (lea src)\n", inst->address, disasm_buf, inst->src.addr_mode);
174+ }
175+ if (inst->op == M68K_PEA) {
176+ subi_areg(opts, 4, 7);
177+ areg_to_native(opts, 7, opts->gen.scratch2);
178+ call(code, opts->write_32_lowfirst);
179+ }
180+}
181+
182+static void push_const(m68k_options *opts, int32_t value)
183+{
184+ ldi_native(opts, value, opts->gen.scratch1);
185+ subi_areg(opts, 4, 7);
186+ areg_to_native(opts, 7, opts->gen.scratch2);
187+ call(&opts->gen.code, opts->write_32_highfirst);
188+}
189+
190+void jump_m68k_abs(m68k_options * opts, uint32_t address)
191+{
192+ code_info *code = &opts->gen.code;
193+ code_ptr dest_addr = get_native_address(opts, address);
194+ if (!dest_addr) {
195+ opts->gen.deferred = defer_address(opts->gen.deferred, address, code->cur + 1);
196+ //dummy address to be replaced later, make sure it generates a 4-byte displacement
197+ dest_addr = code->cur + 256;
198+ }
199+ jmp(code, dest_addr);
200+ //this used to call opts->native_addr for destinations in RAM, but that shouldn't be needed
201+ //since instruction retranslation patches the original native instruction location
202+}
203+
204+static void translate_m68k_bsr(m68k_options * opts, m68kinst * inst)
205+{
206+ code_info *code = &opts->gen.code;
207+ int32_t disp = inst->src.params.immed;
208+ uint32_t after = inst->address + (inst->variant == VAR_BYTE ? 2 : 4);
209+ //TODO: Add cycles in the right place relative to pushing the return address on the stack
210+ cycles(&opts->gen, 10);
211+ push_const(opts, after);
212+ jump_m68k_abs(opts, inst->address + 2 + disp);
213+}
214+
215+static void translate_m68k_jmp_jsr(m68k_options * opts, m68kinst * inst)
216+{
217+ uint8_t is_jsr = inst->op == M68K_JSR;
218+ code_info *code = &opts->gen.code;
219+ code_ptr dest_addr;
220+ uint8_t sec_reg;
221+ uint32_t after;
222+ uint32_t m68k_addr;
223+ switch(inst->src.addr_mode)
224+ {
225+ case MODE_AREG_INDIRECT:
226+ cycles(&opts->gen, BUS*2);
227+ if (is_jsr) {
228+ push_const(opts, inst->address+2);
229+ }
230+ areg_to_native(opts, inst->src.params.regs.pri, opts->gen.scratch1);
231+ call(code, opts->native_addr);
232+ jmp_r(code, opts->gen.scratch1);
233+ break;
234+ case MODE_AREG_DISPLACE:
235+ cycles(&opts->gen, BUS*2);
236+ if (is_jsr) {
237+ push_const(opts, inst->address+4);
238+ }
239+ calc_areg_displace(opts, &inst->src, opts->gen.scratch1);
240+ call(code, opts->native_addr);
241+ jmp_r(code, opts->gen.scratch1);
242+ break;
243+ case MODE_AREG_INDEX_DISP8:
244+ cycles(&opts->gen, BUS*3);//TODO: CHeck that this is correct
245+ if (is_jsr) {
246+ push_const(opts, inst->address+4);
247+ }
248+ calc_areg_index_disp8(opts, &inst->src, opts->gen.scratch1);
249+ call(code, opts->native_addr);
250+ jmp_r(code, opts->gen.scratch1);
251+ break;
252+ case MODE_PC_DISPLACE:
253+ //TODO: Add cycles in the right place relative to pushing the return address on the stack
254+ cycles(&opts->gen, 10);
255+ if (is_jsr) {
256+ push_const(opts, inst->address+4);
257+ }
258+ jump_m68k_abs(opts, inst->src.params.regs.displacement + inst->address + 2);
259+ break;
260+ case MODE_PC_INDEX_DISP8:
261+ cycles(&opts->gen, BUS*3);//TODO: CHeck that this is correct
262+ if (is_jsr) {
263+ push_const(opts, inst->address+4);
264+ }
265+ ldi_native(opts, inst->address+2, opts->gen.scratch1);
266+ calc_index_disp8(opts, &inst->src, opts->gen.scratch1);
267+ call(code, opts->native_addr);
268+ jmp_r(code, opts->gen.scratch1);
269+ break;
270+ case MODE_ABSOLUTE:
271+ case MODE_ABSOLUTE_SHORT:
272+ //TODO: Add cycles in the right place relative to pushing the return address on the stack
273+ cycles(&opts->gen, inst->src.addr_mode == MODE_ABSOLUTE ? 12 : 10);
274+ if (is_jsr) {
275+ push_const(opts, inst->address + (inst->src.addr_mode == MODE_ABSOLUTE ? 6 : 4));
276+ }
277+ jump_m68k_abs(opts, inst->src.params.immed);
278+ break;
279+ default:
280+ m68k_disasm(inst, disasm_buf);
281+ fatal_error("%s\naddress mode %d not yet supported (%s)\n", disasm_buf, inst->src.addr_mode, is_jsr ? "jsr" : "jmp");
282+ }
283+}
284+
285+static void translate_m68k_unlk(m68k_options * opts, m68kinst * inst)
286+{
287+ cycles(&opts->gen, BUS);
288+ if (inst->dst.params.regs.pri != 7) {
289+ areg_to_native(opts, inst->dst.params.regs.pri, opts->aregs[7]);
290+ }
291+ areg_to_native(opts, 7, opts->gen.scratch1);
292+ call(&opts->gen.code, opts->read_32);
293+ native_to_areg(opts, opts->gen.scratch1, inst->dst.params.regs.pri);
294+ if (inst->dst.params.regs.pri != 7) {
295+ addi_areg(opts, 4, 7);
296+ }
297+}
298+
299+static void translate_m68k_link(m68k_options * opts, m68kinst * inst)
300+{
301+ //compensate for displacement word
302+ cycles(&opts->gen, BUS);
303+ subi_areg(opts, 4, 7);
304+ areg_to_native(opts, 7, opts->gen.scratch2);
305+ areg_to_native(opts, inst->src.params.regs.pri, opts->gen.scratch1);
306+ call(&opts->gen.code, opts->write_32_highfirst);
307+ native_to_areg(opts, opts->aregs[7], inst->src.params.regs.pri);
308+ addi_areg(opts, inst->dst.params.immed, 7);
309+ //prefetch
310+ cycles(&opts->gen, BUS);
311+}
312+
313+static void translate_m68k_rts(m68k_options * opts, m68kinst * inst)
314+{
315+ code_info *code = &opts->gen.code;
316+ areg_to_native(opts, 7, opts->gen.scratch1);
317+ addi_areg(opts, 4, 7);
318+ call(code, opts->read_32);
319+ cycles(&opts->gen, 2*BUS);
320+ call(code, opts->native_addr);
321+ jmp_r(code, opts->gen.scratch1);
322+}
323+
324+static void translate_m68k_rtr(m68k_options *opts, m68kinst * inst)
325+{
326+ code_info *code = &opts->gen.code;
327+ //Read saved CCR
328+ areg_to_native(opts, 7, opts->gen.scratch1);
329+ call(code, opts->read_16);
330+ addi_areg(opts, 2, 7);
331+ call(code, opts->set_ccr);
332+ //Read saved PC
333+ areg_to_native(opts, 7, opts->gen.scratch1);
334+ call(code, opts->read_32);
335+ addi_areg(opts, 4, 7);
336+ //Get native address and jump to it
337+ call(code, opts->native_addr);
338+ jmp_r(code, opts->gen.scratch1);
339+}
340+
341+static void translate_m68k_trap(m68k_options *opts, m68kinst *inst)
342+{
343+ code_info *code = &opts->gen.code;
344+ uint32_t vector, pc = inst->address;
345+ switch (inst->op)
346+ {
347+ case M68K_TRAP:
348+ vector = inst->src.params.immed + VECTOR_TRAP_0;
349+ pc += 2;
350+ break;
351+ case M68K_A_LINE_TRAP:
352+ vector = VECTOR_LINE_1010;
353+ break;
354+ case M68K_F_LINE_TRAP:
355+ vector = VECTOR_LINE_1111;
356+ break;
357+ }
358+ ldi_native(opts, vector, opts->gen.scratch2);
359+ ldi_native(opts, pc, opts->gen.scratch1);
360+ jmp(code, opts->trap);
361+}
362+
363+static void translate_m68k_illegal(m68k_options *opts, m68kinst *inst)
364+{
365+ code_info *code = &opts->gen.code;
366+ cycles(&opts->gen, BUS);
367+ ldi_native(opts, VECTOR_ILLEGAL_INST, opts->gen.scratch2);
368+ ldi_native(opts, inst->address, opts->gen.scratch1);
369+ jmp(code, opts->trap);
370+}
371+
372+static void translate_m68k_move_usp(m68k_options *opts, m68kinst *inst)
373+{
374+ m68k_trap_if_not_supervisor(opts, inst);
375+ cycles(&opts->gen, BUS);
376+ int8_t reg;
377+ if (inst->src.addr_mode == MODE_UNUSED) {
378+ reg = native_reg(&inst->dst, opts);
379+ if (reg < 0) {
380+ reg = opts->gen.scratch1;
381+ }
382+ areg_to_native(opts, 8, reg);
383+ if (reg == opts->gen.scratch1) {
384+ native_to_areg(opts, opts->gen.scratch1, inst->dst.params.regs.pri);
385+ }
386+ } else {
387+ reg = native_reg(&inst->src, opts);
388+ if (reg < 0) {
389+ reg = opts->gen.scratch1;
390+ areg_to_native(opts, inst->src.params.regs.pri, reg);
391+ }
392+ native_to_areg(opts, reg, 8);
393+ }
394+}
395+
396+static void translate_movem_regtomem_reglist(m68k_options * opts, m68kinst *inst)
397+{
398+ code_info *code = &opts->gen.code;
399+ int8_t bit,reg,dir;
400+ if (inst->dst.addr_mode == MODE_AREG_PREDEC) {
401+ reg = 15;
402+ dir = -1;
403+ } else {
404+ reg = 0;
405+ dir = 1;
406+ }
407+ for(bit=0; reg < 16 && reg >= 0; reg += dir, bit++) {
408+ if (inst->src.params.immed & (1 << bit)) {
409+ if (inst->dst.addr_mode == MODE_AREG_PREDEC) {
410+ subi_native(opts, (inst->extra.size == OPSIZE_LONG) ? 4 : 2, opts->gen.scratch2);
411+ }
412+ push_native(opts, opts->gen.scratch2);
413+ if (reg > 7) {
414+ areg_to_native(opts, reg-8, opts->gen.scratch1);
415+ } else {
416+ dreg_to_native(opts, reg, opts->gen.scratch1);
417+ }
418+ if (inst->extra.size == OPSIZE_LONG) {
419+ call(code, opts->write_32_lowfirst);
420+ } else {
421+ call(code, opts->write_16);
422+ }
423+ pop_native(opts, opts->gen.scratch2);
424+ if (inst->dst.addr_mode != MODE_AREG_PREDEC) {
425+ addi_native(opts, (inst->extra.size == OPSIZE_LONG) ? 4 : 2, opts->gen.scratch2);
426+ }
427+ }
428+ }
429+}
430+
431+static void translate_movem_memtoreg_reglist(m68k_options * opts, m68kinst *inst)
432+{
433+ code_info *code = &opts->gen.code;
434+ for(uint8_t reg = 0; reg < 16; reg ++) {
435+ if (inst->dst.params.immed & (1 << reg)) {
436+ push_native(opts, opts->gen.scratch1);
437+ if (inst->extra.size == OPSIZE_LONG) {
438+ call(code, opts->read_32);
439+ } else {
440+ call(code, opts->read_16);
441+ }
442+ if (inst->extra.size == OPSIZE_WORD) {
443+ sign_extend16_native(opts, opts->gen.scratch1);
444+ }
445+ if (reg > 7) {
446+ native_to_areg(opts, opts->gen.scratch1, reg-8);
447+ } else {
448+ native_to_dreg(opts, opts->gen.scratch1, reg);
449+ }
450+ pop_native(opts, opts->gen.scratch1);
451+ addi_native(opts, (inst->extra.size == OPSIZE_LONG) ? 4 : 2, opts->gen.scratch1);
452+ }
453+ }
454+}
455+
456+static code_ptr get_movem_impl(m68k_options *opts, m68kinst *inst)
457+{
458+ uint8_t reg_to_mem = inst->src.addr_mode == MODE_REG;
459+ uint8_t size = inst->extra.size;
460+ int8_t dir = reg_to_mem && inst->dst.addr_mode == MODE_AREG_PREDEC ? -1 : 1;
461+ uint16_t reglist = reg_to_mem ? inst->src.params.immed : inst->dst.params.immed;
462+ for (uint32_t i = 0; i < opts->num_movem; i++)
463+ {
464+ if (
465+ opts->big_movem[i].reglist == reglist && opts->big_movem[i].reg_to_mem == reg_to_mem
466+ && opts->big_movem[i].size == size && opts->big_movem[i].dir == dir
467+ ) {
468+ return opts->big_movem[i].impl;
469+ }
470+ }
471+ if (opts->num_movem == opts->movem_storage) {
472+ if (!opts->movem_storage) {
473+ opts->movem_storage = 4;
474+ } else {
475+ opts->movem_storage *= 2;
476+ }
477+ opts->big_movem = realloc(opts->big_movem, sizeof(movem_fun) * opts->movem_storage);
478+ }
479+ if (!opts->extra_code.cur) {
480+ init_code_info(&opts->extra_code);
481+ }
482+ check_alloc_code(&opts->extra_code, 512);
483+ code_ptr impl = opts->extra_code.cur;
484+ code_info tmp = opts->gen.code;
485+ opts->gen.code = opts->extra_code;
486+ if (reg_to_mem) {
487+ translate_movem_regtomem_reglist(opts, inst);
488+ } else {
489+ translate_movem_memtoreg_reglist(opts, inst);
490+ }
491+ opts->extra_code = opts->gen.code;
492+ opts->gen.code = tmp;
493+
494+ rts(&opts->extra_code);
495+ return impl;
496+}
497+
498+static void translate_m68k_movem(m68k_options * opts, m68kinst * inst)
499+{
500+ code_info *code = &opts->gen.code;
501+ uint8_t early_cycles;
502+ uint16_t num_regs = inst->src.addr_mode == MODE_REG ? inst->src.params.immed : inst->dst.params.immed;
503+ {
504+ //TODO: Move this popcount alg to a utility function
505+ uint16_t a = (num_regs & 0b1010101010101010) >> 1;
506+ uint16_t b = num_regs & 0b0101010101010101;
507+ num_regs = a + b;
508+ a = (num_regs & 0b1100110011001100) >> 2;
509+ b = num_regs & 0b0011001100110011;
510+ num_regs = a + b;
511+ a = (num_regs & 0b1111000011110000) >> 4;
512+ b = num_regs & 0b0000111100001111;
513+ num_regs = a + b;
514+ a = (num_regs & 0b1111111100000000) >> 8;
515+ b = num_regs & 0b0000000011111111;
516+ num_regs = a + b;
517+ }
518+ if(inst->src.addr_mode == MODE_REG) {
519+ //reg to mem
520+ early_cycles = 8;
521+ switch (inst->dst.addr_mode)
522+ {
523+ case MODE_AREG_INDIRECT:
524+ case MODE_AREG_PREDEC:
525+ areg_to_native(opts, inst->dst.params.regs.pri, opts->gen.scratch2);
526+ break;
527+ case MODE_AREG_DISPLACE:
528+ early_cycles += BUS;
529+ calc_areg_displace(opts, &inst->dst, opts->gen.scratch2);
530+ break;
531+ case MODE_AREG_INDEX_DISP8:
532+ early_cycles += 6;
533+ calc_areg_index_disp8(opts, &inst->dst, opts->gen.scratch2);
534+ break;
535+ case MODE_PC_DISPLACE:
536+ early_cycles += BUS;
537+ ldi_native(opts, inst->dst.params.regs.displacement + inst->address+2, opts->gen.scratch2);
538+ break;
539+ case MODE_PC_INDEX_DISP8:
540+ early_cycles += 6;
541+ ldi_native(opts, inst->address+2, opts->gen.scratch2);
542+ calc_index_disp8(opts, &inst->dst, opts->gen.scratch2);
543+ case MODE_ABSOLUTE:
544+ early_cycles += 4;
545+ case MODE_ABSOLUTE_SHORT:
546+ early_cycles += 4;
547+ ldi_native(opts, inst->dst.params.immed, opts->gen.scratch2);
548+ break;
549+ default:
550+ m68k_disasm(inst, disasm_buf);
551+ fatal_error("%X: %s\naddress mode %d not implemented (movem dst)\n", inst->address, disasm_buf, inst->dst.addr_mode);
552+ }
553+
554+ cycles(&opts->gen, early_cycles);
555+ if (num_regs <= 9) {
556+ translate_movem_regtomem_reglist(opts, inst);
557+ } else {
558+ call(code, get_movem_impl(opts, inst));
559+ }
560+ if (inst->dst.addr_mode == MODE_AREG_PREDEC) {
561+ native_to_areg(opts, opts->gen.scratch2, inst->dst.params.regs.pri);
562+ }
563+ } else {
564+ //mem to reg
565+ early_cycles = 8; //includes prefetch
566+ switch (inst->src.addr_mode)
567+ {
568+ case MODE_AREG_INDIRECT:
569+ case MODE_AREG_POSTINC:
570+ areg_to_native(opts, inst->src.params.regs.pri, opts->gen.scratch1);
571+ break;
572+ case MODE_AREG_DISPLACE:
573+ early_cycles += BUS;
574+ calc_areg_displace(opts, &inst->src, opts->gen.scratch1);
575+ break;
576+ case MODE_AREG_INDEX_DISP8:
577+ early_cycles += 6;
578+ calc_areg_index_disp8(opts, &inst->src, opts->gen.scratch1);
579+ break;
580+ case MODE_PC_DISPLACE:
581+ early_cycles += BUS;
582+ ldi_native(opts, inst->src.params.regs.displacement + inst->address+2, opts->gen.scratch1);
583+ break;
584+ case MODE_PC_INDEX_DISP8:
585+ early_cycles += 6;
586+ ldi_native(opts, inst->address+2, opts->gen.scratch1);
587+ calc_index_disp8(opts, &inst->src, opts->gen.scratch1);
588+ break;
589+ case MODE_ABSOLUTE:
590+ early_cycles += 4;
591+ case MODE_ABSOLUTE_SHORT:
592+ early_cycles += 4;
593+ ldi_native(opts, inst->src.params.immed, opts->gen.scratch1);
594+ break;
595+ default:
596+ m68k_disasm(inst, disasm_buf);
597+ fatal_error("%X: %s\naddress mode %d not implemented (movem src)\n", inst->address, disasm_buf, inst->src.addr_mode);
598+ }
599+ cycles(&opts->gen, early_cycles);
600+
601+ if (num_regs <= 9) {
602+ translate_movem_memtoreg_reglist(opts, inst);
603+ } else {
604+ call(code, get_movem_impl(opts, inst));
605+ }
606+ if (inst->src.addr_mode == MODE_AREG_POSTINC) {
607+ native_to_areg(opts, opts->gen.scratch1, inst->src.params.regs.pri);
608+ }
609+ //Extra read
610+ call(code, opts->read_16);
611+ }
612+}
613+
614+static void translate_m68k_nop(m68k_options *opts, m68kinst *inst)
615+{
616+ cycles(&opts->gen, BUS);
617+}
618+
619+void swap_ssp_usp(m68k_options * opts)
620+{
621+ areg_to_native(opts, 7, opts->gen.scratch2);
622+ areg_to_native(opts, 8, opts->aregs[7]);
623+ native_to_areg(opts, opts->gen.scratch2, 8);
624+}
625+
626+static void translate_m68k_rte(m68k_options *opts, m68kinst *inst)
627+{
628+ m68k_trap_if_not_supervisor(opts, inst);
629+
630+ code_info *code = &opts->gen.code;
631+ //Read saved SR
632+ areg_to_native(opts, 7, opts->gen.scratch1);
633+ call(code, opts->read_16);
634+ addi_areg(opts, 2, 7);
635+ call(code, opts->set_sr);
636+ //Read saved PC
637+ areg_to_native(opts, 7, opts->gen.scratch1);
638+ call(code, opts->read_32);
639+ addi_areg(opts, 4, 7);
640+ check_user_mode_swap_ssp_usp(opts);
641+ cycles(&opts->gen, 2*BUS);
642+ //Get native address, sync components, recalculate integer points and jump to returned address
643+ call(code, opts->native_addr_and_sync);
644+ jmp_r(code, opts->gen.scratch1);
645+}
646+
647+code_ptr get_native_address(m68k_options *opts, uint32_t address)
648+{
649+ native_map_slot * native_code_map = opts->gen.native_code_map;
650+
651+ memmap_chunk const *mem_chunk = find_map_chunk(address, &opts->gen, 0, NULL);
652+ if (mem_chunk) {
653+ //calculate the lowest alias for this address
654+ address = mem_chunk->start + ((address - mem_chunk->start) & mem_chunk->mask);
655+ } else {
656+ address &= opts->gen.address_mask;
657+ }
658+ uint32_t chunk = address / NATIVE_CHUNK_SIZE;
659+ if (!native_code_map[chunk].base) {
660+ return NULL;
661+ }
662+ uint32_t offset = address % NATIVE_CHUNK_SIZE;
663+ if (native_code_map[chunk].offsets[offset] == INVALID_OFFSET || native_code_map[chunk].offsets[offset] == EXTENSION_WORD) {
664+ return NULL;
665+ }
666+ return native_code_map[chunk].base + native_code_map[chunk].offsets[offset];
667+}
668+
669+code_ptr get_native_from_context(m68k_context * context, uint32_t address)
670+{
671+ return get_native_address(context->options, address);
672+}
673+
674+uint32_t get_instruction_start(m68k_options *opts, uint32_t address)
675+{
676+ native_map_slot * native_code_map = opts->gen.native_code_map;
677+ memmap_chunk const *mem_chunk = find_map_chunk(address, &opts->gen, 0, NULL);
678+ if (mem_chunk) {
679+ //calculate the lowest alias for this address
680+ address = mem_chunk->start + ((address - mem_chunk->start) & mem_chunk->mask);
681+ } else {
682+ address &= opts->gen.address_mask;
683+ }
684+
685+ uint32_t chunk = address / NATIVE_CHUNK_SIZE;
686+ if (!native_code_map[chunk].base) {
687+ return 0;
688+ }
689+ uint32_t offset = address % NATIVE_CHUNK_SIZE;
690+ if (native_code_map[chunk].offsets[offset] == INVALID_OFFSET) {
691+ return 0;
692+ }
693+ while (native_code_map[chunk].offsets[offset] == EXTENSION_WORD)
694+ {
695+ --address;
696+ chunk = address / NATIVE_CHUNK_SIZE;
697+ offset = address % NATIVE_CHUNK_SIZE;
698+ }
699+ return address;
700+}
701+
702+static void map_native_address(m68k_context * context, uint32_t address, code_ptr native_addr, uint8_t size, uint8_t native_size)
703+{
704+ m68k_options * opts = context->options;
705+ native_map_slot * native_code_map = opts->gen.native_code_map;
706+ uint32_t meta_off;
707+ memmap_chunk const *mem_chunk = find_map_chunk(address, &opts->gen, MMAP_CODE, &meta_off);
708+ if (mem_chunk) {
709+ if (mem_chunk->flags & MMAP_CODE) {
710+ uint32_t masked = (address - mem_chunk->start) & mem_chunk->mask;
711+ uint32_t final_off = masked + meta_off;
712+ uint32_t ram_flags_off = final_off >> (opts->gen.ram_flags_shift + 3);
713+ context->ram_code_flags[ram_flags_off] |= 1 << ((final_off >> opts->gen.ram_flags_shift) & 7);
714+
715+ uint32_t slot = final_off / 1024;
716+ if (!opts->gen.ram_inst_sizes[slot]) {
717+ opts->gen.ram_inst_sizes[slot] = malloc(sizeof(uint8_t) * 512);
718+ }
719+ opts->gen.ram_inst_sizes[slot][(final_off/2) & 511] = native_size;
720+
721+ //TODO: Deal with case in which end of instruction is in a different memory chunk
722+ masked = (address + size - 1) & mem_chunk->mask;
723+ final_off = masked + meta_off;
724+ ram_flags_off = final_off >> (opts->gen.ram_flags_shift + 3);
725+ context->ram_code_flags[ram_flags_off] |= 1 << ((final_off >> opts->gen.ram_flags_shift) & 7);
726+ }
727+ //calculate the lowest alias for this address
728+ address = mem_chunk->start + ((address - mem_chunk->start) & mem_chunk->mask);
729+ } else {
730+ address &= opts->gen.address_mask;
731+ }
732+
733+ uint32_t chunk = address / NATIVE_CHUNK_SIZE;
734+ if (!native_code_map[chunk].base) {
735+ native_code_map[chunk].base = native_addr;
736+ native_code_map[chunk].offsets = malloc(sizeof(int32_t) * NATIVE_CHUNK_SIZE);
737+ memset(native_code_map[chunk].offsets, 0xFF, sizeof(int32_t) * NATIVE_CHUNK_SIZE);
738+ }
739+ uint32_t offset = address % NATIVE_CHUNK_SIZE;
740+ native_code_map[chunk].offsets[offset] = native_addr-native_code_map[chunk].base;
741+ for(address++,size-=1; size; address++,size-=1) {
742+ address &= opts->gen.address_mask;
743+ chunk = address / NATIVE_CHUNK_SIZE;
744+ offset = address % NATIVE_CHUNK_SIZE;
745+ if (!native_code_map[chunk].base) {
746+ native_code_map[chunk].base = native_addr;
747+ native_code_map[chunk].offsets = malloc(sizeof(int32_t) * NATIVE_CHUNK_SIZE);
748+ memset(native_code_map[chunk].offsets, 0xFF, sizeof(int32_t) * NATIVE_CHUNK_SIZE);
749+ }
750+ if (native_code_map[chunk].offsets[offset] == INVALID_OFFSET) {
751+ //TODO: Better handling of overlapping instructions
752+ native_code_map[chunk].offsets[offset] = EXTENSION_WORD;
753+ }
754+ }
755+}
756+
757+static uint8_t get_native_inst_size(m68k_options * opts, uint32_t address)
758+{
759+ uint32_t meta_off;
760+ memmap_chunk const *chunk = find_map_chunk(address, &opts->gen, MMAP_CODE, &meta_off);
761+ if (chunk) {
762+ meta_off += (address - chunk->start) & chunk->mask;
763+ }
764+ uint32_t slot = meta_off/1024;
765+ return opts->gen.ram_inst_sizes[slot][(meta_off/2)%512];
766+}
767+
768+uint8_t m68k_is_terminal(m68kinst * inst)
769+{
770+ return inst->op == M68K_RTS || inst->op == M68K_RTE || inst->op == M68K_RTR || inst->op == M68K_JMP
771+ || inst->op == M68K_TRAP || inst->op == M68K_ILLEGAL || inst->op == M68K_INVALID
772+ || (inst->op == M68K_BCC && inst->extra.cond == COND_TRUE);
773+}
774+
775+static void m68k_handle_deferred(m68k_context * context)
776+{
777+ m68k_options * opts = context->options;
778+ process_deferred(&opts->gen.deferred, context, (native_addr_func)get_native_from_context);
779+ if (opts->gen.deferred) {
780+ translate_m68k_stream(opts->gen.deferred->address, context);
781+ }
782+}
783+
784+uint16_t m68k_get_ir(m68k_context *context)
785+{
786+ uint32_t inst_addr = get_instruction_start(context->options, context->last_prefetch_address-2);
787+ uint16_t *native_addr = get_native_pointer(inst_addr, (void **)context->mem_pointers, &context->options->gen);
788+ if (native_addr) {
789+ return *native_addr;
790+ }
791+ fprintf(stderr, "M68K: Failed to calculate value of IR. Last prefetch address: %X\n", context->last_prefetch_address);
792+ return 0xFFFF;
793+}
794+
795+static m68k_debug_handler find_breakpoint(m68k_context *context, uint32_t address)
796+{
797+ for (uint32_t i = 0; i < context->num_breakpoints; i++)
798+ {
799+ if (context->breakpoints[i].address == address) {
800+ return context->breakpoints[i].handler;
801+ }
802+ }
803+ return NULL;
804+}
805+
806+void insert_breakpoint(m68k_context * context, uint32_t address, m68k_debug_handler bp_handler)
807+{
808+ if (!find_breakpoint(context, address)) {
809+ if (context->bp_storage == context->num_breakpoints) {
810+ context->bp_storage *= 2;
811+ if (context->bp_storage < 4) {
812+ context->bp_storage = 4;
813+ }
814+ context->breakpoints = realloc(context->breakpoints, context->bp_storage * sizeof(m68k_breakpoint));
815+ }
816+ context->breakpoints[context->num_breakpoints++] = (m68k_breakpoint){
817+ .handler = bp_handler,
818+ .address = address
819+ };
820+ m68k_breakpoint_patch(context, address, bp_handler, NULL);
821+ }
822+}
823+
824+m68k_context *m68k_bp_dispatcher(m68k_context *context, uint32_t address)
825+{
826+ m68k_debug_handler handler = find_breakpoint(context, address);
827+ if (handler) {
828+ handler(context, address);
829+ } else {
830+ //spurious breakoint?
831+ warning("Spurious breakpoing at %X\n", address);
832+ remove_breakpoint(context, address);
833+ }
834+
835+ return context;
836+}
837+
838+typedef enum {
839+ RAW_FUNC = 1,
840+ BINARY_ARITH,
841+ UNARY_ARITH,
842+ OP_FUNC
843+} impl_type;
844+
845+typedef void (*raw_fun)(m68k_options * opts, m68kinst *inst);
846+typedef void (*op_fun)(m68k_options * opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op);
847+
848+typedef struct {
849+ union {
850+ raw_fun raw;
851+ uint32_t flag_mask;
852+ op_fun op;
853+ } impl;
854+ impl_type itype;
855+} impl_info;
856+
857+#define RAW_IMPL(inst, fun) [inst] = { .impl = { .raw = fun }, .itype = RAW_FUNC }
858+#define OP_IMPL(inst, fun) [inst] = { .impl = { .op = fun }, .itype = OP_FUNC }
859+#define UNARY_IMPL(inst, mask) [inst] = { .impl = { .flag_mask = mask }, .itype = UNARY_ARITH }
860+#define BINARY_IMPL(inst, mask) [inst] = { .impl = { .flag_mask = mask}, .itype = BINARY_ARITH }
861+
862+static impl_info m68k_impls[] = {
863+ //math
864+ BINARY_IMPL(M68K_ADD, X|N|Z|V|C),
865+ BINARY_IMPL(M68K_SUB, X|N|Z|V|C),
866+ //z flag is special cased for ADDX/SUBX
867+ BINARY_IMPL(M68K_ADDX, X|N|V|C),
868+ BINARY_IMPL(M68K_SUBX, X|N|V|C),
869+ OP_IMPL(M68K_ABCD, translate_m68k_abcd_sbcd),
870+ OP_IMPL(M68K_SBCD, translate_m68k_abcd_sbcd),
871+ OP_IMPL(M68K_NBCD, translate_m68k_abcd_sbcd),
872+ BINARY_IMPL(M68K_AND, N|Z|V0|C0),
873+ BINARY_IMPL(M68K_EOR, N|Z|V0|C0),
874+ BINARY_IMPL(M68K_OR, N|Z|V0|C0),
875+ RAW_IMPL(M68K_CMP, translate_m68k_cmp),
876+ OP_IMPL(M68K_DIVS, translate_m68k_div),
877+ OP_IMPL(M68K_DIVU, translate_m68k_div),
878+ OP_IMPL(M68K_MULS, translate_m68k_mul),
879+ OP_IMPL(M68K_MULU, translate_m68k_mul),
880+ RAW_IMPL(M68K_EXT, translate_m68k_ext),
881+ UNARY_IMPL(M68K_NEG, X|N|Z|V|C),
882+ OP_IMPL(M68K_NEGX, translate_m68k_negx),
883+ UNARY_IMPL(M68K_NOT, N|Z|V|C),
884+ UNARY_IMPL(M68K_TST, N|Z|V0|C0),
885+
886+ //shift/rotate
887+ OP_IMPL(M68K_ASL, translate_m68k_sl),
888+ OP_IMPL(M68K_LSL, translate_m68k_sl),
889+ OP_IMPL(M68K_ASR, translate_m68k_asr),
890+ OP_IMPL(M68K_LSR, translate_m68k_lsr),
891+ OP_IMPL(M68K_ROL, translate_m68k_rot),
892+ OP_IMPL(M68K_ROR, translate_m68k_rot),
893+ OP_IMPL(M68K_ROXL, translate_m68k_rot),
894+ OP_IMPL(M68K_ROXR, translate_m68k_rot),
895+ UNARY_IMPL(M68K_SWAP, N|Z|V0|C0),
896+
897+ //bit
898+ OP_IMPL(M68K_BCHG, translate_m68k_bit),
899+ OP_IMPL(M68K_BCLR, translate_m68k_bit),
900+ OP_IMPL(M68K_BSET, translate_m68k_bit),
901+ OP_IMPL(M68K_BTST, translate_m68k_bit),
902+
903+ //data movement
904+ RAW_IMPL(M68K_MOVE, translate_m68k_move),
905+ RAW_IMPL(M68K_MOVEM, translate_m68k_movem),
906+ RAW_IMPL(M68K_MOVEP, translate_m68k_movep),
907+ RAW_IMPL(M68K_MOVE_USP, translate_m68k_move_usp),
908+ RAW_IMPL(M68K_LEA, translate_m68k_lea_pea),
909+ RAW_IMPL(M68K_PEA, translate_m68k_lea_pea),
910+ UNARY_IMPL(M68K_CLR, N0|V0|C0|Z1),
911+ OP_IMPL(M68K_EXG, translate_m68k_exg),
912+ RAW_IMPL(M68K_SCC, translate_m68k_scc),
913+
914+ //function calls and branches
915+ RAW_IMPL(M68K_BCC, translate_m68k_bcc),
916+ RAW_IMPL(M68K_BSR, translate_m68k_bsr),
917+ RAW_IMPL(M68K_DBCC, translate_m68k_dbcc),
918+ RAW_IMPL(M68K_JMP, translate_m68k_jmp_jsr),
919+ RAW_IMPL(M68K_JSR, translate_m68k_jmp_jsr),
920+ RAW_IMPL(M68K_RTS, translate_m68k_rts),
921+ RAW_IMPL(M68K_RTE, translate_m68k_rte),
922+ RAW_IMPL(M68K_RTR, translate_m68k_rtr),
923+ RAW_IMPL(M68K_LINK, translate_m68k_link),
924+ RAW_IMPL(M68K_UNLK, translate_m68k_unlk),
925+
926+ //SR/CCR stuff
927+ RAW_IMPL(M68K_ANDI_CCR, translate_m68k_andi_ori_ccr_sr),
928+ RAW_IMPL(M68K_ANDI_SR, translate_m68k_andi_ori_ccr_sr),
929+ RAW_IMPL(M68K_EORI_CCR, translate_m68k_eori_ccr_sr),
930+ RAW_IMPL(M68K_EORI_SR, translate_m68k_eori_ccr_sr),
931+ RAW_IMPL(M68K_ORI_CCR, translate_m68k_andi_ori_ccr_sr),
932+ RAW_IMPL(M68K_ORI_SR, translate_m68k_andi_ori_ccr_sr),
933+ OP_IMPL(M68K_MOVE_CCR, translate_m68k_move_ccr_sr),
934+ OP_IMPL(M68K_MOVE_SR, translate_m68k_move_ccr_sr),
935+ OP_IMPL(M68K_MOVE_FROM_SR, translate_m68k_move_from_sr),
936+ RAW_IMPL(M68K_STOP, translate_m68k_stop),
937+
938+ //traps
939+ OP_IMPL(M68K_CHK, translate_m68k_chk),
940+ RAW_IMPL(M68K_TRAP, translate_m68k_trap),
941+ RAW_IMPL(M68K_A_LINE_TRAP, translate_m68k_trap),
942+ RAW_IMPL(M68K_F_LINE_TRAP, translate_m68k_trap),
943+ RAW_IMPL(M68K_TRAPV, translate_m68k_trapv),
944+ RAW_IMPL(M68K_ILLEGAL, translate_m68k_illegal),
945+ RAW_IMPL(M68K_INVALID, translate_m68k_illegal),
946+
947+ //misc
948+ RAW_IMPL(M68K_NOP, translate_m68k_nop),
949+ RAW_IMPL(M68K_RESET, translate_m68k_reset),
950+ RAW_IMPL(M68K_TAS, translate_m68k_tas),
951+};
952+
953+static void translate_m68k(m68k_context *context, m68kinst * inst)
954+{
955+ m68k_options * opts = context->options;
956+ if (inst->address & 1) {
957+ translate_m68k_odd(opts, inst);
958+ return;
959+ }
960+ code_ptr start = opts->gen.code.cur;
961+ check_cycles_int(&opts->gen, inst->address);
962+
963+ m68k_debug_handler bp;
964+ if ((bp = find_breakpoint(context, inst->address))) {
965+ m68k_breakpoint_patch(context, inst->address, bp, start);
966+ }
967+
968+ //log_address(&opts->gen, inst->address, "M68K: %X @ %d\n");
969+ if (
970+ (inst->src.addr_mode > MODE_AREG && inst->src.addr_mode < MODE_IMMEDIATE)
971+ || (inst->dst.addr_mode > MODE_AREG && inst->dst.addr_mode < MODE_IMMEDIATE)
972+ || (inst->op == M68K_BCC && (inst->src.params.immed & 1))
973+ ) {
974+ //Not accurate for all cases, but probably good enough for now
975+ m68k_set_last_prefetch(opts, inst->address + inst->bytes);
976+ }
977+ impl_info * info = m68k_impls + inst->op;
978+ if (info->itype == RAW_FUNC) {
979+ info->impl.raw(opts, inst);
980+ return;
981+ }
982+
983+ host_ea src_op, dst_op;
984+ uint8_t needs_int_latch = 0;
985+ if (inst->src.addr_mode != MODE_UNUSED) {
986+ needs_int_latch |= translate_m68k_op(inst, &src_op, opts, 0);
987+ }
988+ if (inst->dst.addr_mode != MODE_UNUSED) {
989+ needs_int_latch |= translate_m68k_op(inst, &dst_op, opts, 1);
990+ }
991+ if (needs_int_latch) {
992+ m68k_check_cycles_int_latch(opts);
993+ }
994+ if (info->itype == OP_FUNC) {
995+ info->impl.op(opts, inst, &src_op, &dst_op);
996+ } else if (info->itype == BINARY_ARITH) {
997+ translate_m68k_arith(opts, inst, info->impl.flag_mask, &src_op, &dst_op);
998+ } else if (info->itype == UNARY_ARITH) {
999+ translate_m68k_unary(opts, inst, info->impl.flag_mask, inst->dst.addr_mode != MODE_UNUSED ? &dst_op : &src_op);
1000+ } else {
1001+ m68k_disasm(inst, disasm_buf);
1002+ fatal_error("%X: %s\ninstruction %d not yet implemented\n", inst->address, disasm_buf, inst->op);
1003+ }
1004+ if (opts->gen.code.stack_off) {
1005+ m68k_disasm(inst, disasm_buf);
1006+ fatal_error("Stack offset is %X after %X: %s\n", opts->gen.code.stack_off, inst->address, disasm_buf);
1007+ }
1008+}
1009+
1010+void translate_m68k_stream(uint32_t address, m68k_context * context)
1011+{
1012+ m68kinst instbuf;
1013+ m68k_options * opts = context->options;
1014+ code_info *code = &opts->gen.code;
1015+ if(get_native_address(opts, address)) {
1016+ return;
1017+ }
1018+ uint16_t *encoded, *next;
1019+ do {
1020+ if (opts->address_log) {
1021+ fprintf(opts->address_log, "%X\n", address);
1022+ fflush(opts->address_log);
1023+ }
1024+ do {
1025+ encoded = get_native_pointer(address, (void **)context->mem_pointers, &opts->gen);
1026+ if (!encoded) {
1027+ code_ptr start = code->cur;
1028+ translate_out_of_bounds(opts, address);
1029+ code_ptr after = code->cur;
1030+ map_native_address(context, address, start, 2, after-start);
1031+ break;
1032+ }
1033+ code_ptr existing = get_native_address(opts, address);
1034+ if (existing) {
1035+ jmp(code, existing);
1036+ break;
1037+ }
1038+ next = m68k_decode(encoded, &instbuf, address);
1039+ if (instbuf.op == M68K_INVALID) {
1040+ instbuf.src.params.immed = *encoded;
1041+ }
1042+ uint16_t m68k_size = (next-encoded)*2;
1043+ address += m68k_size;
1044+ //char disbuf[1024];
1045+ //m68k_disasm(&instbuf, disbuf);
1046+ //printf("%X: %s\n", instbuf.address, disbuf);
1047+
1048+ //make sure the beginning of the code for an instruction is contiguous
1049+ check_code_prologue(code);
1050+ code_ptr start = code->cur;
1051+ translate_m68k(context, &instbuf);
1052+ code_ptr after = code->cur;
1053+ map_native_address(context, instbuf.address, start, m68k_size, after-start);
1054+ } while(!m68k_is_terminal(&instbuf) && !(address & 1));
1055+ process_deferred(&opts->gen.deferred, context, (native_addr_func)get_native_from_context);
1056+ if (opts->gen.deferred) {
1057+ address = opts->gen.deferred->address;
1058+ }
1059+ } while(opts->gen.deferred);
1060+}
1061+
1062+void * m68k_retranslate_inst(uint32_t address, m68k_context * context)
1063+{
1064+ m68k_options * opts = context->options;
1065+ code_info *code = &opts->gen.code;
1066+ uint8_t orig_size = get_native_inst_size(opts, address);
1067+ code_ptr orig_start = get_native_address(context->options, address);
1068+ uint32_t orig = address;
1069+ code_info orig_code = {orig_start, orig_start + orig_size + 5, 0};
1070+ uint16_t *after, *inst = get_native_pointer(address, (void **)context->mem_pointers, &opts->gen);
1071+ m68kinst instbuf;
1072+ after = m68k_decode(inst, &instbuf, orig);
1073+ if (orig_size != MAX_NATIVE_SIZE) {
1074+ deferred_addr * orig_deferred = opts->gen.deferred;
1075+
1076+ //make sure we have enough code space for the max size instruction
1077+ check_alloc_code(code, MAX_NATIVE_SIZE);
1078+ code_ptr native_start = code->cur;
1079+ translate_m68k(context, &instbuf);
1080+ code_ptr native_end = code->cur;
1081+ /*uint8_t is_terminal = m68k_is_terminal(&instbuf);
1082+ if ((native_end - native_start) <= orig_size) {
1083+ code_ptr native_next;
1084+ if (!is_terminal) {
1085+ native_next = get_native_address(context->native_code_map, orig + (after-inst)*2);
1086+ }
1087+ if (is_terminal || (native_next && ((native_next == orig_start + orig_size) || (orig_size - (native_end - native_start)) > 5))) {
1088+ printf("Using original location: %p\n", orig_code.cur);
1089+ remove_deferred_until(&opts->gen.deferred, orig_deferred);
1090+ code_info tmp;
1091+ tmp.cur = code->cur;
1092+ tmp.last = code->last;
1093+ code->cur = orig_code.cur;
1094+ code->last = orig_code.last;
1095+ translate_m68k(context, &instbuf);
1096+ native_end = orig_code.cur = code->cur;
1097+ code->cur = tmp.cur;
1098+ code->last = tmp.last;
1099+ if (!is_terminal) {
1100+ nop_fill_or_jmp_next(&orig_code, orig_start + orig_size, native_next);
1101+ }
1102+ m68k_handle_deferred(context);
1103+ return orig_start;
1104+ }
1105+ }*/
1106+
1107+ map_native_address(context, instbuf.address, native_start, (after-inst)*2, MAX_NATIVE_SIZE);
1108+
1109+ jmp(&orig_code, native_start);
1110+ if (!m68k_is_terminal(&instbuf)) {
1111+ code_ptr native_end = code->cur;
1112+ code->cur = native_start + MAX_NATIVE_SIZE;
1113+ code_ptr rest = get_native_address_trans(context, orig + (after-inst)*2);
1114+ code_info tmp_code = {
1115+ .cur = native_end,
1116+ .last = native_start + MAX_NATIVE_SIZE,
1117+ .stack_off = code->stack_off
1118+ };
1119+ jmp(&tmp_code, rest);
1120+ } else {
1121+ code->cur = native_start + MAX_NATIVE_SIZE;
1122+ }
1123+ m68k_handle_deferred(context);
1124+ return native_start;
1125+ } else {
1126+ code_info tmp = *code;
1127+ *code = orig_code;
1128+ translate_m68k(context, &instbuf);
1129+ orig_code = *code;
1130+ *code = tmp;
1131+ if (!m68k_is_terminal(&instbuf)) {
1132+ jmp(&orig_code, get_native_address_trans(context, orig + (after-inst)*2));
1133+ }
1134+ m68k_handle_deferred(context);
1135+ return orig_start;
1136+ }
1137+}
1138+
1139+code_ptr get_native_address_trans(m68k_context * context, uint32_t address)
1140+{
1141+ code_ptr ret = get_native_address(context->options, address);
1142+ if (!ret) {
1143+ translate_m68k_stream(address, context);
1144+ ret = get_native_address(context->options, address);
1145+ }
1146+ return ret;
1147+}
1148+
1149+void remove_breakpoint(m68k_context * context, uint32_t address)
1150+{
1151+ for (uint32_t i = 0; i < context->num_breakpoints; i++)
1152+ {
1153+ if (context->breakpoints[i].address == address) {
1154+ if (i != (context->num_breakpoints-1)) {
1155+ context->breakpoints[i] = context->breakpoints[context->num_breakpoints-1];
1156+ }
1157+ context->num_breakpoints--;
1158+ break;
1159+ }
1160+ }
1161+ code_ptr native = get_native_address(context->options, address);
1162+ if (!native) {
1163+ return;
1164+ }
1165+ code_info tmp = context->options->gen.code;
1166+ context->options->gen.code.cur = native;
1167+ context->options->gen.code.last = native + MAX_NATIVE_SIZE;
1168+ check_cycles_int(&context->options->gen, address);
1169+ context->options->gen.code = tmp;
1170+}
1171+
1172+void start_68k_context(m68k_context * context, uint32_t address)
1173+{
1174+ code_ptr addr = get_native_address_trans(context, address);
1175+ m68k_options * options = context->options;
1176+ options->start_context(addr, context);
1177+}
1178+
1179+void resume_68k(m68k_context *context)
1180+{
1181+ code_ptr addr = context->resume_pc;
1182+ context->resume_pc = NULL;
1183+ m68k_options * options = context->options;
1184+ context->should_return = 0;
1185+ options->start_context(addr, context);
1186+}
1187+
1188+void m68k_reset(m68k_context * context)
1189+{
1190+ //TODO: Actually execute the M68K reset vector rather than simulating some of its behavior
1191+ uint16_t *reset_vec = get_native_pointer(0, (void **)context->mem_pointers, &context->options->gen);
1192+ context->aregs[7] = reset_vec[0] << 16 | reset_vec[1];
1193+ uint32_t address = reset_vec[2] << 16 | reset_vec[3];
1194+ start_68k_context(context, address);
1195+}
1196+
1197+void m68k_options_free(m68k_options *opts)
1198+{
1199+ for (uint32_t address = 0; address < opts->gen.address_mask; address += NATIVE_CHUNK_SIZE)
1200+ {
1201+ uint32_t chunk = address / NATIVE_CHUNK_SIZE;
1202+ if (opts->gen.native_code_map[chunk].base) {
1203+ free(opts->gen.native_code_map[chunk].offsets);
1204+ }
1205+ }
1206+ free(opts->gen.native_code_map);
1207+ uint32_t ram_inst_slots = ram_size(&opts->gen) / 1024;
1208+ for (uint32_t i = 0; i < ram_inst_slots; i++)
1209+ {
1210+ free(opts->gen.ram_inst_sizes[i]);
1211+ }
1212+ free(opts->gen.ram_inst_sizes);
1213+ free(opts->big_movem);
1214+ free(opts);
1215+}
1216+
1217+
1218+m68k_context * init_68k_context(m68k_options * opts, m68k_reset_handler reset_handler)
1219+{
1220+ m68k_context * context = calloc(1, sizeof(m68k_context) + ram_size(&opts->gen) / (1 << opts->gen.ram_flags_shift) / 8);
1221+ context->options = opts;
1222+ context->int_cycle = CYCLE_NEVER;
1223+ context->status = 0x27;
1224+ context->reset_handler = (code_ptr)reset_handler;
1225+ return context;
1226+}
1227+
1228+void m68k_serialize(m68k_context *context, uint32_t pc, serialize_buffer *buf)
1229+{
1230+ for (int i = 0; i < 8; i++)
1231+ {
1232+ save_int32(buf, context->dregs[i]);
1233+ }
1234+ for (int i = 0; i < 9; i++)
1235+ {
1236+ save_int32(buf, context->aregs[i]);
1237+ }
1238+ save_int32(buf, pc);
1239+ uint16_t sr = context->status << 3;
1240+ for (int flag = 4; flag >= 0; flag--) {
1241+ sr <<= 1;
1242+ sr |= context->flags[flag] != 0;
1243+ }
1244+ save_int16(buf, sr);
1245+ save_int32(buf, context->current_cycle);
1246+ save_int32(buf, context->int_cycle);
1247+ save_int8(buf, context->int_num);
1248+ save_int8(buf, context->int_pending);
1249+ save_int8(buf, context->trace_pending);
1250+}
1251+
1252+void m68k_deserialize(deserialize_buffer *buf, void *vcontext)
1253+{
1254+ m68k_context *context = vcontext;
1255+ for (int i = 0; i < 8; i++)
1256+ {
1257+ context->dregs[i] = load_int32(buf);
1258+ }
1259+ for (int i = 0; i < 9; i++)
1260+ {
1261+ context->aregs[i] = load_int32(buf);
1262+ }
1263+ //hack until both PC and IR registers are represented properly
1264+ context->last_prefetch_address = load_int32(buf);
1265+ uint16_t sr = load_int16(buf);
1266+ context->status = sr >> 8;
1267+ for (int flag = 0; flag < 5; flag++)
1268+ {
1269+ context->flags[flag] = sr & 1;
1270+ sr >>= 1;
1271+ }
1272+ context->current_cycle = load_int32(buf);
1273+ context->int_cycle = load_int32(buf);
1274+ context->int_num = load_int8(buf);
1275+ context->int_pending = load_int8(buf);
1276+ context->trace_pending = load_int8(buf);
1277+}
+124,
-0
1@@ -0,0 +1,124 @@
2+/*
3+ Copyright 2013 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#ifndef M68K_CORE_H_
8+#define M68K_CORE_H_
9+#include <stdint.h>
10+#include <stdio.h>
11+#include "backend.h"
12+#include "serialize.h"
13+//#include "68kinst.h"
14+struct m68kinst;
15+
16+#define NUM_MEM_AREAS 8
17+#define NATIVE_MAP_CHUNKS (64*1024)
18+#define NATIVE_CHUNK_SIZE ((16 * 1024 * 1024 / NATIVE_MAP_CHUNKS))
19+#define MAX_NATIVE_SIZE 255
20+
21+#define M68K_OPT_BROKEN_READ_MODIFY 1
22+
23+#define INT_PENDING_SR_CHANGE 254
24+#define INT_PENDING_NONE 255
25+
26+#define M68K_STATUS_TRACE 0x80
27+
28+typedef void (*start_fun)(uint8_t * addr, void * context);
29+
30+typedef struct {
31+ code_ptr impl;
32+ uint16_t reglist;
33+ uint8_t reg_to_mem;
34+ uint8_t size;
35+ int8_t dir;
36+} movem_fun;
37+
38+typedef struct {
39+ cpu_options gen;
40+
41+ int8_t dregs[8];
42+ int8_t aregs[8];
43+ int8_t flag_regs[5];
44+ FILE *address_log;
45+ code_ptr read_16;
46+ code_ptr write_16;
47+ code_ptr read_8;
48+ code_ptr write_8;
49+ code_ptr read_32;
50+ code_ptr write_32_lowfirst;
51+ code_ptr write_32_highfirst;
52+ code_ptr do_sync;
53+ code_ptr handle_int_latch;
54+ code_ptr trap;
55+ start_fun start_context;
56+ code_ptr retrans_stub;
57+ code_ptr native_addr;
58+ code_ptr native_addr_and_sync;
59+ code_ptr get_sr;
60+ code_ptr set_sr;
61+ code_ptr set_ccr;
62+ code_ptr bp_stub;
63+ code_info extra_code;
64+ movem_fun *big_movem;
65+ uint32_t num_movem;
66+ uint32_t movem_storage;
67+ code_word prologue_start;
68+} m68k_options;
69+
70+typedef struct m68k_context m68k_context;
71+typedef void (*m68k_debug_handler)(m68k_context *context, uint32_t pc);
72+
73+typedef struct {
74+ m68k_debug_handler handler;
75+ uint32_t address;
76+} m68k_breakpoint;
77+
78+struct m68k_context {
79+ uint8_t flags[5];
80+ uint8_t status;
81+ uint16_t int_ack;
82+ uint32_t dregs[8];
83+ uint32_t aregs[9];
84+ uint32_t target_cycle; //cycle at which the next synchronization or interrupt occurs
85+ uint32_t current_cycle;
86+ uint32_t sync_cycle;
87+ uint32_t int_cycle;
88+ uint32_t int_num;
89+ uint32_t last_prefetch_address;
90+ uint16_t *mem_pointers[NUM_MEM_AREAS];
91+ code_ptr resume_pc;
92+ code_ptr reset_handler;
93+ m68k_options *options;
94+ void *system;
95+ m68k_breakpoint *breakpoints;
96+ uint32_t num_breakpoints;
97+ uint32_t bp_storage;
98+ uint8_t int_pending;
99+ uint8_t trace_pending;
100+ uint8_t should_return;
101+ uint8_t ram_code_flags[];
102+};
103+
104+typedef m68k_context *(*m68k_reset_handler)(m68k_context *context);
105+
106+
107+void translate_m68k_stream(uint32_t address, m68k_context * context);
108+void start_68k_context(m68k_context * context, uint32_t address);
109+void resume_68k(m68k_context *context);
110+void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chunks, uint32_t clock_divider);
111+m68k_context * init_68k_context(m68k_options * opts, m68k_reset_handler reset_handler);
112+void m68k_reset(m68k_context * context);
113+void m68k_options_free(m68k_options *opts);
114+void insert_breakpoint(m68k_context * context, uint32_t address, m68k_debug_handler bp_handler);
115+void remove_breakpoint(m68k_context * context, uint32_t address);
116+m68k_context * m68k_handle_code_write(uint32_t address, m68k_context * context);
117+uint32_t get_instruction_start(m68k_options *opts, uint32_t address);
118+uint16_t m68k_get_ir(m68k_context *context);
119+void m68k_print_regs(m68k_context * context);
120+void m68k_invalidate_code_range(m68k_context *context, uint32_t start, uint32_t end);
121+void m68k_serialize(m68k_context *context, uint32_t pc, serialize_buffer *buf);
122+void m68k_deserialize(deserialize_buffer *buf, void *vcontext);
123+
124+#endif //M68K_CORE_H_
125+
+3219,
-0
1@@ -0,0 +1,3219 @@
2+/*
3+ Copyright 2013 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#include "gen_x86.h"
8+#include "m68k_core.h"
9+#include "m68k_internal.h"
10+#include "68kinst.h"
11+#include "mem.h"
12+#include "backend.h"
13+#include "util.h"
14+#include <stdio.h>
15+#include <stddef.h>
16+#include <stdlib.h>
17+#include <string.h>
18+
19+enum {
20+ FLAG_X,
21+ FLAG_N,
22+ FLAG_Z,
23+ FLAG_V,
24+ FLAG_C
25+};
26+
27+void set_flag(m68k_options * opts, uint8_t val, uint8_t flag)
28+{
29+ if (opts->flag_regs[flag] >= 0) {
30+ mov_ir(&opts->gen.code, val, opts->flag_regs[flag], SZ_B);
31+ } else {
32+ int8_t offset = offsetof(m68k_context, flags) + flag;
33+ if (offset) {
34+ mov_irdisp(&opts->gen.code, val, opts->gen.context_reg, offset, SZ_B);
35+ } else {
36+ mov_irind(&opts->gen.code, val, opts->gen.context_reg, SZ_B);
37+ }
38+ }
39+}
40+
41+void set_flag_cond(m68k_options *opts, uint8_t cond, uint8_t flag)
42+{
43+ if (opts->flag_regs[flag] >= 0) {
44+ setcc_r(&opts->gen.code, cond, opts->flag_regs[flag]);
45+ } else {
46+ int8_t offset = offsetof(m68k_context, flags) + flag;
47+ if (offset) {
48+ setcc_rdisp(&opts->gen.code, cond, opts->gen.context_reg, offset);
49+ } else {
50+ setcc_rind(&opts->gen.code, cond, opts->gen.context_reg);
51+ }
52+ }
53+}
54+
55+void check_flag(m68k_options *opts, uint8_t flag)
56+{
57+ if (opts->flag_regs[flag] >= 0) {
58+ cmp_ir(&opts->gen.code, 0, opts->flag_regs[flag], SZ_B);
59+ } else {
60+ cmp_irdisp(&opts->gen.code, 0, opts->gen.context_reg, offsetof(m68k_context, flags) + flag, SZ_B);
61+ }
62+}
63+
64+void flag_to_reg(m68k_options *opts, uint8_t flag, uint8_t reg)
65+{
66+ if (opts->flag_regs[flag] >= 0) {
67+ mov_rr(&opts->gen.code, opts->flag_regs[flag], reg, SZ_B);
68+ } else {
69+ int8_t offset = offsetof(m68k_context, flags) + flag;
70+ if (offset) {
71+ mov_rdispr(&opts->gen.code, opts->gen.context_reg, offset, reg, SZ_B);
72+ } else {
73+ mov_rindr(&opts->gen.code, opts->gen.context_reg, reg, SZ_B);
74+ }
75+ }
76+}
77+
78+void reg_to_flag(m68k_options *opts, uint8_t reg, uint8_t flag)
79+{
80+ if (opts->flag_regs[flag] >= 0) {
81+ mov_rr(&opts->gen.code, reg, opts->flag_regs[flag], SZ_B);
82+ } else {
83+ int8_t offset = offsetof(m68k_context, flags) + flag;
84+ if (offset) {
85+ mov_rrdisp(&opts->gen.code, reg, opts->gen.context_reg, offset, SZ_B);
86+ } else {
87+ mov_rrind(&opts->gen.code, reg, opts->gen.context_reg, SZ_B);
88+ }
89+ }
90+}
91+
92+void flag_to_flag(m68k_options *opts, uint8_t flag1, uint8_t flag2)
93+{
94+ code_info *code = &opts->gen.code;
95+ if (opts->flag_regs[flag1] >= 0 && opts->flag_regs[flag2] >= 0) {
96+ mov_rr(code, opts->flag_regs[flag1], opts->flag_regs[flag2], SZ_B);
97+ } else if(opts->flag_regs[flag1] >= 0) {
98+ mov_rrdisp(code, opts->flag_regs[flag1], opts->gen.context_reg, offsetof(m68k_context, flags) + flag2, SZ_B);
99+ } else if (opts->flag_regs[flag2] >= 0) {
100+ mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, flags) + flag1, opts->flag_regs[flag2], SZ_B);
101+ } else {
102+ push_r(code, opts->gen.scratch1);
103+ mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, flags) + flag1, opts->gen.scratch1, SZ_B);
104+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, flags) + flag2, SZ_B);
105+ pop_r(code, opts->gen.scratch1);
106+ }
107+}
108+
109+void update_flags(m68k_options *opts, uint32_t update_mask)
110+{
111+ uint8_t native_flags[] = {0, CC_S, CC_Z, CC_O, CC_C};
112+ for (int8_t flag = FLAG_C; flag >= FLAG_X; --flag)
113+ {
114+ if (update_mask & X0 << (flag*3)) {
115+ set_flag(opts, 0, flag);
116+ } else if(update_mask & X1 << (flag*3)) {
117+ set_flag(opts, 1, flag);
118+ } else if(update_mask & X << (flag*3)) {
119+ if (flag == FLAG_X) {
120+ if (opts->flag_regs[FLAG_C] >= 0 || !(update_mask & (C0|C1|C))) {
121+ flag_to_flag(opts, FLAG_C, FLAG_X);
122+ } else if(update_mask & C0) {
123+ set_flag(opts, 0, flag);
124+ } else if(update_mask & C1) {
125+ set_flag(opts, 1, flag);
126+ } else {
127+ set_flag_cond(opts, CC_C, flag);
128+ }
129+ } else {
130+ set_flag_cond(opts, native_flags[flag], flag);
131+ }
132+ }
133+ }
134+}
135+
136+void flag_to_carry(m68k_options * opts, uint8_t flag)
137+{
138+ if (opts->flag_regs[flag] >= 0) {
139+ bt_ir(&opts->gen.code, 0, opts->flag_regs[flag], SZ_B);
140+ } else {
141+ bt_irdisp(&opts->gen.code, 0, opts->gen.context_reg, offsetof(m68k_context, flags) + flag, SZ_B);
142+ }
143+}
144+
145+void or_flag_to_reg(m68k_options *opts, uint8_t flag, uint8_t reg)
146+{
147+ if (opts->flag_regs[flag] >= 0) {
148+ or_rr(&opts->gen.code, opts->flag_regs[flag], reg, SZ_B);
149+ } else {
150+ or_rdispr(&opts->gen.code, opts->gen.context_reg, offsetof(m68k_context, flags) + flag, reg, SZ_B);
151+ }
152+}
153+
154+void xor_flag_to_reg(m68k_options *opts, uint8_t flag, uint8_t reg)
155+{
156+ if (opts->flag_regs[flag] >= 0) {
157+ xor_rr(&opts->gen.code, opts->flag_regs[flag], reg, SZ_B);
158+ } else {
159+ xor_rdispr(&opts->gen.code, opts->gen.context_reg, offsetof(m68k_context, flags) + flag, reg, SZ_B);
160+ }
161+}
162+
163+void xor_flag(m68k_options *opts, uint8_t val, uint8_t flag)
164+{
165+ if (opts->flag_regs[flag] >= 0) {
166+ xor_ir(&opts->gen.code, val, opts->flag_regs[flag], SZ_B);
167+ } else {
168+ xor_irdisp(&opts->gen.code, val, opts->gen.context_reg, offsetof(m68k_context, flags) + flag, SZ_B);
169+ }
170+}
171+
172+void cmp_flags(m68k_options *opts, uint8_t flag1, uint8_t flag2)
173+{
174+ code_info *code = &opts->gen.code;
175+ if (opts->flag_regs[flag1] >= 0 && opts->flag_regs[flag2] >= 0) {
176+ cmp_rr(code, opts->flag_regs[flag1], opts->flag_regs[flag2], SZ_B);
177+ } else if(opts->flag_regs[flag1] >= 0 || opts->flag_regs[flag2] >= 0) {
178+ if (opts->flag_regs[flag2] >= 0) {
179+ uint8_t tmp = flag1;
180+ flag1 = flag2;
181+ flag2 = tmp;
182+ }
183+ cmp_rrdisp(code, opts->flag_regs[flag1], opts->gen.context_reg, offsetof(m68k_context, flags) + flag2, SZ_B);
184+ } else {
185+ mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, flags) + flag1, opts->gen.scratch1, SZ_B);
186+ cmp_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, flags) + flag2, SZ_B);
187+ }
188+}
189+
190+void areg_to_native(m68k_options *opts, uint8_t reg, uint8_t native_reg)
191+{
192+ if (opts->aregs[reg] >= 0) {
193+ mov_rr(&opts->gen.code, opts->aregs[reg], native_reg, SZ_D);
194+ } else {
195+ mov_rdispr(&opts->gen.code, opts->gen.context_reg, areg_offset(reg), native_reg, SZ_D);
196+ }
197+}
198+
199+void dreg_to_native(m68k_options *opts, uint8_t reg, uint8_t native_reg)
200+{
201+ if (opts->dregs[reg] >= 0) {
202+ mov_rr(&opts->gen.code, opts->dregs[reg], native_reg, SZ_D);
203+ } else {
204+ mov_rdispr(&opts->gen.code, opts->gen.context_reg, dreg_offset(reg), native_reg, SZ_D);
205+ }
206+}
207+
208+void areg_to_native_sx(m68k_options *opts, uint8_t reg, uint8_t native_reg)
209+{
210+ if (opts->aregs[reg] >= 0) {
211+ movsx_rr(&opts->gen.code, opts->aregs[reg], native_reg, SZ_W, SZ_D);
212+ } else {
213+ movsx_rdispr(&opts->gen.code, opts->gen.context_reg, areg_offset(reg), native_reg, SZ_W, SZ_D);
214+ }
215+}
216+
217+void dreg_to_native_sx(m68k_options *opts, uint8_t reg, uint8_t native_reg)
218+{
219+ if (opts->dregs[reg] >= 0) {
220+ movsx_rr(&opts->gen.code, opts->dregs[reg], native_reg, SZ_W, SZ_D);
221+ } else {
222+ movsx_rdispr(&opts->gen.code, opts->gen.context_reg, dreg_offset(reg), native_reg, SZ_W, SZ_D);
223+ }
224+}
225+
226+void native_to_areg(m68k_options *opts, uint8_t native_reg, uint8_t reg)
227+ {
228+ if (opts->aregs[reg] >= 0) {
229+ mov_rr(&opts->gen.code, native_reg, opts->aregs[reg], SZ_D);
230+ } else {
231+ mov_rrdisp(&opts->gen.code, native_reg, opts->gen.context_reg, areg_offset(reg), SZ_D);
232+ }
233+}
234+
235+void native_to_dreg(m68k_options *opts, uint8_t native_reg, uint8_t reg)
236+{
237+ if (opts->dregs[reg] >= 0) {
238+ mov_rr(&opts->gen.code, native_reg, opts->dregs[reg], SZ_D);
239+ } else {
240+ mov_rrdisp(&opts->gen.code, native_reg, opts->gen.context_reg, dreg_offset(reg), SZ_D);
241+ }
242+}
243+
244+void ldi_areg(m68k_options *opts, int32_t value, uint8_t reg)
245+{
246+ if (opts->aregs[reg] >= 0) {
247+ mov_ir(&opts->gen.code, value, opts->aregs[reg], SZ_D);
248+ } else {
249+ mov_irdisp(&opts->gen.code, value, opts->gen.context_reg, areg_offset(reg), SZ_D);
250+ }
251+}
252+
253+void ldi_native(m68k_options *opts, int32_t value, uint8_t reg)
254+{
255+ mov_ir(&opts->gen.code, value, reg, SZ_D);
256+}
257+
258+void addi_native(m68k_options *opts, int32_t value, uint8_t reg)
259+{
260+ add_ir(&opts->gen.code, value, reg, SZ_D);
261+ }
262+
263+void subi_native(m68k_options *opts, int32_t value, uint8_t reg)
264+{
265+ sub_ir(&opts->gen.code, value, reg, SZ_D);
266+}
267+
268+void push_native(m68k_options *opts, uint8_t reg)
269+{
270+ push_r(&opts->gen.code, reg);
271+}
272+
273+void pop_native(m68k_options *opts, uint8_t reg)
274+{
275+ pop_r(&opts->gen.code, reg);
276+}
277+
278+void sign_extend16_native(m68k_options *opts, uint8_t reg)
279+{
280+ movsx_rr(&opts->gen.code, reg, reg, SZ_W, SZ_D);
281+}
282+
283+void addi_areg(m68k_options *opts, int32_t val, uint8_t reg)
284+{
285+ if (opts->aregs[reg] >= 0) {
286+ add_ir(&opts->gen.code, val, opts->aregs[reg], SZ_D);
287+ } else {
288+ add_irdisp(&opts->gen.code, val, opts->gen.context_reg, areg_offset(reg), SZ_D);
289+ }
290+}
291+
292+void subi_areg(m68k_options *opts, int32_t val, uint8_t reg)
293+{
294+ if (opts->aregs[reg] >= 0) {
295+ sub_ir(&opts->gen.code, val, opts->aregs[reg], SZ_D);
296+ } else {
297+ sub_irdisp(&opts->gen.code, val, opts->gen.context_reg, areg_offset(reg), SZ_D);
298+ }
299+}
300+
301+void add_areg_native(m68k_options *opts, uint8_t reg, uint8_t native_reg)
302+{
303+ if (opts->aregs[reg] >= 0) {
304+ add_rr(&opts->gen.code, opts->aregs[reg], native_reg, SZ_D);
305+ } else {
306+ add_rdispr(&opts->gen.code, opts->gen.context_reg, areg_offset(reg), native_reg, SZ_D);
307+ }
308+}
309+
310+void add_dreg_native(m68k_options *opts, uint8_t reg, uint8_t native_reg)
311+{
312+ if (opts->dregs[reg] >= 0) {
313+ add_rr(&opts->gen.code, opts->dregs[reg], native_reg, SZ_D);
314+ } else {
315+ add_rdispr(&opts->gen.code, opts->gen.context_reg, dreg_offset(reg), native_reg, SZ_D);
316+ }
317+}
318+
319+void calc_areg_displace(m68k_options *opts, m68k_op_info *op, uint8_t native_reg)
320+{
321+ areg_to_native(opts, op->params.regs.pri, native_reg);
322+ add_ir(&opts->gen.code, op->params.regs.displacement & 0x8000 ? op->params.regs.displacement | 0xFFFF0000 : op->params.regs.displacement, native_reg, SZ_D);
323+}
324+
325+void calc_index_disp8(m68k_options *opts, m68k_op_info *op, uint8_t native_reg)
326+{
327+ uint8_t sec_reg = (op->params.regs.sec >> 1) & 0x7;
328+ if (op->params.regs.sec & 1) {
329+ if (op->params.regs.sec & 0x10) {
330+ add_areg_native(opts, sec_reg, native_reg);
331+ } else {
332+ add_dreg_native(opts, sec_reg, native_reg);
333+ }
334+ } else {
335+ uint8_t other_reg = native_reg == opts->gen.scratch1 ? opts->gen.scratch2 : opts->gen.scratch1;
336+ if (op->params.regs.sec & 0x10) {
337+ areg_to_native_sx(opts, sec_reg, other_reg);
338+ } else {
339+ dreg_to_native_sx(opts, sec_reg, other_reg);
340+ }
341+ add_rr(&opts->gen.code, other_reg, native_reg, SZ_D);
342+ }
343+ if (op->params.regs.displacement) {
344+ add_ir(&opts->gen.code, op->params.regs.displacement, native_reg, SZ_D);
345+ }
346+}
347+
348+void calc_areg_index_disp8(m68k_options *opts, m68k_op_info *op, uint8_t native_reg)
349+{
350+ areg_to_native(opts, op->params.regs.pri, native_reg);
351+ calc_index_disp8(opts, op, native_reg);
352+}
353+
354+void m68k_check_cycles_int_latch(m68k_options *opts)
355+{
356+ code_info *code = &opts->gen.code;
357+ check_alloc_code(code, 3*MAX_INST_LEN);
358+ uint8_t cc;
359+ if (opts->gen.limit < 0) {
360+ cmp_ir(code, 1, opts->gen.cycles, SZ_D);
361+ cc = CC_NS;
362+ } else {
363+ cmp_rr(code, opts->gen.cycles, opts->gen.limit, SZ_D);
364+ cc = CC_A;
365+ }
366+ code_ptr jmp_off = code->cur+1;
367+ jcc(code, cc, jmp_off+1);
368+ call(code, opts->handle_int_latch);
369+ *jmp_off = code->cur - (jmp_off+1);
370+}
371+
372+uint8_t translate_m68k_op(m68kinst * inst, host_ea * ea, m68k_options * opts, uint8_t dst)
373+{
374+ code_info *code = &opts->gen.code;
375+ m68k_op_info *op = dst ? &inst->dst : &inst->src;
376+ int8_t reg = native_reg(op, opts);
377+ uint8_t sec_reg;
378+ uint8_t ret = 1;
379+ int32_t dec_amount, inc_amount;
380+ if (reg >= 0) {
381+ ea->mode = MODE_REG_DIRECT;
382+ if (!dst && inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD) {
383+ movsx_rr(code, reg, opts->gen.scratch1, SZ_W, SZ_D);
384+ ea->base = opts->gen.scratch1;
385+#ifdef X86_32
386+ } else if (reg > RBX && inst->extra.size == OPSIZE_BYTE) {
387+ mov_rr(code, reg, opts->gen.scratch1, SZ_D);
388+ ea->base = opts->gen.scratch1;
389+#endif
390+ } else {
391+ ea->base = reg;
392+ }
393+ return 0;
394+ }
395+ switch (op->addr_mode)
396+ {
397+ case MODE_REG:
398+ case MODE_AREG:
399+ //We only get one memory parameter, so if the dst operand is a register in memory,
400+ //we need to copy this to a temp register first if we're translating the src operand
401+ if (dst || native_reg(&(inst->dst), opts) >= 0 || inst->dst.addr_mode == MODE_UNUSED || !(inst->dst.addr_mode == MODE_REG || inst->dst.addr_mode == MODE_AREG)
402+ || inst->op == M68K_EXG) {
403+
404+ ea->mode = MODE_REG_DISPLACE8;
405+ ea->base = opts->gen.context_reg;
406+ ea->disp = reg_offset(op);
407+ } else {
408+ if (inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD) {
409+ movsx_rdispr(code, opts->gen.context_reg, reg_offset(op), opts->gen.scratch1, SZ_W, SZ_D);
410+ } else {
411+ mov_rdispr(code, opts->gen.context_reg, reg_offset(op), opts->gen.scratch1, inst->extra.size);
412+ }
413+ ea->mode = MODE_REG_DIRECT;
414+ ea->base = opts->gen.scratch1;
415+ //we're explicitly handling the areg dest here, so we exit immediately
416+ return 0;
417+ }
418+ ret = 0;
419+ break;
420+ case MODE_AREG_PREDEC:
421+ if (dst && inst->src.addr_mode == MODE_AREG_PREDEC) {
422+ push_r(code, opts->gen.scratch1);
423+ }
424+ dec_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (op->params.regs.pri == 7 ? 2 :1));
425+ if (!dst) {
426+ cycles(&opts->gen, PREDEC_PENALTY);
427+ }
428+ subi_areg(opts, dec_amount, op->params.regs.pri);
429+ case MODE_AREG_INDIRECT:
430+ case MODE_AREG_POSTINC:
431+ areg_to_native(opts, op->params.regs.pri, opts->gen.scratch1);
432+ m68k_read_size(opts, inst->extra.size);
433+
434+ if (dst) {
435+ if (inst->src.addr_mode == MODE_AREG_PREDEC) {
436+ //restore src operand to opts->gen.scratch2
437+ pop_r(code, opts->gen.scratch2);
438+ } else {
439+ //save reg value in opts->gen.scratch2 so we can use it to save the result in memory later
440+ areg_to_native(opts, op->params.regs.pri, opts->gen.scratch2);
441+ }
442+ }
443+
444+ if (op->addr_mode == MODE_AREG_POSTINC) {
445+ inc_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (op->params.regs.pri == 7 ? 2 : 1));
446+ addi_areg(opts, inc_amount, op->params.regs.pri);
447+ }
448+ ea->mode = MODE_REG_DIRECT;
449+ ea->base = (!dst && inst->dst.addr_mode == MODE_AREG_PREDEC && inst->op != M68K_MOVE) ? opts->gen.scratch2 : opts->gen.scratch1;
450+ break;
451+ case MODE_AREG_DISPLACE:
452+ cycles(&opts->gen, BUS);
453+ calc_areg_displace(opts, op, opts->gen.scratch1);
454+ if (dst) {
455+ push_r(code, opts->gen.scratch1);
456+ }
457+ m68k_read_size(opts, inst->extra.size);
458+ if (dst) {
459+ pop_r(code, opts->gen.scratch2);
460+ }
461+
462+ ea->mode = MODE_REG_DIRECT;
463+ ea->base = opts->gen.scratch1;
464+ break;
465+ case MODE_AREG_INDEX_DISP8:
466+ cycles(&opts->gen, 6);
467+ calc_areg_index_disp8(opts, op, opts->gen.scratch1);
468+ if (dst) {
469+ push_r(code, opts->gen.scratch1);
470+ }
471+ m68k_read_size(opts, inst->extra.size);
472+ if (dst) {
473+ pop_r(code, opts->gen.scratch2);
474+ }
475+
476+ ea->mode = MODE_REG_DIRECT;
477+ ea->base = opts->gen.scratch1;
478+ break;
479+ case MODE_PC_DISPLACE:
480+ cycles(&opts->gen, BUS);
481+ mov_ir(code, op->params.regs.displacement + inst->address+2, opts->gen.scratch1, SZ_D);
482+ if (dst) {
483+ push_r(code, opts->gen.scratch1);
484+ }
485+ m68k_read_size(opts, inst->extra.size);
486+ if (dst) {
487+ pop_r(code, opts->gen.scratch2);
488+ }
489+
490+ ea->mode = MODE_REG_DIRECT;
491+ ea->base = opts->gen.scratch1;
492+ break;
493+ case MODE_PC_INDEX_DISP8:
494+ cycles(&opts->gen, 6);
495+ mov_ir(code, inst->address+2, opts->gen.scratch1, SZ_D);
496+ calc_index_disp8(opts, op, opts->gen.scratch1);
497+ if (dst) {
498+ push_r(code, opts->gen.scratch1);
499+ }
500+ m68k_read_size(opts, inst->extra.size);
501+ if (dst) {
502+ pop_r(code, opts->gen.scratch2);
503+ }
504+
505+ ea->mode = MODE_REG_DIRECT;
506+ ea->base = opts->gen.scratch1;
507+ break;
508+ case MODE_ABSOLUTE:
509+ case MODE_ABSOLUTE_SHORT:
510+ cycles(&opts->gen, op->addr_mode == MODE_ABSOLUTE ? BUS*2 : BUS);
511+ mov_ir(code, op->params.immed, opts->gen.scratch1, SZ_D);
512+ if (dst) {
513+ push_r(code, opts->gen.scratch1);
514+ }
515+ m68k_read_size(opts, inst->extra.size);
516+ if (dst) {
517+ pop_r(code, opts->gen.scratch2);
518+ }
519+
520+ ea->mode = MODE_REG_DIRECT;
521+ ea->base = opts->gen.scratch1;
522+ break;
523+ case MODE_IMMEDIATE:
524+ case MODE_IMMEDIATE_WORD:
525+ if (inst->variant != VAR_QUICK) {
526+ cycles(&opts->gen, (inst->extra.size == OPSIZE_LONG && op->addr_mode == MODE_IMMEDIATE) ? BUS*2 : BUS);
527+ }
528+ ea->mode = MODE_IMMED;
529+ ea->disp = op->params.immed;
530+ //sign extend value when the destination is an address register
531+ if (inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD && ea->disp & 0x8000) {
532+ ea->disp |= 0xFFFF0000;
533+ }
534+ return inst->variant != VAR_QUICK;
535+ default:
536+ m68k_disasm(inst, disasm_buf);
537+ fatal_error("%X: %s\naddress mode %d not implemented (%s)\n", inst->address, disasm_buf, op->addr_mode, dst ? "dst" : "src");
538+ }
539+ if (!dst && inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD) {
540+ if (ea->mode == MODE_REG_DIRECT) {
541+ movsx_rr(code, ea->base, opts->gen.scratch1, SZ_W, SZ_D);
542+ } else {
543+ movsx_rdispr(code, ea->base, ea->disp, opts->gen.scratch1, SZ_W, SZ_D);
544+ ea->mode = MODE_REG_DIRECT;
545+ }
546+ ea->base = opts->gen.scratch1;
547+ }
548+ return ret;
549+}
550+
551+void check_user_mode_swap_ssp_usp(m68k_options *opts)
552+{
553+ code_info * code = &opts->gen.code;
554+ //Check if we've switched to user mode and swap stack pointers if needed
555+ bt_irdisp(code, 5, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
556+ code_ptr end_off = code->cur + 1;
557+ jcc(code, CC_C, code->cur + 2);
558+ swap_ssp_usp(opts);
559+ *end_off = code->cur - (end_off + 1);
560+}
561+
562+void translate_m68k_move(m68k_options * opts, m68kinst * inst)
563+{
564+ code_info *code = &opts->gen.code;
565+ int8_t reg, flags_reg, sec_reg;
566+ uint8_t dir = 0;
567+ int32_t offset;
568+ int32_t inc_amount, dec_amount;
569+ host_ea src;
570+ uint8_t needs_int_latch = translate_m68k_op(inst, &src, opts, 0);
571+ reg = native_reg(&(inst->dst), opts);
572+
573+ if (inst->dst.addr_mode != MODE_AREG) {
574+ if (src.mode == MODE_REG_DIRECT) {
575+ flags_reg = src.base;
576+ } else {
577+ if (reg >= 0) {
578+ flags_reg = reg;
579+ } else {
580+ if(src.mode == MODE_REG_DISPLACE8) {
581+ mov_rdispr(code, src.base, src.disp, opts->gen.scratch1, inst->extra.size);
582+ } else {
583+ mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size);
584+ }
585+ src.mode = MODE_REG_DIRECT;
586+ flags_reg = src.base = opts->gen.scratch1;
587+ }
588+ }
589+ }
590+ uint8_t size = inst->extra.size;
591+ switch(inst->dst.addr_mode)
592+ {
593+ case MODE_AREG:
594+ size = OPSIZE_LONG;
595+ case MODE_REG:
596+ if (reg >= 0) {
597+ if (src.mode == MODE_REG_DIRECT) {
598+ mov_rr(code, src.base, reg, size);
599+ } else if (src.mode == MODE_REG_DISPLACE8) {
600+ mov_rdispr(code, src.base, src.disp, reg, size);
601+ } else {
602+ mov_ir(code, src.disp, reg, size);
603+ }
604+ } else if(src.mode == MODE_REG_DIRECT) {
605+ mov_rrdisp(code, src.base, opts->gen.context_reg, reg_offset(&(inst->dst)), size);
606+ } else {
607+ mov_irdisp(code, src.disp, opts->gen.context_reg, reg_offset(&(inst->dst)), size);
608+ }
609+ break;
610+ case MODE_AREG_PREDEC:
611+ dec_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (inst->dst.params.regs.pri == 7 ? 2 : 1));
612+ case MODE_AREG_INDIRECT:
613+ case MODE_AREG_POSTINC:
614+ if (src.mode == MODE_REG_DIRECT) {
615+ if (src.base != opts->gen.scratch1) {
616+ mov_rr(code, src.base, opts->gen.scratch1, inst->extra.size);
617+ }
618+ } else if (src.mode == MODE_REG_DISPLACE8) {
619+ mov_rdispr(code, src.base, src.disp, opts->gen.scratch1, inst->extra.size);
620+ } else {
621+ mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size);
622+ }
623+ if (inst->dst.addr_mode == MODE_AREG_PREDEC) {
624+ subi_areg(opts, dec_amount, inst->dst.params.regs.pri);
625+ }
626+ areg_to_native(opts, inst->dst.params.regs.pri, opts->gen.scratch2);
627+ break;
628+ case MODE_AREG_DISPLACE:
629+ cycles(&opts->gen, BUS);
630+ calc_areg_displace(opts, &inst->dst, opts->gen.scratch2);
631+ if (src.mode == MODE_REG_DIRECT) {
632+ if (src.base != opts->gen.scratch1) {
633+ mov_rr(code, src.base, opts->gen.scratch1, inst->extra.size);
634+ }
635+ } else if (src.mode == MODE_REG_DISPLACE8) {
636+ mov_rdispr(code, src.base, src.disp, opts->gen.scratch1, inst->extra.size);
637+ } else {
638+ mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size);
639+ }
640+ break;
641+ case MODE_AREG_INDEX_DISP8:
642+ cycles(&opts->gen, 6);//TODO: Check to make sure this is correct
643+ //calc_areg_index_disp8 will clober scratch1 when a 16-bit index is used
644+ if (src.base == opts->gen.scratch1 && !(inst->dst.params.regs.sec & 1)) {
645+ push_r(code, opts->gen.scratch1);
646+ }
647+ calc_areg_index_disp8(opts, &inst->dst, opts->gen.scratch2);
648+ if (src.base == opts->gen.scratch1 && !(inst->dst.params.regs.sec & 1)) {
649+ pop_r(code, opts->gen.scratch1);
650+ }
651+ if (src.mode == MODE_REG_DIRECT) {
652+ if (src.base != opts->gen.scratch1) {
653+ mov_rr(code, src.base, opts->gen.scratch1, inst->extra.size);
654+ }
655+ } else if (src.mode == MODE_REG_DISPLACE8) {
656+ mov_rdispr(code, src.base, src.disp, opts->gen.scratch1, inst->extra.size);
657+ } else {
658+ mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size);
659+ }
660+ break;
661+ case MODE_PC_DISPLACE:
662+ cycles(&opts->gen, BUS);
663+ mov_ir(code, inst->dst.params.regs.displacement + inst->address+2, opts->gen.scratch2, SZ_D);
664+ if (src.mode == MODE_REG_DIRECT) {
665+ if (src.base != opts->gen.scratch1) {
666+ mov_rr(code, src.base, opts->gen.scratch1, inst->extra.size);
667+ }
668+ } else if (src.mode == MODE_REG_DISPLACE8) {
669+ mov_rdispr(code, src.base, src.disp, opts->gen.scratch1, inst->extra.size);
670+ } else {
671+ mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size);
672+ }
673+ break;
674+ case MODE_PC_INDEX_DISP8:
675+ cycles(&opts->gen, 6);//TODO: Check to make sure this is correct
676+ mov_ir(code, inst->address, opts->gen.scratch2, SZ_D);
677+ if (src.base == opts->gen.scratch1 && !(inst->dst.params.regs.sec & 1)) {
678+ push_r(code, opts->gen.scratch1);
679+ }
680+ calc_index_disp8(opts, &inst->dst, opts->gen.scratch2);
681+ if (src.base == opts->gen.scratch1 && !(inst->dst.params.regs.sec & 1)) {
682+ pop_r(code, opts->gen.scratch1);
683+ }
684+ if (src.mode == MODE_REG_DIRECT) {
685+ if (src.base != opts->gen.scratch1) {
686+ mov_rr(code, src.base, opts->gen.scratch1, inst->extra.size);
687+ }
688+ } else if (src.mode == MODE_REG_DISPLACE8) {
689+ mov_rdispr(code, src.base, src.disp, opts->gen.scratch1, inst->extra.size);
690+ } else {
691+ mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size);
692+ }
693+ break;
694+ case MODE_ABSOLUTE:
695+ case MODE_ABSOLUTE_SHORT:
696+ if (src.mode == MODE_REG_DIRECT) {
697+ if (src.base != opts->gen.scratch1) {
698+ mov_rr(code, src.base, opts->gen.scratch1, inst->extra.size);
699+ }
700+ } else if (src.mode == MODE_REG_DISPLACE8) {
701+ mov_rdispr(code, src.base, src.disp, opts->gen.scratch1, inst->extra.size);
702+ } else {
703+ mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size);
704+ }
705+ if (inst->dst.addr_mode == MODE_ABSOLUTE) {
706+ cycles(&opts->gen, BUS*2);
707+ } else {
708+ cycles(&opts->gen, BUS);
709+ }
710+ mov_ir(code, inst->dst.params.immed, opts->gen.scratch2, SZ_D);
711+ break;
712+ default:
713+ m68k_disasm(inst, disasm_buf);
714+ fatal_error("%X: %s\naddress mode %d not implemented (move dst)\n", inst->address, disasm_buf, inst->dst.addr_mode);
715+ }
716+
717+ if (inst->dst.addr_mode != MODE_AREG) {
718+ cmp_ir(code, 0, flags_reg, inst->extra.size);
719+ update_flags(opts, N|Z|V0|C0);
720+ }
721+ if (inst->dst.addr_mode != MODE_REG && inst->dst.addr_mode != MODE_AREG) {
722+ if (inst->extra.size == OPSIZE_LONG) {
723+ //We want the int latch to occur between the two writes,
724+ //but that's a pain to do without refactoring how 32-bit writes work
725+ //workaround it by temporarily increasing the cycle count before the check
726+ cycles(&opts->gen, BUS);
727+ }
728+ m68k_check_cycles_int_latch(opts);
729+ if (inst->extra.size == OPSIZE_LONG) {
730+ //and then backing out that extra increment here before the write happens
731+ cycles(&opts->gen, -BUS);
732+ }
733+ m68k_write_size(opts, inst->extra.size, inst->dst.addr_mode == MODE_AREG_PREDEC);
734+ if (inst->dst.addr_mode == MODE_AREG_POSTINC) {
735+ inc_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (inst->dst.params.regs.pri == 7 ? 2 : 1));
736+ addi_areg(opts, inc_amount, inst->dst.params.regs.pri);
737+ }
738+ } else if (needs_int_latch) {
739+ m68k_check_cycles_int_latch(opts);
740+ }
741+
742+ //add cycles for prefetch
743+ cycles(&opts->gen, BUS);
744+}
745+
746+void translate_m68k_ext(m68k_options * opts, m68kinst * inst)
747+{
748+ code_info *code = &opts->gen.code;
749+ host_ea dst_op;
750+ uint8_t dst_size = inst->extra.size;
751+ inst->extra.size--;
752+ translate_m68k_op(inst, &dst_op, opts, 1);
753+ if (dst_op.mode == MODE_REG_DIRECT) {
754+ movsx_rr(code, dst_op.base, dst_op.base, inst->extra.size, dst_size);
755+ cmp_ir(code, 0, dst_op.base, dst_size);
756+ } else {
757+ movsx_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch1, inst->extra.size, dst_size);
758+ cmp_ir(code, 0, opts->gen.scratch1, dst_size);
759+ mov_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, dst_size);
760+ }
761+ inst->extra.size = dst_size;
762+ update_flags(opts, N|V0|C0|Z);
763+ cycles(&opts->gen, BUS);
764+ //M68K EXT only operates on registers so no need for a call to save result here
765+}
766+
767+uint8_t m68k_eval_cond(m68k_options * opts, uint8_t cc)
768+{
769+ uint8_t cond = CC_NZ;
770+ switch (cc)
771+ {
772+ case COND_HIGH:
773+ cond = CC_Z;
774+ case COND_LOW_SAME:
775+ flag_to_reg(opts, FLAG_Z, opts->gen.scratch1);
776+ or_flag_to_reg(opts, FLAG_C, opts->gen.scratch1);
777+ break;
778+ case COND_CARRY_CLR:
779+ cond = CC_Z;
780+ case COND_CARRY_SET:
781+ check_flag(opts, FLAG_C);
782+ break;
783+ case COND_NOT_EQ:
784+ cond = CC_Z;
785+ case COND_EQ:
786+ check_flag(opts, FLAG_Z);
787+ break;
788+ case COND_OVERF_CLR:
789+ cond = CC_Z;
790+ case COND_OVERF_SET:
791+ check_flag(opts, FLAG_V);
792+ break;
793+ case COND_PLUS:
794+ cond = CC_Z;
795+ case COND_MINUS:
796+ check_flag(opts, FLAG_N);
797+ break;
798+ case COND_GREATER_EQ:
799+ cond = CC_Z;
800+ case COND_LESS:
801+ cmp_flags(opts, FLAG_N, FLAG_V);
802+ break;
803+ case COND_GREATER:
804+ cond = CC_Z;
805+ case COND_LESS_EQ:
806+ flag_to_reg(opts, FLAG_V, opts->gen.scratch1);
807+ xor_flag_to_reg(opts, FLAG_N, opts->gen.scratch1);
808+ or_flag_to_reg(opts, FLAG_Z, opts->gen.scratch1);
809+ break;
810+ }
811+ return cond;
812+}
813+
814+void translate_m68k_bcc(m68k_options * opts, m68kinst * inst)
815+{
816+ code_info *code = &opts->gen.code;
817+
818+ int32_t disp = inst->src.params.immed;
819+ uint32_t after = inst->address + 2;
820+ if (inst->extra.cond == COND_TRUE) {
821+ cycles(&opts->gen, 10);
822+ jump_m68k_abs(opts, after + disp);
823+ } else {
824+ uint8_t cond = m68k_eval_cond(opts, inst->extra.cond);
825+ code_ptr do_branch = code->cur + 1;
826+ jcc(code, cond, do_branch);
827+
828+ cycles(&opts->gen, inst->variant == VAR_BYTE ? 8 : 12);
829+ code_ptr done = code->cur + 1;
830+ jmp(code, done);
831+
832+ *do_branch = code->cur - (do_branch + 1);
833+ cycles(&opts->gen, 10);
834+ code_ptr dest_addr = get_native_address(opts, after + disp);
835+ if (!dest_addr) {
836+ opts->gen.deferred = defer_address(opts->gen.deferred, after + disp, code->cur + 1);
837+ //dummy address to be replaced later, make sure it generates a 4-byte displacement
838+ dest_addr = code->cur + 256;
839+ }
840+ jmp(code, dest_addr);
841+
842+ *done = code->cur - (done + 1);
843+ }
844+}
845+
846+void translate_m68k_scc(m68k_options * opts, m68kinst * inst)
847+{
848+ code_info *code = &opts->gen.code;
849+ uint8_t cond = inst->extra.cond;
850+ host_ea dst_op;
851+ inst->extra.size = OPSIZE_BYTE;
852+ translate_m68k_op(inst, &dst_op, opts, 1);
853+ if (cond == COND_TRUE || cond == COND_FALSE) {
854+ if ((inst->dst.addr_mode == MODE_REG || inst->dst.addr_mode == MODE_AREG) && inst->extra.cond == COND_TRUE) {
855+ cycles(&opts->gen, 6);
856+ } else {
857+ cycles(&opts->gen, BUS);
858+ }
859+ if (dst_op.mode == MODE_REG_DIRECT) {
860+ mov_ir(code, cond == COND_TRUE ? 0xFF : 0, dst_op.base, SZ_B);
861+ } else {
862+ mov_irdisp(code, cond == COND_TRUE ? 0xFF : 0, dst_op.base, dst_op.disp, SZ_B);
863+ }
864+ } else {
865+ uint8_t cc = m68k_eval_cond(opts, cond);
866+ check_alloc_code(code, 6*MAX_INST_LEN);
867+ code_ptr true_off = code->cur + 1;
868+ jcc(code, cc, code->cur+2);
869+ cycles(&opts->gen, BUS);
870+ if (dst_op.mode == MODE_REG_DIRECT) {
871+ mov_ir(code, 0, dst_op.base, SZ_B);
872+ } else {
873+ mov_irdisp(code, 0, dst_op.base, dst_op.disp, SZ_B);
874+ }
875+ code_ptr end_off = code->cur+1;
876+ jmp(code, code->cur+2);
877+ *true_off = code->cur - (true_off+1);
878+ cycles(&opts->gen, 6);
879+ if (dst_op.mode == MODE_REG_DIRECT) {
880+ mov_ir(code, 0xFF, dst_op.base, SZ_B);
881+ } else {
882+ mov_irdisp(code, 0xFF, dst_op.base, dst_op.disp, SZ_B);
883+ }
884+ *end_off = code->cur - (end_off+1);
885+ }
886+ m68k_save_result(inst, opts);
887+}
888+
889+void translate_m68k_dbcc(m68k_options * opts, m68kinst * inst)
890+{
891+ code_info *code = &opts->gen.code;
892+ //best case duration
893+ cycles(&opts->gen, 10);
894+ code_ptr skip_loc = NULL;
895+ //TODO: Check if COND_TRUE technically valid here even though
896+ //it's basically a slow NOP
897+ if (inst->extra.cond != COND_FALSE) {
898+ uint8_t cond = m68k_eval_cond(opts, inst->extra.cond);
899+ check_alloc_code(code, 6*MAX_INST_LEN);
900+ skip_loc = code->cur + 1;
901+ jcc(code, cond, code->cur + 2);
902+ }
903+ if (opts->dregs[inst->dst.params.regs.pri] >= 0) {
904+ sub_ir(code, 1, opts->dregs[inst->dst.params.regs.pri], SZ_W);
905+ cmp_ir(code, -1, opts->dregs[inst->dst.params.regs.pri], SZ_W);
906+ } else {
907+ sub_irdisp(code, 1, opts->gen.context_reg, offsetof(m68k_context, dregs) + 4 * inst->dst.params.regs.pri, SZ_W);
908+ cmp_irdisp(code, -1, opts->gen.context_reg, offsetof(m68k_context, dregs) + 4 * inst->dst.params.regs.pri, SZ_W);
909+ }
910+ code_ptr loop_end_loc = code->cur + 1;
911+ jcc(code, CC_Z, code->cur + 2);
912+ uint32_t after = inst->address + 2;
913+ jump_m68k_abs(opts, after + inst->src.params.immed);
914+ *loop_end_loc = code->cur - (loop_end_loc+1);
915+ if (skip_loc) {
916+ cycles(&opts->gen, 2);
917+ *skip_loc = code->cur - (skip_loc+1);
918+ cycles(&opts->gen, 2);
919+ } else {
920+ cycles(&opts->gen, 4);
921+ }
922+}
923+
924+void translate_m68k_movep(m68k_options * opts, m68kinst * inst)
925+{
926+ code_info *code = &opts->gen.code;
927+ int8_t reg;
928+ cycles(&opts->gen, BUS*2);
929+ if (inst->src.addr_mode == MODE_REG) {
930+ calc_areg_displace(opts, &inst->dst, opts->gen.scratch2);
931+ reg = native_reg(&(inst->src), opts);
932+ if (inst->extra.size == OPSIZE_LONG) {
933+ if (reg >= 0) {
934+ mov_rr(code, reg, opts->gen.scratch1, SZ_D);
935+ shr_ir(code, 24, opts->gen.scratch1, SZ_D);
936+ push_r(code, opts->gen.scratch2);
937+ call(code, opts->write_8);
938+ pop_r(code, opts->gen.scratch2);
939+ mov_rr(code, reg, opts->gen.scratch1, SZ_D);
940+ shr_ir(code, 16, opts->gen.scratch1, SZ_D);
941+
942+ } else {
943+ mov_rdispr(code, opts->gen.context_reg, reg_offset(&(inst->src))+3, opts->gen.scratch1, SZ_B);
944+ push_r(code, opts->gen.scratch2);
945+ call(code, opts->write_8);
946+ pop_r(code, opts->gen.scratch2);
947+ mov_rdispr(code, opts->gen.context_reg, reg_offset(&(inst->src))+2, opts->gen.scratch1, SZ_B);
948+ }
949+ add_ir(code, 2, opts->gen.scratch2, SZ_D);
950+ push_r(code, opts->gen.scratch2);
951+ call(code, opts->write_8);
952+ pop_r(code, opts->gen.scratch2);
953+ add_ir(code, 2, opts->gen.scratch2, SZ_D);
954+ }
955+ if (reg >= 0) {
956+ mov_rr(code, reg, opts->gen.scratch1, SZ_W);
957+ shr_ir(code, 8, opts->gen.scratch1, SZ_W);
958+ push_r(code, opts->gen.scratch2);
959+ call(code, opts->write_8);
960+ pop_r(code, opts->gen.scratch2);
961+ mov_rr(code, reg, opts->gen.scratch1, SZ_W);
962+ } else {
963+ mov_rdispr(code, opts->gen.context_reg, reg_offset(&(inst->src))+1, opts->gen.scratch1, SZ_B);
964+ push_r(code, opts->gen.scratch2);
965+ call(code, opts->write_8);
966+ pop_r(code, opts->gen.scratch2);
967+ mov_rdispr(code, opts->gen.context_reg, reg_offset(&(inst->src)), opts->gen.scratch1, SZ_B);
968+ }
969+ add_ir(code, 2, opts->gen.scratch2, SZ_D);
970+ call(code, opts->write_8);
971+ } else {
972+ calc_areg_displace(opts, &inst->src, opts->gen.scratch1);
973+ reg = native_reg(&(inst->dst), opts);
974+ if (inst->extra.size == OPSIZE_LONG) {
975+ if (reg >= 0) {
976+ push_r(code, opts->gen.scratch1);
977+ call(code, opts->read_8);
978+ shl_ir(code, 24, opts->gen.scratch1, SZ_D);
979+ mov_rr(code, opts->gen.scratch1, reg, SZ_D);
980+ pop_r(code, opts->gen.scratch1);
981+ add_ir(code, 2, opts->gen.scratch1, SZ_D);
982+ push_r(code, opts->gen.scratch1);
983+ call(code, opts->read_8);
984+ movzx_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_B, SZ_W);
985+ shl_ir(code, 16, opts->gen.scratch1, SZ_D);
986+ or_rr(code, opts->gen.scratch1, reg, SZ_D);
987+ } else {
988+ push_r(code, opts->gen.scratch1);
989+ call(code, opts->read_8);
990+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, reg_offset(&(inst->dst))+3, SZ_B);
991+ pop_r(code, opts->gen.scratch1);
992+ add_ir(code, 2, opts->gen.scratch1, SZ_D);
993+ push_r(code, opts->gen.scratch1);
994+ call(code, opts->read_8);
995+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, reg_offset(&(inst->dst))+2, SZ_B);
996+ }
997+ pop_r(code, opts->gen.scratch1);
998+ add_ir(code, 2, opts->gen.scratch1, SZ_D);
999+ }
1000+ push_r(code, opts->gen.scratch1);
1001+ call(code, opts->read_8);
1002+ if (reg >= 0) {
1003+
1004+ shl_ir(code, 8, opts->gen.scratch1, SZ_W);
1005+ mov_rr(code, opts->gen.scratch1, reg, SZ_W);
1006+ pop_r(code, opts->gen.scratch1);
1007+ add_ir(code, 2, opts->gen.scratch1, SZ_D);
1008+ call(code, opts->read_8);
1009+ mov_rr(code, opts->gen.scratch1, reg, SZ_B);
1010+ } else {
1011+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, reg_offset(&(inst->dst))+1, SZ_B);
1012+ pop_r(code, opts->gen.scratch1);
1013+ add_ir(code, 2, opts->gen.scratch1, SZ_D);
1014+ call(code, opts->read_8);
1015+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, reg_offset(&(inst->dst)), SZ_B);
1016+ }
1017+ }
1018+}
1019+
1020+typedef void (*shift_ir_t)(code_info *code, uint8_t val, uint8_t dst, uint8_t size);
1021+typedef void (*shift_irdisp_t)(code_info *code, uint8_t val, uint8_t dst_base, int32_t disp, uint8_t size);
1022+typedef void (*shift_clr_t)(code_info *code, uint8_t dst, uint8_t size);
1023+typedef void (*shift_clrdisp_t)(code_info *code, uint8_t dst_base, int32_t disp, uint8_t size);
1024+
1025+void translate_shift(m68k_options * opts, m68kinst * inst, host_ea *src_op, host_ea * dst_op, shift_ir_t shift_ir, shift_irdisp_t shift_irdisp, shift_clr_t shift_clr, shift_clrdisp_t shift_clrdisp, shift_ir_t special, shift_irdisp_t special_disp)
1026+{
1027+ code_info *code = &opts->gen.code;
1028+ code_ptr end_off = NULL;
1029+ code_ptr nz_off = NULL;
1030+ code_ptr z_off = NULL;
1031+ if (inst->src.addr_mode == MODE_UNUSED) {
1032+ cycles(&opts->gen, BUS);
1033+ //Memory shift
1034+ shift_ir(code, 1, dst_op->base, SZ_W);
1035+ } else {
1036+ if (src_op->mode == MODE_IMMED) {
1037+ cycles(&opts->gen, (inst->extra.size == OPSIZE_LONG ? 8 : 6) + 2 * src_op->disp);
1038+ if (src_op->disp != 1 && inst->op == M68K_ASL) {
1039+ set_flag(opts, 0, FLAG_V);
1040+ for (int i = 0; i < src_op->disp; i++) {
1041+ if (dst_op->mode == MODE_REG_DIRECT) {
1042+ shift_ir(code, 1, dst_op->base, inst->extra.size);
1043+ } else {
1044+ shift_irdisp(code, 1, dst_op->base, dst_op->disp, inst->extra.size);
1045+ }
1046+ check_alloc_code(code, 2*MAX_INST_LEN);
1047+ code_ptr after_flag_set = code->cur + 1;
1048+ jcc(code, CC_NO, code->cur + 2);
1049+ set_flag(opts, 1, FLAG_V);
1050+ *after_flag_set = code->cur - (after_flag_set+1);
1051+ }
1052+ } else {
1053+ if (dst_op->mode == MODE_REG_DIRECT) {
1054+ shift_ir(code, src_op->disp, dst_op->base, inst->extra.size);
1055+ } else {
1056+ shift_irdisp(code, src_op->disp, dst_op->base, dst_op->disp, inst->extra.size);
1057+ }
1058+ set_flag_cond(opts, CC_O, FLAG_V);
1059+ }
1060+ } else {
1061+ cycles(&opts->gen, inst->extra.size == OPSIZE_LONG ? 8 : 6);
1062+ if (src_op->base != RCX) {
1063+ if (src_op->mode == MODE_REG_DIRECT) {
1064+ mov_rr(code, src_op->base, RCX, SZ_B);
1065+ } else {
1066+ mov_rdispr(code, src_op->base, src_op->disp, RCX, SZ_B);
1067+ }
1068+
1069+ }
1070+ and_ir(code, 63, RCX, SZ_D);
1071+ check_alloc_code(code, 7*MAX_INST_LEN);
1072+ nz_off = code->cur + 1;
1073+ jcc(code, CC_NZ, code->cur + 2);
1074+ //Flag behavior for shift count of 0 is different for x86 than 68K
1075+ if (dst_op->mode == MODE_REG_DIRECT) {
1076+ cmp_ir(code, 0, dst_op->base, inst->extra.size);
1077+ } else {
1078+ cmp_irdisp(code, 0, dst_op->base, dst_op->disp, inst->extra.size);
1079+ }
1080+ set_flag_cond(opts, CC_Z, FLAG_Z);
1081+ set_flag_cond(opts, CC_S, FLAG_N);
1082+ set_flag(opts, 0, FLAG_C);
1083+ //For other instructions, this flag will be set below
1084+ if (inst->op == M68K_ASL) {
1085+ set_flag(opts, 0, FLAG_V);
1086+ }
1087+ z_off = code->cur + 1;
1088+ jmp(code, code->cur + 2);
1089+ *nz_off = code->cur - (nz_off + 1);
1090+ //add 2 cycles for every bit shifted
1091+ mov_ir(code, 2 * opts->gen.clock_divider, opts->gen.scratch2, SZ_D);
1092+ imul_rr(code, RCX, opts->gen.scratch2, SZ_D);
1093+ add_rr(code, opts->gen.scratch2, opts->gen.cycles, SZ_D);
1094+ if (inst->op == M68K_ASL) {
1095+ //ASL has Overflow flag behavior that depends on all of the bits shifted through the MSB
1096+ //Easiest way to deal with this is to shift one bit at a time
1097+ set_flag(opts, 0, FLAG_V);
1098+ check_alloc_code(code, 5*MAX_INST_LEN);
1099+ code_ptr loop_start = code->cur;
1100+ if (dst_op->mode == MODE_REG_DIRECT) {
1101+ shift_ir(code, 1, dst_op->base, inst->extra.size);
1102+ } else {
1103+ shift_irdisp(code, 1, dst_op->base, dst_op->disp, inst->extra.size);
1104+ }
1105+ code_ptr after_flag_set = code->cur + 1;
1106+ jcc(code, CC_NO, code->cur + 2);
1107+ set_flag(opts, 1, FLAG_V);
1108+ *after_flag_set = code->cur - (after_flag_set+1);
1109+ loop(code, loop_start);
1110+ } else {
1111+ //x86 shifts modulo 32 for operand sizes less than 64-bits
1112+ //but M68K shifts modulo 64, so we need to check for large shifts here
1113+ cmp_ir(code, 32, RCX, SZ_B);
1114+ check_alloc_code(code, 14*MAX_INST_LEN);
1115+ code_ptr norm_shift_off = code->cur + 1;
1116+ jcc(code, CC_L, code->cur + 2);
1117+ if (special) {
1118+ code_ptr after_flag_set = NULL;
1119+ if (inst->extra.size == OPSIZE_LONG) {
1120+ code_ptr neq_32_off = code->cur + 1;
1121+ jcc(code, CC_NZ, code->cur + 2);
1122+
1123+ //set the carry bit to the lsb
1124+ if (dst_op->mode == MODE_REG_DIRECT) {
1125+ special(code, 1, dst_op->base, SZ_D);
1126+ } else {
1127+ special_disp(code, 1, dst_op->base, dst_op->disp, SZ_D);
1128+ }
1129+ set_flag_cond(opts, CC_C, FLAG_C);
1130+ after_flag_set = code->cur + 1;
1131+ jmp(code, code->cur + 2);
1132+ *neq_32_off = code->cur - (neq_32_off+1);
1133+ }
1134+ set_flag(opts, 0, FLAG_C);
1135+ if (after_flag_set) {
1136+ *after_flag_set = code->cur - (after_flag_set+1);
1137+ }
1138+ set_flag(opts, 1, FLAG_Z);
1139+ set_flag(opts, 0, FLAG_N);
1140+ if (dst_op->mode == MODE_REG_DIRECT) {
1141+ xor_rr(code, dst_op->base, dst_op->base, inst->extra.size);
1142+ } else {
1143+ mov_irdisp(code, 0, dst_op->base, dst_op->disp, inst->extra.size);
1144+ }
1145+ } else {
1146+ if (dst_op->mode == MODE_REG_DIRECT) {
1147+ shift_ir(code, 31, dst_op->base, inst->extra.size);
1148+ shift_ir(code, 1, dst_op->base, inst->extra.size);
1149+ } else {
1150+ shift_irdisp(code, 31, dst_op->base, dst_op->disp, inst->extra.size);
1151+ shift_irdisp(code, 1, dst_op->base, dst_op->disp, inst->extra.size);
1152+ }
1153+
1154+ }
1155+ end_off = code->cur + 1;
1156+ jmp(code, code->cur + 2);
1157+ *norm_shift_off = code->cur - (norm_shift_off+1);
1158+ if (dst_op->mode == MODE_REG_DIRECT) {
1159+ shift_clr(code, dst_op->base, inst->extra.size);
1160+ } else {
1161+ shift_clrdisp(code, dst_op->base, dst_op->disp, inst->extra.size);
1162+ }
1163+ }
1164+ }
1165+
1166+ }
1167+ if (!special && end_off) {
1168+ *end_off = code->cur - (end_off + 1);
1169+ }
1170+ update_flags(opts, C|Z|N);
1171+ if (special && end_off) {
1172+ *end_off = code->cur - (end_off + 1);
1173+ }
1174+ //set X flag to same as C flag
1175+ if (opts->flag_regs[FLAG_C] >= 0) {
1176+ flag_to_flag(opts, FLAG_C, FLAG_X);
1177+ } else {
1178+ set_flag_cond(opts, CC_C, FLAG_X);
1179+ }
1180+ if (z_off) {
1181+ *z_off = code->cur - (z_off + 1);
1182+ }
1183+ if (inst->op != M68K_ASL) {
1184+ set_flag(opts, 0, FLAG_V);
1185+ }
1186+ if (inst->src.addr_mode == MODE_UNUSED) {
1187+ m68k_save_result(inst, opts);
1188+ }
1189+}
1190+
1191+void translate_m68k_reset(m68k_options *opts, m68kinst *inst)
1192+{
1193+ code_info *code = &opts->gen.code;
1194+ //RESET instructions take a long time to give peripherals time to reset themselves
1195+ cycles(&opts->gen, 132);
1196+ mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, reset_handler), opts->gen.scratch1, SZ_PTR);
1197+ cmp_ir(code, 0, opts->gen.scratch1, SZ_PTR);
1198+ code_ptr no_reset_handler = code->cur + 1;
1199+ jcc(code, CC_Z, code->cur+2);
1200+ call(code, opts->gen.save_context);
1201+ call_args_r(code, opts->gen.scratch1, 1, opts->gen.context_reg);
1202+ mov_rr(code, RAX, opts->gen.context_reg, SZ_PTR);
1203+ call(code, opts->gen.load_context);
1204+ *no_reset_handler = code->cur - (no_reset_handler + 1);
1205+}
1206+
1207+void op_ir(code_info *code, m68kinst *inst, int32_t val, uint8_t dst, uint8_t size)
1208+{
1209+ switch (inst->op)
1210+ {
1211+ case M68K_ADD: add_ir(code, val, dst, size); break;
1212+ case M68K_ADDX: adc_ir(code, val, dst, size); break;
1213+ case M68K_AND: and_ir(code, val, dst, size); break;
1214+ case M68K_BTST: bt_ir(code, val, dst, size); break;
1215+ case M68K_BSET: bts_ir(code, val, dst, size); break;
1216+ case M68K_BCLR: btr_ir(code, val, dst, size); break;
1217+ case M68K_BCHG: btc_ir(code, val, dst, size); break;
1218+ case M68K_CMP: cmp_ir(code, val, dst, size); break;
1219+ case M68K_EOR: xor_ir(code, val, dst, size); break;
1220+ case M68K_OR: or_ir(code, val, dst, size); break;
1221+ case M68K_ROL: rol_ir(code, val, dst, size); break;
1222+ case M68K_ROR: ror_ir(code, val, dst, size); break;
1223+ case M68K_ROXL: rcl_ir(code, val, dst, size); break;
1224+ case M68K_ROXR: rcr_ir(code, val, dst, size); break;
1225+ case M68K_SUB: sub_ir(code, val, dst, size); break;
1226+ case M68K_SUBX: sbb_ir(code, val, dst, size); break;
1227+ }
1228+}
1229+
1230+void op_irdisp(code_info *code, m68kinst *inst, int32_t val, uint8_t dst, int32_t disp, uint8_t size)
1231+{
1232+ switch (inst->op)
1233+ {
1234+ case M68K_ADD: add_irdisp(code, val, dst, disp, size); break;
1235+ case M68K_ADDX: adc_irdisp(code, val, dst, disp, size); break;
1236+ case M68K_AND: and_irdisp(code, val, dst, disp, size); break;
1237+ case M68K_BTST: bt_irdisp(code, val, dst, disp, size); break;
1238+ case M68K_BSET: bts_irdisp(code, val, dst, disp, size); break;
1239+ case M68K_BCLR: btr_irdisp(code, val, dst, disp, size); break;
1240+ case M68K_BCHG: btc_irdisp(code, val, dst, disp, size); break;
1241+ case M68K_CMP: cmp_irdisp(code, val, dst, disp, size); break;
1242+ case M68K_EOR: xor_irdisp(code, val, dst, disp, size); break;
1243+ case M68K_OR: or_irdisp(code, val, dst, disp, size); break;
1244+ case M68K_ROL: rol_irdisp(code, val, dst, disp, size); break;
1245+ case M68K_ROR: ror_irdisp(code, val, dst, disp, size); break;
1246+ case M68K_ROXL: rcl_irdisp(code, val, dst, disp, size); break;
1247+ case M68K_ROXR: rcr_irdisp(code, val, dst, disp, size); break;
1248+ case M68K_SUB: sub_irdisp(code, val, dst, disp, size); break;
1249+ case M68K_SUBX: sbb_irdisp(code, val, dst, disp, size); break;
1250+ }
1251+}
1252+
1253+void op_rr(code_info *code, m68kinst *inst, uint8_t src, uint8_t dst, uint8_t size)
1254+{
1255+ switch (inst->op)
1256+ {
1257+ case M68K_ADD: add_rr(code, src, dst, size); break;
1258+ case M68K_ADDX: adc_rr(code, src, dst, size); break;
1259+ case M68K_AND: and_rr(code, src, dst, size); break;
1260+ case M68K_BTST: bt_rr(code, src, dst, size); break;
1261+ case M68K_BSET: bts_rr(code, src, dst, size); break;
1262+ case M68K_BCLR: btr_rr(code, src, dst, size); break;
1263+ case M68K_BCHG: btc_rr(code, src, dst, size); break;
1264+ case M68K_CMP: cmp_rr(code, src, dst, size); break;
1265+ case M68K_EOR: xor_rr(code, src, dst, size); break;
1266+ case M68K_OR: or_rr(code, src, dst, size); break;
1267+ case M68K_SUB: sub_rr(code, src, dst, size); break;
1268+ case M68K_SUBX: sbb_rr(code, src, dst, size); break;
1269+ }
1270+}
1271+
1272+void op_rrdisp(code_info *code, m68kinst *inst, uint8_t src, uint8_t dst, int32_t disp, uint8_t size)
1273+{
1274+ switch(inst->op)
1275+ {
1276+ case M68K_ADD: add_rrdisp(code, src, dst, disp, size); break;
1277+ case M68K_ADDX: adc_rrdisp(code, src, dst, disp, size); break;
1278+ case M68K_AND: and_rrdisp(code, src, dst, disp, size); break;
1279+ case M68K_BTST: bt_rrdisp(code, src, dst, disp, size); break;
1280+ case M68K_BSET: bts_rrdisp(code, src, dst, disp, size); break;
1281+ case M68K_BCLR: btr_rrdisp(code, src, dst, disp, size); break;
1282+ case M68K_BCHG: btc_rrdisp(code, src, dst, disp, size); break;
1283+ case M68K_CMP: cmp_rrdisp(code, src, dst, disp, size); break;
1284+ case M68K_EOR: xor_rrdisp(code, src, dst, disp, size); break;
1285+ case M68K_OR: or_rrdisp(code, src, dst, disp, size); break;
1286+ case M68K_SUB: sub_rrdisp(code, src, dst, disp, size); break;
1287+ case M68K_SUBX: sbb_rrdisp(code, src, dst, disp, size); break;
1288+ }
1289+}
1290+
1291+void op_rdispr(code_info *code, m68kinst *inst, uint8_t src, int32_t disp, uint8_t dst, uint8_t size)
1292+{
1293+ switch (inst->op)
1294+ {
1295+ case M68K_ADD: add_rdispr(code, src, disp, dst, size); break;
1296+ case M68K_ADDX: adc_rdispr(code, src, disp, dst, size); break;
1297+ case M68K_AND: and_rdispr(code, src, disp, dst, size); break;
1298+ case M68K_CMP: cmp_rdispr(code, src, disp, dst, size); break;
1299+ case M68K_EOR: xor_rdispr(code, src, disp, dst, size); break;
1300+ case M68K_OR: or_rdispr(code, src, disp, dst, size); break;
1301+ case M68K_SUB: sub_rdispr(code, src, disp, dst, size); break;
1302+ case M68K_SUBX: sbb_rdispr(code, src, disp, dst, size); break;
1303+ }
1304+}
1305+
1306+void translate_m68k_arith(m68k_options *opts, m68kinst * inst, uint32_t flag_mask, host_ea *src_op, host_ea *dst_op)
1307+{
1308+ code_info *code = &opts->gen.code;
1309+ uint8_t size = inst->dst.addr_mode == MODE_AREG ? OPSIZE_LONG : inst->extra.size;
1310+
1311+ uint32_t numcycles;
1312+ if ((inst->op == M68K_ADDX || inst->op == M68K_SUBX) && inst->src.addr_mode != MODE_REG) {
1313+ numcycles = 6;
1314+ } else if (size == OPSIZE_LONG) {
1315+ if (inst->op == M68K_CMP) {
1316+ numcycles = 6;
1317+ } else if (inst->op == M68K_AND && inst->variant == VAR_IMMEDIATE) {
1318+ numcycles = 6;
1319+ } else if (inst->op == M68K_ADD && inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD && inst->variant == VAR_QUICK) {
1320+ numcycles = 4;
1321+ } else if (inst->dst.addr_mode <= MODE_AREG) {
1322+ numcycles = inst->src.addr_mode <= MODE_AREG || inst->src.addr_mode == MODE_IMMEDIATE ? 8 : 6;
1323+ } else {
1324+ numcycles = 4;
1325+ }
1326+ } else {
1327+ numcycles = 4;
1328+ }
1329+ cycles(&opts->gen, numcycles);
1330+
1331+ if (inst->op == M68K_ADDX || inst->op == M68K_SUBX) {
1332+ flag_to_carry(opts, FLAG_X);
1333+ }
1334+
1335+ if (src_op->mode == MODE_REG_DIRECT) {
1336+ if (dst_op->mode == MODE_REG_DIRECT) {
1337+ op_rr(code, inst, src_op->base, dst_op->base, size);
1338+ } else {
1339+ op_rrdisp(code, inst, src_op->base, dst_op->base, dst_op->disp, size);
1340+ }
1341+ } else if (src_op->mode == MODE_REG_DISPLACE8) {
1342+ op_rdispr(code, inst, src_op->base, src_op->disp, dst_op->base, size);
1343+ } else {
1344+ if (dst_op->mode == MODE_REG_DIRECT) {
1345+ op_ir(code, inst, src_op->disp, dst_op->base, size);
1346+ } else {
1347+ op_irdisp(code, inst, src_op->disp, dst_op->base, dst_op->disp, size);
1348+ }
1349+ }
1350+ if (inst->dst.addr_mode != MODE_AREG || inst->op == M68K_CMP) {
1351+ update_flags(opts, flag_mask);
1352+ if (inst->op == M68K_ADDX || inst->op == M68K_SUBX) {
1353+ check_alloc_code(code, 2*MAX_INST_LEN);
1354+ code_ptr after_flag_set = code->cur + 1;
1355+ jcc(code, CC_Z, code->cur + 2);
1356+ set_flag(opts, 0, FLAG_Z);
1357+ *after_flag_set = code->cur - (after_flag_set+1);
1358+ }
1359+ }
1360+ if (inst->op != M68K_CMP) {
1361+ m68k_save_result(inst, opts);
1362+ }
1363+}
1364+
1365+void translate_m68k_cmp(m68k_options * opts, m68kinst * inst)
1366+{
1367+ code_info *code = &opts->gen.code;
1368+ uint8_t size = inst->extra.size;
1369+ host_ea src_op, dst_op;
1370+ translate_m68k_op(inst, &src_op, opts, 0);
1371+ if (inst->dst.addr_mode == MODE_AREG_POSTINC) {
1372+ push_r(code, opts->gen.scratch1);
1373+ translate_m68k_op(inst, &dst_op, opts, 1);
1374+ pop_r(code, opts->gen.scratch2);
1375+ src_op.base = opts->gen.scratch2;
1376+ } else {
1377+ translate_m68k_op(inst, &dst_op, opts, 1);
1378+ if (inst->dst.addr_mode == MODE_AREG && size == OPSIZE_WORD) {
1379+ size = OPSIZE_LONG;
1380+ }
1381+ }
1382+ translate_m68k_arith(opts, inst, N|Z|V|C, &src_op, &dst_op);
1383+}
1384+
1385+void translate_m68k_tas(m68k_options *opts, m68kinst *inst)
1386+{
1387+ code_info *code = &opts->gen.code;
1388+ host_ea op;
1389+ translate_m68k_op(inst, &op, opts, 1);
1390+ if (op.mode == MODE_REG_DIRECT) {
1391+ cmp_ir(code, 0, op.base, SZ_B);
1392+ } else {
1393+ cmp_irdisp(code, 0, op.base, op.disp, SZ_B);
1394+ }
1395+ update_flags(opts, N|Z|V0|C0);
1396+ if (inst->dst.addr_mode == MODE_REG) {
1397+ cycles(&opts->gen, BUS);
1398+ if (op.mode == MODE_REG_DIRECT) {
1399+ bts_ir(code, 7, op.base, SZ_B);
1400+ } else {
1401+ bts_irdisp(code, 7, op.base, op.disp, SZ_B);
1402+ }
1403+ } else {
1404+ if (opts->gen.flags & M68K_OPT_BROKEN_READ_MODIFY) {
1405+ //2 cycles for processing
1406+ //4 for failed writeback
1407+ //4 for prefetch
1408+ cycles(&opts->gen, BUS * 2 + 2);
1409+ } else {
1410+ cycles(&opts->gen, 2);
1411+ bts_ir(code, 7, op.base, SZ_B);
1412+ m68k_save_result(inst, opts);
1413+ cycles(&opts->gen, BUS);
1414+ }
1415+ }
1416+}
1417+
1418+void op_r(code_info *code, m68kinst *inst, uint8_t dst, uint8_t size)
1419+{
1420+ switch(inst->op)
1421+ {
1422+ case M68K_CLR: xor_rr(code, dst, dst, size); break;
1423+ case M68K_NEG: neg_r(code, dst, size); break;
1424+ case M68K_NOT: not_r(code, dst, size); cmp_ir(code, 0, dst, size); break;
1425+ case M68K_ROL: rol_clr(code, dst, size); break;
1426+ case M68K_ROR: ror_clr(code, dst, size); break;
1427+ case M68K_ROXL: rcl_clr(code, dst, size); break;
1428+ case M68K_ROXR: rcr_clr(code, dst, size); break;
1429+ case M68K_SWAP: rol_ir(code, 16, dst, SZ_D); cmp_ir(code, 0, dst, SZ_D); break;
1430+ case M68K_TST: cmp_ir(code, 0, dst, size); break;
1431+ }
1432+}
1433+
1434+void op_rdisp(code_info *code, m68kinst *inst, uint8_t dst, int32_t disp, uint8_t size)
1435+{
1436+ switch(inst->op)
1437+ {
1438+ case M68K_CLR: mov_irdisp(code, 0, dst, disp, size); break;
1439+ case M68K_NEG: neg_rdisp(code, dst, disp, size); break;
1440+ case M68K_NOT: not_rdisp(code, dst, disp, size); cmp_irdisp(code, 0, dst, disp, size); break;
1441+ case M68K_ROL: rol_clrdisp(code, dst, disp, size); break;
1442+ case M68K_ROR: ror_clrdisp(code, dst, disp, size); break;
1443+ case M68K_ROXL: rcl_clrdisp(code, dst, disp, size); break;
1444+ case M68K_ROXR: rcr_clrdisp(code, dst, disp, size); break;
1445+ case M68K_SWAP: rol_irdisp(code, 16, dst, disp, SZ_D); cmp_irdisp(code, 0, dst, disp, SZ_D); break;
1446+ case M68K_TST: cmp_irdisp(code, 0, dst, disp, size); break;
1447+ }
1448+}
1449+
1450+void translate_m68k_unary(m68k_options *opts, m68kinst *inst, uint32_t flag_mask, host_ea *dst_op)
1451+{
1452+ code_info *code = &opts->gen.code;
1453+ uint32_t num_cycles = BUS;
1454+ if (inst->extra.size == OPSIZE_LONG && (inst->dst.addr_mode == MODE_REG || inst->dst.addr_mode == MODE_AREG)) {
1455+ num_cycles += 2;
1456+ }
1457+ cycles(&opts->gen, num_cycles);
1458+ if (dst_op->mode == MODE_REG_DIRECT) {
1459+ op_r(code, inst, dst_op->base, inst->extra.size);
1460+ } else {
1461+ op_rdisp(code, inst, dst_op->base, dst_op->disp, inst->extra.size);
1462+ }
1463+ update_flags(opts, flag_mask);
1464+ m68k_save_result(inst, opts);
1465+}
1466+
1467+void translate_m68k_abcd_sbcd(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
1468+{
1469+ code_info *code = &opts->gen.code;
1470+ if (inst->op == M68K_NBCD) {
1471+ if (dst_op->base != opts->gen.scratch2) {
1472+ if (dst_op->mode == MODE_REG_DIRECT) {
1473+ mov_rr(code, dst_op->base, opts->gen.scratch2, SZ_B);
1474+ } else {
1475+ mov_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch2, SZ_B);
1476+ }
1477+ }
1478+ xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_B);
1479+ } else {
1480+ if (src_op->base != opts->gen.scratch2) {
1481+ if (src_op->mode == MODE_REG_DIRECT) {
1482+ mov_rr(code, src_op->base, opts->gen.scratch2, SZ_B);
1483+ } else {
1484+ mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch2, SZ_B);
1485+ }
1486+ }
1487+ if (dst_op->base != opts->gen.scratch1) {
1488+ if (dst_op->mode == MODE_REG_DIRECT) {
1489+ mov_rr(code, dst_op->base, opts->gen.scratch1, SZ_B);
1490+ } else {
1491+ mov_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch1, SZ_B);
1492+ }
1493+ }
1494+ }
1495+ if (inst->dst.addr_mode != MODE_REG && inst->dst.addr_mode != MODE_AREG && inst->dst.addr_mode != MODE_AREG_PREDEC) {
1496+ //destination is in memory so we need to preserve scratch2 for the write at the end
1497+ push_r(code, opts->gen.scratch2);
1498+ }
1499+ //MC68000 User's Manual suggests NBCD hides the 2 cycle penalty during the write cycle somehow
1500+ cycles(&opts->gen, inst->op == M68K_NBCD && inst->dst.addr_mode != MODE_REG_DIRECT ? BUS : BUS + 2);
1501+ uint8_t other_reg;
1502+ //WARNING: This may need adjustment if register assignments change
1503+ if (opts->gen.scratch2 > RBX) {
1504+ other_reg = RAX;
1505+ xchg_rr(code, opts->gen.scratch2, RAX, SZ_D);
1506+ } else {
1507+ other_reg = opts->gen.scratch2;
1508+ }
1509+ mov_rr(code, opts->gen.scratch1, opts->gen.scratch1 + (AH-RAX), SZ_B);
1510+ mov_rr(code, other_reg, other_reg + (AH-RAX), SZ_B);
1511+ and_ir(code, 0xF, opts->gen.scratch1 + (AH-RAX), SZ_B);
1512+ and_ir(code, 0xF, other_reg + (AH-RAX), SZ_B);
1513+ //do op on low nibble so we can determine if an adjustment is necessary
1514+ flag_to_carry(opts, FLAG_X);
1515+ if (inst->op == M68K_ABCD) {
1516+ adc_rr(code, other_reg + (AH-RAX), opts->gen.scratch1 + (AH-RAX), SZ_B);
1517+ } else {
1518+ sbb_rr(code, other_reg + (AH-RAX), opts->gen.scratch1 + (AH-RAX), SZ_B);
1519+ }
1520+ cmp_ir(code, inst->op == M68K_SBCD ? 0x10 : 0xA, opts->gen.scratch1 + (AH-RAX), SZ_B);
1521+ mov_ir(code, 0xA0, other_reg + (AH-RAX), SZ_B);
1522+ code_ptr no_adjust = code->cur+1;
1523+ //add correction factor if necessary
1524+ jcc(code, CC_B, no_adjust);
1525+ mov_ir(code, 6, opts->gen.scratch1 + (AH-RAX), SZ_B);
1526+ mov_ir(code, inst->op == M68K_ABCD ? 0x9A : 0xA6, other_reg + (AH-RAX), SZ_B);
1527+ code_ptr after_adjust = code->cur+1;
1528+ jmp(code, after_adjust);
1529+
1530+ *no_adjust = code->cur - (no_adjust+1);
1531+ xor_rr(code, opts->gen.scratch1 + (AH-RAX), opts->gen.scratch1 + (AH-RAX), SZ_B);
1532+ *after_adjust = code->cur - (after_adjust+1);
1533+
1534+ //do op on full byte
1535+ flag_to_carry(opts, FLAG_X);
1536+ if (inst->op == M68K_ABCD) {
1537+ adc_rr(code, other_reg, opts->gen.scratch1, SZ_B);
1538+ } else {
1539+ sbb_rr(code, other_reg, opts->gen.scratch1, SZ_B);
1540+ }
1541+ set_flag(opts, 0, FLAG_C);
1542+ //determine if we need a correction on the upper nibble
1543+ code_ptr def_adjust = code->cur+1;
1544+ jcc(code, CC_C, def_adjust);
1545+ if (inst->op == M68K_SBCD) {
1546+ no_adjust = code->cur+1;
1547+ jmp(code, no_adjust);
1548+ } else {
1549+ cmp_rr(code, other_reg + (AH-RAX), opts->gen.scratch1, SZ_B);
1550+ no_adjust = code->cur+1;
1551+ jcc(code, CC_B, no_adjust);
1552+ }
1553+ *def_adjust = code->cur - (def_adjust + 1);
1554+ set_flag(opts, 1, FLAG_C);
1555+ or_ir(code, 0x60, opts->gen.scratch1 + (AH-RAX), SZ_B);
1556+ *no_adjust = code->cur - (no_adjust+1);
1557+ if (inst->op == M68K_ABCD) {
1558+ add_rr(code, opts->gen.scratch1 + (AH-RAX), opts->gen.scratch1, SZ_B);
1559+ } else {
1560+ sub_rr(code, opts->gen.scratch1 + (AH-RAX), opts->gen.scratch1, SZ_B);
1561+ }
1562+ code_ptr no_ensure_carry = code->cur+1;
1563+ jcc(code, CC_NC, no_ensure_carry);
1564+ set_flag(opts, 1, FLAG_C);
1565+ *no_ensure_carry = code->cur - (no_ensure_carry+1);
1566+ //restore RAX if necessary
1567+ if (opts->gen.scratch2 > RBX) {
1568+ mov_rr(code, opts->gen.scratch2, RAX, SZ_D);
1569+ }
1570+ //V flag is set based on the result of the addition/subtraction of the
1571+ //result and the correction factor
1572+ set_flag_cond(opts, CC_O, FLAG_V);
1573+
1574+ flag_to_flag(opts, FLAG_C, FLAG_X);
1575+
1576+ cmp_ir(code, 0, opts->gen.scratch1, SZ_B);
1577+ set_flag_cond(opts, CC_S, FLAG_N);
1578+ code_ptr no_setz = code->cur+1;
1579+ jcc(code, CC_Z, no_setz);
1580+ set_flag(opts, 0, FLAG_Z);
1581+ *no_setz = code->cur - (no_setz + 1);
1582+ if (dst_op->base != opts->gen.scratch1) {
1583+ if (dst_op->mode == MODE_REG_DIRECT) {
1584+ mov_rr(code, opts->gen.scratch1, dst_op->base, SZ_B);
1585+ } else {
1586+ mov_rrdisp(code, opts->gen.scratch1, dst_op->base, dst_op->disp, SZ_B);
1587+ }
1588+ }
1589+ if (inst->dst.addr_mode != MODE_REG && inst->dst.addr_mode != MODE_AREG && inst->dst.addr_mode != MODE_AREG_PREDEC) {
1590+ //destination is in memory so we need to restore scratch2 for the write at the end
1591+ pop_r(code, opts->gen.scratch2);
1592+ }
1593+ m68k_save_result(inst, opts);
1594+}
1595+
1596+void translate_m68k_sl(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
1597+{
1598+ translate_shift(opts, inst, src_op, dst_op, shl_ir, shl_irdisp, shl_clr, shl_clrdisp, shr_ir, shr_irdisp);
1599+}
1600+
1601+void translate_m68k_asr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
1602+{
1603+ translate_shift(opts, inst, src_op, dst_op, sar_ir, sar_irdisp, sar_clr, sar_clrdisp, NULL, NULL);
1604+}
1605+
1606+void translate_m68k_lsr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
1607+{
1608+ translate_shift(opts, inst, src_op, dst_op, shr_ir, shr_irdisp, shr_clr, shr_clrdisp, shl_ir, shl_irdisp);
1609+}
1610+
1611+void translate_m68k_bit(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
1612+{
1613+ code_info *code = &opts->gen.code;
1614+ cycles(&opts->gen, inst->extra.size == OPSIZE_BYTE ? 4 : (
1615+ inst->op == M68K_BTST ? 6 : (inst->op == M68K_BCLR ? 10 : 8))
1616+ );
1617+ if (src_op->mode == MODE_IMMED) {
1618+ if (inst->extra.size == OPSIZE_BYTE) {
1619+ src_op->disp &= 0x7;
1620+ }
1621+ if (dst_op->mode == MODE_REG_DIRECT) {
1622+ op_ir(code, inst, src_op->disp, dst_op->base, inst->extra.size);
1623+ } else {
1624+ op_irdisp(code, inst, src_op->disp, dst_op->base, dst_op->disp, inst->extra.size);
1625+ }
1626+ } else {
1627+ if (src_op->mode == MODE_REG_DISPLACE8 || (inst->dst.addr_mode != MODE_REG && src_op->base != opts->gen.scratch1 && src_op->base != opts->gen.scratch2)) {
1628+ if (dst_op->base == opts->gen.scratch1) {
1629+ push_r(code, opts->gen.scratch2);
1630+ if (src_op->mode == MODE_REG_DIRECT) {
1631+ mov_rr(code, src_op->base, opts->gen.scratch2, SZ_B);
1632+ } else {
1633+ mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch2, SZ_B);
1634+ }
1635+ src_op->base = opts->gen.scratch2;
1636+ } else {
1637+ if (src_op->mode == MODE_REG_DIRECT) {
1638+ mov_rr(code, src_op->base, opts->gen.scratch1, SZ_B);
1639+ } else {
1640+ mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_B);
1641+ }
1642+ src_op->base = opts->gen.scratch1;
1643+ }
1644+ }
1645+ uint8_t size = inst->extra.size;
1646+ if (dst_op->mode == MODE_REG_DISPLACE8) {
1647+ if (src_op->base != opts->gen.scratch1 && src_op->base != opts->gen.scratch2) {
1648+ if (src_op->mode == MODE_REG_DIRECT) {
1649+ mov_rr(code, src_op->base, opts->gen.scratch1, SZ_D);
1650+ } else {
1651+ mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_D);
1652+ src_op->mode = MODE_REG_DIRECT;
1653+ }
1654+ src_op->base = opts->gen.scratch1;
1655+ }
1656+ //b### with register destination is modulo 32
1657+ //x86 with a memory destination isn't modulo anything
1658+ //so use an and here to force the value to be modulo 32
1659+ and_ir(code, 31, opts->gen.scratch1, SZ_D);
1660+ } else if(inst->dst.addr_mode != MODE_REG) {
1661+ //b### with memory destination is modulo 8
1662+ //x86-64 doesn't support 8-bit bit operations
1663+ //so we fake it by forcing the bit number to be modulo 8
1664+ and_ir(code, 7, src_op->base, SZ_D);
1665+ size = SZ_D;
1666+ }
1667+ if (dst_op->mode == MODE_IMMED) {
1668+ dst_op->base = src_op->base == opts->gen.scratch1 ? opts->gen.scratch2 : opts->gen.scratch1;
1669+ mov_ir(code, dst_op->disp, dst_op->base, SZ_B);
1670+ dst_op->mode = MODE_REG_DIRECT;
1671+ }
1672+ if (dst_op->mode == MODE_REG_DIRECT) {
1673+ op_rr(code, inst, src_op->base, dst_op->base, size);
1674+ } else {
1675+ op_rrdisp(code, inst, src_op->base, dst_op->base, dst_op->disp, size);
1676+ }
1677+ if (src_op->base == opts->gen.scratch2) {
1678+ pop_r(code, opts->gen.scratch2);
1679+ }
1680+ }
1681+ //x86 sets the carry flag to the value of the bit tested
1682+ //68K sets the zero flag to the complement of the bit tested
1683+ set_flag_cond(opts, CC_NC, FLAG_Z);
1684+ if (inst->op != M68K_BTST) {
1685+ m68k_save_result(inst, opts);
1686+ }
1687+}
1688+
1689+void translate_m68k_chk(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
1690+ {
1691+ code_info *code = &opts->gen.code;
1692+ cycles(&opts->gen, 6);
1693+ if (dst_op->mode == MODE_REG_DIRECT) {
1694+ cmp_ir(code, 0, dst_op->base, inst->extra.size);
1695+ } else {
1696+ cmp_irdisp(code, 0, dst_op->base, dst_op->disp, inst->extra.size);
1697+ }
1698+ uint32_t isize;
1699+ switch(inst->src.addr_mode)
1700+ {
1701+ case MODE_AREG_DISPLACE:
1702+ case MODE_AREG_INDEX_DISP8:
1703+ case MODE_ABSOLUTE_SHORT:
1704+ case MODE_PC_INDEX_DISP8:
1705+ case MODE_PC_DISPLACE:
1706+ case MODE_IMMEDIATE:
1707+ isize = 4;
1708+ break;
1709+ case MODE_ABSOLUTE:
1710+ isize = 6;
1711+ break;
1712+ default:
1713+ isize = 2;
1714+ }
1715+ //make sure we won't start a new chunk in the middle of these branches
1716+ check_alloc_code(code, MAX_INST_LEN * 11);
1717+ code_ptr passed = code->cur + 1;
1718+ jcc(code, CC_GE, code->cur + 2);
1719+ set_flag(opts, 1, FLAG_N);
1720+ mov_ir(code, VECTOR_CHK, opts->gen.scratch2, SZ_D);
1721+ mov_ir(code, inst->address+isize, opts->gen.scratch1, SZ_D);
1722+ jmp(code, opts->trap);
1723+ *passed = code->cur - (passed+1);
1724+ if (dst_op->mode == MODE_REG_DIRECT) {
1725+ if (src_op->mode == MODE_REG_DIRECT) {
1726+ cmp_rr(code, src_op->base, dst_op->base, inst->extra.size);
1727+ } else if(src_op->mode == MODE_REG_DISPLACE8) {
1728+ cmp_rdispr(code, src_op->base, src_op->disp, dst_op->base, inst->extra.size);
1729+ } else {
1730+ cmp_ir(code, src_op->disp, dst_op->base, inst->extra.size);
1731+ }
1732+ } else if(dst_op->mode == MODE_REG_DISPLACE8) {
1733+ if (src_op->mode == MODE_REG_DIRECT) {
1734+ cmp_rrdisp(code, src_op->base, dst_op->base, dst_op->disp, inst->extra.size);
1735+ } else {
1736+ cmp_irdisp(code, src_op->disp, dst_op->base, dst_op->disp, inst->extra.size);
1737+ }
1738+ }
1739+ passed = code->cur + 1;
1740+ jcc(code, CC_LE, code->cur + 2);
1741+ set_flag(opts, 0, FLAG_N);
1742+ mov_ir(code, VECTOR_CHK, opts->gen.scratch2, SZ_D);
1743+ mov_ir(code, inst->address+isize, opts->gen.scratch1, SZ_D);
1744+ jmp(code, opts->trap);
1745+ *passed = code->cur - (passed+1);
1746+ cycles(&opts->gen, 4);
1747+}
1748+
1749+static uint32_t divu(uint32_t dividend, m68k_context *context, uint32_t divisor_shift)
1750+{
1751+ uint16_t quotient = 0;
1752+ uint8_t force = 0;
1753+ uint16_t bit = 0;
1754+ uint32_t cycles = 6;
1755+ for (int i = 0; i < 16; i++)
1756+ {
1757+ force = dividend >> 31;
1758+ quotient = quotient << 1 | bit;
1759+ dividend = dividend << 1;
1760+
1761+ if (force || dividend >= divisor_shift) {
1762+ dividend -= divisor_shift;
1763+ cycles += force ? 4 : 6;
1764+ bit = 1;
1765+ } else {
1766+ bit = 0;
1767+ cycles += 8;
1768+ }
1769+ }
1770+ cycles += force ? 6 : bit ? 4 : 2;
1771+ context->current_cycle += cycles * context->options->gen.clock_divider;
1772+ quotient = quotient << 1 | bit;
1773+ return dividend | quotient;
1774+}
1775+
1776+static uint32_t divs(uint32_t dividend, m68k_context *context, uint32_t divisor_shift)
1777+{
1778+ uint32_t orig_divisor = divisor_shift, orig_dividend = dividend;
1779+ if (divisor_shift & 0x80000000) {
1780+ divisor_shift = 0 - divisor_shift;
1781+ }
1782+
1783+ uint32_t cycles = 12;
1784+ if (dividend & 0x80000000) {
1785+ //dvs10
1786+ dividend = 0 - dividend;
1787+ cycles += 2;
1788+ }
1789+ if (divisor_shift <= dividend) {
1790+ context->flags[FLAG_V] = 1;
1791+ context->flags[FLAG_N] = 1;
1792+ context->flags[FLAG_Z] = 0;
1793+ cycles += 2;
1794+ context->current_cycle += cycles * context->options->gen.clock_divider;
1795+ return orig_dividend;
1796+ }
1797+ uint16_t quotient = 0;
1798+ uint16_t bit = 0;
1799+ for (int i = 0; i < 15; i++)
1800+ {
1801+ quotient = quotient << 1 | bit;
1802+ dividend = dividend << 1;
1803+
1804+ if (dividend >= divisor_shift) {
1805+ dividend -= divisor_shift;
1806+ cycles += 6;
1807+ bit = 1;
1808+ } else {
1809+ bit = 0;
1810+ cycles += 8;
1811+ }
1812+ }
1813+ quotient = quotient << 1 | bit;
1814+ dividend = dividend << 1;
1815+ if (dividend >= divisor_shift) {
1816+ dividend -= divisor_shift;
1817+ quotient = quotient << 1 | 1;
1818+ } else {
1819+ quotient = quotient << 1;
1820+ }
1821+ cycles += 4;
1822+
1823+ context->flags[FLAG_V] = 0;
1824+ if (orig_divisor & 0x80000000) {
1825+ cycles += 16; //was 10
1826+ if (orig_dividend & 0x80000000) {
1827+ if (quotient & 0x8000) {
1828+ context->flags[FLAG_V] = 1;
1829+ context->flags[FLAG_N] = 1;
1830+ context->flags[FLAG_Z] = 0;
1831+ context->current_cycle += cycles * context->options->gen.clock_divider;
1832+ return orig_dividend;
1833+ } else {
1834+ dividend = -dividend;
1835+ }
1836+ } else {
1837+ quotient = -quotient;
1838+ if (quotient && !(quotient & 0x8000)) {
1839+ context->flags[FLAG_V] = 1;
1840+ }
1841+ }
1842+ } else if (orig_dividend & 0x80000000) {
1843+ cycles += 18; // was 12
1844+ quotient = -quotient;
1845+ if (quotient && !(quotient & 0x8000)) {
1846+ context->flags[FLAG_V] = 1;
1847+ } else {
1848+ dividend = -dividend;
1849+ }
1850+ } else {
1851+ cycles += 14; //was 10
1852+ if (quotient & 0x8000) {
1853+ context->flags[FLAG_V] = 1;
1854+ }
1855+ }
1856+ if (context->flags[FLAG_V]) {
1857+ context->flags[FLAG_N] = 1;
1858+ context->flags[FLAG_Z] = 0;
1859+ context->current_cycle += cycles * context->options->gen.clock_divider;
1860+ return orig_dividend;
1861+ }
1862+ context->flags[FLAG_N] = (quotient & 0x8000) ? 1 : 0;
1863+ context->flags[FLAG_Z] = quotient == 0;
1864+ //V was cleared above, C is cleared by the generated machine code
1865+ context->current_cycle += cycles * context->options->gen.clock_divider;
1866+ return dividend | quotient;
1867+}
1868+
1869+void translate_m68k_div(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
1870+{
1871+ code_info *code = &opts->gen.code;
1872+ check_alloc_code(code, MAX_NATIVE_SIZE);
1873+ set_flag(opts, 0, FLAG_C);
1874+ if (dst_op->mode == MODE_REG_DIRECT) {
1875+ mov_rr(code, dst_op->base, opts->gen.scratch2, SZ_D);
1876+ } else {
1877+ mov_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch2, SZ_D);
1878+ }
1879+ if (src_op->mode == MODE_IMMED) {
1880+ mov_ir(code, src_op->disp << 16, opts->gen.scratch1, SZ_D);
1881+ } else {
1882+ if (src_op->mode == MODE_REG_DISPLACE8) {
1883+ movzx_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_W, SZ_D);
1884+ } else if (src_op->base != opts->gen.scratch1) {
1885+ movzx_rr(code, src_op->base, opts->gen.scratch1, SZ_W, SZ_D);
1886+ }
1887+ shl_ir(code, 16, opts->gen.scratch1, SZ_D);
1888+ }
1889+ cmp_ir(code, 0, opts->gen.scratch1, SZ_D);
1890+ code_ptr not_zero = code->cur+1;
1891+ jcc(code, CC_NZ, not_zero);
1892+
1893+ //TODO: Check that opts->trap includes the cycles conumed by the first trap0 microinstruction
1894+ cycles(&opts->gen, 4);
1895+ uint32_t isize = 2;
1896+ switch(inst->src.addr_mode)
1897+ {
1898+ case MODE_AREG_DISPLACE:
1899+ case MODE_AREG_INDEX_DISP8:
1900+ case MODE_ABSOLUTE_SHORT:
1901+ case MODE_PC_DISPLACE:
1902+ case MODE_PC_INDEX_DISP8:
1903+ case MODE_IMMEDIATE:
1904+ isize = 4;
1905+ break;
1906+ case MODE_ABSOLUTE:
1907+ isize = 6;
1908+ break;
1909+ }
1910+ //zero seems to clear all flags
1911+ update_flags(opts, N0|Z0|V0);
1912+ mov_ir(code, VECTOR_INT_DIV_ZERO, opts->gen.scratch2, SZ_D);
1913+ mov_ir(code, inst->address+isize, opts->gen.scratch1, SZ_D);
1914+ jmp(code, opts->trap);
1915+
1916+ *not_zero = code->cur - (not_zero + 1);
1917+ code_ptr end = NULL;
1918+ if (inst->op == M68K_DIVU) {
1919+ //initial overflow check needs to be done in the C code for divs
1920+ //but can be done before dumping state to mem in divu as an optimization
1921+ cmp_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_D);
1922+ code_ptr not_overflow = code->cur+1;
1923+ jcc(code, CC_C, not_overflow);
1924+
1925+ //overflow seems to always set the N and clear Z
1926+ update_flags(opts, N1|Z0|V1);
1927+ cycles(&opts->gen, 10);
1928+ end = code->cur+1;
1929+ jmp(code, end);
1930+
1931+ *not_overflow = code->cur - (not_overflow + 1);
1932+ }
1933+ call(code, opts->gen.save_context);
1934+ push_r(code, opts->gen.context_reg);
1935+ //TODO: inline the functionality of divudivs/ so we don't need to dump context to memory
1936+ call_args(code, (code_ptr)(inst->op == M68K_DIVU ? divu : divs), 3, opts->gen.scratch2, opts->gen.context_reg, opts->gen.scratch1);
1937+ pop_r(code, opts->gen.context_reg);
1938+ mov_rr(code, RAX, opts->gen.scratch1, SZ_D);
1939+
1940+ call(code, opts->gen.load_context);
1941+
1942+ if (inst->op == M68K_DIVU) {
1943+ cmp_ir(code, 0, opts->gen.scratch1, SZ_W);
1944+ update_flags(opts, V0|Z|N);
1945+ }
1946+
1947+ if (dst_op->mode == MODE_REG_DIRECT) {
1948+ mov_rr(code, opts->gen.scratch1, dst_op->base, SZ_D);
1949+ } else {
1950+ mov_rrdisp(code, opts->gen.scratch1, dst_op->base, dst_op->disp, SZ_D);
1951+ }
1952+ if (end) {
1953+ *end = code->cur - (end + 1);
1954+ }
1955+}
1956+
1957+void translate_m68k_exg(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
1958+{
1959+ code_info *code = &opts->gen.code;
1960+ cycles(&opts->gen, 6);
1961+ if (dst_op->mode == MODE_REG_DIRECT) {
1962+ mov_rr(code, dst_op->base, opts->gen.scratch2, SZ_D);
1963+ if (src_op->mode == MODE_REG_DIRECT) {
1964+ mov_rr(code, src_op->base, dst_op->base, SZ_D);
1965+ mov_rr(code, opts->gen.scratch2, src_op->base, SZ_D);
1966+ } else {
1967+ mov_rdispr(code, src_op->base, src_op->disp, dst_op->base, SZ_D);
1968+ mov_rrdisp(code, opts->gen.scratch2, src_op->base, src_op->disp, SZ_D);
1969+ }
1970+ } else {
1971+ mov_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch2, SZ_D);
1972+ if (src_op->mode == MODE_REG_DIRECT) {
1973+ mov_rrdisp(code, src_op->base, dst_op->base, dst_op->disp, SZ_D);
1974+ mov_rr(code, opts->gen.scratch2, src_op->base, SZ_D);
1975+ } else {
1976+ mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_D);
1977+ mov_rrdisp(code, opts->gen.scratch1, dst_op->base, dst_op->disp, SZ_D);
1978+ mov_rrdisp(code, opts->gen.scratch2, src_op->base, src_op->disp, SZ_D);
1979+ }
1980+ }
1981+}
1982+
1983+
1984+
1985+static uint32_t mulu_cycles(uint16_t value)
1986+{
1987+ //4 for prefetch, 2-cycles per bit x 16, 2 for cleanup
1988+ uint32_t cycles = 38;
1989+ uint16_t a = (value & 0b1010101010101010) >> 1;
1990+ uint16_t b = value & 0b0101010101010101;
1991+ value = a + b;
1992+ a = (value & 0b1100110011001100) >> 2;
1993+ b = value & 0b0011001100110011;
1994+ value = a + b;
1995+ a = (value & 0b1111000011110000) >> 4;
1996+ b = value & 0b0000111100001111;
1997+ value = a + b;
1998+ a = (value & 0b1111111100000000) >> 8;
1999+ b = value & 0b0000000011111111;
2000+ value = a + b;
2001+ return cycles + 2*value;
2002+}
2003+
2004+static uint32_t muls_cycles(uint16_t value)
2005+{
2006+ //muls timing is essentially the same as muls, but it's based on the number of 0/1
2007+ //transitions rather than the number of 1 bits. xoring the value with itself shifted
2008+ //by one effectively sets one bit for every transition
2009+ return mulu_cycles((value << 1) ^ value);
2010+}
2011+
2012+void translate_m68k_mul(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
2013+{
2014+ code_info *code = &opts->gen.code;
2015+ if (src_op->mode == MODE_IMMED) {
2016+ cycles(&opts->gen, inst->op == M68K_MULU ? mulu_cycles(src_op->disp) : muls_cycles(src_op->disp));
2017+ mov_ir(code, inst->op == M68K_MULU ? (src_op->disp & 0xFFFF) : ((src_op->disp & 0x8000) ? src_op->disp | 0xFFFF0000 : src_op->disp), opts->gen.scratch1, SZ_D);
2018+ } else if (src_op->mode == MODE_REG_DIRECT) {
2019+ if (inst->op == M68K_MULS) {
2020+ movsx_rr(code, src_op->base, opts->gen.scratch1, SZ_W, SZ_D);
2021+ } else {
2022+ movzx_rr(code, src_op->base, opts->gen.scratch1, SZ_W, SZ_D);
2023+ }
2024+ } else {
2025+ if (inst->op == M68K_MULS) {
2026+ movsx_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_W, SZ_D);
2027+ } else {
2028+ movzx_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_W, SZ_D);
2029+ }
2030+ }
2031+ if (src_op->mode != MODE_IMMED) {
2032+ //TODO: Inline cycle calculation so we don't need to save/restore a bunch of registers
2033+ //save context to memory and call the relevant C function for calculating the cycle count
2034+ call(code, opts->gen.save_context);
2035+ push_r(code, opts->gen.scratch1);
2036+ push_r(code, opts->gen.context_reg);
2037+ call_args(code, (code_ptr)(inst->op == M68K_MULS ? muls_cycles : mulu_cycles), 1, opts->gen.scratch1);
2038+ pop_r(code, opts->gen.context_reg);
2039+ //turn 68K cycles into master clock cycles and add to the current cycle count
2040+ imul_irr(code, opts->gen.clock_divider, RAX, RAX, SZ_D);
2041+ add_rrdisp(code, RAX, opts->gen.context_reg, offsetof(m68k_context, current_cycle), SZ_D);
2042+ //restore context and scratch1
2043+ call(code, opts->gen.load_context);
2044+ pop_r(code, opts->gen.scratch1);
2045+ }
2046+
2047+ uint8_t dst_reg;
2048+ if (dst_op->mode == MODE_REG_DIRECT) {
2049+ dst_reg = dst_op->base;
2050+ if (inst->op == M68K_MULS) {
2051+ movsx_rr(code, dst_reg, dst_reg, SZ_W, SZ_D);
2052+ } else {
2053+ movzx_rr(code, dst_reg, dst_reg, SZ_W, SZ_D);
2054+ }
2055+ } else {
2056+ dst_reg = opts->gen.scratch2;
2057+ if (inst->op == M68K_MULS) {
2058+ movsx_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch2, SZ_W, SZ_D);
2059+ } else {
2060+ movzx_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch2, SZ_W, SZ_D);
2061+ }
2062+ }
2063+ imul_rr(code, opts->gen.scratch1, dst_reg, SZ_D);
2064+ if (dst_op->mode == MODE_REG_DISPLACE8) {
2065+ mov_rrdisp(code, dst_reg, dst_op->base, dst_op->disp, SZ_D);
2066+ }
2067+ cmp_ir(code, 0, dst_reg, SZ_D);
2068+ update_flags(opts, N|Z|V0|C0);
2069+}
2070+
2071+void translate_m68k_negx(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
2072+{
2073+ code_info *code = &opts->gen.code;
2074+ cycles(&opts->gen, BUS);
2075+ if (dst_op->mode == MODE_REG_DIRECT) {
2076+ if (dst_op->base == opts->gen.scratch1) {
2077+ push_r(code, opts->gen.scratch2);
2078+ xor_rr(code, opts->gen.scratch2, opts->gen.scratch2, inst->extra.size);
2079+ flag_to_carry(opts, FLAG_X);
2080+ sbb_rr(code, dst_op->base, opts->gen.scratch2, inst->extra.size);
2081+ mov_rr(code, opts->gen.scratch2, dst_op->base, inst->extra.size);
2082+ pop_r(code, opts->gen.scratch2);
2083+ } else {
2084+ xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, inst->extra.size);
2085+ flag_to_carry(opts, FLAG_X);
2086+ sbb_rr(code, dst_op->base, opts->gen.scratch1, inst->extra.size);
2087+ mov_rr(code, opts->gen.scratch1, dst_op->base, inst->extra.size);
2088+ }
2089+ } else {
2090+ xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, inst->extra.size);
2091+ flag_to_carry(opts, FLAG_X);
2092+ sbb_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch1, inst->extra.size);
2093+ mov_rrdisp(code, opts->gen.scratch1, dst_op->base, dst_op->disp, inst->extra.size);
2094+ }
2095+ set_flag_cond(opts, CC_C, FLAG_C);
2096+ code_ptr after_flag_set = code->cur + 1;
2097+ jcc(code, CC_Z, code->cur + 2);
2098+ set_flag(opts, 0, FLAG_Z);
2099+ *after_flag_set = code->cur - (after_flag_set+1);
2100+ set_flag_cond(opts, CC_S, FLAG_N);
2101+ set_flag_cond(opts, CC_O, FLAG_V);
2102+ if (opts->flag_regs[FLAG_C] >= 0) {
2103+ flag_to_flag(opts, FLAG_C, FLAG_X);
2104+ } else {
2105+ set_flag_cond(opts, CC_C, FLAG_X);
2106+ }
2107+ m68k_save_result(inst, opts);
2108+}
2109+
2110+void translate_m68k_rot(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
2111+{
2112+ code_info *code = &opts->gen.code;
2113+ int32_t init_flags = C|V0;
2114+ if (inst->src.addr_mode == MODE_UNUSED) {
2115+ cycles(&opts->gen, BUS);
2116+ //Memory rotate
2117+ if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) {
2118+ flag_to_carry(opts, FLAG_X);
2119+ init_flags |= X;
2120+ }
2121+ op_ir(code, inst, 1, dst_op->base, inst->extra.size);
2122+ update_flags(opts, init_flags);
2123+ cmp_ir(code, 0, dst_op->base, inst->extra.size);
2124+ update_flags(opts, Z|N);
2125+ m68k_save_result(inst, opts);
2126+ } else {
2127+ if (src_op->mode == MODE_IMMED) {
2128+ cycles(&opts->gen, (inst->extra.size == OPSIZE_LONG ? 8 : 6) + src_op->disp*2);
2129+ if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) {
2130+ flag_to_carry(opts, FLAG_X);
2131+ init_flags |= X;
2132+ }
2133+ if (dst_op->mode == MODE_REG_DIRECT) {
2134+ op_ir(code, inst, src_op->disp, dst_op->base, inst->extra.size);
2135+ } else {
2136+ op_irdisp(code, inst, src_op->disp, dst_op->base, dst_op->disp, inst->extra.size);
2137+ }
2138+ update_flags(opts, init_flags);
2139+ } else {
2140+ if (src_op->mode == MODE_REG_DIRECT) {
2141+ if (src_op->base != opts->gen.scratch1) {
2142+ mov_rr(code, src_op->base, opts->gen.scratch1, SZ_B);
2143+ }
2144+ } else {
2145+ mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_B);
2146+ }
2147+ and_ir(code, 63, opts->gen.scratch1, SZ_D);
2148+ code_ptr zero_off = code->cur + 1;
2149+ jcc(code, CC_Z, code->cur + 2);
2150+ //add 2 cycles for every bit shifted
2151+ mov_ir(code, 2 * opts->gen.clock_divider, opts->gen.scratch2, SZ_D);
2152+ imul_rr(code, RCX, opts->gen.scratch2, SZ_D);
2153+ add_rr(code, opts->gen.scratch2, opts->gen.cycles, SZ_D);
2154+ cmp_ir(code, 32, opts->gen.scratch1, SZ_B);
2155+ code_ptr norm_off = code->cur + 1;
2156+ jcc(code, CC_L, code->cur + 2);
2157+ if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) {
2158+ flag_to_carry(opts, FLAG_X);
2159+ init_flags |= X;
2160+ } else {
2161+ sub_ir(code, 32, opts->gen.scratch1, SZ_B);
2162+ }
2163+ if (dst_op->mode == MODE_REG_DIRECT) {
2164+ op_ir(code, inst, 31, dst_op->base, inst->extra.size);
2165+ op_ir(code, inst, 1, dst_op->base, inst->extra.size);
2166+ } else {
2167+ op_irdisp(code, inst, 31, dst_op->base, dst_op->disp, inst->extra.size);
2168+ op_irdisp(code, inst, 1, dst_op->base, dst_op->disp, inst->extra.size);
2169+ }
2170+
2171+ if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) {
2172+ set_flag_cond(opts, CC_C, FLAG_X);
2173+ sub_ir(code, 32, opts->gen.scratch1, SZ_B);
2174+ *norm_off = code->cur - (norm_off+1);
2175+ flag_to_carry(opts, FLAG_X);
2176+ } else {
2177+ *norm_off = code->cur - (norm_off+1);
2178+ }
2179+ if (dst_op->mode == MODE_REG_DIRECT) {
2180+ op_r(code, inst, dst_op->base, inst->extra.size);
2181+ } else {
2182+ op_rdisp(code, inst, dst_op->base, dst_op->disp, inst->extra.size);
2183+ }
2184+ update_flags(opts, init_flags);
2185+ code_ptr end_off = code->cur + 1;
2186+ jmp(code, code->cur + 2);
2187+ *zero_off = code->cur - (zero_off+1);
2188+ if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) {
2189+ //Carry flag is set to X flag when count is 0, this is different from ROR/ROL
2190+ flag_to_flag(opts, FLAG_X, FLAG_C);
2191+ } else {
2192+ set_flag(opts, 0, FLAG_C);
2193+ }
2194+ *end_off = code->cur - (end_off+1);
2195+ }
2196+ if (dst_op->mode == MODE_REG_DIRECT) {
2197+ cmp_ir(code, 0, dst_op->base, inst->extra.size);
2198+ } else {
2199+ cmp_irdisp(code, 0, dst_op->base, dst_op->disp, inst->extra.size);
2200+ }
2201+ update_flags(opts, Z|N);
2202+ }
2203+}
2204+
2205+#define BIT_SUPERVISOR 5
2206+
2207+void m68k_trap_if_not_supervisor(m68k_options *opts, m68kinst *inst)
2208+{
2209+ code_info *code = &opts->gen.code;
2210+ //check supervisor bit in SR and trap if not in supervisor mode
2211+ bt_irdisp(code, BIT_SUPERVISOR, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
2212+ code_ptr in_sup_mode = code->cur + 1;
2213+ jcc(code, CC_C, code->cur + 2);
2214+
2215+ ldi_native(opts, VECTOR_PRIV_VIOLATION, opts->gen.scratch2);
2216+ ldi_native(opts, inst->address, opts->gen.scratch1);
2217+ jmp(code, opts->trap);
2218+
2219+ *in_sup_mode = code->cur - (in_sup_mode + 1);
2220+}
2221+
2222+void translate_m68k_andi_ori_ccr_sr(m68k_options *opts, m68kinst *inst)
2223+{
2224+ code_info *code = &opts->gen.code;
2225+ if (inst->op == M68K_ANDI_SR || inst->op == M68K_ORI_SR) {
2226+ m68k_trap_if_not_supervisor(opts, inst);
2227+ }
2228+ cycles(&opts->gen, 20);
2229+ uint32_t flag_mask = 0;
2230+ uint32_t base_flag = inst->op == M68K_ANDI_SR || inst->op == M68K_ANDI_CCR ? X0 : X1;
2231+ for (int i = 0; i < 5; i++)
2232+ {
2233+ if ((base_flag == X0) ^ ((inst->src.params.immed & 1 << i) > 0))
2234+ {
2235+ flag_mask |= base_flag << ((4 - i) * 3);
2236+ }
2237+ }
2238+ update_flags(opts, flag_mask);
2239+ if (inst->op == M68K_ANDI_SR || inst->op == M68K_ORI_SR) {
2240+ if (inst->op == M68K_ANDI_SR) {
2241+ and_irdisp(code, inst->src.params.immed >> 8, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
2242+ } else {
2243+ or_irdisp(code, inst->src.params.immed >> 8, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
2244+ }
2245+ if (inst->op == M68K_ANDI_SR && !(inst->src.params.immed & (1 << (BIT_SUPERVISOR + 8)))) {
2246+ //leave supervisor mode
2247+ swap_ssp_usp(opts);
2248+ }
2249+ if ((inst->op == M68K_ANDI_SR && (inst->src.params.immed & 0x700) != 0x700)
2250+ || (inst->op == M68K_ORI_SR && inst->src.params.immed & 0x8700)) {
2251+ if (inst->op == M68K_ANDI_SR) {
2252+ //set int pending flag in case we trigger an interrupt as a result of the mask change
2253+ mov_irdisp(code, INT_PENDING_SR_CHANGE, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
2254+ }
2255+ call(code, opts->do_sync);
2256+ }
2257+ }
2258+}
2259+
2260+void translate_m68k_eori_ccr_sr(m68k_options *opts, m68kinst *inst)
2261+{
2262+ code_info *code = &opts->gen.code;
2263+ if (inst->op == M68K_EORI_SR) {
2264+ m68k_trap_if_not_supervisor(opts, inst);
2265+ }
2266+ cycles(&opts->gen, 20);
2267+ if (inst->src.params.immed & 0x1) {
2268+ xor_flag(opts, 1, FLAG_C);
2269+ }
2270+ if (inst->src.params.immed & 0x2) {
2271+ xor_flag(opts, 1, FLAG_V);
2272+ }
2273+ if (inst->src.params.immed & 0x4) {
2274+ xor_flag(opts, 1, FLAG_Z);
2275+ }
2276+ if (inst->src.params.immed & 0x8) {
2277+ xor_flag(opts, 1, FLAG_N);
2278+ }
2279+ if (inst->src.params.immed & 0x10) {
2280+ xor_flag(opts, 1, FLAG_X);
2281+ }
2282+ if (inst->op == M68K_EORI_SR) {
2283+ xor_irdisp(code, inst->src.params.immed >> 8, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
2284+ if (inst->src.params.immed & 0x8700) {
2285+ //set int pending flag in case we trigger an interrupt as a result of the mask change
2286+ mov_irdisp(code, INT_PENDING_SR_CHANGE, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
2287+ call(code, opts->do_sync);
2288+ }
2289+ }
2290+}
2291+
2292+void set_all_flags(m68k_options *opts, uint8_t flags)
2293+{
2294+ uint32_t flag_mask = flags & 0x10 ? X1 : X0;
2295+ flag_mask |= flags & 0x8 ? N1 : N0;
2296+ flag_mask |= flags & 0x4 ? Z1 : Z0;
2297+ flag_mask |= flags & 0x2 ? V1 : V0;
2298+ flag_mask |= flags & 0x1 ? C1 : C0;
2299+ update_flags(opts, flag_mask);
2300+}
2301+
2302+void translate_m68k_move_ccr_sr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
2303+{
2304+ code_info *code = &opts->gen.code;
2305+ if (inst->op == M68K_MOVE_SR) {
2306+ m68k_trap_if_not_supervisor(opts, inst);
2307+ }
2308+ if (src_op->mode == MODE_IMMED) {
2309+ set_all_flags(opts, src_op->disp);
2310+ if (inst->op == M68K_MOVE_SR) {
2311+ mov_irdisp(code, (src_op->disp >> 8), opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
2312+ if (!((inst->src.params.immed >> 8) & (1 << BIT_SUPERVISOR))) {
2313+ //leave supervisor mode
2314+ swap_ssp_usp(opts);
2315+ }
2316+ if (((src_op->disp >> 8) & 7) < 7) {
2317+ //set int pending flag in case we trigger an interrupt as a result of the mask change
2318+ mov_irdisp(code, INT_PENDING_SR_CHANGE, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
2319+ }
2320+ call(code, opts->do_sync);
2321+ }
2322+ cycles(&opts->gen, 12);
2323+ } else {
2324+ if (src_op->base != opts->gen.scratch1) {
2325+ if (src_op->mode == MODE_REG_DIRECT) {
2326+ mov_rr(code, src_op->base, opts->gen.scratch1, SZ_W);
2327+ } else {
2328+ mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_W);
2329+ }
2330+ }
2331+ if (inst->op == M68K_MOVE_SR) {
2332+ call(code, opts->set_sr);
2333+ call(code, opts->do_sync);
2334+ } else {
2335+ call(code, opts->set_ccr);
2336+ }
2337+ cycles(&opts->gen, 12);
2338+ }
2339+}
2340+
2341+void translate_m68k_stop(m68k_options *opts, m68kinst *inst)
2342+{
2343+ m68k_trap_if_not_supervisor(opts, inst);
2344+ //manual says 4 cycles, but it has to be at least 8 since it's a 2-word instruction
2345+ //possibly even 12 since that's how long MOVE to SR takes
2346+ //On further thought prefetch + the fact that this stops the CPU may make
2347+ //Motorola's accounting make sense here
2348+ code_info *code = &opts->gen.code;
2349+ cycles(&opts->gen, BUS*2);
2350+ set_all_flags(opts, inst->src.params.immed);
2351+ mov_irdisp(code, (inst->src.params.immed >> 8), opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
2352+ if (!((inst->src.params.immed >> 8) & (1 << BIT_SUPERVISOR))) {
2353+ //leave supervisor mode
2354+ swap_ssp_usp(opts);
2355+ }
2356+ code_ptr loop_top = code->cur;
2357+ call(code, opts->do_sync);
2358+ cmp_rr(code, opts->gen.cycles, opts->gen.limit, SZ_D);
2359+ code_ptr normal_cycle_up = code->cur + 1;
2360+ jcc(code, CC_A, code->cur + 2);
2361+ cycles(&opts->gen, BUS);
2362+ code_ptr after_cycle_up = code->cur + 1;
2363+ jmp(code, code->cur + 2);
2364+ *normal_cycle_up = code->cur - (normal_cycle_up + 1);
2365+ mov_rr(code, opts->gen.limit, opts->gen.cycles, SZ_D);
2366+ *after_cycle_up = code->cur - (after_cycle_up+1);
2367+ cmp_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_cycle), opts->gen.cycles, SZ_D);
2368+ jcc(code, CC_C, loop_top);
2369+ //set int pending flag so interrupt fires immediately after stop is done
2370+ mov_irdisp(code, INT_PENDING_SR_CHANGE, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
2371+}
2372+
2373+void translate_m68k_trapv(m68k_options *opts, m68kinst *inst)
2374+{
2375+ code_info *code = &opts->gen.code;
2376+ cycles(&opts->gen, BUS);
2377+ flag_to_carry(opts, FLAG_V);
2378+ code_ptr no_trap = code->cur + 1;
2379+ jcc(code, CC_NC, no_trap);
2380+ ldi_native(opts, VECTOR_TRAPV, opts->gen.scratch2);
2381+ ldi_native(opts, inst->address+2, opts->gen.scratch1);
2382+ jmp(code, opts->trap);
2383+ *no_trap = code->cur - (no_trap + 1);
2384+}
2385+
2386+void translate_m68k_odd(m68k_options *opts, m68kinst *inst)
2387+{
2388+ code_info *code = &opts->gen.code;
2389+ //swap USP and SSP if not already in supervisor mode
2390+ check_user_mode_swap_ssp_usp(opts);
2391+ //save PC
2392+ subi_areg(opts, 4, 7);
2393+ areg_to_native(opts, 7, opts->gen.scratch2);
2394+ mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, last_prefetch_address), opts->gen.scratch1, SZ_D);
2395+ call(code, opts->write_32_lowfirst);
2396+ //save status register
2397+ subi_areg(opts, 2, 7);
2398+ call(code, opts->get_sr);
2399+ areg_to_native(opts, 7, opts->gen.scratch2);
2400+ call(code, opts->write_16);
2401+ //save instruction register
2402+ subi_areg(opts, 2, 7);
2403+ //calculate IR
2404+ push_r(code, opts->gen.context_reg);
2405+ call(code, opts->gen.save_context);
2406+ call_args_abi(code, (code_ptr)m68k_get_ir, 1, opts->gen.context_reg);
2407+ mov_rr(code, RAX, opts->gen.scratch1, SZ_W);
2408+ pop_r(code, opts->gen.context_reg);
2409+ push_r(code, RAX); //save it for use in the "info" word
2410+ call(code, opts->gen.load_context);
2411+ //write it to the stack
2412+ areg_to_native(opts, 7, opts->gen.scratch2);
2413+ call(code, opts->write_16);
2414+ //save access address
2415+ subi_areg(opts, 4, 7);
2416+ mov_ir(code, inst->address, opts->gen.scratch1, SZ_D);
2417+ areg_to_native(opts, 7, opts->gen.scratch2);
2418+ call(code, opts->write_32_lowfirst);
2419+ //save FC, I/N and R/W word'
2420+ xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_W);
2421+ //FC3 is basically the same as the supervisor bit
2422+ mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, status), opts->gen.scratch1, SZ_B);
2423+ shr_ir(code, 3, opts->gen.scratch1, SZ_B);
2424+ and_ir(code, 4, opts->gen.scratch1, SZ_B);
2425+ //set FC1 to one to indicate instruction fetch, and R/W to indicate read
2426+ or_ir(code, 0x12, opts->gen.scratch1, SZ_B);
2427+ //set undefined bits to IR value
2428+ pop_r(code, opts->gen.scratch2);
2429+ and_ir(code, 0xFFE0, opts->gen.scratch2, SZ_W);
2430+ or_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_W);
2431+ subi_areg(opts, 2, 7);
2432+ areg_to_native(opts, 7, opts->gen.scratch2);
2433+ call(code, opts->write_16);
2434+ //set supervisor bit
2435+ or_irdisp(code, 0x20, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
2436+ //load vector address
2437+ mov_ir(code, 4 * VECTOR_ADDRESS_ERROR, opts->gen.scratch1, SZ_D);
2438+ call(code, opts->read_32);
2439+ call(code, opts->native_addr_and_sync);
2440+ cycles(&opts->gen, 18);
2441+ jmp_r(code, opts->gen.scratch1);
2442+}
2443+
2444+void translate_m68k_move_from_sr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op)
2445+{
2446+ code_info *code = &opts->gen.code;
2447+ cycles(&opts->gen, inst->dst.addr_mode == MODE_REG_DIRECT ? BUS+2 : BUS);
2448+ call(code, opts->get_sr);
2449+ if (dst_op->mode == MODE_REG_DIRECT) {
2450+ mov_rr(code, opts->gen.scratch1, dst_op->base, SZ_W);
2451+ } else {
2452+ mov_rrdisp(code, opts->gen.scratch1, dst_op->base, dst_op->disp, SZ_W);
2453+ }
2454+ m68k_save_result(inst, opts);
2455+}
2456+
2457+void m68k_out_of_bounds_execution(uint32_t address)
2458+{
2459+ fatal_error("M68K attempted to execute code at unmapped or I/O address %X\n", address);
2460+}
2461+
2462+void translate_out_of_bounds(m68k_options *opts, uint32_t address)
2463+{
2464+ code_info *code = &opts->gen.code;
2465+ check_cycles_int(&opts->gen, address);
2466+ mov_ir(code, address, opts->gen.scratch1, SZ_D);
2467+ call_args(code, (code_ptr)m68k_out_of_bounds_execution, 1, opts->gen.scratch1);
2468+}
2469+
2470+void m68k_set_last_prefetch(m68k_options *opts, uint32_t address)
2471+{
2472+ mov_irdisp(&opts->gen.code, address, opts->gen.context_reg, offsetof(m68k_context, last_prefetch_address), SZ_D);
2473+}
2474+
2475+void nop_fill_or_jmp_next(code_info *code, code_ptr old_end, code_ptr next_inst)
2476+{
2477+ if (next_inst == old_end && next_inst - code->cur < 2) {
2478+ while (code->cur < old_end) {
2479+ *(code->cur++) = 0x90; //NOP
2480+ }
2481+ } else {
2482+ jmp(code, next_inst);
2483+ }
2484+}
2485+
2486+#define M68K_MAX_INST_SIZE (2*(1+2+2))
2487+
2488+m68k_context * m68k_handle_code_write(uint32_t address, m68k_context * context)
2489+{
2490+ m68k_options * options = context->options;
2491+ uint32_t inst_start = get_instruction_start(options, address);
2492+ while (inst_start && (address - inst_start) < M68K_MAX_INST_SIZE) {
2493+ code_ptr dst = get_native_address(context->options, inst_start);
2494+ patch_for_retranslate(&options->gen, dst, options->retrans_stub);
2495+ inst_start = get_instruction_start(options, inst_start - 2);
2496+ }
2497+ return context;
2498+}
2499+
2500+void m68k_invalidate_code_range(m68k_context *context, uint32_t start, uint32_t end)
2501+{
2502+ m68k_options *opts = context->options;
2503+ native_map_slot *native_code_map = opts->gen.native_code_map;
2504+ memmap_chunk const *mem_chunk = find_map_chunk(start, &opts->gen, 0, NULL);
2505+ if (mem_chunk) {
2506+ //calculate the lowest alias for this address
2507+ start = mem_chunk->start + ((start - mem_chunk->start) & mem_chunk->mask);
2508+ }
2509+ mem_chunk = find_map_chunk(end, &opts->gen, 0, NULL);
2510+ if (mem_chunk) {
2511+ //calculate the lowest alias for this address
2512+ end = mem_chunk->start + ((end - mem_chunk->start) & mem_chunk->mask);
2513+ }
2514+ uint32_t start_chunk = start / NATIVE_CHUNK_SIZE, end_chunk = end / NATIVE_CHUNK_SIZE;
2515+ for (uint32_t chunk = start_chunk; chunk <= end_chunk; chunk++)
2516+ {
2517+ if (native_code_map[chunk].base) {
2518+ uint32_t start_offset = chunk == start_chunk ? start % NATIVE_CHUNK_SIZE : 0;
2519+ uint32_t end_offset = chunk == end_chunk ? end % NATIVE_CHUNK_SIZE : NATIVE_CHUNK_SIZE;
2520+ for (uint32_t offset = start_offset; offset < end_offset; offset++)
2521+ {
2522+ if (native_code_map[chunk].offsets[offset] != INVALID_OFFSET && native_code_map[chunk].offsets[offset] != EXTENSION_WORD) {
2523+ patch_for_retranslate(&opts->gen, native_code_map[chunk].base + native_code_map[chunk].offsets[offset], opts->retrans_stub);
2524+ /*code_info code;
2525+ code.cur = native_code_map[chunk].base + native_code_map[chunk].offsets[offset];
2526+ code.last = code.cur + 32;
2527+ code.stack_off = 0;
2528+ mov_ir(&code, chunk * NATIVE_CHUNK_SIZE + offset, opts->gen.scratch2, SZ_D);
2529+ jmp(&code, opts->retrans_stub);*/
2530+ }
2531+ }
2532+ }
2533+ }
2534+}
2535+
2536+void m68k_breakpoint_patch(m68k_context *context, uint32_t address, m68k_debug_handler bp_handler, code_ptr native_addr)
2537+{
2538+ m68k_options * opts = context->options;
2539+ code_info native;
2540+ native.cur = native_addr ? native_addr : get_native_address(context->options, address);
2541+
2542+ if (!native.cur) {
2543+ return;
2544+ }
2545+
2546+ if (*native.cur != opts->prologue_start) {
2547+ //instruction has already been patched, probably for retranslation
2548+ return;
2549+ }
2550+ native.last = native.cur + 128;
2551+ native.stack_off = 0;
2552+ code_ptr start_native = native.cur;
2553+ mov_ir(&native, address, opts->gen.scratch1, SZ_D);
2554+
2555+
2556+ call(&native, opts->bp_stub);
2557+}
2558+
2559+void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chunks, uint32_t clock_divider)
2560+{
2561+ memset(opts, 0, sizeof(*opts));
2562+ opts->gen.memmap = memmap;
2563+ opts->gen.memmap_chunks = num_chunks;
2564+ opts->gen.address_size = SZ_D;
2565+ opts->gen.address_mask = 0xFFFFFF;
2566+ opts->gen.byte_swap = 1;
2567+ opts->gen.max_address = 0x1000000;
2568+ opts->gen.bus_cycles = BUS;
2569+ opts->gen.clock_divider = clock_divider;
2570+ opts->gen.mem_ptr_off = offsetof(m68k_context, mem_pointers);
2571+ opts->gen.ram_flags_off = offsetof(m68k_context, ram_code_flags);
2572+ opts->gen.ram_flags_shift = 11;
2573+ for (int i = 0; i < 8; i++)
2574+ {
2575+ opts->dregs[i] = opts->aregs[i] = -1;
2576+ }
2577+#ifdef X86_64
2578+ opts->dregs[0] = R10;
2579+ opts->dregs[1] = R11;
2580+ opts->dregs[2] = R12;
2581+ opts->dregs[3] = R8;
2582+ opts->aregs[0] = R13;
2583+ opts->aregs[1] = R14;
2584+ opts->aregs[2] = R9;
2585+ opts->aregs[7] = R15;
2586+
2587+ opts->flag_regs[0] = -1;
2588+ opts->flag_regs[1] = RBX;
2589+ opts->flag_regs[2] = RDX;
2590+ opts->flag_regs[3] = BH;
2591+ opts->flag_regs[4] = DH;
2592+
2593+ opts->gen.scratch2 = RDI;
2594+#else
2595+ opts->dregs[0] = RDX;
2596+ opts->aregs[7] = RDI;
2597+
2598+ for (int i = 0; i < 5; i++)
2599+ {
2600+ opts->flag_regs[i] = -1;
2601+ }
2602+ opts->gen.scratch2 = RBX;
2603+#endif
2604+ opts->gen.context_reg = RSI;
2605+ opts->gen.cycles = RAX;
2606+ opts->gen.limit = RBP;
2607+ opts->gen.scratch1 = RCX;
2608+ opts->gen.align_error_mask = 1;
2609+
2610+
2611+ opts->gen.native_code_map = malloc(sizeof(native_map_slot) * NATIVE_MAP_CHUNKS);
2612+ memset(opts->gen.native_code_map, 0, sizeof(native_map_slot) * NATIVE_MAP_CHUNKS);
2613+ opts->gen.deferred = NULL;
2614+
2615+ uint32_t inst_size_size = sizeof(uint8_t *) * ram_size(&opts->gen) / 1024;
2616+ opts->gen.ram_inst_sizes = malloc(inst_size_size);
2617+ memset(opts->gen.ram_inst_sizes, 0, inst_size_size);
2618+
2619+ code_info *code = &opts->gen.code;
2620+ init_code_info(code);
2621+
2622+ opts->gen.save_context = code->cur;
2623+ for (int i = 0; i < 5; i++)
2624+ if (opts->flag_regs[i] >= 0) {
2625+ mov_rrdisp(code, opts->flag_regs[i], opts->gen.context_reg, offsetof(m68k_context, flags) + i, SZ_B);
2626+ }
2627+ for (int i = 0; i < 8; i++)
2628+ {
2629+ if (opts->dregs[i] >= 0) {
2630+ mov_rrdisp(code, opts->dregs[i], opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t) * i, SZ_D);
2631+ }
2632+ if (opts->aregs[i] >= 0) {
2633+ mov_rrdisp(code, opts->aregs[i], opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t) * i, SZ_D);
2634+ }
2635+ }
2636+ mov_rrdisp(code, opts->gen.cycles, opts->gen.context_reg, offsetof(m68k_context, current_cycle), SZ_D);
2637+ retn(code);
2638+
2639+ opts->gen.load_context = code->cur;
2640+ for (int i = 0; i < 5; i++)
2641+ {
2642+ if (opts->flag_regs[i] >= 0) {
2643+ mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, flags) + i, opts->flag_regs[i], SZ_B);
2644+ }
2645+ }
2646+ for (int i = 0; i < 8; i++)
2647+ {
2648+ if (opts->dregs[i] >= 0) {
2649+ mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, dregs) + sizeof(uint32_t) * i, opts->dregs[i], SZ_D);
2650+ }
2651+ if (opts->aregs[i] >= 0) {
2652+ mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t) * i, opts->aregs[i], SZ_D);
2653+ }
2654+ }
2655+ mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, current_cycle), opts->gen.cycles, SZ_D);
2656+ mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, target_cycle), opts->gen.limit, SZ_D);
2657+ retn(code);
2658+
2659+ opts->start_context = (start_fun)code->cur;
2660+ save_callee_save_regs(code);
2661+#ifdef X86_64
2662+ if (opts->gen.scratch2 != RDI) {
2663+ mov_rr(code, RDI, opts->gen.scratch2, SZ_PTR);
2664+ }
2665+#else
2666+ mov_rdispr(code, RSP, 20, opts->gen.scratch2, SZ_D);
2667+ mov_rdispr(code, RSP, 24, opts->gen.context_reg, SZ_D);
2668+#endif
2669+ call(code, opts->gen.load_context);
2670+ call_r(code, opts->gen.scratch2);
2671+ call(code, opts->gen.save_context);
2672+ restore_callee_save_regs(code);
2673+ retn(code);
2674+
2675+ opts->native_addr = code->cur;
2676+ call(code, opts->gen.save_context);
2677+ push_r(code, opts->gen.context_reg);
2678+ call_args(code, (code_ptr)get_native_address_trans, 2, opts->gen.context_reg, opts->gen.scratch1);
2679+ mov_rr(code, RAX, opts->gen.scratch1, SZ_PTR); //move result to scratch reg
2680+ pop_r(code, opts->gen.context_reg);
2681+ call(code, opts->gen.load_context);
2682+ retn(code);
2683+
2684+ opts->native_addr_and_sync = code->cur;
2685+ call(code, opts->gen.save_context);
2686+ push_r(code, opts->gen.scratch1);
2687+
2688+ xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_D);
2689+ call_args_abi(code, (code_ptr)sync_components, 2, opts->gen.context_reg, opts->gen.scratch1);
2690+ pop_r(code, RSI); //restore saved address from opts->gen.scratch1
2691+ push_r(code, RAX); //save context pointer for later
2692+ call_args(code, (code_ptr)get_native_address_trans, 2, RAX, RSI);
2693+ mov_rr(code, RAX, opts->gen.scratch1, SZ_PTR); //move result to scratch reg
2694+ pop_r(code, opts->gen.context_reg);
2695+ call(code, opts->gen.load_context);
2696+ retn(code);
2697+
2698+ opts->gen.handle_cycle_limit = code->cur;
2699+ cmp_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, sync_cycle), opts->gen.cycles, SZ_D);
2700+ code_ptr skip_sync = code->cur + 1;
2701+ jcc(code, CC_C, code->cur + 2);
2702+ opts->do_sync = code->cur;
2703+ push_r(code, opts->gen.scratch1);
2704+ push_r(code, opts->gen.scratch2);
2705+ call(code, opts->gen.save_context);
2706+ xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_D);
2707+ call_args_abi(code, (code_ptr)sync_components, 2, opts->gen.context_reg, opts->gen.scratch1);
2708+ mov_rr(code, RAX, opts->gen.context_reg, SZ_PTR);
2709+ call(code, opts->gen.load_context);
2710+ pop_r(code, opts->gen.scratch2);
2711+ pop_r(code, opts->gen.scratch1);
2712+ *skip_sync = code->cur - (skip_sync+1);
2713+ retn(code);
2714+
2715+ opts->gen.handle_code_write = (code_ptr)m68k_handle_code_write;
2716+
2717+ check_alloc_code(code, 256);
2718+ opts->gen.handle_align_error_write = code->cur;
2719+ code->cur += 256;
2720+ check_alloc_code(code, 256);
2721+ opts->gen.handle_align_error_read = code->cur;
2722+ code->cur += 256;
2723+
2724+ opts->read_16 = gen_mem_fun(&opts->gen, memmap, num_chunks, READ_16, NULL);
2725+ opts->read_8 = gen_mem_fun(&opts->gen, memmap, num_chunks, READ_8, NULL);
2726+ opts->write_16 = gen_mem_fun(&opts->gen, memmap, num_chunks, WRITE_16, NULL);
2727+ opts->write_8 = gen_mem_fun(&opts->gen, memmap, num_chunks, WRITE_8, NULL);
2728+
2729+ opts->read_32 = code->cur;
2730+ push_r(code, opts->gen.scratch1);
2731+ call(code, opts->read_16);
2732+ mov_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_W);
2733+ pop_r(code, opts->gen.scratch1);
2734+ push_r(code, opts->gen.scratch2);
2735+ add_ir(code, 2, opts->gen.scratch1, SZ_D);
2736+ call(code, opts->read_16);
2737+ pop_r(code, opts->gen.scratch2);
2738+ movzx_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_W, SZ_D);
2739+ shl_ir(code, 16, opts->gen.scratch2, SZ_D);
2740+ or_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_D);
2741+ retn(code);
2742+
2743+ opts->write_32_lowfirst = code->cur;
2744+ push_r(code, opts->gen.scratch2);
2745+ push_r(code, opts->gen.scratch1);
2746+ add_ir(code, 2, opts->gen.scratch2, SZ_D);
2747+ call(code, opts->write_16);
2748+ pop_r(code, opts->gen.scratch1);
2749+ pop_r(code, opts->gen.scratch2);
2750+ shr_ir(code, 16, opts->gen.scratch1, SZ_D);
2751+ jmp(code, opts->write_16);
2752+
2753+ opts->write_32_highfirst = code->cur;
2754+ push_r(code, opts->gen.scratch1);
2755+ push_r(code, opts->gen.scratch2);
2756+ shr_ir(code, 16, opts->gen.scratch1, SZ_D);
2757+ call(code, opts->write_16);
2758+ pop_r(code, opts->gen.scratch2);
2759+ pop_r(code, opts->gen.scratch1);
2760+ add_ir(code, 2, opts->gen.scratch2, SZ_D);
2761+ jmp(code, opts->write_16);
2762+
2763+ opts->get_sr = code->cur;
2764+ mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, status), opts->gen.scratch1, SZ_B);
2765+ shl_ir(code, 8, opts->gen.scratch1, SZ_W);
2766+ if (opts->flag_regs[FLAG_X] >= 0) {
2767+ mov_rr(code, opts->flag_regs[FLAG_X], opts->gen.scratch1, SZ_B);
2768+ } else {
2769+ int8_t offset = offsetof(m68k_context, flags);
2770+ if (offset) {
2771+ mov_rdispr(code, opts->gen.context_reg, offset, opts->gen.scratch1, SZ_B);
2772+ } else {
2773+ mov_rindr(code, opts->gen.context_reg, opts->gen.scratch1, SZ_B);
2774+ }
2775+ }
2776+ for (int flag = FLAG_N; flag <= FLAG_C; flag++)
2777+ {
2778+ shl_ir(code, 1, opts->gen.scratch1, SZ_B);
2779+ if (opts->flag_regs[flag] >= 0) {
2780+ or_rr(code, opts->flag_regs[flag], opts->gen.scratch1, SZ_B);
2781+ } else {
2782+ or_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, flags) + flag, opts->gen.scratch1, SZ_B);
2783+ }
2784+ }
2785+ retn(code);
2786+
2787+ opts->set_sr = code->cur;
2788+ for (int flag = FLAG_C; flag >= FLAG_X; flag--)
2789+ {
2790+ rcr_ir(code, 1, opts->gen.scratch1, SZ_B);
2791+ if (opts->flag_regs[flag] >= 0) {
2792+ setcc_r(code, CC_C, opts->flag_regs[flag]);
2793+ } else {
2794+ int8_t offset = offsetof(m68k_context, flags) + flag;
2795+ if (offset) {
2796+ setcc_rdisp(code, CC_C, opts->gen.context_reg, offset);
2797+ } else {
2798+ setcc_rind(code, CC_C, opts->gen.context_reg);
2799+ }
2800+ }
2801+ }
2802+ shr_ir(code, 8, opts->gen.scratch1, SZ_W);
2803+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
2804+ //set int pending flag in case we trigger an interrupt as a result of the mask change
2805+ mov_irdisp(code, INT_PENDING_SR_CHANGE, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
2806+ retn(code);
2807+
2808+ opts->set_ccr = code->cur;
2809+ for (int flag = FLAG_C; flag >= FLAG_X; flag--)
2810+ {
2811+ rcr_ir(code, 1, opts->gen.scratch1, SZ_B);
2812+ if (opts->flag_regs[flag] >= 0) {
2813+ setcc_r(code, CC_C, opts->flag_regs[flag]);
2814+ } else {
2815+ int8_t offset = offsetof(m68k_context, flags) + flag;
2816+ if (offset) {
2817+ setcc_rdisp(code, CC_C, opts->gen.context_reg, offset);
2818+ } else {
2819+ setcc_rind(code, CC_C, opts->gen.context_reg);
2820+ }
2821+ }
2822+ }
2823+ retn(code);
2824+
2825+ code_info tmp_code = *code;
2826+ code->cur = opts->gen.handle_align_error_write;
2827+ code->last = code->cur + 256;
2828+ //unwind the stack one functinon call
2829+ add_ir(code, 16, RSP, SZ_PTR);
2830+ //save address that triggered error so we can write it to the 68K stack at the appropriate place
2831+ push_r(code, opts->gen.scratch2);
2832+ //swap USP and SSP if not already in supervisor mode
2833+ check_user_mode_swap_ssp_usp(opts);
2834+ //save PC
2835+ subi_areg(opts, 4, 7);
2836+ areg_to_native(opts, 7, opts->gen.scratch2);
2837+ mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, last_prefetch_address), opts->gen.scratch1, SZ_D);
2838+ call(code, opts->write_32_lowfirst);
2839+ //save status register
2840+ subi_areg(opts, 2, 7);
2841+ call(code, opts->get_sr);
2842+ areg_to_native(opts, 7, opts->gen.scratch2);
2843+ call(code, opts->write_16);
2844+ //save instruction register
2845+ subi_areg(opts, 2, 7);
2846+ //calculate IR
2847+ push_r(code, opts->gen.context_reg);
2848+ call(code, opts->gen.save_context);
2849+ call_args_abi(code, (code_ptr)m68k_get_ir, 1, opts->gen.context_reg);
2850+ mov_rr(code, RAX, opts->gen.scratch1, SZ_W);
2851+ pop_r(code, opts->gen.context_reg);
2852+ pop_r(code, opts->gen.scratch2); //access address
2853+ push_r(code, RAX); //save it for use in the "info" word
2854+ push_r(code, opts->gen.scratch2); //access address
2855+ call(code, opts->gen.load_context);
2856+ //write it to the stack
2857+ areg_to_native(opts, 7, opts->gen.scratch2);
2858+ call(code, opts->write_16);
2859+ //save access address
2860+ subi_areg(opts, 4, 7);
2861+ pop_r(code, opts->gen.scratch1);
2862+ areg_to_native(opts, 7, opts->gen.scratch2);
2863+ call(code, opts->write_32_lowfirst);
2864+ //save FC, I/N and R/W word'
2865+ xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_W);
2866+ //FC3 is basically the same as the supervisor bit
2867+ mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, status), opts->gen.scratch1, SZ_B);
2868+ shr_ir(code, 3, opts->gen.scratch1, SZ_B);
2869+ and_ir(code, 4, opts->gen.scratch1, SZ_B);
2870+ //set FC0 to one to indicate data access
2871+ or_ir(code, 1, opts->gen.scratch1, SZ_B);
2872+ //set undefined bits to IR value
2873+ pop_r(code, opts->gen.scratch2);
2874+ and_ir(code, 0xFFE0, opts->gen.scratch2, SZ_W);
2875+ or_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_W);
2876+ subi_areg(opts, 2, 7);
2877+ areg_to_native(opts, 7, opts->gen.scratch2);
2878+ call(code, opts->write_16);
2879+ //set supervisor bit
2880+ or_irdisp(code, 0x20, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
2881+ //load vector address
2882+ mov_ir(code, 4 * VECTOR_ADDRESS_ERROR, opts->gen.scratch1, SZ_D);
2883+ call(code, opts->read_32);
2884+ call(code, opts->native_addr_and_sync);
2885+ cycles(&opts->gen, 18);
2886+ jmp_r(code, opts->gen.scratch1);
2887+
2888+ code->cur = opts->gen.handle_align_error_read;
2889+ code->last = code->cur + 256;
2890+ //unwind the stack one functinon call
2891+ add_ir(code, 16, RSP, SZ_PTR);
2892+ //save address that triggered error so we can write it to the 68K stack at the appropriate place
2893+ push_r(code, opts->gen.scratch1);
2894+ //swap USP and SSP if not already in supervisor mode
2895+ check_user_mode_swap_ssp_usp(opts);
2896+ //save PC
2897+ subi_areg(opts, 4, 7);
2898+ areg_to_native(opts, 7, opts->gen.scratch2);
2899+ mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, last_prefetch_address), opts->gen.scratch1, SZ_D);
2900+ call(code, opts->write_32_lowfirst);
2901+ //save status register
2902+ subi_areg(opts, 2, 7);
2903+ call(code, opts->get_sr);
2904+ areg_to_native(opts, 7, opts->gen.scratch2);
2905+ call(code, opts->write_16);
2906+ //save instruction register
2907+ subi_areg(opts, 2, 7);
2908+ //calculate IR
2909+ push_r(code, opts->gen.context_reg);
2910+ call(code, opts->gen.save_context);
2911+ call_args_abi(code, (code_ptr)m68k_get_ir, 1, opts->gen.context_reg);
2912+ mov_rr(code, RAX, opts->gen.scratch1, SZ_W);
2913+ pop_r(code, opts->gen.context_reg);
2914+ pop_r(code, opts->gen.scratch2); //access address
2915+ push_r(code, RAX); //save it for use in the "info" word
2916+ push_r(code, opts->gen.scratch2); //access address
2917+ call(code, opts->gen.load_context);
2918+ //write it to the stack
2919+ areg_to_native(opts, 7, opts->gen.scratch2);
2920+ call(code, opts->write_16);
2921+ //save access address
2922+ subi_areg(opts, 4, 7);
2923+ pop_r(code, opts->gen.scratch1);
2924+ areg_to_native(opts, 7, opts->gen.scratch2);
2925+ call(code, opts->write_32_lowfirst);
2926+ //save FC, I/N and R/W word'
2927+ xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_W);
2928+ //FC3 is basically the same as the supervisor bit
2929+ mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, status), opts->gen.scratch1, SZ_B);
2930+ shr_ir(code, 3, opts->gen.scratch1, SZ_B);
2931+ and_ir(code, 4, opts->gen.scratch1, SZ_B);
2932+ //set FC0 to one to indicate data access, and R/W to indicate read
2933+ or_ir(code, 0x11, opts->gen.scratch1, SZ_B);
2934+ //set undefined bits to IR value
2935+ pop_r(code, opts->gen.scratch2);
2936+ and_ir(code, 0xFFE0, opts->gen.scratch2, SZ_W);
2937+ or_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_W);
2938+ subi_areg(opts, 2, 7);
2939+ areg_to_native(opts, 7, opts->gen.scratch2);
2940+ call(code, opts->write_16);
2941+ //set supervisor bit
2942+ or_irdisp(code, 0x20, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
2943+ //load vector address
2944+ mov_ir(code, 4 * VECTOR_ADDRESS_ERROR, opts->gen.scratch1, SZ_D);
2945+ call(code, opts->read_32);
2946+ call(code, opts->native_addr_and_sync);
2947+ cycles(&opts->gen, 18);
2948+ jmp_r(code, opts->gen.scratch1);
2949+
2950+ *code = tmp_code;
2951+
2952+ opts->gen.handle_cycle_limit_int = code->cur;
2953+ //calculate stack adjust size
2954+ add_ir(code, 16-sizeof(void*), RSP, SZ_PTR);
2955+ uint32_t adjust_size = code->cur - opts->gen.handle_cycle_limit_int;
2956+ code->cur = opts->gen.handle_cycle_limit_int;
2957+ //handle trace mode
2958+ cmp_irdisp(code, 0, opts->gen.context_reg, offsetof(m68k_context, trace_pending), SZ_B);
2959+ code_ptr do_trace = code->cur + 1;
2960+ jcc(code, CC_NZ, do_trace);
2961+ bt_irdisp(code, 7, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
2962+ code_ptr no_trace = code->cur + 1;
2963+ jcc(code, CC_NC, no_trace);
2964+ mov_irdisp(code, 1, opts->gen.context_reg, offsetof(m68k_context, trace_pending), SZ_B);
2965+ *no_trace = code->cur - (no_trace + 1);
2966+ //handle interrupts
2967+ cmp_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_cycle), opts->gen.cycles, SZ_D);
2968+ code_ptr do_int = code->cur + 2;
2969+ jcc(code, CC_NC, do_int+512);//force 32-bit displacement
2970+ //handle component synchronization
2971+ cmp_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, sync_cycle), opts->gen.cycles, SZ_D);
2972+ skip_sync = code->cur + 1;
2973+ jcc(code, CC_C, code->cur + 2);
2974+ call(code, opts->gen.save_context);
2975+ call_args_abi(code, (code_ptr)sync_components, 2, opts->gen.context_reg, opts->gen.scratch1);
2976+ mov_rr(code, RAX, opts->gen.context_reg, SZ_PTR);
2977+ jmp(code, opts->gen.load_context);
2978+ *skip_sync = code->cur - (skip_sync+1);
2979+ cmp_irdisp(code, 0, opts->gen.context_reg, offsetof(m68k_context, should_return), SZ_B);
2980+ code_ptr do_ret = code->cur + 1;
2981+ jcc(code, CC_NZ, do_ret);
2982+ retn(code);
2983+ *do_ret = code->cur - (do_ret+1);
2984+ uint32_t tmp_stack_off = code->stack_off;
2985+ //fetch return address and adjust RSP
2986+ pop_r(code, opts->gen.scratch1);
2987+ add_ir(code, 16-sizeof(void *), RSP, SZ_PTR);
2988+ add_ir(code, adjust_size, opts->gen.scratch1, SZ_PTR);
2989+ //save return address for restoring later
2990+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, resume_pc), SZ_PTR);
2991+ retn(code);
2992+ code->stack_off = tmp_stack_off;
2993+ *do_trace = code->cur - (do_trace + 1);
2994+ //clear out trace pending flag
2995+ mov_irdisp(code, 0, opts->gen.context_reg, offsetof(m68k_context, trace_pending), SZ_B);
2996+ //save PC as stored in scratch1 for later
2997+ push_r(code, opts->gen.scratch1);
2998+ //swap USP and SSP if not already in supervisor mode
2999+ check_user_mode_swap_ssp_usp(opts);
3000+ //save status register
3001+ subi_areg(opts, 6, 7);
3002+ call(code, opts->get_sr);
3003+ cycles(&opts->gen, 6);
3004+ //save SR to stack
3005+ areg_to_native(opts, 7, opts->gen.scratch2);
3006+ call(code, opts->write_16);
3007+ //update the status register
3008+ and_irdisp(code, 0x7F, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
3009+ or_irdisp(code, 0x20, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
3010+ //save PC
3011+ areg_to_native(opts, 7, opts->gen.scratch2);
3012+ add_ir(code, 2, opts->gen.scratch2, SZ_D);
3013+ pop_r(code, opts->gen.scratch1);
3014+ call(code, opts->write_32_lowfirst);
3015+ //read vector
3016+ mov_ir(code, 0x24, opts->gen.scratch1, SZ_D);
3017+ call(code, opts->read_32);
3018+ call(code, opts->native_addr_and_sync);
3019+ //2 prefetch bus operations + 2 idle bus cycles
3020+ cycles(&opts->gen, 10);
3021+ //discard function return address
3022+ pop_r(code, opts->gen.scratch2);
3023+ add_ir(code, 16-sizeof(void *), RSP, SZ_PTR);
3024+ jmp_r(code, opts->gen.scratch1);
3025+
3026+ code->stack_off = tmp_stack_off;
3027+
3028+ *((uint32_t *)do_int) = code->cur - (do_int+4);
3029+ //implement 1 instruction latency
3030+ cmp_irdisp(code, INT_PENDING_NONE, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
3031+ do_int = code->cur + 1;
3032+ jcc(code, CC_NZ, do_int);
3033+ //store current interrupt number so it doesn't change before we start processing the vector
3034+ mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_num), opts->gen.scratch1, SZ_B);
3035+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
3036+ retn(code);
3037+ *do_int = code->cur - (do_int + 1);
3038+ //Check if int_pending has an actual interrupt priority in it
3039+ cmp_irdisp(code, INT_PENDING_SR_CHANGE, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
3040+ code_ptr already_int_num = code->cur + 1;
3041+ jcc(code, CC_NZ, already_int_num);
3042+
3043+ mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_num), opts->gen.scratch2, SZ_B);
3044+ mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
3045+
3046+ *already_int_num = code->cur - (already_int_num + 1);
3047+ //save PC as stored in scratch1 for later
3048+ push_r(code, opts->gen.scratch1);
3049+ //set target cycle to sync cycle
3050+ mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, sync_cycle), opts->gen.limit, SZ_D);
3051+ //swap USP and SSP if not already in supervisor mode
3052+ check_user_mode_swap_ssp_usp(opts);
3053+ //save status register
3054+ subi_areg(opts, 6, 7);
3055+ call(code, opts->get_sr);
3056+ //6 cycles before SR gets saved
3057+ cycles(&opts->gen, 6);
3058+ //save SR to stack
3059+ areg_to_native(opts, 7, opts->gen.scratch2);
3060+ call(code, opts->write_16);
3061+ //interrupt ack cycle
3062+ //the Genesis responds to these exclusively with !VPA which means its a slow
3063+ //6800 operation. documentation says these can take between 10 and 19 cycles.
3064+ //actual results measurements seem to suggest it's actually between 9 and 18
3065+ //WARNING: this code might break with register assignment changes
3066+ //save RDX
3067+ push_r(code, RDX);
3068+ //save cycle count
3069+ mov_rr(code, RAX, opts->gen.scratch1, SZ_D);
3070+ //clear top doubleword of dividend
3071+ xor_rr(code, RDX, RDX, SZ_D);
3072+ //set divisor to clock divider
3073+ mov_ir(code, opts->gen.clock_divider, opts->gen.scratch2, SZ_D);
3074+ div_r(code, opts->gen.scratch2, SZ_D);
3075+ //discard remainder
3076+ xor_rr(code, RDX, RDX, SZ_D);
3077+ //set divisor to 10, the period of E
3078+ mov_ir(code, 10, opts->gen.scratch2, SZ_D);
3079+ div_r(code, opts->gen.scratch2, SZ_D);
3080+ //delay will be (9 + 4 + the remainder) * clock_divider
3081+ //the extra 4 is to cover the idle bus period after the ack
3082+ add_ir(code, 9 + 4, RDX, SZ_D);
3083+ mov_ir(code, opts->gen.clock_divider, RAX, SZ_D);
3084+ mul_r(code, RDX, SZ_D);
3085+ pop_r(code, RDX);
3086+ //add saved cycle count to result
3087+ add_rr(code, opts->gen.scratch1, RAX, SZ_D);
3088+
3089+ //update status register
3090+ and_irdisp(code, 0x78, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
3091+ mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_num), opts->gen.scratch1, SZ_B);
3092+ //clear trace pending flag
3093+ mov_irdisp(code, 0, opts->gen.context_reg, offsetof(m68k_context, trace_pending), SZ_B);
3094+ //need to separate int priority and interrupt vector, but for now mask out large interrupt numbers
3095+ and_ir(code, 0x7, opts->gen.scratch1, SZ_B);
3096+ or_ir(code, 0x20, opts->gen.scratch1, SZ_B);
3097+ or_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
3098+
3099+ pop_r(code, opts->gen.scratch1);
3100+
3101+ //save PC
3102+ areg_to_native(opts, 7, opts->gen.scratch2);
3103+ add_ir(code, 2, opts->gen.scratch2, SZ_D);
3104+ call(code, opts->write_32_lowfirst);
3105+
3106+ //grab saved interrupt number
3107+ xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_D);
3108+ mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_pending), opts->gen.scratch1, SZ_B);
3109+ //ack the interrupt (happens earlier on hardware, but shouldn't be an observable difference)
3110+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, int_ack), SZ_W);
3111+ //calculate the vector address
3112+ shl_ir(code, 2, opts->gen.scratch1, SZ_D);
3113+ add_ir(code, 0x60, opts->gen.scratch1, SZ_D);
3114+ //clear out pending flag
3115+ mov_irdisp(code, INT_PENDING_NONE, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
3116+ //read vector
3117+ call(code, opts->read_32);
3118+ call(code, opts->native_addr_and_sync);
3119+ //2 prefetch bus operations + 2 idle bus cycles
3120+ cycles(&opts->gen, 10);
3121+ tmp_stack_off = code->stack_off;
3122+ //discard function return address
3123+ pop_r(code, opts->gen.scratch2);
3124+ add_ir(code, 16-sizeof(void *), RSP, SZ_PTR);
3125+ jmp_r(code, opts->gen.scratch1);
3126+ code->stack_off = tmp_stack_off;
3127+
3128+ opts->handle_int_latch = code->cur;
3129+ cmp_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_cycle), opts->gen.cycles, SZ_D);
3130+ code_ptr do_latch = code->cur + 1;
3131+ jcc(code, CC_NC, do_latch);
3132+ retn(code);
3133+ *do_latch = code->cur - (do_latch + 1);
3134+ cmp_irdisp(code, INT_PENDING_NONE, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
3135+ do_latch = code->cur + 1;
3136+ jcc(code, CC_Z, do_latch);
3137+ retn(code);
3138+ *do_latch = code->cur - (do_latch + 1);
3139+ //store current interrupt number so it doesn't change before we start processing the vector
3140+ push_r(code, opts->gen.scratch1);
3141+ mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_num), opts->gen.scratch1, SZ_B);
3142+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B);
3143+ pop_r(code, opts->gen.scratch1);
3144+ retn(code);
3145+
3146+ opts->trap = code->cur;
3147+ push_r(code, opts->gen.scratch2);
3148+ //swap USP and SSP if not already in supervisor mode
3149+ check_user_mode_swap_ssp_usp(opts);
3150+ //save PC
3151+ subi_areg(opts, 4, 7);
3152+ areg_to_native(opts, 7, opts->gen.scratch2);
3153+ call(code, opts->write_32_lowfirst);
3154+ //save status register
3155+ subi_areg(opts, 2, 7);
3156+ call(code, opts->get_sr);
3157+ areg_to_native(opts, 7, opts->gen.scratch2);
3158+ call(code, opts->write_16);
3159+ //set supervisor bit
3160+ or_irdisp(code, 0x20, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
3161+ //clear trace bit
3162+ and_irdisp(code, 0x7F, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B);
3163+ mov_irdisp(code, 0, opts->gen.context_reg, offsetof(m68k_context, trace_pending), SZ_B);
3164+ //calculate vector address
3165+ pop_r(code, opts->gen.scratch1);
3166+ shl_ir(code, 2, opts->gen.scratch1, SZ_D);
3167+ call(code, opts->read_32);
3168+ call(code, opts->native_addr_and_sync);
3169+ cycles(&opts->gen, 18);
3170+ jmp_r(code, opts->gen.scratch1);
3171+
3172+ opts->retrans_stub = code->cur;
3173+ call(code, opts->gen.save_context);
3174+ push_r(code, opts->gen.context_reg);
3175+ call_args(code,(code_ptr)m68k_retranslate_inst, 2, opts->gen.scratch1, opts->gen.context_reg);
3176+ pop_r(code, opts->gen.context_reg);
3177+ mov_rr(code, RAX, opts->gen.scratch1, SZ_PTR);
3178+ call(code, opts->gen.load_context);
3179+ jmp_r(code, opts->gen.scratch1);
3180+
3181+
3182+ check_code_prologue(code);
3183+ opts->bp_stub = code->cur;
3184+
3185+ tmp_stack_off = code->stack_off;
3186+ //Calculate length of prologue
3187+ check_cycles_int(&opts->gen, 0x1234);
3188+ int check_int_size = code->cur-opts->bp_stub;
3189+ code->cur = opts->bp_stub;
3190+ code->stack_off = tmp_stack_off;
3191+ opts->prologue_start = *opts->bp_stub;
3192+ //Calculate length of patch
3193+ mov_ir(code, 0x1234, opts->gen.scratch1, SZ_D);
3194+ call(code, opts->bp_stub);
3195+ int patch_size = code->cur - opts->bp_stub;
3196+ code->cur = opts->bp_stub;
3197+ code->stack_off = tmp_stack_off;
3198+
3199+ //Save context and call breakpoint handler
3200+ call(code, opts->gen.save_context);
3201+ push_r(code, opts->gen.scratch1);
3202+ call_args_abi(code, (code_ptr)m68k_bp_dispatcher, 2, opts->gen.context_reg, opts->gen.scratch1);
3203+ mov_rr(code, RAX, opts->gen.context_reg, SZ_PTR);
3204+ //Restore context
3205+ call(code, opts->gen.load_context);
3206+ pop_r(code, opts->gen.scratch1);
3207+ //do prologue stuff
3208+ cmp_rr(code, opts->gen.cycles, opts->gen.limit, SZ_D);
3209+ code_ptr jmp_off = code->cur + 1;
3210+ jcc(code, CC_NC, code->cur + 7);
3211+ call(code, opts->gen.handle_cycle_limit_int);
3212+ *jmp_off = code->cur - (jmp_off+1);
3213+ //jump back to body of translated instruction
3214+ pop_r(code, opts->gen.scratch1);
3215+ add_ir(code, check_int_size - patch_size, opts->gen.scratch1, SZ_PTR);
3216+ jmp_r(code, opts->gen.scratch1);
3217+ code->stack_off = tmp_stack_off;
3218+
3219+ retranslate_calc(&opts->gen);
3220+}
+115,
-0
1@@ -0,0 +1,115 @@
2+/*
3+ Copyright 2014 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#ifndef M68K_INTERNAL_H_
8+#define M68K_INTERNAL_H_
9+
10+#include "68kinst.h"
11+
12+//functions implemented in host CPU specfic file
13+void translate_out_of_bounds(m68k_options *opts, uint32_t address);
14+void areg_to_native(m68k_options *opts, uint8_t reg, uint8_t native_reg);
15+void dreg_to_native(m68k_options *opts, uint8_t reg, uint8_t native_reg);
16+void areg_to_native_sx(m68k_options *opts, uint8_t reg, uint8_t native_reg);
17+void dreg_to_native_sx(m68k_options *opts, uint8_t reg, uint8_t native_reg);
18+void native_to_areg(m68k_options *opts, uint8_t native_reg, uint8_t reg);
19+void native_to_dreg(m68k_options *opts, uint8_t native_reg, uint8_t reg);
20+void ldi_areg(m68k_options *opts, int32_t value, uint8_t reg);
21+void ldi_native(m68k_options *opts, int32_t value, uint8_t reg);
22+void addi_native(m68k_options *opts, int32_t value, uint8_t reg);
23+void subi_native(m68k_options *opts, int32_t value, uint8_t reg);
24+void push_native(m68k_options *opts, uint8_t reg);
25+void pop_native(m68k_options *opts, uint8_t reg);
26+void sign_extend16_native(m68k_options *opts, uint8_t reg);
27+void addi_areg(m68k_options *opts, int32_t val, uint8_t reg);
28+void subi_areg(m68k_options *opts, int32_t val, uint8_t reg);
29+void add_areg_native(m68k_options *opts, uint8_t reg, uint8_t native_reg);
30+void add_dreg_native(m68k_options *opts, uint8_t reg, uint8_t native_reg);
31+void calc_areg_displace(m68k_options *opts, m68k_op_info *op, uint8_t native_reg);
32+void calc_index_disp8(m68k_options *opts, m68k_op_info *op, uint8_t native_reg);
33+void calc_areg_index_disp8(m68k_options *opts, m68k_op_info *op, uint8_t native_reg);
34+void nop_fill_or_jmp_next(code_info *code, code_ptr old_end, code_ptr next_inst);
35+void check_user_mode_swap_ssp_usp(m68k_options *opts);
36+void m68k_set_last_prefetch(m68k_options *opts, uint32_t address);
37+void translate_m68k_odd(m68k_options *opts, m68kinst *inst);
38+void m68k_trap_if_not_supervisor(m68k_options *opts, m68kinst *inst);
39+void m68k_breakpoint_patch(m68k_context *context, uint32_t address, m68k_debug_handler bp_handler, code_ptr native_addr);
40+void m68k_check_cycles_int_latch(m68k_options *opts);
41+uint8_t translate_m68k_op(m68kinst * inst, host_ea * ea, m68k_options * opts, uint8_t dst);
42+
43+//functions implemented in m68k_core.c
44+int8_t native_reg(m68k_op_info * op, m68k_options * opts);
45+size_t dreg_offset(uint8_t reg);
46+size_t areg_offset(uint8_t reg);
47+size_t reg_offset(m68k_op_info *op);
48+void m68k_read_size(m68k_options *opts, uint8_t size);
49+void m68k_write_size(m68k_options *opts, uint8_t size, uint8_t lowfirst);
50+void m68k_save_result(m68kinst * inst, m68k_options * opts);
51+void jump_m68k_abs(m68k_options * opts, uint32_t address);
52+void swap_ssp_usp(m68k_options * opts);
53+code_ptr get_native_address(m68k_options *opts, uint32_t address);
54+uint8_t m68k_is_terminal(m68kinst * inst);
55+code_ptr get_native_address_trans(m68k_context * context, uint32_t address);
56+void * m68k_retranslate_inst(uint32_t address, m68k_context * context);
57+m68k_context *m68k_bp_dispatcher(m68k_context *context, uint32_t address);
58+
59+//individual instructions
60+void translate_m68k_bcc(m68k_options * opts, m68kinst * inst);
61+void translate_m68k_scc(m68k_options * opts, m68kinst * inst);
62+void translate_m68k_dbcc(m68k_options * opts, m68kinst * inst);
63+void translate_m68k_trapv(m68k_options *opts, m68kinst *inst);
64+void translate_m68k_move(m68k_options * opts, m68kinst * inst);
65+void translate_m68k_movep(m68k_options * opts, m68kinst * inst);
66+void translate_m68k_arith(m68k_options *opts, m68kinst * inst, uint32_t flag_mask, host_ea *src_op, host_ea *dst_op);
67+void translate_m68k_unary(m68k_options *opts, m68kinst *inst, uint32_t flag_mask, host_ea *dst_op);
68+void translate_m68k_cmp(m68k_options * opts, m68kinst * inst);
69+void translate_m68k_tas(m68k_options * opts, m68kinst * inst);
70+void translate_m68k_ext(m68k_options * opts, m68kinst * inst);
71+void translate_m68k_abcd_sbcd(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op);
72+void translate_m68k_sl(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op);
73+void translate_m68k_asr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op);
74+void translate_m68k_lsr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op);
75+void translate_m68k_bit(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op);
76+void translate_m68k_chk(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op);
77+void translate_m68k_div(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op);
78+void translate_m68k_exg(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op);
79+void translate_m68k_mul(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op);
80+void translate_m68k_negx(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op);
81+void translate_m68k_rot(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op);
82+void translate_m68k_andi_ori_ccr_sr(m68k_options *opts, m68kinst *inst);
83+void translate_m68k_eori_ccr_sr(m68k_options *opts, m68kinst *inst);
84+void translate_m68k_move_ccr_sr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op);
85+void translate_m68k_stop(m68k_options *opts, m68kinst *inst);
86+void translate_m68k_move_from_sr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op);
87+void translate_m68k_reset(m68k_options *opts, m68kinst *inst);
88+
89+//flag update bits
90+#define X0 0x0001
91+#define X1 0x0002
92+#define X 0x0004
93+#define N0 0x0008
94+#define N1 0x0010
95+#define N 0x0020
96+#define Z0 0x0040
97+#define Z1 0x0080
98+#define Z 0x0100
99+#define V0 0x0200
100+#define V1 0x0400
101+#define V 0x0800
102+#define C0 0x1000
103+#define C1 0x2000
104+#define C 0x4000
105+
106+#define BUS 4
107+#define PREDEC_PENALTY 2
108+extern char disasm_buf[1024];
109+
110+m68k_context * sync_components(m68k_context * context, uint32_t address);
111+
112+void m68k_invalid();
113+void bcd_add();
114+void bcd_sub();
115+
116+#endif //M68K_INTERNAL_H_
+22,
-0
1@@ -0,0 +1,22 @@
2+#!/usr/bin/env python
3+from glob import glob
4+import subprocess
5+from sys import exit
6+
7+sources = set()
8+for path in glob('generated_tests/*/*.s68'):
9+ sources.add(path)
10+
11+bins = set()
12+for path in glob('generated_tests/*/*.bin'):
13+ bins.add(path)
14+
15+for path in sources:
16+ binpath = path.replace('.s68', '.bin')
17+ if not binpath in bins:
18+ print binpath
19+ res = subprocess.call(['vasmm68k_mot', '-Fbin', '-m68000', '-no-opt', '-spaces', '-o', binpath, path])
20+ if res != 0:
21+ print 'vasmm68k_mot returned non-zero status code', res
22+ exit(1)
23+
+427,
-0
1@@ -0,0 +1,427 @@
2+#include <stdlib.h>
3+#include <stdint.h>
4+#include <string.h>
5+#include <sys/types.h>
6+#include <sys/socket.h>
7+#include <unistd.h>
8+#include <netinet/in.h>
9+#include <errno.h>
10+#include <fcntl.h>
11+#include "genesis.h"
12+#include "net.h"
13+
14+enum {
15+ TX_IDLE,
16+ TX_LEN1,
17+ TX_LEN2,
18+ TX_PAYLOAD,
19+ TX_WAIT_ETX
20+};
21+#define STX 0x7E
22+#define ETX 0x7E
23+#define MAX_RECV_SIZE 1440
24+
25+#define E(N) N
26+enum {
27+#include "mw_commands.c"
28+ CMD_ERROR = 255
29+};
30+#undef E
31+#define E(N) #N
32+static const char *cmd_names[] = {
33+#include "mw_commands.c"
34+ [255] = "CMD_ERROR"
35+};
36+
37+#ifndef MSG_NOSIGNAL
38+#define MSG_NOSIGNAL 0
39+#endif
40+
41+enum {
42+ STATE_IDLE=1,
43+ STATE_AP_JOIN,
44+ STATE_SCAN,
45+ STATE_READY,
46+ STATE_TRANSPARENT
47+};
48+
49+#define FLAG_ONLINE
50+
51+typedef struct {
52+ uint32_t transmit_bytes;
53+ uint32_t expected_bytes;
54+ uint32_t receive_bytes;
55+ uint32_t receive_read;
56+ int sock_fds[15];
57+ uint16_t channel_flags;
58+ uint8_t channel_state[15];
59+ uint8_t scratchpad;
60+ uint8_t transmit_channel;
61+ uint8_t transmit_state;
62+ uint8_t module_state;
63+ uint8_t flags;
64+ uint8_t transmit_buffer[4096];
65+ uint8_t receive_buffer[4096];
66+} megawifi;
67+
68+static megawifi *get_megawifi(void *context)
69+{
70+ m68k_context *m68k = context;
71+ genesis_context *gen = m68k->system;
72+ if (!gen->extra) {
73+ gen->extra = calloc(1, sizeof(megawifi));
74+ megawifi *mw = gen->extra;
75+ mw->module_state = STATE_IDLE;
76+ for (int i = 0; i < 15; i++)
77+ {
78+ mw->sock_fds[i] = -1;
79+ }
80+ }
81+ return gen->extra;
82+}
83+
84+static void mw_putc(megawifi *mw, uint8_t v)
85+{
86+ if (mw->receive_bytes == sizeof(mw->receive_buffer)) {
87+ return;
88+ }
89+ mw->receive_buffer[mw->receive_bytes++] = v;
90+}
91+
92+static void mw_set(megawifi *mw, uint8_t val, uint32_t count)
93+{
94+ if (count + mw->receive_bytes > sizeof(mw->receive_buffer)) {
95+ count = sizeof(mw->receive_buffer) - mw->receive_bytes;
96+ }
97+ memset(mw->receive_buffer + mw->receive_bytes, val, count);
98+ mw->receive_bytes += count;
99+}
100+
101+static void mw_copy(megawifi *mw, const uint8_t *src, uint32_t count)
102+{
103+ if (count + mw->receive_bytes > sizeof(mw->receive_buffer)) {
104+ count = sizeof(mw->receive_buffer) - mw->receive_bytes;
105+ }
106+ memcpy(mw->receive_buffer + mw->receive_bytes, src, count);
107+ mw->receive_bytes += count;
108+}
109+
110+static void mw_puts(megawifi *mw, char *s)
111+{
112+ uint32_t len = strlen(s);
113+ if ((mw->receive_bytes + len) > sizeof(mw->receive_buffer)) {
114+ return;
115+ }
116+ memcpy(mw->receive_buffer + mw->receive_bytes, s, len);
117+ mw->receive_bytes += len;
118+}
119+
120+static void poll_socket(megawifi *mw, uint8_t channel)
121+{
122+ if (mw->sock_fds[channel] < 0) {
123+ return;
124+ }
125+ if (mw->channel_state[channel] == 1) {
126+ int res = accept(mw->sock_fds[channel], NULL, NULL);
127+ if (res >= 0) {
128+ close(mw->sock_fds[channel]);
129+ fcntl(res, F_SETFL, O_NONBLOCK);
130+ mw->sock_fds[channel] = res;
131+ mw->channel_state[channel] = 2;
132+ mw->channel_flags |= 1 << (channel + 1);
133+ } else if (errno != EAGAIN && errno != EWOULDBLOCK) {
134+ close(mw->sock_fds[channel]);
135+ mw->channel_state[channel] = 0;
136+ mw->channel_flags |= 1 << (channel + 1);
137+ }
138+ } else if (mw->channel_state[channel] == 2 && mw->receive_bytes < sizeof(mw->receive_buffer) - 4) {
139+ size_t max = sizeof(mw->receive_buffer) - 4 - mw->receive_bytes;
140+ if (max > MAX_RECV_SIZE) {
141+ max = MAX_RECV_SIZE;
142+ }
143+ int bytes = recv(mw->sock_fds[channel], mw->receive_buffer + mw->receive_bytes + 3, max, 0);
144+ if (bytes > 0) {
145+ mw_putc(mw, STX);
146+ mw_putc(mw, bytes >> 8 | (channel+1) << 4);
147+ mw_putc(mw, bytes);
148+ mw->receive_bytes += bytes;
149+ mw_putc(mw, ETX);
150+ //should this set the channel flag?
151+ } else if (bytes < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
152+ close(mw->sock_fds[channel]);
153+ mw->channel_state[channel] = 0;
154+ mw->channel_flags |= 1 << (channel + 1);
155+ }
156+ }
157+}
158+
159+static void poll_all_sockets(megawifi *mw)
160+{
161+ for (int i = 0; i < 15; i++)
162+ {
163+ poll_socket(mw, i);
164+ }
165+}
166+
167+static void start_reply(megawifi *mw, uint8_t cmd)
168+{
169+ mw_putc(mw, STX);
170+ //reserve space for length
171+ mw->receive_bytes += 2;
172+ //cmd
173+ mw_putc(mw, 0);
174+ mw_putc(mw, cmd);
175+ //reserve space for length
176+ mw->receive_bytes += 2;
177+}
178+
179+static void end_reply(megawifi *mw)
180+{
181+ uint32_t len = mw->receive_bytes - 3;
182+ //LSD packet length
183+ mw->receive_buffer[1] = len >> 8;
184+ mw->receive_buffer[2] = len;
185+ //command length
186+ len -= 4;
187+ mw->receive_buffer[5] = len >> 8;
188+ mw->receive_buffer[6] = len;
189+ mw_putc(mw, ETX);
190+}
191+
192+static void process_packet(megawifi *mw)
193+{
194+ if (mw->transmit_channel == 0) {
195+ uint32_t command = mw->transmit_buffer[0] << 8 | mw->transmit_buffer[1];
196+ uint32_t size = mw->transmit_buffer[2] << 8 | mw->transmit_buffer[3];
197+ if (size > mw->transmit_bytes - 4) {
198+ size = mw->transmit_bytes - 4;
199+ }
200+ int orig_receive_bytes = mw->receive_bytes;
201+ switch (command)
202+ {
203+ case CMD_VERSION:
204+ start_reply(mw, CMD_OK);
205+ mw_putc(mw, 1);
206+ mw_putc(mw, 0);
207+ mw_puts(mw, "blastem");
208+ end_reply(mw);
209+ break;
210+ case CMD_ECHO:
211+ mw->receive_bytes = mw->transmit_bytes;
212+ memcpy(mw->receive_buffer, mw->transmit_buffer, mw->transmit_bytes);
213+ break;
214+ case CMD_IP_CURRENT: {
215+ iface_info i;
216+ if (get_host_address(&i)) {
217+ start_reply(mw, CMD_OK);
218+ //config number and reserved bytes
219+ mw_set(mw, 0, 4);
220+ //ip
221+ mw_copy(mw, i.ip, sizeof(i.ip));
222+ //net mask
223+ mw_copy(mw, i.net_mask, sizeof(i.net_mask));
224+ //gateway guess
225+ mw_putc(mw, i.ip[0] & i.net_mask[0]);
226+ mw_putc(mw, i.ip[1] & i.net_mask[1]);
227+ mw_putc(mw, i.ip[2] & i.net_mask[2]);
228+ mw_putc(mw, (i.ip[3] & i.net_mask[3]) + 1);
229+ //dns
230+ static const uint8_t localhost[] = {127,0,0,1};
231+ mw_copy(mw, localhost, sizeof(localhost));
232+ mw_copy(mw, localhost, sizeof(localhost));
233+
234+ } else {
235+ start_reply(mw, CMD_ERROR);
236+ }
237+ end_reply(mw);
238+ break;
239+ }
240+ case CMD_AP_JOIN:
241+ mw->module_state = STATE_READY;
242+ start_reply(mw, CMD_OK);
243+ end_reply(mw);
244+ break;
245+ case CMD_TCP_BIND:{
246+ if (size < 7){
247+ start_reply(mw, CMD_ERROR);
248+ end_reply(mw);
249+ break;
250+ }
251+ uint8_t channel = mw->transmit_buffer[10];
252+ if (!channel || channel > 15) {
253+ start_reply(mw, CMD_ERROR);
254+ end_reply(mw);
255+ break;
256+ }
257+ channel--;
258+ if (mw->sock_fds[channel] >= 0) {
259+ close(mw->sock_fds[channel]);
260+ }
261+ mw->sock_fds[channel] = socket(AF_INET, SOCK_STREAM, 0);
262+ if (mw->sock_fds[channel] < 0) {
263+ start_reply(mw, CMD_ERROR);
264+ end_reply(mw);
265+ break;
266+ }
267+ int value = 1;
268+ setsockopt(mw->sock_fds[channel], SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value));
269+ struct sockaddr_in bind_addr;
270+ memset(&bind_addr, 0, sizeof(bind_addr));
271+ bind_addr.sin_family = AF_INET;
272+ bind_addr.sin_port = htons(mw->transmit_buffer[8] << 8 | mw->transmit_buffer[9]);
273+ if (bind(mw->sock_fds[channel], (struct sockaddr *)&bind_addr, sizeof(bind_addr)) != 0) {
274+ close(mw->sock_fds[channel]);
275+ mw->sock_fds[channel] = -1;
276+ start_reply(mw, CMD_ERROR);
277+ end_reply(mw);
278+ break;
279+ }
280+ int res = listen(mw->sock_fds[channel], 2);
281+ start_reply(mw, res ? CMD_ERROR : CMD_OK);
282+ if (res) {
283+ close(mw->sock_fds[channel]);
284+ mw->sock_fds[channel] = -1;
285+ } else {
286+ mw->channel_flags |= 1 << (channel + 1);
287+ mw->channel_state[channel] = 1;
288+ fcntl(mw->sock_fds[channel], F_SETFL, O_NONBLOCK);
289+ }
290+ end_reply(mw);
291+ break;
292+ }
293+ case CMD_SOCK_STAT: {
294+ uint8_t channel = mw->transmit_buffer[4];
295+ if (!channel || channel > 15) {
296+ start_reply(mw, CMD_ERROR);
297+ end_reply(mw);
298+ break;
299+ }
300+ mw->channel_flags &= ~(1 << channel);
301+ channel--;
302+ poll_socket(mw, channel);
303+ start_reply(mw, CMD_OK);
304+ mw_putc(mw, mw->channel_state[channel]);
305+ end_reply(mw);
306+ break;
307+ }
308+ case CMD_SYS_STAT:
309+ poll_all_sockets(mw);
310+ start_reply(mw, CMD_OK);
311+ mw_putc(mw, mw->module_state);
312+ mw_putc(mw, mw->flags);
313+ mw_putc(mw, mw->channel_flags >> 8);
314+ mw_putc(mw, mw->channel_flags);
315+ end_reply(mw);
316+ break;
317+ default:
318+ printf("Unhandled MegaWiFi command %s(%d) with length %X\n", cmd_names[command], command, size);
319+ break;
320+ }
321+ } else if (mw->sock_fds[mw->transmit_channel - 1] >= 0 && mw->channel_state[mw->transmit_channel - 1] == 2) {
322+ uint8_t channel = mw->transmit_channel - 1;
323+ int sent = send(mw->sock_fds[channel], mw->transmit_buffer, mw->transmit_bytes, MSG_NOSIGNAL);
324+ if (sent < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
325+ close(mw->sock_fds[channel]);
326+ mw->sock_fds[channel] = -1;
327+ mw->channel_state[channel] = 0;
328+ mw->channel_flags |= 1 << mw->transmit_channel;
329+ } else if (sent < mw->transmit_bytes) {
330+ //TODO: save this data somewhere so it can be sent in poll_socket
331+ printf("Sent %d bytes on channel %d, but %d were requested\n", sent, mw->transmit_channel, mw->transmit_bytes);
332+ }
333+ } else {
334+ printf("Unhandled receive of MegaWiFi data on channel %d\n", mw->transmit_channel);
335+ }
336+ mw->transmit_bytes = mw->expected_bytes = 0;
337+}
338+
339+void *megawifi_write_b(uint32_t address, void *context, uint8_t value)
340+{
341+ if (!(address & 1)) {
342+ return context;
343+ }
344+ megawifi *mw = get_megawifi(context);
345+ address = address >> 1 & 7;
346+ switch (address)
347+ {
348+ case 0:
349+ switch (mw->transmit_state)
350+ {
351+ case TX_IDLE:
352+ if (value == STX) {
353+ mw->transmit_state = TX_LEN1;
354+ }
355+ break;
356+ case TX_LEN1:
357+ mw->transmit_channel = value >> 4;
358+ mw->expected_bytes = value << 8 & 0xF00;
359+ mw->transmit_state = TX_LEN2;
360+ break;
361+ case TX_LEN2:
362+ mw->expected_bytes |= value;
363+ mw->transmit_state = TX_PAYLOAD;
364+ break;
365+ case TX_PAYLOAD:
366+ mw->transmit_buffer[mw->transmit_bytes++] = value;
367+ if (mw->transmit_bytes == mw->expected_bytes) {
368+ mw->transmit_state = TX_WAIT_ETX;
369+ }
370+ break;
371+ case TX_WAIT_ETX:
372+ if (value == ETX) {
373+ mw->transmit_state = TX_IDLE;
374+ process_packet(mw);
375+ }
376+ break;
377+ }
378+ break;
379+ case 7:
380+ mw->scratchpad = value;
381+ break;
382+ default:
383+ printf("Unhandled write to MegaWiFi UART register %X: %X\n", address, value);
384+ }
385+ return context;
386+}
387+
388+void *megawifi_write_w(uint32_t address, void *context, uint16_t value)
389+{
390+ return megawifi_write_b(address | 1, context, value);
391+}
392+
393+uint8_t megawifi_read_b(uint32_t address, void *context)
394+{
395+
396+ if (!(address & 1)) {
397+ return 0xFF;
398+ }
399+ megawifi *mw = get_megawifi(context);
400+ address = address >> 1 & 7;
401+ switch (address)
402+ {
403+ case 0:
404+ poll_all_sockets(mw);
405+ if (mw->receive_read < mw->receive_bytes) {
406+ uint8_t ret = mw->receive_buffer[mw->receive_read++];
407+ if (mw->receive_read == mw->receive_bytes) {
408+ mw->receive_read = mw->receive_bytes = 0;
409+ }
410+ return ret;
411+ }
412+ return 0xFF;
413+ case 5:
414+ poll_all_sockets(mw);
415+ //line status
416+ return 0x60 | (mw->receive_read < mw->receive_bytes);
417+ case 7:
418+ return mw->scratchpad;
419+ default:
420+ printf("Unhandled read from MegaWiFi UART register %X\n", address);
421+ return 0xFF;
422+ }
423+}
424+
425+uint16_t megawifi_read_w(uint32_t address, void *context)
426+{
427+ return 0xFF00 | megawifi_read_b(address | 1, context);
428+}
+9,
-0
1@@ -0,0 +1,9 @@
2+#ifndef MEGAWIFI_H_
3+#define MEGAWIFI_H_
4+
5+void *megawifi_write_w(uint32_t address, void *context, uint16_t value);
6+void *megawifi_write_b(uint32_t address, void *context, uint8_t value);
7+uint16_t megawifi_read_w(uint32_t address, void *context);
8+uint8_t megawifi_read_b(uint32_t address, void *context);
9+
10+#endif //MEGAWIFI_H_
A
mem.c
+45,
-0
1@@ -0,0 +1,45 @@
2+/*
3+ Copyright 2013 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#include <sys/mman.h>
8+#include <stddef.h>
9+#include <stdint.h>
10+#include <stdlib.h>
11+#include <unistd.h>
12+#include <errno.h>
13+#include <stdio.h>
14+
15+#include "mem.h"
16+#include "arena.h"
17+#ifndef MAP_ANONYMOUS
18+#define MAP_ANONYMOUS MAP_ANON
19+#endif
20+
21+#ifndef MAP_32BIT
22+#define MAP_32BIT 0
23+#endif
24+
25+void * alloc_code(size_t *size)
26+{
27+ //start at the 1GB mark to allow plenty of room for sbrk based malloc implementations
28+ //while still keeping well within 32-bit displacement range for calling code compiled into the executable
29+ static uint8_t *next = (uint8_t *)0x40000000;
30+ uint8_t *ret = try_alloc_arena();
31+ if (ret) {
32+ return ret;
33+ }
34+ if (*size & (PAGE_SIZE -1)) {
35+ *size += PAGE_SIZE - (*size & (PAGE_SIZE - 1));
36+ }
37+ ret = mmap(next, *size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_32BIT, -1, 0);
38+ if (ret == MAP_FAILED) {
39+ perror("alloc_code");
40+ return NULL;
41+ }
42+ track_block(ret);
43+ next = ret + *size;
44+ return ret;
45+}
46+
A
mem.h
+16,
-0
1@@ -0,0 +1,16 @@
2+/*
3+ Copyright 2013 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#ifndef MEM_H_
8+#define MEM_H_
9+
10+#include <stddef.h>
11+
12+#define PAGE_SIZE 4096
13+
14+void * alloc_code(size_t *size);
15+
16+#endif //MEM_H_
17+
A
memmap.h
+41,
-0
1@@ -0,0 +1,41 @@
2+#ifndef MEMMAP_H_
3+#define MEMMAP_H_
4+
5+typedef enum {
6+ READ_16,
7+ READ_8,
8+ WRITE_16,
9+ WRITE_8
10+} ftype;
11+
12+#define MMAP_READ 0x01
13+#define MMAP_WRITE 0x02
14+#define MMAP_CODE 0x04
15+#define MMAP_PTR_IDX 0x08
16+#define MMAP_ONLY_ODD 0x10
17+#define MMAP_ONLY_EVEN 0x20
18+#define MMAP_FUNC_NULL 0x40
19+#define MMAP_BYTESWAP 0x80
20+#define MMAP_AUX_BUFF 0x100
21+#define MMAP_READ_CODE 0x200
22+
23+typedef uint16_t (*read_16_fun)(uint32_t address, void * context);
24+typedef uint8_t (*read_8_fun)(uint32_t address, void * context);
25+typedef void * (*write_16_fun)(uint32_t address, void * context, uint16_t value);
26+typedef void * (*write_8_fun)(uint32_t address, void * context, uint8_t value);
27+
28+typedef struct {
29+ uint32_t start;
30+ uint32_t end;
31+ uint32_t mask;
32+ uint32_t aux_mask;
33+ uint16_t ptr_index;
34+ uint16_t flags;
35+ void * buffer;
36+ read_16_fun read_16;
37+ write_16_fun write_16;
38+ read_8_fun read_8;
39+ write_8_fun write_8;
40+} memmap_chunk;
41+
42+#endif //MEMMAP_H_
1@@ -0,0 +1,260 @@
2+#include <stdint.h>
3+#include <stdlib.h>
4+#include <string.h>
5+#include <stdio.h>
6+#include <errno.h>
7+#include "genesis.h"
8+#include "menu.h"
9+#include "backend.h"
10+#include "util.h"
11+#include "gst.h"
12+#include "paths.h"
13+#include "saves.h"
14+#include "config.h"
15+
16+static menu_context *get_menu(genesis_context *gen)
17+{
18+ menu_context *menu = gen->extra;
19+ if (!menu) {
20+ gen->extra = menu = calloc(1, sizeof(menu_context));
21+ get_initial_browse_path(&menu->curpath);
22+ }
23+ return menu;
24+}
25+
26+uint16_t menu_read_w(uint32_t address, void * vcontext)
27+{
28+ if ((address >> 1) == 14) {
29+ m68k_context *context = vcontext;
30+ menu_context *menu = get_menu(context->system);
31+ uint16_t value = menu->external_game_load;
32+ if (value) {
33+ printf("Read: %X\n", value);
34+ }
35+ menu->external_game_load = 0;
36+ return value;
37+ } else {
38+ //This should return the status of the last request with 0
39+ //meaning either the request is complete or no request is pending
40+ //in the current implementation, the operations happen instantly
41+ //in emulated time so we can always return 0
42+ return 0;
43+ }
44+}
45+
46+void copy_string_from_guest(m68k_context *m68k, uint32_t guest_addr, char *buf, size_t maxchars)
47+{
48+ char *cur;
49+ char *src = NULL;
50+ for (cur = buf; cur < buf+maxchars; cur+=2, guest_addr+=2, src+=2)
51+ {
52+ if (!src || !(guest_addr & 0xFFFF)) {
53+ //we may have walked off the end of a memory block, get a fresh native pointer
54+ src = get_native_pointer(guest_addr, (void **)m68k->mem_pointers, &m68k->options->gen);
55+ if (!src) {
56+ break;
57+ }
58+ }
59+ *cur = src[1];
60+ cur[1] = *src;
61+ if (!*src || !src[1]) {
62+ break;
63+ }
64+ }
65+ //make sure we terminate the string even if we did not hit a null terminator in the source
66+ buf[maxchars-1] = 0;
67+}
68+
69+void copy_to_guest(m68k_context *m68k, uint32_t guest_addr, char *src, size_t tocopy)
70+{
71+ char *dst = NULL;
72+ for (char *cur = src; cur < src+tocopy; cur+=2, guest_addr+=2, dst+=2)
73+ {
74+ if (!dst || !(guest_addr & 0xFFFF)) {
75+ //we may have walked off the end of a memory block, get a fresh native pointer
76+ dst = get_native_pointer(guest_addr, (void **)m68k->mem_pointers, &m68k->options->gen);
77+ if (!dst) {
78+ break;
79+ }
80+ }
81+ dst[1] = *cur;
82+ *dst = cur[1];
83+ }
84+}
85+
86+#define SAVE_INFO_BUFFER_SIZE (11*40)
87+
88+uint32_t copy_dir_entry_to_guest(uint32_t dst, m68k_context *m68k, char *name, uint8_t is_dir)
89+{
90+ uint8_t *dest = get_native_pointer(dst, (void **)m68k->mem_pointers, &m68k->options->gen);
91+ if (!dest) {
92+ return 0;
93+ }
94+ *(dest++) = is_dir;
95+ *(dest++) = 1;
96+ dst += 2;
97+ uint8_t term = 0;
98+ for (char *cpos = name; *cpos; cpos++)
99+ {
100+ dest[1] = *cpos;
101+ dest[0] = cpos[1];
102+ if (cpos[1]) {
103+ cpos++;
104+ } else {
105+ term = 1;
106+ }
107+ dst += 2;
108+ if (!(dst & 0xFFFF)) {
109+ //we may have walked off the end of a memory block, get a fresh native pointer
110+ dest = get_native_pointer(dst, (void **)m68k->mem_pointers, &m68k->options->gen);
111+ if (!dest) {
112+ break;
113+ }
114+ } else {
115+ dest += 2;
116+ }
117+ }
118+ if (!term) {
119+ *(dest++) = 0;
120+ *dest = 0;
121+ dst += 2;
122+ }
123+ return dst;
124+}
125+void * menu_write_w(uint32_t address, void * context, uint16_t value)
126+{
127+ m68k_context *m68k = context;
128+ genesis_context *gen = m68k->system;
129+ menu_context *menu = get_menu(gen);
130+ if (menu->state) {
131+ uint32_t dst = menu->latch << 16 | value;
132+ switch (address >> 2)
133+ {
134+ case 0: {
135+ size_t num_entries;
136+ dir_entry *entries = get_dir_list(menu->curpath, &num_entries);
137+ if (entries) {
138+ sort_dir_list(entries, num_entries);
139+ } else {
140+ warning("Failed to open directory %s: %s\n", menu->curpath, strerror(errno));
141+ entries = malloc(sizeof(dir_entry));
142+ entries->name = strdup("..");
143+ entries->is_dir = 1;
144+ num_entries = 1;
145+ }
146+ uint32_t num_exts;
147+ char **ext_list = get_extension_list(config, &num_exts);
148+ for (size_t i = 0; dst && i < num_entries; i++)
149+ {
150+ if (num_exts && !entries[i].is_dir) {
151+ if (!path_matches_extensions(entries[i].name, ext_list, num_exts)) {
152+ continue;
153+ }
154+ }
155+ dst = copy_dir_entry_to_guest(dst, m68k, entries[i].name, entries[i].is_dir);
156+ }
157+ free(ext_list);
158+ //terminate list
159+ uint8_t *dest = get_native_pointer(dst, (void **)m68k->mem_pointers, &m68k->options->gen);
160+ if (dest) {
161+ *dest = dest[1] = 0;
162+ }
163+ free_dir_list(entries, num_entries);
164+ break;
165+ }
166+ case 1: {
167+ char buf[4096];
168+ copy_string_from_guest(m68k, dst, buf, sizeof(buf));
169+ buf[sizeof(buf)-1] = 0;
170+ char *tmp = menu->curpath;
171+ menu->curpath = path_append(tmp, buf);
172+ free(tmp);
173+ break;
174+ }
175+ case 2:
176+ case 8: {
177+ char buf[4096];
178+ copy_string_from_guest(m68k, dst, buf, sizeof(buf));
179+ char const *pieces[] = {menu->curpath, PATH_SEP, buf};
180+ char *selected = alloc_concat_m(3, pieces);
181+ if ((address >> 2) == 2) {
182+ gen->header.next_rom = selected;
183+ m68k->should_return = 1;
184+ } else {
185+ lockon_media(selected);
186+ free(selected);
187+ }
188+ break;
189+ }
190+ case 3: {
191+ switch (dst)
192+ {
193+ case 1:
194+ m68k->should_return = 1;
195+ gen->header.should_exit = 1;
196+ break;
197+ case 2:
198+ m68k->should_return = 1;
199+ break;
200+ }
201+
202+ break;
203+ }
204+ case 4: {
205+ char *buffer = malloc(SAVE_INFO_BUFFER_SIZE);
206+ char *cur = buffer;
207+ if (gen->header.next_context && gen->header.next_context->save_dir) {
208+ char *end = buffer + SAVE_INFO_BUFFER_SIZE;
209+ uint32_t num_slots;
210+ save_slot_info *slots = get_slot_info(gen->header.next_context, &num_slots);
211+ for (uint32_t i = 0; i < num_slots; i++)
212+ {
213+ size_t desc_len = strlen(slots[i].desc) + 1;//+1 for string terminator
214+ char *after = cur + desc_len + 1;//+1 for list terminator
215+ if (after > cur) {
216+ desc_len -= after - cur;
217+ }
218+ memcpy(cur, slots[i].desc, desc_len);
219+ cur = after;
220+ }
221+ *cur = 0;//terminate list
222+ } else {
223+ *(cur++) = 0;
224+ *(cur++) = 0;
225+ }
226+ copy_to_guest(m68k, dst, buffer, cur-buffer);
227+ break;
228+ }
229+ case 5:
230+ //save state
231+ if (gen->header.next_context) {
232+ gen->header.next_context->save_state = dst + 1;
233+ }
234+ m68k->should_return = 1;
235+ break;
236+ case 6:
237+ //load state
238+ if (gen->header.next_context && gen->header.next_context->save_dir) {
239+ if (!gen->header.next_context->load_state(gen->header.next_context, dst)) {
240+ break;
241+ }
242+ }
243+ m68k->should_return = 1;
244+ break;
245+ case 7:
246+ //read only port
247+ break;
248+ default:
249+ fprintf(stderr, "WARNING: write to undefined menu port %X\n", address);
250+ }
251+ menu->state = 0;
252+ } else {
253+ menu->latch = value;
254+ menu->state = 1;
255+ }
256+ if (m68k->should_return) {
257+ m68k->target_cycle = m68k->current_cycle;
258+ }
259+
260+ return context;
261+}
1@@ -0,0 +1,19 @@
2+/*
3+ Copyright 2015 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#ifndef MENU_H_
8+#define MENU_H_
9+typedef struct {
10+ char *curpath;
11+ uint16_t latch;
12+ uint16_t state;
13+ uint8_t external_game_load;
14+} menu_context;
15+
16+
17+uint16_t menu_read_w(uint32_t address, void * context);
18+void * menu_write_w(uint32_t address, void * context, uint16_t value);
19+
20+#endif // MENU_H_
1@@ -0,0 +1,1440 @@
2+ dc.l $0, start
3+ dc.l empty_handler
4+ dc.l empty_handler
5+ ;$10
6+ dc.l empty_handler
7+ dc.l empty_handler
8+ dc.l empty_handler
9+ dc.l empty_handler
10+ ;$20
11+ dc.l empty_handler
12+ dc.l empty_handler
13+ dc.l empty_handler
14+ dc.l empty_handler
15+ ;$30
16+ dc.l empty_handler
17+ dc.l empty_handler
18+ dc.l empty_handler
19+ dc.l empty_handler
20+ ;$40
21+ dc.l empty_handler
22+ dc.l empty_handler
23+ dc.l empty_handler
24+ dc.l empty_handler
25+ ;$50
26+ dc.l empty_handler
27+ dc.l empty_handler
28+ dc.l empty_handler
29+ dc.l empty_handler
30+ ;$60
31+ dc.l empty_handler
32+ dc.l empty_handler
33+ dc.l empty_handler
34+ dc.l empty_handler
35+ ;$70
36+ dc.l int_4
37+ dc.l empty_handler
38+ dc.l int_6
39+ dc.l empty_handler
40+ ;$80
41+ dc.l empty_handler
42+ dc.l empty_handler
43+ dc.l empty_handler
44+ dc.l empty_handler
45+ ;$90
46+ dc.l empty_handler
47+ dc.l empty_handler
48+ dc.l empty_handler
49+ dc.l empty_handler
50+ ;$A0
51+ dc.l empty_handler
52+ dc.l empty_handler
53+ dc.l empty_handler
54+ dc.l empty_handler
55+ ;$B0
56+ dc.l empty_handler
57+ dc.l empty_handler
58+ dc.l empty_handler
59+ dc.l empty_handler
60+ ;$C0
61+ dc.l empty_handler
62+ dc.l empty_handler
63+ dc.l empty_handler
64+ dc.l empty_handler
65+ ;$D0
66+ dc.l empty_handler
67+ dc.l empty_handler
68+ dc.l empty_handler
69+ dc.l empty_handler
70+ ;$E0
71+ dc.l empty_handler
72+ dc.l empty_handler
73+ dc.l empty_handler
74+ dc.l empty_handler
75+ ;$F0
76+ dc.l empty_handler
77+ dc.l empty_handler
78+ dc.l empty_handler
79+ dc.l empty_handler
80+ dc.b "SEGA GENESIS "
81+ dc.b "(c) 2015.JULY "
82+ dc.b "Menu "
83+ dc.b " "
84+ dc.b " "
85+ dc.b "Menu "
86+ dc.b " "
87+ dc.b " "
88+ dc.b "MP BlstMenu-00", 0, 0
89+ dc.b " "
90+ dc.l $0, rom_end-1, $FF0000, $FFFFFF
91+ dc.b " "
92+ dc.b " "
93+ dc.b " "
94+ dc.b " "
95+ dc.b "JU "
96+
97+;register addresses
98+VDP_DATA equ $C00000
99+VDP_CTRL equ $C00004
100+VDP_HV equ $C00008
101+Z80_RAM equ $A00000
102+IO_AREA equ $A10000
103+PAD1_DATA equ (IO_AREA + 3)
104+PAD2_DATA equ (IO_AREA + 5)
105+EXT_DATA equ (IO_AREA + 7)
106+PAD1_CTRL equ (IO_AREA + 9)
107+PAD2_CTRL equ (IO_AREA + 11)
108+EXT_CTRL equ (IO_AREA + 13)
109+
110+MODE_1 equ 0
111+MODE_2 equ 1
112+SCROLL_A equ 2
113+WINDOW equ 3
114+SCROLL_B equ 4
115+SAT equ 5
116+BG_COLOR equ 7
117+HINT equ $A
118+MODE_3 equ $B
119+MODE_4 equ $C
120+HSCROLL equ $D
121+AUTOINC equ $F
122+SCROLL EQU $10
123+WINDOW_H equ $11
124+WINDOW_V equ $12
125+DMALEN_L equ $13
126+DMALEN_H equ $14
127+DMASRC_L equ $15
128+DMASRC_M equ $16
129+DMASRC_H equ $17
130+
131+VDP_VRAM_WRITE equ $40000000
132+VDP_CRAM_WRITE equ $C0000000
133+VDP_VSRAM_WRITE equ $40000010
134+VDP_DMA_FLAG equ $80
135+
136+vdpregset macro
137+ move.w #(((\1) << 8) | $8000 | (\2)), (a1)
138+ endm
139+
140+vdpreg macro
141+ dc.w (((\1) << 8) | $8000 | (\2))
142+ endm
143+
144+;Writes a normal VDP command to the control port
145+;\1 - VDP address
146+;\2 - Access type
147+vdpaccess macro
148+ ifeq NARG-2
149+ move.l #((\2) | (\1) << 16 & $3FFF0000 | (\1) >> 14 & 3), (a1)
150+ else
151+ move.l #((\2) | (\1) << 16 & $3FFF0000 | (\1) >> 14 & 3), \3
152+ endif
153+ endm
154+
155+;Writes a DMA command to the control port
156+;\1 - Destination address
157+;\2 - Destination type
158+startdma macro
159+ move.l #(\2 | VDP_DMA_FLAG | (\1 << 16) & $3FFF0000 | (\1 >> 14) & 3), (a1)
160+ endm
161+
162+DMA_SRC_68K equ 0
163+DMA_SRC_VRAM equ $C0
164+DMA_SRC_FILL equ $80
165+
166+dmasrc macro
167+ move.l #($95009600 + (\1) << 15 & $FF0000 + (\1) >> 9 & $FF), (a1)
168+ move.w #($9700 + (\1) >> 17 & $7F | (\2)), (a1)
169+ endm
170+
171+dir_buffer equ $100000
172+menu_port equ $180000
173+load_rom_port equ (menu_port+2*4)
174+lock_on_port equ (menu_port+8*4)
175+
176+MAX_DISPLAY equ 24
177+
178+ rsset $FFFF8000
179+x_pos rs.w 1
180+base_cmd rs.l 1
181+sprite_list rs.l 160
182+page_index rs.l MAX_DISPLAY+1
183+page_stack rs.l 1
184+page_pointers rs.l 1024
185+mouse_sprite rs.l 1
186+menu_functions rs.l 1
187+cursor_show_fun rs.l 1
188+special_click rs.l 1
189+rom_load_addr rs.l 1
190+mouse_x rs.w 1
191+selection_top rs.w 1
192+selection_bot rs.w 1
193+selection_mask rs.w 1
194+num_sprites rs.b 1
195+last_pad1 rs.b 1
196+last_pad2 rs.b 1
197+selected rs.b 1
198+more_pages rs.b 1
199+mouse_buf rs.b 3
200+mouse_shown rs.b 1
201+last_mbuttons rs.b 1
202+num_menu rs.b 1
203+num_slots rs.b 1
204+port_off rs.b 1
205+
206+
207+int_6:
208+ dmasrc sprite_list, DMA_SRC_68K
209+ ;set DMA length
210+ move.l #$94009300, d0
211+ moveq #0, d1
212+ move.b num_sprites.w, d1
213+ add.w d1, d1
214+ add.w d1, d1
215+ move.b d1, d0
216+ swap d0
217+ lsr.w #8, d1
218+ move.b d1, d0
219+ move.l d0, (a1)
220+ startdma $C000, VDP_VRAM_WRITE
221+
222+ move.w (menu_port+4*7), d0
223+ btst #0, d0
224+ bne show_pause_menu
225+
226+ ;read gamepad/mouse in port 1
227+ lea PAD1_DATA, a2
228+
229+ bsr io_read
230+
231+ cmp.b #3, d2
232+ beq .mouse
233+
234+ move.b last_pad1.w, d1
235+ eor.b d0, d1
236+ and.b d0, d1
237+ move.b d0, last_pad1.w
238+
239+ bsr handle_pad_buttons
240+
241+ bra pad2
242+.mouse
243+ bsr handle_mouse
244+
245+pad2:
246+ ;read gamepad/mouse in port 2
247+ lea PAD2_DATA, a2
248+
249+ bsr io_read
250+
251+ cmp.b #3, d2
252+ beq .mouse
253+
254+ move.b last_pad2.w, d1
255+ eor.b d0, d1
256+ and.b d0, d1
257+ move.b d0, last_pad2.w
258+
259+ bsr handle_pad_buttons
260+ rte
261+.mouse
262+ bsr handle_mouse
263+ rte
264+
265+
266+;d0 = SACBRLUD
267+;d1 = newly pressed buttons
268+handle_pad_buttons:
269+ tst.b num_menu.w
270+ bne handle_buttons_menu
271+ tst.b num_slots.w
272+ bne handle_buttons_save
273+ moveq #16, d2
274+
275+
276+ btst #3, d1
277+ bne right
278+ btst #2, d1
279+ bne left
280+buttons_no_leftright
281+ btst #1, d1
282+ bne down
283+ btst #0, d1
284+ bne up
285+ btst #7, d1
286+ bne select_entry
287+ btst #5, d1
288+ bne select_entry
289+handle_done:
290+ rts
291+handle_buttons_menu
292+ moveq #48, d2
293+ bra buttons_no_leftright
294+handle_buttons_save
295+ moveq #32, d2
296+ bra buttons_no_leftright
297+
298+down:
299+
300+ ;check if we are already at the bottom of the page
301+ moveq #1, d0
302+ add.b (selected).w, d0
303+ tst.b num_menu.w
304+ bne .menu
305+ tst.b num_slots.w
306+ bne .slots
307+ move.w d0, d1
308+ add.w d1, d1
309+ add.w d1, d1
310+ lea page_index.w, a2
311+ tst.l (0, a2, d1.w)
312+ beq handle_done
313+.do_move
314+ move.b d0, (selected).w
315+
316+ add.w d2, (sprite_list).w
317+ add.w d2, (sprite_list+8).w
318+ rts
319+.menu:
320+ cmp.b num_menu.w, d0
321+ beq handle_done
322+ bra .do_move
323+.slots:
324+ cmp.b num_slots.w, d0
325+ beq handle_done
326+ bra .do_move
327+
328+up:
329+ ;check if we are already at the top of the page
330+ move.b (selected).w, d0
331+ beq handle_done
332+ subq #1, d0
333+ move.b d0, (selected).w
334+
335+ sub.w d2, (sprite_list).w
336+ sub.w d2, (sprite_list+8).w
337+ rts
338+
339+right:
340+ ;check that we have another page to go to
341+ tst.b more_pages.w
342+ beq handle_done
343+ ;switch to the next page
344+ move.l page_stack.w, a6
345+ move.l (-4, a6), a6
346+
347+ addq #6, a7
348+ bra render_page
349+
350+left:
351+ move.l page_stack.w, a5
352+ ;check if we're already on the first page
353+ cmp.l #(page_pointers+8), a5
354+ beq handle_done
355+ ;switch to previous page
356+ lea (-12, a5), a5
357+ move.l (a5)+, a6
358+ move.l a5, page_stack.w
359+
360+ addq #6, a7
361+ bra render_page
362+
363+select_entry:
364+ moveq #0, d0
365+ move.b (selected).w, d0
366+ add.w d0, d0
367+ add.w d0, d0
368+ tst.b num_menu.w
369+ bne .select_menu_button
370+ tst.b num_slots.w
371+ bne .select_save_slot
372+ lea page_index.w, a2
373+ move.l (0, a2, d0.w), a2
374+ tst.b (-1, a2)
375+ bne enter_dir
376+ ;regular file
377+ move.l rom_load_addr.w, a3
378+ move.l a2, (a3)
379+
380+ addq #6, a7
381+ bra show_pause_menu
382+.select_menu_button:
383+ movea.l menu_functions.w, a2
384+ move.l (0, a2, d0.w), a2
385+ addq #6, a7
386+ jmp (a2)
387+.select_save_slot:
388+ lea menu_port, a3
389+ moveq #0, d0
390+ move.b port_off.w, d0
391+ add.w d0, a3
392+ move.b selected.w, d0
393+ move.l d0, (a3)
394+ addq #6, a7
395+ jmp show_pause_menu
396+
397+enter_dir:
398+ lea menu_port+4, a3
399+ move.l a2, (a3)
400+.wait_complete
401+ tst.w (a3)
402+ bne .wait_complete
403+ addq #6, a7
404+ bra menu_start
405+
406+handle_mouse:
407+ move.b last_mbuttons.w, d4
408+ eor.b d3, d4
409+ and.b d3, d4
410+ move.b d3, last_mbuttons.w
411+
412+ move.b d0, d2
413+ or.b d1, d2
414+ beq .no_mouse_move
415+
416+
417+ tst.b mouse_shown.w
418+ bne .skip_show_check
419+
420+ moveq #0, d2
421+ move.b num_sprites.w, d2
422+ move.w d2, d4
423+ lsl.w #3, d4
424+ lea sprite_list.w, a2
425+ move.b d2, (-5, a2, d4.w)
426+ lea (0, a2, d4.w), a2
427+ move.l a2, mouse_sprite.w
428+ move.l #$00EA0500, (a2)+
429+ move.w #$8083, (a2)
430+ move.w #$100, mouse_x.w
431+ addq #1, d2
432+ move.b d2, num_sprites.w
433+
434+ move.b #1, mouse_shown.w
435+
436+ move.l cursor_show_fun.w, d2
437+ beq .skip_show_check
438+ move.l d2, a2
439+ jsr (a2)
440+
441+
442+.skip_show_check
443+ neg.w d1
444+ move.l mouse_sprite.w, a2
445+ add.w d1, (a2)
446+ add.w d0, mouse_x.w
447+ move.w mouse_x.w, d0
448+ asr.w #1, d0
449+ move.w d0, (6, a2)
450+ move.w (a2), d1
451+ cmp.w selection_top.w, d1
452+ blo .done
453+ cmp.w selection_bot.w, d1
454+ bhi .special_click
455+ tst.b num_menu.w
456+ bne .handle_menu
457+ tst.b num_slots.w
458+ bne .handle_slots
459+ and.w #$FFF0, d1
460+ subq #8, d1
461+ move.w d1, (sprite_list).w
462+ move.w d1, (sprite_list+8).w
463+
464+ sub.w #264, d1
465+ lsr.w #4, d1
466+ move.b d1, selected.w
467+ bra .normal_click
468+.handle_menu
469+ ;TODO: FIXME
470+ and.w #$FFF0, d1
471+ moveq #0, d0
472+ move.w d1, d0
473+ sub.w selection_top.w, d0
474+ divu.w #48, d0
475+ swap d0
476+ tst.w d0
477+ beq .no_adjust
478+
479+ cmp.w #16, d0
480+ bne .round_up
481+ swap d0
482+ sub.w #16, d1
483+ bra .set_cursor_pos
484+
485+.round_up
486+ swap d0
487+ addq #1, d0
488+ add.w #16, d1
489+ bra .set_cursor_pos
490+
491+.no_adjust
492+ swap d0
493+.set_cursor_pos
494+ move.w d1, (sprite_list).w
495+ move.w d1, (sprite_list+8).w
496+
497+ move.b d0, selected.w
498+
499+ bra .normal_click
500+.handle_slots
501+ and.w #$FFE0, d1
502+ subq #8, d1
503+ move.w d1, (sprite_list).w
504+ move.w d1, (sprite_list+8).w
505+
506+ sub.w #264, d1
507+ lsr.w #5, d1
508+ move.b d1, selected.w
509+.normal_click
510+ btst #0, d4
511+ bne select_entry
512+.done
513+ rts
514+.no_mouse_move
515+ tst.b mouse_shown
516+ bne .skip_show_check
517+ rts
518+.special_click:
519+ btst #0, d4
520+ beq .done
521+ move.l special_click.w, d2
522+ beq .done
523+ move.l d2, a2
524+ jmp (a2)
525+int_4:
526+empty_handler:
527+ rte
528+
529+id_lookup:
530+ dc.b $0, $1, $4, $5
531+ dc.b $2, $3, $6, $7
532+ dc.b $8, $9, $C, $D
533+ dc.b $A, $B, $E, $F
534+
535+io_read:
536+ ;read TH=1
537+ move.b (a2), d0
538+ ;read TH=0
539+ move.b #0, (a2)
540+ nop
541+ nop
542+ move.b (a2), d1
543+ ;reset TH to 1
544+ move.b #$40, (a2)
545+
546+ moveq #0, d2 ;4
547+
548+ ;calculate Mega Drive peripheral ID
549+ move.b d1, d2 ;4
550+ lsr.b #1, d2 ;8, 12
551+ or.b d1, d2 ;4, 16
552+ and.b #5, d2 ;8, 24
553+
554+ move.b d0, d3 ;4
555+ add.b d3, d3 ;4, 8
556+ or.b d0, d3 ;4, 12
557+ and.b #$A, d3 ;8, 20
558+
559+ or.b d3, d2 ;4
560+ move.b (id_lookup, pc, d2.w), d2 ;14
561+
562+
563+ cmp.b #$3, d2
564+ beq .mouse
565+
566+ cmp.b #$D, d2
567+ bne .not_pad
568+
569+ and.b #$3F, d0
570+ and.b #$30, d1
571+ add.b d1, d1
572+ add.b d1, d1
573+ or.b d1, d0
574+ not.b d0
575+ rts
576+.not_pad:
577+ moveq #0, d0
578+ rts
579+
580+.mouse:
581+
582+ move.b #$60, (a2)
583+ move.b #$60, (PAD1_CTRL-PAD1_DATA, a2)
584+ move.b #$60, (a2)
585+
586+ moveq #$f, d4
587+wait_hi_init:
588+ btst #4, (a2)
589+ beq wait_hi_init
590+ nop
591+ nop
592+ move.b #$20, (a2)
593+ nop
594+ nop
595+ moveq #$f, d4
596+ move.b #0, (a2)
597+.wait_lo
598+ btst #4, (a2)
599+ bne .wait_lo
600+ moveq #$f, d4
601+ move.b #$20, (a2)
602+.wait_hi
603+ btst #4, (a2)
604+ beq .wait_hi
605+
606+ lea mouse_buf.w, a3
607+ move.l a3, a4
608+ moveq #2, d3
609+ moveq #0, d0
610+loop:
611+ moveq #$f, d4
612+ move.b #0, (a2)
613+.wait_lo
614+ btst #4, (a2)
615+ bne .wait_lo
616+ move.b (a2), d0
617+ lsl.b #4, d0
618+ moveq #$f, d4
619+ move.b #$20, (a2)
620+.wait_hi
621+ btst #4, (a2)
622+ beq .wait_hi
623+ move.b (a2), d1
624+ and.b #$f, d1
625+ or.b d1, d0
626+ move.b d0, (a3)+
627+
628+ dbra d3, loop
629+
630+ ;end request
631+ move.b #$60, (a2)
632+
633+
634+ ;massage data
635+ moveq #0, d1
636+ move.b d0, d1
637+ move.b (a4)+, d3
638+ move.b (a4), d0
639+
640+ btst #4, d3
641+ beq xpos
642+ or.w #$FF00, d0
643+xpos
644+ btst #5, d3
645+ beq ypos
646+ or.w #$FF00, d1
647+ypos
648+ ;set port config back to normal controller mode
649+ move.b #$40, (PAD1_CTRL-PAD1_DATA, a2)
650+ rts
651+
652+topcorner equ (button-font)/64 + 32
653+topmiddle equ topcorner+1
654+botcorner equ topmiddle+1
655+botmiddle equ botcorner+1
656+horiz_flip equ $800
657+vert_flip equ $1000
658+
659+; draws a button
660+; d0.w - x in cells
661+; d1.w - y in cells
662+; d2.w - width in cells
663+;
664+; clobbers a6
665+draw_button:
666+ ;multiply x by 2
667+ add.w d0, d0
668+ ;multiply y by 128
669+ lsl.w #7, d1
670+ add.w d1, d0
671+ add.w #$A000, d0
672+ move.w d0, d1
673+ and.w #$3FFF, d0
674+ rol.w #2, d1
675+ and.w #3, d1
676+ ori.w #(VDP_VRAM_WRITE >> 16), d0
677+ swap d0
678+ move.w d1, d0
679+ move.l d0, (a1)
680+ move.w d2, d1
681+ ;top left corner
682+ move.w #topcorner, (a0)
683+ subq #3, d1
684+ bmi .notopmiddle
685+.toploop:
686+ ;top middle
687+ move.w #topmiddle, (a0)
688+ dbra d1, .toploop
689+.notopmiddle
690+ ;top right corner
691+ move.w #(topcorner | horiz_flip), (a0)
692+ ;go to next row in name table
693+ add.l #((2*64) << 16), d0
694+ move.l d0, (a1)
695+ ;bottom left corner
696+ move.w #botcorner, (a0)
697+ subq #3, d2
698+ bmi .nomiddlebot
699+.botloop:
700+ ;bottom middle
701+ move.w #botmiddle, (a0)
702+ dbra d2, .botloop
703+.nomiddlebot
704+ ;bottom right corner
705+ move.w #(botcorner | horiz_flip), (a0)
706+ rts
707+
708+;a5 - menu pointer
709+;d6 - initial Y position of menu
710+draw_menu:
711+ moveq #0, d7
712+ moveq #0, d5
713+ ;clear out save slot state
714+ move.b d5, num_slots.w
715+ ;clear out event handlers
716+ move.l d5, cursor_show_fun.w
717+ move.l d5, special_click.w
718+ ;select first item
719+ move.b d7, selected.w
720+ ;save menu pointer for second pass
721+ movea.l a5, a4
722+ ;adjust arrow mask
723+ move.w #$FFE0, selection_mask.w
724+.lenloop
725+ tst.b (a5)
726+ beq .lendone
727+ addq #1, d5
728+ movea.l a5, a6
729+ bsr strlen
730+ cmp.w d7, d0
731+ blo .nochange
732+ move.w d0, d7
733+.nochange
734+ lea (1, a5, d0.w), a5
735+ bra .lenloop
736+.lendone
737+
738+ addq #2, d7
739+ move.b d5, num_menu.w
740+
741+ ;calculate X position
742+ move.w d7, d4
743+ lsr.w #1, d4
744+ moveq #20, d5
745+ sub.w d4, d5
746+ ;calculate left arrow X
747+ move.w d5, d4
748+ lsl.w #3, d4
749+ add.w #(128-24), d4
750+ move.w d4, (sprite_list+6).w
751+ ;calculate right arrow x
752+ move.w d7, d3
753+ lsl.w #3, d3
754+ add.w d3, d4
755+ add.w #32, d4
756+ move.w d4, (sprite_list+6+8).w
757+ ;update left arrow Y
758+ move.w d6, d4
759+ lsl.w #4, d4
760+ add.w #256, d4
761+ move.w d4, (sprite_list).w
762+ move.w d4, (sprite_list+8).w
763+ ;update mouse top limit
764+ move.w d4, selection_top.w
765+ ;restore menu pointer
766+ movea.l a4, a5
767+.drawloop
768+ tst.b (a5)
769+ beq .done
770+ ;x pos
771+ move.w d5, d0
772+ ;y pos
773+ move.w d6, d1
774+ ;width
775+ move.w d7, d2
776+ bsr draw_button
777+
778+ movea.l a5, a6
779+ bsr strlen
780+ movea.l a5, a6
781+ lea (1, a5, d0.w), a5
782+ ;x pos
783+ move.w d7, d1
784+ lsr.w #1, d1
785+ add.w d5, d1
786+ lsr.w #1, d0
787+ sub.w d0, d1
788+ ;y pos
789+ move.w d6, d2
790+ ;base attribute
791+ move.w #$206B, d0
792+ bsr print_string_fixed
793+
794+ addq #3, d6
795+ bra .drawloop
796+.done
797+ ;update mouse bottom limit
798+ lsl.w #4, d6
799+ add.w #224, d6
800+ move.w d6, selection_bot.w
801+ rts
802+
803+clear_screen:
804+ ;clear name tables
805+ vdpaccess $8000, VDP_VRAM_WRITE
806+ moveq #32, d0
807+ swap d0
808+ move.b #32, d0
809+ move.w #(64*64-1), d1
810+ploop:
811+ move.l d0, (a0)
812+ dbra d1, ploop
813+ rts
814+
815+initial_regs:
816+ vdpreg MODE_2, $4 ;Mode 5, everything turned off
817+ vdpreg MODE_1, $4
818+ vdpreg SCROLL_A, $20 ;Scroll a table $8000
819+ vdpreg SCROLL_B, $05 ;Scroll b table $A000
820+ vdpreg SAT, $60 ;SAT table $C000
821+ vdpreg BG_COLOR, 0
822+ vdpreg HINT, $FF
823+ vdpreg MODE_3, 0 ;full screen scroll
824+ vdpreg MODE_4, $87 ;40 cell mode, double-res interlace
825+ vdpreg HSCROLL, 0
826+ vdpreg AUTOINC, 2
827+ vdpreg SCROLL, 1 ;64x32 scroll size
828+end_initial_regs
829+
830+start:
831+ lea $FF0000, a0
832+ moveq #0, d0
833+ move.w #($10000/8 - 1), d1
834+.clearloop:
835+ move.l d0, (a0)+
836+ move.l d0, (a0)+
837+ dbra d1, .clearloop
838+
839+ lea $C00000, a0
840+ lea $C00004, a1
841+
842+ moveq #(end_initial_regs-initial_regs-1), d0
843+ lea initial_regs.w, a2
844+.regloop
845+ move.w (a2)+, (a1)
846+ dbra d0, .regloop
847+
848+ vdpaccess $0, VDP_CRAM_WRITE
849+ move.w #$400, (a0)
850+ move.w #$EEE, (a0)
851+ move.w #$222, (a0)
852+
853+ ;init scroll table
854+ vdpaccess $0, VDP_VRAM_WRITE
855+ move.w #0, (a0)
856+ move.w #0, (a0)
857+
858+
859+ ;load tiles
860+ vdpaccess $800, VDP_VRAM_WRITE
861+ lea font(pc), a2
862+ move.w #((buttonend-font)/4 - 1), d0
863+tloop:
864+ move.l (a2)+, (a0)
865+ dbra d0, tloop
866+ move.w #((fontfixedend-fontfixed)/4 - 1), d0
867+dtloop:
868+ move.l (a2)+, d1
869+ move.l d1, (a0)
870+ move.l d1, (a0)
871+ dbra d0, dtloop
872+
873+
874+ ;setup SAT
875+ ;;vdpaccess $C000, VDP_VRAM_WRITE
876+
877+ lea sprite_list.w, a2
878+ ;left arrow
879+ move.l #$01080501, (a2)+
880+ move.l #$807F0086, (a2)+
881+
882+ ;right arrow
883+ move.l #$01080500, (a2)+
884+ move.l #$887F01AA, (a2)+
885+ move.b #2, num_sprites.w
886+
887+show_main_menu:
888+ bsr clear_screen
889+ ;init vertical scroll RAM
890+ vdpaccess $0, VDP_VSRAM_WRITE
891+ move.w #-4, (a0)
892+ move.w #0, (a0)
893+
894+ moveq #8, d6
895+ move.l #main_menu_func, menu_functions.w
896+ lea main_menu(pc), a5
897+ bsr draw_menu
898+ bra gamepad_setup
899+
900+show_pause_menu:
901+ bsr clear_screen
902+ ;init vertical scroll RAM
903+ vdpaccess $0, VDP_VSRAM_WRITE
904+ move.w #-4, (a0)
905+ move.w #0, (a0)
906+ moveq #8, d6
907+ move.l #pause_menu_func, menu_functions.w
908+ lea pause_menu(pc), a5
909+ bsr draw_menu
910+ bra gamepad_setup
911+
912+lock_on:
913+ move.l #lock_on_port, rom_load_addr.w
914+ bra menu_common
915+menu_start:
916+ move.l #load_rom_port, rom_load_addr.w
917+menu_common:
918+ moveq #0, d0
919+ ;init vertical scroll RAM
920+ vdpaccess $0, VDP_VSRAM_WRITE
921+ move.w d0, (a0)
922+ move.w d0, (a0)
923+
924+ ;reset arrow position
925+ move.w #$0108, sprite_list.w
926+ move.w #$0108, (sprite_list + 8).w
927+ move.w #$0086, (sprite_list + 6).w
928+ move.w #$01AA, (sprite_list + 6 + 8).w
929+
930+ ;reset selection
931+ move.b d0, selected.w
932+
933+ ;reset special click handler
934+ move.l d0, special_click.w
935+
936+
937+ lea page_pointers.w, a5
938+ lea dir_buffer, a6
939+ move.l a6, (a5)+
940+ move.l a5, page_stack.w
941+ lea menu_port, a2
942+ move.l a6, (a2)
943+
944+wait_complete:
945+ tst.w (a2)
946+ bne wait_complete
947+
948+render_page:
949+ bsr clear_screen
950+
951+ ;clear menu state
952+ move.b #0, num_menu.w
953+ move.w #272, selection_top.w
954+ move.w #655, selection_bot.w
955+ move.w #$FFF0, selection_mask.w
956+
957+ ;init scroll table
958+ vdpaccess $0, VDP_VRAM_WRITE
959+ move.w #0, (a0)
960+ move.w #4, (a0)
961+
962+ move.l #$40860002, d3
963+ move.l d3, (a1)
964+ move.l d3, base_cmd.w
965+
966+ move.b #0, more_pages.w
967+ lea page_index.w, a3
968+ moveq #MAX_DISPLAY-1, d7
969+file_loop:
970+ tst.b (a6)+
971+ beq done_files
972+ addq #1, a6 ;TODO: Do something with directory flag
973+
974+ ;skip over entries starting with a dot except ..
975+ cmp.b #$2E, (a6)
976+ bne normal
977+ cmp.b #$2E, (1, a6)
978+ beq normal
979+ addq #1, a6
980+.skip_loop:
981+ tst.b (a6)+
982+ bne .skip_loop
983+ addq #1, d7
984+ move.l a6, d6
985+ bra skip
986+normal:
987+ ;save entry pointer to page index
988+ move.l a6, (a3)+
989+ ;print name on screen
990+ moveq #0, d0
991+ bsr print_string
992+ move.l a6, d6
993+
994+ lea Newline(pc), a6
995+ bsr print_string
996+
997+skip:
998+ ;word align pointer
999+ addq #1, d6
1000+ and.w #$FFFE, d6
1001+ move.l d6, a6
1002+
1003+ dbra d7, file_loop
1004+ tst.b (a6)
1005+ beq done_files
1006+ move.b #1, more_pages.w
1007+done_files:
1008+ move.l page_stack.w, a5
1009+ move.l a6, (a5)+
1010+ move.l a5, page_stack.w
1011+
1012+ ;null terminate page_index
1013+ moveq #0, d0
1014+ move.l d0, (a3)
1015+
1016+ tst.b mouse_shown
1017+ beq .no_mouse
1018+
1019+ tst.b more_pages.w
1020+ beq .no_next_page
1021+
1022+ ;draw Next button
1023+ moveq #30, d0
1024+ moveq #26, d1
1025+ moveq #6, d2
1026+ bsr draw_button
1027+
1028+ ;base attribute
1029+ move.w #$206B, d0
1030+ ;x pos
1031+ moveq #32, d1
1032+ ;y pos
1033+ moveq #26, d2
1034+ lea next_str(pc), a6
1035+ bsr print_string_fixed
1036+
1037+.no_next_page
1038+
1039+ cmp.l #(page_pointers+8), a5
1040+ beq .no_prev_page
1041+
1042+ ;draw Prev button
1043+ moveq #3, d0
1044+ moveq #26, d1
1045+ moveq #6, d2
1046+ bsr draw_button
1047+
1048+ ;base attribute
1049+ move.w #$206B, d0
1050+ ;x pos
1051+ moveq #5, d1
1052+ ;y pos
1053+ moveq #26, d2
1054+ lea prev_str(pc), a6
1055+ bsr print_string_fixed
1056+
1057+.no_prev_page
1058+
1059+ move.l #0, cursor_show_fun.w
1060+
1061+ bra .done_page_buttons
1062+.no_mouse
1063+ move.l #show_prev_next_buttons, cursor_show_fun.w
1064+.done_page_buttons
1065+ move.l #handle_prev_next_click, special_click.w
1066+
1067+gamepad_setup:
1068+ ;setup gamepads
1069+ move.b #$40, PAD1_CTRL
1070+ move.b #$40, PAD2_CTRL
1071+
1072+ move.w #$8174, (a1) ;enable display, vertical interrupts, DMA
1073+
1074+
1075+wait_forever
1076+ stop #2500
1077+ bra wait_forever
1078+
1079+handle_prev_next_click:
1080+ ;make sure we're actually low enough
1081+ cmp.w #663, d1
1082+ bls .no_prev_page
1083+
1084+
1085+ tst.b more_pages.w
1086+ beq .no_next_page
1087+
1088+ cmp.w #373, d0
1089+ blo .no_next_page
1090+
1091+ cmp.w #419, d0
1092+ bhi .no_next_page
1093+
1094+ ;switch to the next page
1095+ move.l page_stack.w, a6
1096+ move.l (-4, a6), a6
1097+
1098+ add.w #10, a7
1099+ bra render_page
1100+
1101+.no_next_page
1102+ cmp.l #(page_pointers+8), a5
1103+ beq .no_prev_page
1104+
1105+ cmp.w #157, d0
1106+ blo .no_prev_page
1107+
1108+ cmp.w #203, d0
1109+ bhi .no_prev_page
1110+
1111+ ;switch to previous page
1112+ lea (-12, a5), a5
1113+ move.l (a5)+, a6
1114+ move.l a5, page_stack.w
1115+
1116+ add.w #10, a7
1117+ bra render_page
1118+
1119+.no_prev_page
1120+ rts
1121+
1122+show_prev_next_buttons:
1123+ movem.l d0-d2/a6, -(a7)
1124+ tst.b more_pages.w
1125+ beq .no_next_page
1126+
1127+ ;draw Next button
1128+ moveq #30, d0
1129+ moveq #26, d1
1130+ moveq #6, d2
1131+ bsr draw_button
1132+
1133+ ;base attribute
1134+ move.w #$206B, d0
1135+ ;x pos
1136+ moveq #32, d1
1137+ ;y pos
1138+ moveq #26, d2
1139+ lea next_str(pc), a6
1140+ bsr print_string_fixed
1141+
1142+.no_next_page
1143+
1144+ cmp.l #(page_pointers+8), a5
1145+ beq .no_prev_page
1146+
1147+ ;draw Prev button
1148+ moveq #3, d0
1149+ moveq #26, d1
1150+ moveq #6, d2
1151+ bsr draw_button
1152+
1153+ ;base attribute
1154+ move.w #$206B, d0
1155+ ;x pos
1156+ moveq #5, d1
1157+ ;y pos
1158+ moveq #26, d2
1159+ lea prev_str(pc), a6
1160+ bsr print_string_fixed
1161+
1162+.no_prev_page
1163+ move.l #0, cursor_show_fun.w
1164+ movem.l (a7)+, d0-d2/a6
1165+ rts
1166+
1167+show_about:
1168+ bsr clear_screen
1169+ moveq #1, d7
1170+ lea about_text(pc), a6
1171+ ;base attribute
1172+ move.w #$006B, d0
1173+.loop
1174+ tst.b (a6)
1175+ beq .done
1176+ ;x pos
1177+ moveq #1, d1
1178+ ;y pos
1179+ move.w d7, d2
1180+ bsr print_string_fixed
1181+ addq #1, d7
1182+ bra .loop
1183+.done
1184+ moveq #8, d6
1185+ move.l #about_menu_func, menu_functions.w
1186+ lea about_menu(pc), a5
1187+ bsr draw_menu
1188+.wait
1189+ stop #$2500
1190+ bra .wait
1191+
1192+exit:
1193+ move.l #1, menu_port+12
1194+ bra exit
1195+
1196+resume:
1197+ move.l #2, menu_port+12
1198+ bra show_pause_menu
1199+
1200+show_save_slots:
1201+ move.w #(256+26), sprite_list.w
1202+ move.w #(256+26), (sprite_list+8).w
1203+ move.w #(128+8), (sprite_list+6).w
1204+ move.w #(128+320-24), (sprite_list+6+8).w
1205+ move.w #(256+32), selection_top.w
1206+ move.b #0, selected.w
1207+ move.b #0, num_menu.w
1208+ lea dir_buffer, a6
1209+ lea menu_port+16, a3
1210+ move.l a6, (a3)
1211+.waitdone:
1212+ tst.w (a3)
1213+ bne .waitdone
1214+ bsr clear_screen
1215+ moveq #0, d0
1216+
1217+ moveq #0, d6
1218+ moveq #2, d7
1219+.slotloop
1220+ tst.b (a6)
1221+ beq .done
1222+ addq #1, d6
1223+ moveq #4, d1
1224+ move.w d7, d2
1225+ bsr print_string_fixed
1226+ addq #2, d7
1227+ bra .slotloop
1228+.done
1229+ lsl.w #4, d7
1230+ add.w #248, d7
1231+ move.w d7, selection_bot.w
1232+ move.b d6, num_slots.w
1233+ rts
1234+
1235+save_state:
1236+ move.b #(5*4), port_off.w
1237+ bsr show_save_slots
1238+.wait
1239+ stop #$2500
1240+ bra .wait
1241+
1242+load_state:
1243+ move.b #(6*4), port_off.w
1244+ bsr show_save_slots
1245+.wait
1246+ stop #$2500
1247+ bra .wait
1248+
1249+next_str:
1250+ dc.b "Next", 0
1251+prev_str:
1252+ dc.b "Prev", 0
1253+
1254+about_text:
1255+ dc.b "BlastEm v0.6.2", 0
1256+ dc.b "Copyright 2011-2019 Michael Pavone", 0
1257+ dc.b " ", 0
1258+ dc.b "BlastEm is a high performance, open", 0
1259+ dc.b "source (GPLv3) Genesis/Megadrive", 0
1260+ dc.b "emulator.",0
1261+ dc.b " ", 0
1262+ dc.b " ", 0
1263+ dc.b " ", 0
1264+ dc.b " ", 0
1265+ dc.b " --- Special Thanks ---", 0
1266+ dc.b " ", 0
1267+ dc.b "Nemesis: Documentatino and test ROMs", 0
1268+ dc.b "Charles MacDonald: Documentation", 0
1269+ dc.b "Eke-Eke: Documentation", 0
1270+ dc.b "Bart Trzynadlowski: Documentation", 0
1271+ dc.b "KanedaFR: Hosting the best Sega forum", 0
1272+ dc.b "Titan: Awesome demos and documentation", 0
1273+ dc.b "flamewing: BCD info and test ROM", 0
1274+ dc.b "r57shell: Opcode size test ROM", 0
1275+ dc.b "micky: Testing", 0
1276+ dc.b "Sasha: Testing", 0
1277+ dc.b "lol-frank: Testing", 0
1278+ dc.b "Sik: Testing", 0
1279+ dc.b "Tim Lawrence : Testing", 0
1280+ dc.b "ComradeOj: Testing", 0
1281+ dc.b "Vladikcomper: Testing", 0
1282+ dc.b 0
1283+
1284+
1285+Newline:
1286+ dc.b $A, 0
1287+
1288+ align 1
1289+
1290+;Prints a null terminated string
1291+;a6 - pointer to string
1292+;a0 - VDP data port
1293+;d0 - base tile attribute
1294+;
1295+;Clobbers: d1.w, d2.w, d3.l
1296+print_string:
1297+ lea widths(pc), a5
1298+ move.w x_pos.w, d2
1299+ move.l base_cmd.w, d3
1300+.loop
1301+ moveq #0, d1
1302+ move.b (a6)+, d1
1303+ beq .end
1304+ cmp.b #$A, d1
1305+ beq .newline
1306+ tst.b (-32, a5, d1.w)
1307+ beq .narrow
1308+ add.w d0, d1
1309+ move.w d1, (a0)
1310+ addq #2, d2
1311+ bra .loop
1312+.narrow
1313+ add.w d0, d1
1314+ move.w d1, (a0)
1315+ addq #1, d2
1316+ move.l d2, d1
1317+ ;switch to other plane
1318+ and.w #$FFFE, d1
1319+ swap d1
1320+ eor.l #$20000000, d3
1321+ add.l d3, d1
1322+ move.l d1, (a1)
1323+ bra .loop
1324+.newline
1325+ moveq #0, d2
1326+ ;switch back to plane A
1327+ and.l #$DFFFFFFF, d3
1328+ ;skip to next row
1329+ add.l #$00800000, d3
1330+ move.l d3, (a1)
1331+ bra .loop
1332+.end
1333+ move.w d2, x_pos.w
1334+ move.l d3, base_cmd.w
1335+ rts
1336+
1337+;Prints a null-terminated string with a fixed width font
1338+;a6 - pointer to string
1339+;a0 - VDP data port
1340+;d0 - base tile attribute
1341+;d1 - x col
1342+;d2 - y col
1343+;
1344+print_string_fixed:
1345+ ;multiply x by 2
1346+ add.w d1, d1
1347+ ;multiply y by 128
1348+ lsl.w #7, d2
1349+ add.w d2, d1
1350+ add.w #$8000, d1
1351+ move.w d1, d2
1352+ and.w #$3FFF, d1
1353+ rol.w #2, d2
1354+ and.w #3, d2
1355+ ori.w #(VDP_VRAM_WRITE >> 16), d1
1356+ swap d1
1357+ move.w d2, d1
1358+ move.l d1, (a1)
1359+.loop
1360+ moveq #0, d1
1361+ move.b (a6)+, d1
1362+ beq .end
1363+ add.w d0, d1
1364+ move.w d1, (a0)
1365+ bra .loop
1366+.end
1367+ rts
1368+
1369+;Returns string length in d0
1370+;a6 - pointer to string
1371+strlen:
1372+ moveq #-1, d0
1373+.loop
1374+ addq #1, d0
1375+ tst.b (a6)+
1376+ bne .loop
1377+ rts
1378+
1379+ align 1
1380+font:
1381+ incbin font_interlace_variable.tiles
1382+fontend
1383+arrow:
1384+ incbin arrow.tiles
1385+arrowend:
1386+cursor:
1387+ incbin cursor.tiles
1388+cursorend:
1389+button:
1390+ incbin button.tiles
1391+buttonend:
1392+fontfixed:
1393+ incbin font.tiles
1394+fontfixedend:
1395+
1396+widths:
1397+ dc.b 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1
1398+ dc.b 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0
1399+ dc.b 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1
1400+ dc.b 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
1401+ dc.b 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1
1402+
1403+main_menu:
1404+ dc.b "Load ROM", 0
1405+ dc.b "About", 0
1406+ dc.b "Exit", 0
1407+ dc.b 0
1408+
1409+ align 1
1410+main_menu_func:
1411+ dc.l menu_start
1412+ dc.l show_about
1413+ dc.l exit
1414+
1415+about_menu:
1416+ dc.b "Return", 0
1417+ dc.b 0
1418+
1419+ align 1
1420+about_menu_func:
1421+ dc.l show_main_menu
1422+
1423+pause_menu:
1424+ dc.b "Resume", 0
1425+ dc.b "Load ROM", 0
1426+ dc.b "Lock On", 0
1427+ dc.b "Save State", 0
1428+ dc.b "Load State", 0
1429+ dc.b "Exit", 0
1430+ dc.b 0
1431+
1432+ align 1
1433+pause_menu_func
1434+ dc.l resume
1435+ dc.l menu_start
1436+ dc.l lock_on
1437+ dc.l save_state
1438+ dc.l load_state
1439+ dc.l exit
1440+
1441+rom_end:
+37,
-0
1@@ -0,0 +1,37 @@
2+#include "genesis.h"
3+
4+void *write_multi_game_b(uint32_t address, void *vcontext, uint8_t value)
5+{
6+ m68k_context *context = vcontext;
7+ genesis_context *gen = context->system;
8+ gen->bank_regs[0] = address;
9+ uint32_t base = (address & 0x3F) << 16, start = 0, end = 0x400000;
10+ //find the memmap chunk, so we can properly mask the base value
11+ for (int i = 0; i < context->options->gen.memmap_chunks; i++)
12+ {
13+ if (context->options->gen.memmap[i].flags & MMAP_PTR_IDX) {
14+ base &= context->options->gen.memmap[i].mask;
15+ start = context->options->gen.memmap[i].start;
16+ end = context->options->gen.memmap[i].end;
17+ break;
18+ }
19+ }
20+ context->mem_pointers[gen->mapper_start_index] = gen->cart + base/2;
21+ m68k_invalidate_code_range(context, start, end);
22+ return vcontext;
23+}
24+
25+void *write_multi_game_w(uint32_t address, void *context, uint16_t value)
26+{
27+ return write_multi_game_b(address, context, value);
28+}
29+
30+void multi_game_serialize(genesis_context *gen, serialize_buffer *buf)
31+{
32+ save_int8(buf, gen->bank_regs[0]);
33+}
34+
35+void multi_game_deserialize(deserialize_buffer *buf, genesis_context *gen)
36+{
37+ write_multi_game_b(load_int8(buf), gen->m68k, 0);
38+}
+9,
-0
1@@ -0,0 +1,9 @@
2+#ifndef MULTI_GAME_H_
3+#define MULTI_GAME_H_
4+#include "serialize.h"
5+
6+void *write_multi_game_b(uint32_t address, void *context, uint8_t value);
7+void *write_multi_game_w(uint32_t address, void *context, uint16_t value);
8+void multi_game_serialize(genesis_context *gen, serialize_buffer *buf);
9+void multi_game_deserialize(deserialize_buffer *buf, genesis_context *gen);
10+#endif //MULTI_GAME_H_
+33,
-0
1@@ -0,0 +1,33 @@
2+ E(CMD_OK),
3+ E(CMD_VERSION),
4+ E(CMD_ECHO),
5+ E(CMD_AP_SCAN),
6+ E(CMD_AP_CFG),
7+ E(CMD_AP_CFG_GET),
8+ E(CMD_IP_CURRENT),
9+ E(CMD_RESERVED),
10+ E(CMD_IP_CFG),
11+ E(CMD_IP_CFG_GET),
12+ E(CMD_DEF_AP_CFG),
13+ E(CMD_DEF_AP_CFG_GET),
14+ E(CMD_AP_JOIN),
15+ E(CMD_AP_LEAVE),
16+ E(CMD_TCP_CON),
17+ E(CMD_TCP_BIND),
18+ E(CMD_TCP_ACCEPT),
19+ E(CMD_TCP_DISC),
20+ E(CMD_UDP_SET),
21+ E(CMD_UDP_CLR),
22+ E(CMD_SOCK_STAT),
23+ E(CMD_PING),
24+ E(CMD_SNTP_CFG),
25+ E(CMD_SNTP_CFG_GET),
26+ E(CMD_DATETIME),
27+ E(CMD_DT_SET),
28+ E(CMD_FLASH_WRITE),
29+ E(CMD_FLASH_READ),
30+ E(CMD_FLASH_ERASE),
31+ E(CMD_FLASH_ID),
32+ E(CMD_SYS_STAT),
33+ E(CMD_DEF_CFG_SET),
34+ E(CMD_HRNG_GET),
A
net.c
+49,
-0
1@@ -0,0 +1,49 @@
2+#include <sys/types.h>
3+#include <ifaddrs.h>
4+#include <netinet/in.h>
5+#include "net.h"
6+
7+static uint8_t is_loopback(struct sockaddr_in *addr)
8+{
9+ return (addr->sin_addr.s_addr & 0xFF) == 127;
10+}
11+
12+static void format_address(uint8_t *dst, struct sockaddr_in *addr)
13+{
14+ long ip = addr->sin_addr.s_addr;
15+ dst[0] = ip;
16+ dst[1] = ip >> 8;
17+ dst[2] = ip >> 16;
18+ dst[3] = ip >> 24;
19+}
20+
21+uint8_t get_host_address(iface_info *out)
22+{
23+ struct ifaddrs *entries, *current, *localhost;
24+ if (getifaddrs(&entries)) {
25+ return 0;
26+ }
27+
28+ for (current = entries; current; current = current->ifa_next)
29+ {
30+ if (current->ifa_addr && current->ifa_addr->sa_family == AF_INET) {
31+ struct sockaddr_in *addr = (struct sockaddr_in *)current->ifa_addr;
32+ if (is_loopback(addr)) {
33+ localhost = current;
34+ } else {
35+ break;
36+ }
37+ }
38+ }
39+ if (!current && localhost) {
40+ current = localhost;
41+ }
42+ uint8_t ret = 0;
43+ if (current) {
44+ ret = 1;
45+ format_address(out->ip, (struct sockaddr_in *)current->ifa_addr);
46+ format_address(out->net_mask, (struct sockaddr_in *)current->ifa_netmask);
47+ }
48+ freeifaddrs(entries);
49+ return ret;
50+}
A
net.h
+12,
-0
1@@ -0,0 +1,12 @@
2+#ifndef NET_H_
3+#define NET_H_
4+#include <stdint.h>
5+
6+typedef struct {
7+ uint8_t ip[4];
8+ uint8_t net_mask[4];
9+} iface_info;
10+
11+uint8_t get_host_address(iface_info *out);
12+
13+#endif //NET_H_
A
nor.c
+217,
-0
1@@ -0,0 +1,217 @@
2+#include "genesis.h"
3+#include <stdlib.h>
4+#include <string.h>
5+#include "util.h"
6+
7+enum {
8+ NOR_NORMAL,
9+ NOR_PRODUCTID,
10+ NOR_BOOTBLOCK
11+};
12+
13+enum {
14+ NOR_CMD_IDLE,
15+ NOR_CMD_AA,
16+ NOR_CMD_55
17+};
18+
19+//Technically this value shoudl be slightly different between NTSC and PAL
20+//as it's defined as 200 micro-seconds, not in clock cycles
21+#define NOR_WRITE_PAUSE 10690
22+
23+void nor_flash_init(nor_state *state, uint8_t *buffer, uint32_t size, uint32_t page_size, uint16_t product_id, uint8_t bus_flags)
24+{
25+ state->buffer = buffer;
26+ state->page_buffer = malloc(page_size);
27+ memset(state->page_buffer, 0xFF, page_size);
28+ state->size = size;
29+ state->page_size = page_size;
30+ state->product_id = product_id;
31+ state->last_write_cycle = 0xFFFFFFFF;
32+ state->mode = NOR_NORMAL;
33+ state->cmd_state = NOR_CMD_IDLE;
34+ state->alt_cmd = 0;
35+ state->bus_flags = bus_flags;
36+ state->cmd_address1 = 0x5555;
37+ state->cmd_address2 = 0x2AAA;
38+}
39+
40+void nor_run(nor_state *state, m68k_context *m68k, uint32_t cycle)
41+{
42+ if (state->last_write_cycle == 0xFFFFFFFF) {
43+ return;
44+ }
45+ if (cycle - state->last_write_cycle >= NOR_WRITE_PAUSE) {
46+ state->last_write_cycle = 0xFFFFFFFF;
47+ for (uint32_t i = 0; i < state->page_size; i++) {
48+ state->buffer[state->current_page + i] = state->page_buffer[i];
49+ }
50+ memset(state->page_buffer, 0xFF, state->page_size);
51+ if (state->bus_flags == RAM_FLAG_BOTH) {
52+ //TODO: add base address of NOR device to start and end addresses
53+ m68k_invalidate_code_range(m68k, state->current_page, state->current_page + state->page_size);
54+ }
55+ }
56+}
57+
58+uint8_t nor_flash_read_b(uint32_t address, void *vcontext)
59+{
60+ m68k_context *m68k = vcontext;
61+ genesis_context *gen = m68k->system;
62+ nor_state *state = &gen->nor;
63+ if (
64+ ((address & 1) && state->bus_flags == RAM_FLAG_EVEN) ||
65+ (!(address & 1) && state->bus_flags == RAM_FLAG_ODD)
66+ ) {
67+ return 0xFF;
68+ }
69+ if (state->bus_flags != RAM_FLAG_BOTH) {
70+ address = address >> 1;
71+ }
72+
73+ nor_run(state, m68k, m68k->current_cycle);
74+ switch (state->mode)
75+ {
76+ case NOR_NORMAL:
77+ if (state->bus_flags == RAM_FLAG_BOTH) {
78+ address ^= 1;
79+ }
80+ return state->buffer[address & (state->size-1)];
81+ break;
82+ case NOR_PRODUCTID:
83+ switch (address & (state->size - 1))
84+ {
85+ case 0:
86+ return state->product_id >> 8;
87+ case 1:
88+ return state->product_id;
89+ case 2:
90+ //TODO: Implement boot block protection
91+ return 0xFE;
92+ default:
93+ return 0xFE;
94+ } //HERE
95+ break;
96+ case NOR_BOOTBLOCK:
97+ break;
98+ }
99+ return 0xFF;
100+}
101+
102+uint16_t nor_flash_read_w(uint32_t address, void *context)
103+{
104+ uint16_t value = nor_flash_read_b(address, context) << 8;
105+ value |= nor_flash_read_b(address+1, context);
106+ return value;
107+}
108+
109+void nor_write_byte(nor_state *state, uint32_t address, uint8_t value, uint32_t cycle)
110+{
111+ switch(state->mode)
112+ {
113+ case NOR_NORMAL:
114+ if (state->last_write_cycle != 0xFFFFFFFF) {
115+ state->current_page = address & (state->size - 1) & ~(state->page_size - 1);
116+ }
117+ if (state->bus_flags == RAM_FLAG_BOTH) {
118+ address ^= 1;
119+ }
120+ state->page_buffer[address & (state->page_size - 1)] = value;
121+ break;
122+ case NOR_PRODUCTID:
123+ break;
124+ case NOR_BOOTBLOCK:
125+ //TODO: Implement boot block protection
126+ state->mode = NOR_NORMAL;
127+ break;
128+ }
129+}
130+
131+void *nor_flash_write_b(uint32_t address, void *vcontext, uint8_t value)
132+{
133+ m68k_context *m68k = vcontext;
134+ genesis_context *gen = m68k->system;
135+ nor_state *state = &gen->nor;
136+ if (
137+ ((address & 1) && state->bus_flags == RAM_FLAG_EVEN) ||
138+ (!(address & 1) && state->bus_flags == RAM_FLAG_ODD)
139+ ) {
140+ return vcontext;
141+ }
142+ if (state->bus_flags != RAM_FLAG_BOTH) {
143+ address = address >> 1;
144+ }
145+
146+ nor_run(state, m68k, m68k->current_cycle);
147+ switch (state->cmd_state)
148+ {
149+ case NOR_CMD_IDLE:
150+ if (value == 0xAA && (address & (state->size - 1)) == state->cmd_address1) {
151+ state->cmd_state = NOR_CMD_AA;
152+ } else {
153+ nor_write_byte(state, address, value, m68k->current_cycle);
154+ state->cmd_state = NOR_CMD_IDLE;
155+ }
156+ break;
157+ case NOR_CMD_AA:
158+ if (value == 0x55 && (address & (state->size - 1)) == state->cmd_address2) {
159+ state->cmd_state = NOR_CMD_55;
160+ } else {
161+ nor_write_byte(state, state->cmd_address1, 0xAA, m68k->current_cycle);
162+ nor_write_byte(state, address, value, m68k->current_cycle);
163+ state->cmd_state = NOR_CMD_IDLE;
164+ }
165+ break;
166+ case NOR_CMD_55:
167+ if ((address & (state->size - 1)) == state->cmd_address1) {
168+ if (state->alt_cmd) {
169+ switch(value)
170+ {
171+ case 0x10:
172+ puts("UNIMPLEMENTED: NOR flash erase");
173+ break;
174+ case 0x20:
175+ puts("UNIMPLEMENTED: NOR flash disable protection");
176+ break;
177+ case 0x40:
178+ state->mode = NOR_BOOTBLOCK;
179+ break;
180+ case 0x60:
181+ state->mode = NOR_PRODUCTID;
182+ break;
183+ }
184+ } else {
185+ switch(value)
186+ {
187+ case 0x80:
188+ state->alt_cmd = 1;
189+ break;
190+ case 0x90:
191+ state->mode = NOR_PRODUCTID;
192+ break;
193+ case 0xA0:
194+ puts("UNIMPLEMENTED: NOR flash enable protection");
195+ break;
196+ case 0xF0:
197+ state->mode = NOR_NORMAL;
198+ break;
199+ default:
200+ printf("Unrecognized unshifted NOR flash command %X\n", value);
201+ }
202+ }
203+ } else {
204+ nor_write_byte(state, state->cmd_address1, 0xAA, m68k->current_cycle);
205+ nor_write_byte(state, state->cmd_address2, 0x55, m68k->current_cycle);
206+ nor_write_byte(state, address, value, m68k->current_cycle);
207+ }
208+ state->cmd_state = NOR_CMD_IDLE;
209+ break;
210+ }
211+ return vcontext;
212+}
213+
214+void *nor_flash_write_w(uint32_t address, void *vcontext, uint16_t value)
215+{
216+ nor_flash_write_b(address, vcontext, value >> 8);
217+ return nor_flash_write_b(address + 1, vcontext, value);
218+}
A
nor.h
+10,
-0
1@@ -0,0 +1,10 @@
2+#ifndef NOR_H_
3+#define NOR_H_
4+
5+void nor_flash_init(nor_state *state, uint8_t *buffer, uint32_t size, uint32_t page_size, uint16_t product_id, uint8_t bus_flags);
6+uint8_t nor_flash_read_b(uint32_t address, void *vcontext);
7+uint16_t nor_flash_read_w(uint32_t address, void *context);
8+void *nor_flash_write_b(uint32_t address, void *vcontext, uint8_t value);
9+void *nor_flash_write_w(uint32_t address, void *vcontext, uint16_t value);
10+
11+#endif //NOR_H_
+76,
-0
1@@ -0,0 +1,76 @@
2+cmp.w <ea>, Dn 4(1/0) + <ea> time
3+cmp.l <ea>, Dn 6(1/0) + <ea> time
4+cmp.w #num, Dn 4(1/0) + 4(1/0)
5+cmp.l #num, Dn 6(1/0) + 8(2/0)
6+
7+cmpi.w #num, Dn 8(2/0)
8+cmpi.l #num, Dn 14(3/0)
9+
10+
11+movem
12+
13+subtype field (bits 9-11) = 110 or 100 depending on direction
14+bit 8 = 0
15+bit 7 = 1
16+bit 6 = size
17+
18+
19+
20+x86-64 registers in 68K core
21+
22+1. native stack pointer
23+2. current cycle count
24+3. target cycle count
25+4. cartridge address
26+5. work ram address
27+6. scratch register
28+7. context pointer (contains 68K registers and memory pointers not in registers)
29+8. status register (maybe, depends on how well I can abuse native x86 status stuff)
30+Rest of registers used for holding 68K registers
31+
32+rax = cycle counter
33+bl = N flag
34+bh = V flag
35+rcx = scratch register
36+dl = Z flag
37+dh = C flag
38+rbp = target cycle count
39+rsi = context pointer
40+rdi = scratch register
41+r8 = cartridge address
42+r9 = work ram address
43+r10 = d0
44+r11 = d1
45+r12 = d2
46+r13 = a0
47+r14 = a1
48+r15 = a7
49+rsp = native stack pointer
50+
51+68K context:
52+uint8_t flags[5];
53+uint8_t pad??[3]
54+uint32_t dregs[8]; //8 + 4 * reg
55+uint32_t aregs[8]; //40 + 4 * reg
56+.....
57+
58+x86-64 registers in Z80 core
59+
60+ax = HL
61+bx = BC
62+cx = DE
63+dx = IX
64+ebp = current cycle count
65+rsi = context pointer
66+edi = target cycle count
67+rsp = native stack pointer
68+r8 = IY
69+r9 = SP
70+r10 = A (maybe AF?)
71+r11 = z80 ram address
72+r12 = cartridge address if bank is pointed at ROM
73+r13 = scratch1
74+r14 = scratch2
75+r15 = ?maybe z80 bank register?
76+
77+
A
paths.c
+89,
-0
1@@ -0,0 +1,89 @@
2+#include <string.h>
3+#include <stdlib.h>
4+#include "blastem.h"
5+#include "util.h"
6+
7+static char **current_path;
8+
9+static void persist_path(void)
10+{
11+ char *pathfname = alloc_concat(get_userdata_dir(), PATH_SEP "blastem" PATH_SEP "sticky_path");
12+ FILE *f = fopen(pathfname, "wb");
13+ if (f) {
14+ if (fwrite(*current_path, 1, strlen(*current_path), f) != strlen(*current_path)) {
15+ warning("Failed to save menu path");
16+ }
17+ fclose(f);
18+ } else {
19+ warning("Failed to save menu path: Could not open %s for writing\n", pathfname);
20+
21+ }
22+ free(pathfname);
23+}
24+
25+void get_initial_browse_path(char **dst)
26+{
27+ *dst = NULL;
28+ char *remember_path = tern_find_path(config, "ui\0remember_path\0", TVAL_PTR).ptrval;
29+ if (!remember_path || !strcmp("on", remember_path)) {
30+ char *pathfname = alloc_concat(get_userdata_dir(), PATH_SEP "blastem" PATH_SEP "sticky_path");
31+ FILE *f = fopen(pathfname, "rb");
32+ if (f) {
33+ long pathsize = file_size(f);
34+ if (pathsize > 0) {
35+ *dst = malloc(pathsize + 1);
36+ if (fread(*dst, 1, pathsize, f) != pathsize) {
37+ warning("Error restoring saved file browser path");
38+ free(*dst);
39+ *dst = NULL;
40+ } else {
41+ (*dst)[pathsize] = 0;
42+ }
43+ }
44+ fclose(f);
45+ }
46+ free(pathfname);
47+ if (!current_path) {
48+ atexit(persist_path);
49+ current_path = dst;
50+ }
51+ }
52+ if (!*dst) {
53+ *dst = tern_find_path(config, "ui\0initial_path\0", TVAL_PTR).ptrval;
54+ }
55+ if (!*dst){
56+ *dst = "$HOME";
57+ }
58+ tern_node *vars = tern_insert_ptr(NULL, "HOME", get_home_dir());
59+ vars = tern_insert_ptr(vars, "EXEDIR", get_exe_dir());
60+ *dst = replace_vars(*dst, vars, 1);
61+ tern_free(vars);
62+}
63+
64+char *path_append(const char *base, const char *suffix)
65+{
66+ if (!strcmp(suffix, "..")) {
67+ size_t len = strlen(base);
68+ while (len > 0) {
69+ --len;
70+ if (is_path_sep(base[len])) {
71+ if (!len) {
72+ //special handling for /
73+ len++;
74+ }
75+ char *ret = malloc(len+1);
76+ memcpy(ret, base, len);
77+ ret[len] = 0;
78+ return ret;
79+ }
80+ }
81+ return strdup(PATH_SEP);
82+ } else {
83+ if (is_path_sep(base[strlen(base) - 1])) {
84+ return alloc_concat(base, suffix);
85+ } else {
86+ char const *pieces[] = {base, PATH_SEP, suffix};
87+ return alloc_concat_m(3, pieces);
88+ }
89+ }
90+}
A
paths.h
+7,
-0
1@@ -0,0 +1,7 @@
2+#ifndef PATHS_H_
3+#define PATHS_H_
4+
5+void get_initial_browse_path(char **dst);
6+char *path_append(const char *base, const char *suffix);
7+
8+#endif //PATHS_H_
A
png.c
+447,
-0
1@@ -0,0 +1,447 @@
2+#include <stdint.h>
3+#include <stdlib.h>
4+#include <stdio.h>
5+#include <string.h>
6+#include <zlib.h>
7+
8+static const char png_magic[] = {0x89, 'P', 'N', 'G', '\r', '\n', 0x1A, '\n'};
9+static const char ihdr[] = {'I', 'H', 'D', 'R'};
10+static const char plte[] = {'P', 'L', 'T', 'E'};
11+static const char idat[] = {'I', 'D', 'A', 'T'};
12+static const char iend[] = {'I', 'E', 'N', 'D'};
13+
14+enum {
15+ COLOR_GRAY,
16+ COLOR_TRUE = 2,
17+ COLOR_INDEXED,
18+ COLOR_GRAY_ALPHA,
19+ COLOR_TRUE_ALPHA=6
20+};
21+
22+static void write_chunk(FILE *f, const char*id, uint8_t *buffer, uint32_t size)
23+{
24+ uint8_t tmp[4] = {size >> 24, size >> 16, size >> 8, size};
25+ uint8_t warn = 0;
26+ warn = warn || (sizeof(tmp) != fwrite(tmp, 1, sizeof(tmp), f));
27+ warn = warn || (4 != fwrite(id, 1, 4, f));
28+ if (size) {
29+ warn = warn || (size != fwrite(buffer, 1, size, f));
30+ }
31+
32+ uint32_t crc = crc32(0, NULL, 0);
33+ crc = crc32(crc, id, 4);
34+ if (size) {
35+ crc = crc32(crc, buffer, size);
36+ }
37+ tmp[0] = crc >> 24;
38+ tmp[1] = crc >> 16;
39+ tmp[2] = crc >> 8;
40+ tmp[3] = crc;
41+ warn = warn || (sizeof(tmp) != fwrite(tmp, 1, sizeof(tmp), f));
42+ if (warn) {
43+ fprintf(stderr, "Failure during write of %c%c%c%c chunk\n", id[0], id[1], id[2], id[3]);
44+ }
45+}
46+
47+static void write_header(FILE *f, uint32_t width, uint32_t height, uint8_t color_type)
48+{
49+ uint8_t chunk[13] = {
50+ width >> 24, width >> 16, width >> 8, width,
51+ height >> 24, height >> 16, height >> 8, height,
52+ 8, color_type, 0, 0, 0
53+ };
54+ if (sizeof(png_magic) != fwrite(png_magic, 1, sizeof(png_magic), f)) {
55+ fputs("Error writing PNG magic\n", stderr);
56+ }
57+ write_chunk(f, ihdr, chunk, sizeof(chunk));
58+}
59+
60+void save_png24(FILE *f, uint32_t *buffer, uint32_t width, uint32_t height, uint32_t pitch)
61+{
62+ uint32_t idat_size = (1 + width*3) * height;
63+ uint8_t *idat_buffer = malloc(idat_size);
64+ uint32_t *pixel = buffer;
65+ uint8_t *cur = idat_buffer;
66+ for (uint32_t y = 0; y < height; y++)
67+ {
68+ //save filter type
69+ *(cur++) = 0;
70+ uint32_t *start = pixel;
71+ for (uint32_t x = 0; x < width; x++, pixel++)
72+ {
73+ uint32_t value = *pixel;
74+ *(cur++) = value >> 16;
75+ *(cur++) = value >> 8;
76+ *(cur++) = value;
77+ }
78+ pixel = start + pitch / sizeof(uint32_t);
79+ }
80+ write_header(f, width, height, COLOR_TRUE);
81+ uLongf compress_buffer_size = idat_size + 5 * (idat_size/16383 + 1) + 3;
82+ uint8_t *compressed = malloc(compress_buffer_size);
83+ compress(compressed, &compress_buffer_size, idat_buffer, idat_size);
84+ free(idat_buffer);
85+ write_chunk(f, idat, compressed, compress_buffer_size);
86+ write_chunk(f, iend, NULL, 0);
87+ free(compressed);
88+}
89+
90+void save_png(FILE *f, uint32_t *buffer, uint32_t width, uint32_t height, uint32_t pitch)
91+{
92+ uint32_t palette[256];
93+ uint8_t pal_buffer[256*3];
94+ uint32_t num_pal = 0;
95+ uint32_t index_size = (1 + width) * height;
96+ uint8_t *index_buffer = malloc(index_size);
97+ uint8_t *cur = index_buffer;
98+ uint32_t *pixel = buffer;
99+ for (uint32_t y = 0; y < height; y++)
100+ {
101+ //save filter type
102+ *(cur++) = 0;
103+ uint32_t *start = pixel;
104+ for (uint32_t x = 0; x < width; x++, pixel++, cur++)
105+ {
106+ uint32_t value = (*pixel) & 0xFFFFFF;
107+ uint32_t i;
108+ for (i = 0; i < num_pal; i++)
109+ {
110+ if (palette[i] == value) {
111+ break;
112+ }
113+ }
114+ if (i == num_pal) {
115+ if (num_pal == 256) {
116+ free(index_buffer);
117+ save_png24(f, buffer, width, height, pitch);
118+ return;
119+ }
120+ palette[i] = value;
121+ num_pal++;
122+ }
123+ *cur = i;
124+ }
125+ pixel = start + pitch / sizeof(uint32_t);
126+ }
127+ write_header(f, width, height, COLOR_INDEXED);
128+ cur = pal_buffer;
129+ for (uint32_t i = 0; i < num_pal; i++)
130+ {
131+ *(cur++) = palette[i] >> 16;
132+ *(cur++) = palette[i] >> 8;
133+ *(cur++) = palette[i];
134+ }
135+ write_chunk(f, plte, pal_buffer, num_pal * 3);
136+ uLongf compress_buffer_size = index_size + 5 * (index_size/16383 + 1) + 3;
137+ uint8_t *compressed = malloc(compress_buffer_size);
138+ compress(compressed, &compress_buffer_size, index_buffer, index_size);
139+ free(index_buffer);
140+ write_chunk(f, idat, compressed, compress_buffer_size);
141+ write_chunk(f, iend, NULL, 0);
142+ free(compressed);
143+}
144+
145+typedef uint8_t (*filter_fun)(uint8_t *cur, uint8_t *last, uint8_t bpp, uint32_t x);
146+typedef uint32_t (*pixel_fun)(uint8_t **cur, uint8_t **last, uint8_t bpp, uint32_t x, filter_fun);
147+
148+static uint8_t filter_none(uint8_t *cur, uint8_t *last, uint8_t bpp, uint32_t x)
149+{
150+ return *cur;
151+}
152+
153+static uint8_t filter_sub(uint8_t *cur, uint8_t *last, uint8_t bpp, uint32_t x)
154+{
155+ if (x) {
156+ return *cur + *(cur - bpp);
157+ } else {
158+ return *cur;
159+ }
160+}
161+
162+static uint8_t filter_up(uint8_t *cur, uint8_t *last, uint8_t bpp, uint32_t x)
163+{
164+ if (last) {
165+ return *cur + *last;
166+ } else {
167+ return *cur;
168+ }
169+}
170+
171+static uint8_t filter_avg(uint8_t *cur, uint8_t *last, uint8_t bpp, uint32_t x)
172+{
173+ uint8_t prev = x ? *(cur - bpp) : 0;
174+ uint8_t prior = last ? *last : 0;
175+ return *cur + ((prev + prior) >> 1);
176+}
177+
178+static uint8_t paeth(uint8_t a, uint8_t b, uint8_t c)
179+{
180+ int32_t p = a + b - c;
181+ int32_t pa = abs(p - a);
182+ int32_t pb = abs(p - b);
183+ int32_t pc = abs(p - c);
184+ if (pa <= pb && pa <= pc) {
185+ return a;
186+ }
187+ if (pb <= pc) {
188+ return b;
189+ }
190+ return c;
191+}
192+
193+static uint8_t filter_paeth(uint8_t *cur, uint8_t *last, uint8_t bpp, uint32_t x)
194+{
195+ uint8_t prev, prev_prior;
196+ if (x) {
197+ prev = *(cur - bpp);
198+ prev_prior = *(last - bpp);
199+ } else {
200+ prev = prev_prior = 0;
201+ }
202+ uint8_t prior = last ? *last : 0;
203+ return *cur + paeth(prev, prior, prev_prior);
204+}
205+
206+static uint32_t pixel_gray(uint8_t **cur, uint8_t **last, uint8_t bpp, uint32_t x, filter_fun filter)
207+{
208+ uint8_t value = filter(*cur, *last, bpp, x);
209+ (*cur)++;
210+ if (*last) {
211+ (*last)++;
212+ }
213+ return 0xFF000000 | value << 16 | value << 8 | value;
214+}
215+
216+static uint32_t pixel_true(uint8_t **cur, uint8_t **last, uint8_t bpp, uint32_t x, filter_fun filter)
217+{
218+ uint8_t red = filter(*cur, *last, bpp, x);
219+ (*cur)++;
220+ if (*last) {
221+ (*last)++;
222+ }
223+ uint8_t green = filter(*cur, *last, bpp, x);
224+ (*cur)++;
225+ if (*last) {
226+ (*last)++;
227+ }
228+ uint8_t blue = filter(*cur, *last, bpp, x);
229+ (*cur)++;
230+ if (*last) {
231+ (*last)++;
232+ }
233+ return 0xFF000000 | red << 16 | green << 8 | blue;
234+}
235+
236+static uint32_t pixel_gray_alpha(uint8_t **cur, uint8_t **last, uint8_t bpp, uint32_t x, filter_fun filter)
237+{
238+ uint8_t value = filter(*cur, *last, bpp, x);
239+ (*cur)++;
240+ if (*last) {
241+ (*last)++;
242+ }
243+ uint8_t alpha = filter(*cur, *last, bpp, x);
244+ (*cur)++;
245+ if (*last) {
246+ (*last)++;
247+ }
248+ return alpha << 24 | value << 16 | value << 8 | value;
249+}
250+
251+static uint32_t pixel_true_alpha(uint8_t **cur, uint8_t **last, uint8_t bpp, uint32_t x, filter_fun filter)
252+{
253+ uint8_t red = filter(*cur, *last, bpp, x);
254+ (*cur)++;
255+ if (*last) {
256+ (*last)++;
257+ }
258+ uint8_t green = filter(*cur, *last, bpp, x);
259+ (*cur)++;
260+ if (*last) {
261+ (*last)++;
262+ }
263+ uint8_t blue = filter(*cur, *last, bpp, x);
264+ (*cur)++;
265+ if (*last) {
266+ (*last)++;
267+ }
268+ uint8_t alpha = filter(*cur, *last, bpp, x);
269+ (*cur)++;
270+ if (*last) {
271+ (*last)++;
272+ }
273+ return alpha << 24 | red << 16 | green << 8 | blue;
274+}
275+
276+static filter_fun filters[] = {filter_none, filter_sub, filter_up, filter_avg, filter_paeth};
277+
278+#define MIN_CHUNK_SIZE 12
279+#define MIN_IHDR_SIZE 0xD
280+#define MAX_SUPPORTED_DIM 32767 //chosen to avoid possibility of overflow when calculating uncompressed size
281+uint32_t *load_png(uint8_t *buffer, uint32_t buf_size, uint32_t *width, uint32_t *height)
282+{
283+ if (buf_size < sizeof(png_magic) || memcmp(buffer, png_magic, sizeof(png_magic))) {
284+ return NULL;
285+ }
286+ uint32_t cur = sizeof(png_magic);
287+ uint8_t has_header = 0;
288+ uint8_t bits, color_type, comp_type, filter_type, interlace;
289+ uint8_t *idat_buf = NULL;
290+ uint8_t idat_needs_free = 0;
291+ uint32_t idat_size;
292+ uint32_t *out = NULL;
293+ uint32_t *palette = NULL;
294+ while(cur + MIN_CHUNK_SIZE <= buf_size)
295+ {
296+ uint32_t chunk_size = buffer[cur++] << 24;
297+ chunk_size |= buffer[cur++] << 16;
298+ chunk_size |= buffer[cur++] << 8;
299+ chunk_size |= buffer[cur++];
300+ if (!memcmp(ihdr, buffer + cur, sizeof(ihdr))) {
301+ if (chunk_size < MIN_IHDR_SIZE || cur + MIN_IHDR_SIZE > buf_size) {
302+ return NULL;
303+ }
304+ cur += sizeof(ihdr);
305+ *width = buffer[cur++] << 24;
306+ *width |= buffer[cur++] << 16;
307+ *width |= buffer[cur++] << 8;
308+ *width |= buffer[cur++];
309+ *height = buffer[cur++] << 24;
310+ *height |= buffer[cur++] << 16;
311+ *height |= buffer[cur++] << 8;
312+ *height |= buffer[cur++];
313+ if (*width > MAX_SUPPORTED_DIM || *height > MAX_SUPPORTED_DIM) {
314+ return NULL;
315+ }
316+ bits = buffer[cur++];
317+ if (bits != 8) {
318+ //only support 8-bits per element for now
319+ return NULL;
320+ }
321+ color_type = buffer[cur++];
322+ if (color_type > COLOR_TRUE_ALPHA || color_type == 1 || color_type == 5) {
323+ //reject invalid color type
324+ return NULL;
325+ }
326+ comp_type = buffer[cur++];
327+ if (comp_type) {
328+ //only compression type 0 is defined by the spec
329+ return NULL;
330+ }
331+ filter_type = buffer[cur++];
332+ interlace = buffer[cur++];
333+ if (interlace) {
334+ //interlacing not supported for now
335+ return NULL;
336+ }
337+ cur += chunk_size - MIN_IHDR_SIZE;
338+ has_header = 1;
339+ } else {
340+ if (!has_header) {
341+ //IHDR is required to be the first chunk, fail if it isn't
342+ break;
343+ }
344+ if (!memcmp(plte, buffer + cur, sizeof(plte))) {
345+ //TODO: implement paletted images
346+ } else if (!memcmp(idat, buffer + cur, sizeof(idat))) {
347+ cur += sizeof(idat);
348+ if (idat_buf) {
349+ if (idat_needs_free) {
350+ idat_buf = realloc(idat_buf, idat_size + chunk_size);
351+ } else {
352+ uint8_t *tmp = idat_buf;
353+ idat_buf = malloc(idat_size + chunk_size);
354+ memcpy(idat_buf, tmp, idat_size);
355+ }
356+ memcpy(idat_buf + idat_size, buffer + cur, chunk_size);
357+ idat_size += chunk_size;
358+ } else {
359+ idat_buf = buffer + cur;
360+ idat_size = chunk_size;
361+ }
362+ cur += chunk_size;
363+ } else if (!memcmp(iend, buffer + cur, sizeof(iend))) {
364+ if (!idat_buf) {
365+ break;
366+ }
367+ if (!palette && color_type == COLOR_INDEXED) {
368+ //indexed color, but no PLTE chunk found
369+ return NULL;
370+ }
371+ uLongf uncompressed_size = *width * *height;
372+ uint8_t bpp;
373+ pixel_fun pixel;
374+ switch (color_type)
375+ {
376+ case COLOR_GRAY:
377+ uncompressed_size *= bits / 8;
378+ bpp = bits/8;
379+ pixel = pixel_gray;
380+ break;
381+ case COLOR_TRUE:
382+ uncompressed_size *= 3 * bits / 8;
383+ bpp = 3 * bits/8;
384+ pixel = pixel_true;
385+ break;
386+ case COLOR_INDEXED: {
387+ uint32_t pixels_per_byte = 8 / bits;
388+ uncompressed_size = (*width / pixels_per_byte) * *height;
389+ if (*width % pixels_per_byte) {
390+ uncompressed_size += *height;
391+ }
392+ bpp = 1;
393+ break;
394+ }
395+ case COLOR_GRAY_ALPHA:
396+ uncompressed_size *= bits / 4;
397+ bpp = bits / 4;
398+ pixel = pixel_gray_alpha;
399+ break;
400+ case COLOR_TRUE_ALPHA:
401+ uncompressed_size *= bits / 2;
402+ bpp = bits / 2;
403+ pixel = pixel_true_alpha;
404+ break;
405+ }
406+ //add filter type byte
407+ uncompressed_size += *height;
408+ uint8_t *decomp_buffer = malloc(uncompressed_size);
409+ if (Z_OK != uncompress(decomp_buffer, &uncompressed_size, idat_buf, idat_size)) {
410+ free(decomp_buffer);
411+ break;
412+ }
413+ out = calloc(*width * *height, sizeof(uint32_t));
414+ uint32_t *cur_pixel = out;
415+ uint8_t *cur_byte = decomp_buffer;
416+ uint8_t *last_line = NULL;
417+ for (uint32_t y = 0; y < *height; y++)
418+ {
419+ uint8_t filter_type = *(cur_byte++);
420+ if (filter_type >= sizeof(filters)/sizeof(*filters)) {
421+ free(out);
422+ out = NULL;
423+ free(decomp_buffer);
424+ break;
425+ }
426+ filter_fun filter = filters[filter_type];
427+ uint8_t *line_start = cur_byte;
428+ for (uint32_t x = 0; x < *width; x++)
429+ {
430+ *(cur_pixel++) = pixel(&cur_byte, &last_line, bpp, x, filter);
431+ }
432+ last_line = line_start;
433+ }
434+ free(decomp_buffer);
435+ } else {
436+ //skip uncrecognized chunks
437+ cur += 4 + chunk_size;
438+ }
439+ }
440+ //skip CRC for now
441+ cur += sizeof(uint32_t);
442+ }
443+ if (idat_needs_free) {
444+ free(idat_buf);
445+ }
446+ free(palette);
447+ return out;
448+}
A
png.h
+8,
-0
1@@ -0,0 +1,8 @@
2+#ifndef PNG_H_
3+#define PNG_H_
4+
5+void save_png24(FILE *f, uint32_t *buffer, uint32_t width, uint32_t height, uint32_t pitch);
6+void save_png(FILE *f, uint32_t *buffer, uint32_t width, uint32_t height, uint32_t pitch);
7+uint32_t *load_png(uint8_t *buffer, uint32_t buf_size, uint32_t *width, uint32_t *height);
8+
9+#endif //PNG_H_
A
ppm.c
+21,
-0
1@@ -0,0 +1,21 @@
2+#include <stdint.h>
3+#include <stdio.h>
4+
5+void save_ppm(FILE *f, uint32_t *buffer, uint32_t width, uint32_t height, uint32_t pitch)
6+{
7+ fprintf(f, "P6\n%d %d\n255\n", width, height);
8+ for(uint32_t y = 0; y < height; y++)
9+ {
10+ uint32_t *line = buffer;
11+ for (uint32_t x = 0; x < width; x++, line++)
12+ {
13+ uint8_t buf[3] = {
14+ *line >> 16, //red
15+ *line >> 8, //green
16+ *line //blue
17+ };
18+ fwrite(buf, 1, sizeof(buf), f);
19+ }
20+ buffer = buffer + pitch / sizeof(uint32_t);
21+ }
22+}
A
ppm.h
+6,
-0
1@@ -0,0 +1,6 @@
2+#ifndef PPM_H_
3+#define PPM_H_
4+
5+void save_ppm(FILE *f, uint32_t *buffer, uint32_t width, uint32_t height, uint32_t pitch);
6+
7+#endif //PPM_H_
A
psg.c
+157,
-0
1@@ -0,0 +1,157 @@
2+/*
3+ Copyright 2013 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#include "psg.h"
8+#include "render.h"
9+#include "blastem.h"
10+#include <string.h>
11+#include <stdlib.h>
12+#include <stdio.h>
13+#include <math.h>
14+void psg_init(psg_context * context, uint32_t master_clock, uint32_t clock_div)
15+{
16+ memset(context, 0, sizeof(*context));
17+ context->audio = render_audio_source(master_clock, clock_div, 1);
18+ context->clock_inc = clock_div;
19+ for (int i = 0; i < 4; i++) {
20+ context->volume[i] = 0xF;
21+ }
22+}
23+
24+void psg_free(psg_context *context)
25+{
26+ render_free_source(context->audio);
27+ free(context);
28+}
29+
30+void psg_adjust_master_clock(psg_context * context, uint32_t master_clock)
31+{
32+ render_audio_adjust_clock(context->audio, master_clock, context->clock_inc);
33+}
34+
35+void psg_write(psg_context * context, uint8_t value)
36+{
37+ if (value & 0x80) {
38+ context->latch = value & 0x70;
39+ uint8_t channel = value >> 5 & 0x3;
40+ if (value & 0x10) {
41+ context->volume[channel] = value & 0xF;
42+ } else {
43+ if (channel == 3) {
44+ switch(value & 0x3)
45+ {
46+ case 0:
47+ case 1:
48+ case 2:
49+ context->counter_load[3] = 0x10 << (value & 0x3);
50+ context->noise_use_tone = 0;
51+ break;
52+ default:
53+ context->counter_load[3] = context->counter_load[2];
54+ context->noise_use_tone = 1;
55+ }
56+ context->noise_type = value & 0x4;
57+ context->lsfr = 0x8000;
58+ } else {
59+ context->counter_load[channel] = (context->counter_load[channel] & 0x3F0) | (value & 0xF);
60+ if (channel == 2 && context->noise_use_tone) {
61+ context->counter_load[3] = context->counter_load[2];
62+ }
63+ }
64+ }
65+ } else {
66+ if (!(context->latch & 0x10)) {
67+ uint8_t channel = context->latch >> 5 & 0x3;
68+ if (channel != 3) {
69+ context->counter_load[channel] = (value << 4 & 0x3F0) | (context->counter_load[channel] & 0xF);
70+ if (channel == 2 && context->noise_use_tone) {
71+ context->counter_load[3] = context->counter_load[2];
72+ }
73+ }
74+ }
75+ }
76+}
77+
78+#define PSG_VOL_DIV 14
79+
80+//table shamelessly swiped from PSG doc from smspower.org
81+static int16_t volume_table[16] = {
82+ 32767/PSG_VOL_DIV, 26028/PSG_VOL_DIV, 20675/PSG_VOL_DIV, 16422/PSG_VOL_DIV, 13045/PSG_VOL_DIV, 10362/PSG_VOL_DIV,
83+ 8231/PSG_VOL_DIV, 6568/PSG_VOL_DIV, 5193/PSG_VOL_DIV, 4125/PSG_VOL_DIV, 3277/PSG_VOL_DIV, 2603/PSG_VOL_DIV,
84+ 2067/PSG_VOL_DIV, 1642/PSG_VOL_DIV, 1304/PSG_VOL_DIV, 0
85+};
86+
87+void psg_run(psg_context * context, uint32_t cycles)
88+{
89+ while (context->cycles < cycles) {
90+ for (int i = 0; i < 4; i++) {
91+ if (context->counters[i]) {
92+ context->counters[i] -= 1;
93+ }
94+ if (!context->counters[i]) {
95+ context->counters[i] = context->counter_load[i];
96+ context->output_state[i] = !context->output_state[i];
97+ if (i == 3 && context->output_state[i]) {
98+ context->noise_out = context->lsfr & 1;
99+ context->lsfr = (context->lsfr >> 1) | (context->lsfr << 15);
100+ if (context->noise_type) {
101+ //white noise
102+ if (context->lsfr & 0x40) {
103+ context->lsfr ^= 0x8000;
104+ }
105+ }
106+ }
107+ }
108+ }
109+
110+ int16_t accum = 0;
111+
112+ for (int i = 0; i < 3; i++) {
113+ if (context->output_state[i]) {
114+ accum += volume_table[context->volume[i]];
115+ }
116+ }
117+ if (context->noise_out) {
118+ accum += volume_table[context->volume[3]];
119+ }
120+
121+ render_put_mono_sample(context->audio, accum);
122+
123+ context->cycles += context->clock_inc;
124+ }
125+}
126+
127+void psg_serialize(psg_context *context, serialize_buffer *buf)
128+{
129+ save_int16(buf, context->lsfr);
130+ save_buffer16(buf, context->counter_load, 4);
131+ save_buffer16(buf, context->counters, 4);
132+ save_buffer8(buf, context->volume, 4);
133+ uint8_t output_state = context->output_state[0] << 3 | context->output_state[1] << 2
134+ | context->output_state[2] << 1 | context->output_state[3]
135+ | context->noise_use_tone << 4;
136+ save_int8(buf, output_state);
137+ save_int8(buf, context->noise_type);
138+ save_int8(buf, context->latch);
139+ save_int32(buf, context->cycles);
140+}
141+
142+void psg_deserialize(deserialize_buffer *buf, void *vcontext)
143+{
144+ psg_context *context = vcontext;
145+ context->lsfr = load_int16(buf);
146+ load_buffer16(buf, context->counter_load, 4);
147+ load_buffer16(buf, context->counters, 4);
148+ load_buffer8(buf, context->volume, 4);
149+ uint8_t output_state = load_int8(buf);
150+ context->output_state[0] = output_state >> 3 & 1;
151+ context->output_state[1] = output_state >> 2 & 1;
152+ context->output_state[2] = output_state >> 1 & 1;
153+ context->output_state[3] = output_state & 1;
154+ context->noise_use_tone = output_state >> 4 & 1;
155+ context->noise_type = load_int8(buf);
156+ context->latch = load_int8(buf);
157+ context->cycles = load_int32(buf);
158+}
A
psg.h
+38,
-0
1@@ -0,0 +1,38 @@
2+/*
3+ Copyright 2013 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#ifndef PSG_CONTEXT_H_
8+#define PSG_CONTEXT_H_
9+
10+#include <stdint.h>
11+#include "serialize.h"
12+#include "render.h"
13+
14+typedef struct {
15+ audio_source *audio;
16+ uint32_t clock_inc;
17+ uint32_t cycles;
18+ uint16_t lsfr;
19+ uint16_t counter_load[4];
20+ uint16_t counters[4];
21+ uint8_t volume[4];
22+ uint8_t output_state[4];
23+ uint8_t noise_out;
24+ uint8_t noise_use_tone;
25+ uint8_t noise_type;
26+ uint8_t latch;
27+} psg_context;
28+
29+
30+void psg_init(psg_context * context, uint32_t master_clock, uint32_t clock_div);
31+void psg_free(psg_context *context);
32+void psg_adjust_master_clock(psg_context * context, uint32_t master_clock);
33+void psg_write(psg_context * context, uint8_t value);
34+void psg_run(psg_context * context, uint32_t cycles);
35+void psg_serialize(psg_context *context, serialize_buffer *buf);
36+void psg_deserialize(deserialize_buffer *buf, void *vcontext);
37+
38+#endif //PSG_CONTEXT_H_
39+
+151,
-0
1@@ -0,0 +1,151 @@
2+#include <stdint.h>
3+#include <stdlib.h>
4+#include <string.h>
5+#include "romdb.h"
6+#include "genesis.h"
7+#include "util.h"
8+
9+typedef struct {
10+ uint8_t rom_space[512*1024];
11+ uint8_t regs[3];
12+} realtec;
13+
14+
15+uint8_t realtec_detect(uint8_t *rom, uint32_t rom_size)
16+{
17+ //All Realtec mapper games are 512KB total
18+ if (rom_size != 512*1024) {
19+ return 0;
20+ }
21+ return memcmp(rom + 0x7E100, "SEGA", 4) == 0;
22+}
23+
24+static realtec *get_realtec(genesis_context *gen)
25+{
26+ if (!gen->extra) {
27+ gen->extra = gen->m68k->mem_pointers[0];
28+ }
29+ return gen->extra;
30+}
31+
32+static void *realtec_write_b(uint32_t address, void *context, uint8_t value)
33+{
34+ if (address & 1) {
35+ return context;
36+ }
37+ m68k_context *m68k = context;
38+ genesis_context *gen = m68k->system;
39+ realtec *r = get_realtec(gen);
40+ uint32_t offset = address >> 13;
41+ if (offset < 3 && r->regs[offset] != value) {
42+ r->regs[offset] = value;
43+ //other regs are only 3 bits, so assume 3 for this one too
44+ uint32_t size = (r->regs[1] & 0x7) << 17;
45+ uint32_t start = (r->regs[2] & 7) << 17 | (r->regs[0] & 6) << 19;
46+ if (!size || size > 512*1024) {
47+ size = 512*1024;
48+ }
49+ for(uint32_t cur = 0; cur < 512*1024; cur += size)
50+ {
51+ if (start + size > 512*1024) {
52+ memcpy(r->rom_space + cur, gen->cart + start/2, 512*1024-start);
53+ //assume it wraps
54+ memcpy(r->rom_space + cur + 512*1024-start, gen->cart, size - (512*1024-start));
55+ } else {
56+ memcpy(r->rom_space + cur, gen->cart + start/2, size);
57+ }
58+ }
59+ m68k_invalidate_code_range(gen->m68k, 0, 0x400000);
60+ }
61+ return context;
62+}
63+
64+static void *realtec_write_w(uint32_t address, void *context, uint16_t value)
65+{
66+ return realtec_write_b(address, context, value >> 8);
67+}
68+
69+void realtec_serialize(genesis_context *gen, serialize_buffer *buf)
70+{
71+ realtec *r = get_realtec(gen);
72+ save_buffer8(buf, r->regs, sizeof(r->regs));
73+}
74+
75+void realtec_deserialize(deserialize_buffer *buf, genesis_context *gen)
76+{
77+ realtec *r = get_realtec(gen);
78+ for (int i = 0; i < sizeof(r->regs); i++)
79+ {
80+ realtec_write_b(i << 13, gen->m68k, load_int8(buf));
81+ }
82+}
83+
84+rom_info realtec_configure_rom(uint8_t *rom, uint32_t rom_size, memmap_chunk const *base_map, uint32_t base_chunks)
85+{
86+ rom_info info;
87+ realtec *r = calloc(sizeof(realtec), 1);
88+ for (uint32_t i = 0; i < 512*1024; i += 8*1024)
89+ {
90+ memcpy(r->rom_space + i, rom + 0x7E000, 8*1024);
91+ }
92+ byteswap_rom(512*1024, (uint16_t *)r->rom_space);
93+
94+ uint8_t *name_start = NULL, *name_end = NULL;
95+ for (int i = 0x94; i < 0xE0; i++)
96+ {
97+ if (name_start) {
98+ if (rom[i] < ' ' || rom[i] > 0x80 || !memcmp(rom+i, "ARE", 3) || !memcmp(rom+i, "are", 3)) {
99+ name_end = rom+i;
100+ break;
101+ }
102+ } else if (rom[i] > ' ' && rom[i] < 0x80 && rom[i] != ':') {
103+ name_start = rom + i;
104+ }
105+ }
106+ if (name_start && !name_end) {
107+ name_end = rom + 0xE0;
108+ }
109+ if (name_end) {
110+ while (name_end > name_start && name_end[-1] == ' ')
111+ {
112+ name_end--;
113+ }
114+ info.name = malloc(name_end-name_start+1);
115+ memcpy(info.name, name_start, name_end-name_start);
116+ info.name[name_end-name_start] = 0;
117+ } else {
118+ info.name = strdup("Realtec Game");
119+ }
120+ info.save_type = SAVE_NONE;
121+ info.save_size = 0;
122+ info.save_buffer = NULL;
123+ info.num_eeprom = 0;
124+ info.eeprom_map = NULL;
125+ info.rom = rom;
126+ info.rom_size = rom_size;
127+ info.mapper_type = MAPPER_REALTEC;
128+ info.is_save_lock_on = 0;
129+ info.port1_override = info.port2_override = info.ext_override = info.mouse_mode = NULL;
130+ info.map_chunks = base_chunks + 2;
131+ info.map = calloc(sizeof(memmap_chunk), info.map_chunks);
132+ info.map[0].mask = sizeof(r->rom_space)-1;
133+ info.map[0].flags = MMAP_READ|MMAP_CODE|MMAP_PTR_IDX;
134+ info.map[0].start = 0;
135+ info.map[0].end = 0x400000;
136+ info.map[0].buffer = r->rom_space;
137+ info.map[0].write_16 = NULL;
138+ info.map[0].read_16 = NULL;
139+ info.map[0].write_8 = NULL;
140+ info.map[0].read_8 = NULL;
141+ info.map[1].mask = 0x7FFF;
142+ info.map[1].flags = 0;
143+ info.map[1].start = 0x400000;
144+ info.map[1].end = 0x800000;
145+ info.map[1].write_16 = realtec_write_w;
146+ info.map[1].write_8 = realtec_write_b;
147+ info.map[1].read_16 = NULL;
148+ info.map[1].read_8 = NULL;
149+ memcpy(info.map + 2, base_map, base_chunks * sizeof(memmap_chunk));
150+
151+ return info;
152+}
+10,
-0
1@@ -0,0 +1,10 @@
2+#ifndef REALTEC_H_
3+#define REALTEC_H_
4+#include "serialize.h"
5+
6+uint8_t realtec_detect(uint8_t *rom, uint32_t rom_size);
7+rom_info realtec_configure_rom(uint8_t *rom, uint32_t rom_size, memmap_chunk const *base_map, uint32_t base_chunks);
8+void realtec_serialize(genesis_context *gen, serialize_buffer *buf);
9+void realtec_deserialize(deserialize_buffer *buf, genesis_context *gen);
10+
11+#endif //REALTEC_H_
A
render.h
+80,
-0
1@@ -0,0 +1,80 @@
2+/*
3+ Copyright 2013 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#ifndef RENDER_H_
8+#define RENDER_H_
9+
10+#include "special_keys_evdev.h"
11+#define render_relative_mouse(V)
12+
13+#define MAX_JOYSTICKS 8
14+#define MAX_MICE 8
15+#define MAX_MOUSE_BUTTONS 8
16+
17+#define VIDEO_BUFFER_ODD 0
18+#define VIDEO_BUFFER_EVEN 1
19+#define VIDEO_BUFFER_USER_START 2
20+
21+#include "vdp.h"
22+
23+typedef enum {
24+ VID_NTSC,
25+ VID_PAL,
26+ NUM_VID_STD
27+} vid_std;
28+
29+#define RENDER_DPAD_BIT 0x40000000
30+#define RENDER_AXIS_BIT 0x20000000
31+#define RENDER_AXIS_POS 0x10000000
32+#define RENDER_INVALID_NAME -1
33+#define RENDER_NOT_MAPPED -2
34+#define RENDER_NOT_PLUGGED_IN -3
35+
36+typedef struct audio_source audio_source;
37+typedef void (*window_close_handler)(uint8_t which);
38+
39+uint32_t render_map_color(uint8_t r, uint8_t g, uint8_t b);
40+void render_save_screenshot(char *path);
41+uint8_t render_create_window(char *caption, uint32_t width, uint32_t height, window_close_handler close_handler);
42+void render_destroy_window(uint8_t which);
43+uint32_t *render_get_video_buffer(uint8_t which, int *pitch);
44+void render_video_buffer_updated(uint8_t which, int width);
45+//returns the video buffer index associated with the window that has focus
46+uint8_t render_get_active_video_buffer(void);
47+void render_init(int width, int height, char * title);
48+void render_set_video_standard(vid_std std);
49+void render_update_caption(char *title);
50+void render_wait_quit(vdp_context * context);
51+uint32_t render_audio_buffer();
52+uint32_t render_sample_rate();
53+void process_events();
54+int render_width();
55+int render_height();
56+void process_events();
57+int32_t render_translate_input_name(int32_t controller, char *name, uint8_t is_axis);
58+int32_t render_dpad_part(int32_t input);
59+int32_t render_axis_part(int32_t input);
60+uint8_t render_direction_part(int32_t input);
61+char* render_joystick_type_id(int index);
62+void render_errorbox(char *title, char *message);
63+void render_warnbox(char *title, char *message);
64+void render_infobox(char *title, char *message);
65+uint32_t render_emulated_width();
66+uint32_t render_emulated_height();
67+uint32_t render_overscan_top();
68+uint32_t render_overscan_left();
69+uint32_t render_elapsed_ms(void);
70+void render_sleep_ms(uint32_t delay);
71+audio_source *render_audio_source(uint64_t master_clock, uint64_t sample_divider, uint8_t channels);
72+void render_audio_source_gaindb(audio_source *src, float gain);
73+void render_audio_adjust_clock(audio_source *src, uint64_t master_clock, uint64_t sample_divider);
74+void render_put_mono_sample(audio_source *src, int16_t value);
75+void render_put_stereo_sample(audio_source *src, int16_t left, int16_t right);
76+void render_pause_source(audio_source *src);
77+void render_resume_source(audio_source *src);
78+void render_free_source(audio_source *src);
79+void render_config_updated(void);
80+
81+#endif //RENDER_H_
+1800,
-0
1@@ -0,0 +1,1800 @@
2+/*
3+ Copyright 2013 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#include <stdlib.h>
8+#include <stdio.h>
9+#include <string.h>
10+#include <stdint.h>
11+#include <errno.h>
12+#include <math.h>
13+#include <linux/input.h>
14+#include <linux/kd.h>
15+#include <alsa/asoundlib.h>
16+#include <sys/types.h>
17+#include <sys/stat.h>
18+#include <sys/ioctl.h>
19+#include <sys/mman.h>
20+#include <poll.h>
21+#include <fcntl.h>
22+#include <unistd.h>
23+#include <pthread.h>
24+#include <dirent.h>
25+#include <wayland-client.h>
26+#include "xdg-shell-client-protocol.h"
27+#include <sys/syscall.h>
28+#include <time.h>
29+#include "render.h"
30+#include "blastem.h"
31+#include "genesis.h"
32+#include "bindings.h"
33+#include "util.h"
34+#include "paths.h"
35+#include "ppm.h"
36+#include "png.h"
37+#include "config.h"
38+#include "controller_info.h"
39+
40+#define MAX_EVENT_POLL_PER_FRAME 2
41+
42+static int main_width, main_height;
43+static snd_pcm_uframes_t buffer_samples;
44+static unsigned int output_channels, sample_rate;
45+
46+
47+struct audio_source {
48+ int16_t *front;
49+ int16_t *back;
50+ double dt;
51+ uint64_t buffer_fraction;
52+ uint64_t buffer_inc;
53+ uint32_t buffer_pos;
54+ uint32_t read_start;
55+ uint32_t read_end;
56+ uint32_t lowpass_alpha;
57+ uint32_t mask;
58+ float gain_mult;
59+ int16_t last_left;
60+ int16_t last_right;
61+ uint8_t num_channels;
62+ uint8_t front_populated;
63+};
64+
65+static audio_source *audio_sources[8];
66+static audio_source *inactive_audio_sources[8];
67+static uint8_t num_audio_sources;
68+static uint8_t num_inactive_audio_sources;
69+
70+typedef int32_t (*mix_func)(audio_source *audio, void *vstream, int len);
71+
72+static int32_t mix_s16(audio_source *audio, void *vstream, int len)
73+{
74+ int samples = len/(sizeof(int16_t)*output_channels);
75+ int16_t *stream = vstream;
76+ int16_t *end = stream + output_channels*samples;
77+ int16_t *src = audio->front;
78+ uint32_t i = audio->read_start;
79+ uint32_t i_end = audio->read_end;
80+ int16_t *cur = stream;
81+ size_t first_add = output_channels > 1 ? 1 : 0, second_add = output_channels > 1 ? output_channels - 1 : 1;
82+ if (audio->num_channels == 1) {
83+ while (cur < end && i != i_end)
84+ {
85+ *cur += src[i];
86+ cur += first_add;
87+ *cur += src[i++];
88+ cur += second_add;
89+ i &= audio->mask;
90+ }
91+ } else {
92+ while (cur < end && i != i_end)
93+ {
94+ *cur += src[i++];
95+ cur += first_add;
96+ *cur += src[i++];
97+ cur += second_add;
98+ i &= audio->mask;
99+ }
100+ }
101+
102+ if (cur != end) {
103+ printf("Underflow of %d samples, read_start: %d, read_end: %d, mask: %X\n", (int)(end-cur)/2, audio->read_start, audio->read_end, audio->mask);
104+ }
105+ if (cur != end) {
106+ //printf("Underflow of %d samples, read_start: %d, read_end: %d, mask: %X\n", (int)(end-cur)/2, audio->read_start, audio->read_end, audio->mask);
107+ return (cur-end)/2;
108+ } else {
109+ return ((i_end - i) & audio->mask) / audio->num_channels;
110+ }
111+}
112+
113+static int32_t mix_f32(audio_source *audio, void *vstream, int len)
114+{
115+ int samples = len/(sizeof(float)*output_channels);
116+ float *stream = vstream;
117+ float *end = stream + output_channels*samples;
118+ int16_t *src = audio->front;
119+ uint32_t i = audio->read_start;
120+ uint32_t i_end = audio->read_end;
121+ float *cur = stream;
122+ size_t first_add = output_channels > 1 ? 1 : 0, second_add = output_channels > 1 ? output_channels - 1 : 1;
123+ if (audio->num_channels == 1) {
124+ while (cur < end && i != i_end)
125+ {
126+ *cur += ((float)src[i]) / 0x7FFF;
127+ cur += first_add;
128+ *cur += ((float)src[i++]) / 0x7FFF;
129+ cur += second_add;
130+ i &= audio->mask;
131+ }
132+ } else {
133+ while(cur < end && i != i_end)
134+ {
135+ *cur += ((float)src[i++]) / 0x7FFF;
136+ cur += first_add;
137+ *cur += ((float)src[i++]) / 0x7FFF;
138+ cur += second_add;
139+ i &= audio->mask;
140+ }
141+ }
142+ if (cur != end) {
143+ printf("Underflow of %d samples, read_start: %d, read_end: %d, mask: %X\n", (int)(end-cur)/2, audio->read_start, audio->read_end, audio->mask);
144+ return (cur-end)/2;
145+ } else {
146+ return ((i_end - i) & audio->mask) / audio->num_channels;
147+ }
148+}
149+
150+static mix_func mix;
151+
152+static snd_pcm_t *audio_handle;
153+static void render_close_audio()
154+{
155+ if (audio_handle) {
156+ snd_pcm_close(audio_handle);
157+ audio_handle = NULL;
158+ }
159+}
160+
161+static void destroy_wayland(void);
162+
163+#define BUFFER_INC_RES 0x40000000UL
164+
165+void render_audio_adjust_clock(audio_source *src, uint64_t master_clock, uint64_t sample_divider)
166+{
167+ src->buffer_inc = ((BUFFER_INC_RES * (uint64_t)sample_rate) / master_clock) * sample_divider;
168+}
169+
170+audio_source *render_audio_source(uint64_t master_clock, uint64_t sample_divider, uint8_t channels)
171+{
172+ audio_source *ret = NULL;
173+ uint32_t alloc_size = channels * buffer_samples;
174+ if (num_audio_sources < 8) {
175+ ret = malloc(sizeof(audio_source));
176+ ret->back = malloc(alloc_size * sizeof(int16_t));
177+ ret->front = malloc(alloc_size * sizeof(int16_t));
178+ ret->front_populated = 0;
179+ ret->num_channels = channels;
180+ audio_sources[num_audio_sources++] = ret;
181+ }
182+ if (!ret) {
183+ fatal_error("Too many audio sources!");
184+ } else {
185+ render_audio_adjust_clock(ret, master_clock, sample_divider);
186+ double lowpass_cutoff = get_lowpass_cutoff(config);
187+ double rc = (1.0 / lowpass_cutoff) / (2.0 * M_PI);
188+ ret->dt = 1.0 / ((double)master_clock / (double)(sample_divider));
189+ double alpha = ret->dt / (ret->dt + rc);
190+ ret->lowpass_alpha = (int32_t)(((double)0x10000) * alpha);
191+ ret->buffer_pos = 0;
192+ ret->buffer_fraction = 0;
193+ ret->gain_mult = 1.0f;
194+ ret->last_left = ret->last_right = 0;
195+ ret->read_start = 0;
196+ ret->read_end = buffer_samples * channels;
197+ ret->mask = 0xFFFFFFFF;
198+ }
199+ return ret;
200+}
201+
202+static float db_to_mult(float gain)
203+{
204+ return powf(10.0f, gain / 20.0f);
205+}
206+
207+void render_audio_source_gaindb(audio_source *src, float gain)
208+{
209+ src->gain_mult = db_to_mult(gain);
210+}
211+
212+void render_pause_source(audio_source *src)
213+{
214+ for (uint8_t i = 0; i < num_audio_sources; i++)
215+ {
216+ if (audio_sources[i] == src) {
217+ audio_sources[i] = audio_sources[--num_audio_sources];
218+ break;
219+ }
220+ }
221+ inactive_audio_sources[num_inactive_audio_sources++] = src;
222+}
223+
224+void render_resume_source(audio_source *src)
225+{
226+ if (num_audio_sources < 8) {
227+ audio_sources[num_audio_sources++] = src;
228+ }
229+ for (uint8_t i = 0; i < num_inactive_audio_sources; i++)
230+ {
231+ if (inactive_audio_sources[i] == src) {
232+ inactive_audio_sources[i] = inactive_audio_sources[--num_inactive_audio_sources];
233+ }
234+ }
235+}
236+
237+void render_free_source(audio_source *src)
238+{
239+ render_pause_source(src);
240+
241+ free(src->front);
242+ free(src->back);
243+ free(src);
244+}
245+static void do_audio_ready(audio_source *src)
246+{
247+ if (src->front_populated) {
248+ fatal_error("Audio source filled up a buffer a second time before other sources finished their first\n");
249+ }
250+ int16_t *tmp = src->front;
251+ src->front = src->back;
252+ src->back = tmp;
253+ src->front_populated = 1;
254+ src->buffer_pos = 0;
255+
256+ for (uint8_t i = 0; i < num_audio_sources; i++)
257+ {
258+ if (!audio_sources[i]->front_populated) {
259+ //at least one audio source is not ready yet.
260+ return;
261+ }
262+ }
263+
264+ size_t bytes = (mix == mix_s16 ? sizeof(int16_t) : sizeof(float)) * output_channels * buffer_samples;
265+ void *buffer = calloc(1, bytes);
266+ for (uint8_t i = 0; i < num_audio_sources; i++)
267+ {
268+ mix(audio_sources[i], buffer, bytes);
269+ audio_sources[i]->front_populated = 0;
270+ }
271+ int frames = snd_pcm_writei(audio_handle, buffer, buffer_samples);
272+ if (frames < 0) {
273+ frames = snd_pcm_recover(audio_handle, frames, 0);
274+ }
275+ if (frames < 0) {
276+ fprintf(stderr, "Failed to write samples: %s\n", snd_strerror(frames));
277+ }
278+ free(buffer);
279+}
280+
281+static int16_t lowpass_sample(audio_source *src, int16_t last, int16_t current)
282+{
283+ int32_t tmp = current * src->lowpass_alpha + last * (0x10000 - src->lowpass_alpha);
284+ current = tmp >> 16;
285+ return current;
286+}
287+
288+static void interp_sample(audio_source *src, int16_t last, int16_t current)
289+{
290+ int64_t tmp = last * ((src->buffer_fraction << 16) / src->buffer_inc);
291+ tmp += current * (0x10000 - ((src->buffer_fraction << 16) / src->buffer_inc));
292+ src->back[src->buffer_pos++] = tmp >> 16;
293+}
294+
295+void render_put_mono_sample(audio_source *src, int16_t value)
296+{
297+ value = lowpass_sample(src, src->last_left, value);
298+ src->buffer_fraction += src->buffer_inc;
299+ uint32_t base = 0;
300+ while (src->buffer_fraction > BUFFER_INC_RES)
301+ {
302+ src->buffer_fraction -= BUFFER_INC_RES;
303+ interp_sample(src, src->last_left, value);
304+
305+ if (((src->buffer_pos - base) & src->mask) >= buffer_samples) {
306+ do_audio_ready(src);
307+ }
308+ src->buffer_pos &= src->mask;
309+ }
310+ src->last_left = value;
311+}
312+
313+void render_put_stereo_sample(audio_source *src, int16_t left, int16_t right)
314+{
315+ left = lowpass_sample(src, src->last_left, left);
316+ right = lowpass_sample(src, src->last_right, right);
317+ src->buffer_fraction += src->buffer_inc;
318+ uint32_t base = 0;
319+ while (src->buffer_fraction > BUFFER_INC_RES)
320+ {
321+ src->buffer_fraction -= BUFFER_INC_RES;
322+
323+ interp_sample(src, src->last_left, left);
324+ interp_sample(src, src->last_right, right);
325+
326+ if (((src->buffer_pos - base) & src->mask)/2 >= buffer_samples) {
327+ do_audio_ready(src);
328+ }
329+ src->buffer_pos &= src->mask;
330+ }
331+ src->last_left = left;
332+ src->last_right = right;
333+}
334+
335+int render_width()
336+{
337+ return main_width;
338+}
339+
340+int render_height()
341+{
342+ return main_height;
343+}
344+
345+uint32_t render_map_color(uint8_t r, uint8_t g, uint8_t b)
346+{
347+ return 0xFF000000 | r << 16 | g << 8 | b;
348+}
349+
350+#define MAX_VIDEO_BUFFER_LINES 590
351+static uint32_t video_buffer[MAX_VIDEO_BUFFER_LINES * LINEBUF_SIZE * 2];
352+
353+static char * caption = NULL;
354+static char * fps_caption = NULL;
355+
356+static void render_quit()
357+{
358+ render_close_audio();
359+ destroy_wayland();
360+}
361+
362+static float config_aspect()
363+{
364+ static float aspect = 0.0f;
365+ if (aspect == 0.0f) {
366+ char *config_aspect = tern_find_path_default(config, "video\0aspect\0", (tern_val){.ptrval = "4:3"}, TVAL_PTR).ptrval;
367+ if (strcmp("stretch", config_aspect)) {
368+ aspect = 4.0f/3.0f;
369+ char *end;
370+ float aspect_numerator = strtof(config_aspect, &end);
371+ if (aspect_numerator > 0.0f && *end == ':') {
372+ float aspect_denominator = strtof(end+1, &end);
373+ if (aspect_denominator > 0.0f && !*end) {
374+ aspect = aspect_numerator / aspect_denominator;
375+ }
376+ }
377+ } else {
378+ aspect = -1.0f;
379+ }
380+ }
381+ return aspect;
382+}
383+
384+static uint8_t scancode_map[128] = {
385+ [KEY_A] = 0x1C,
386+ [KEY_B] = 0x32,
387+ [KEY_C] = 0x21,
388+ [KEY_D] = 0x23,
389+ [KEY_E] = 0x24,
390+ [KEY_F] = 0x2B,
391+ [KEY_G] = 0x34,
392+ [KEY_H] = 0x33,
393+ [KEY_I] = 0x43,
394+ [KEY_J] = 0x3B,
395+ [KEY_K] = 0x42,
396+ [KEY_L] = 0x4B,
397+ [KEY_M] = 0x3A,
398+ [KEY_N] = 0x31,
399+ [KEY_O] = 0x44,
400+ [KEY_P] = 0x4D,
401+ [KEY_Q] = 0x15,
402+ [KEY_R] = 0x2D,
403+ [KEY_S] = 0x1B,
404+ [KEY_T] = 0x2C,
405+ [KEY_U] = 0x3C,
406+ [KEY_V] = 0x2A,
407+ [KEY_W] = 0x1D,
408+ [KEY_X] = 0x22,
409+ [KEY_Y] = 0x35,
410+ [KEY_Z] = 0x1A,
411+ [KEY_1] = 0x16,
412+ [KEY_2] = 0x1E,
413+ [KEY_3] = 0x26,
414+ [KEY_4] = 0x25,
415+ [KEY_5] = 0x2E,
416+ [KEY_6] = 0x36,
417+ [KEY_7] = 0x3D,
418+ [KEY_8] = 0x3E,
419+ [KEY_9] = 0x46,
420+ [KEY_0] = 0x45,
421+ [KEY_ENTER] = 0x5A,
422+ [KEY_ESC] = 0x76,
423+ [KEY_SPACE] = 0x29,
424+ [KEY_TAB] = 0x0D,
425+ [KEY_BACKSPACE] = 0x66,
426+ [KEY_MINUS] = 0x4E,
427+ [KEY_EQUAL] = 0x55,
428+ [KEY_LEFTBRACE] = 0x54,
429+ [KEY_RIGHTBRACE] = 0x5B,
430+ [KEY_BACKSLASH] = 0x5D,
431+ [KEY_SEMICOLON] = 0x4C,
432+ [KEY_APOSTROPHE] = 0x52,
433+ [KEY_GRAVE] = 0x0E,
434+ [KEY_COMMA] = 0x41,
435+ [KEY_DOT] = 0x49,
436+ [KEY_SLASH] = 0x4A,
437+ [KEY_CAPSLOCK] = 0x58,
438+ [KEY_F1] = 0x05,
439+ [KEY_F2] = 0x06,
440+ [KEY_F3] = 0x04,
441+ [KEY_F4] = 0x0C,
442+ [KEY_F5] = 0x03,
443+ [KEY_F6] = 0x0B,
444+ [KEY_F7] = 0x83,
445+ [KEY_F8] = 0x0A,
446+ [KEY_F9] = 0x01,
447+ [KEY_F10] = 0x09,
448+ [KEY_F11] = 0x78,
449+ [KEY_F12] = 0x07,
450+ [KEY_LEFTCTRL] = 0x14,
451+ [KEY_LEFTSHIFT] = 0x12,
452+ [KEY_LEFTALT] = 0x11,
453+ [KEY_RIGHTCTRL] = 0x18,
454+ [KEY_RIGHTSHIFT] = 0x59,
455+ [KEY_RIGHTALT] = 0x17,
456+ [KEY_INSERT] = 0x81,
457+ [KEY_PAUSE] = 0x82,
458+ [KEY_SYSRQ] = 0x84,
459+ [KEY_SCROLLLOCK] = 0x7E,
460+ [KEY_DELETE] = 0x85,
461+ [KEY_LEFT] = 0x86,
462+ [KEY_HOME] = 0x87,
463+ [KEY_END] = 0x88,
464+ [KEY_UP] = 0x89,
465+ [KEY_DOWN] = 0x8A,
466+ [KEY_PAGEUP] = 0x8B,
467+ [KEY_PAGEDOWN] = 0x8C,
468+ [KEY_RIGHT] = 0x8D,
469+ [KEY_NUMLOCK] = 0x77,
470+ [KEY_KPSLASH] = 0x80,
471+ [KEY_KPASTERISK] = 0x7C,
472+ [KEY_KPMINUS] = 0x7B,
473+ [KEY_KPPLUS] = 0x79,
474+ [KEY_KPENTER] = 0x19,
475+ [KEY_KP1] = 0x69,
476+ [KEY_KP2] = 0x72,
477+ [KEY_KP3] = 0x7A,
478+ [KEY_KP4] = 0x6B,
479+ [KEY_KP5] = 0x73,
480+ [KEY_KP6] = 0x74,
481+ [KEY_KP7] = 0x6C,
482+ [KEY_KP8] = 0x75,
483+ [KEY_KP9] = 0x7D,
484+ [KEY_KP0] = 0x70,
485+ [KEY_KPDOT] = 0x71,
486+};
487+
488+#include "special_keys_evdev.h"
489+static uint8_t sym_map[128] = {
490+ [KEY_A] = 'a',
491+ [KEY_B] = 'b',
492+ [KEY_C] = 'c',
493+ [KEY_D] = 'd',
494+ [KEY_E] = 'e',
495+ [KEY_F] = 'f',
496+ [KEY_G] = 'g',
497+ [KEY_H] = 'h',
498+ [KEY_I] = 'i',
499+ [KEY_J] = 'j',
500+ [KEY_K] = 'k',
501+ [KEY_L] = 'l',
502+ [KEY_M] = 'm',
503+ [KEY_N] = 'n',
504+ [KEY_O] = 'o',
505+ [KEY_P] = 'p',
506+ [KEY_Q] = 'q',
507+ [KEY_R] = 'r',
508+ [KEY_S] = 's',
509+ [KEY_T] = 't',
510+ [KEY_U] = 'u',
511+ [KEY_V] = 'v',
512+ [KEY_W] = 'w',
513+ [KEY_X] = 'x',
514+ [KEY_Y] = 'y',
515+ [KEY_Z] = 'z',
516+ [KEY_1] = '1',
517+ [KEY_2] = '2',
518+ [KEY_3] = '3',
519+ [KEY_4] = '4',
520+ [KEY_5] = '5',
521+ [KEY_6] = '6',
522+ [KEY_7] = '7',
523+ [KEY_8] = '8',
524+ [KEY_9] = '9',
525+ [KEY_0] = '0',
526+ [KEY_ENTER] = '\r',
527+ [KEY_SPACE] = ' ',
528+ [KEY_TAB] = '\t',
529+ [KEY_BACKSPACE] = '\b',
530+ [KEY_MINUS] = '-',
531+ [KEY_EQUAL] = '=',
532+ [KEY_LEFTBRACE] = '[',
533+ [KEY_RIGHTBRACE] = ']',
534+ [KEY_BACKSLASH] = '\\',
535+ [KEY_SEMICOLON] = ';',
536+ [KEY_APOSTROPHE] = '\'',
537+ [KEY_GRAVE] = '`',
538+ [KEY_COMMA] = ',',
539+ [KEY_DOT] = '.',
540+ [KEY_SLASH] = '/',
541+ [KEY_ESC] = RENDERKEY_ESC,
542+ [KEY_F1] = RENDERKEY_F1,
543+ [KEY_F2] = RENDERKEY_F2,
544+ [KEY_F3] = RENDERKEY_F3,
545+ [KEY_F4] = RENDERKEY_F4,
546+ [KEY_F5] = RENDERKEY_F5,
547+ [KEY_F6] = RENDERKEY_F6,
548+ [KEY_F7] = RENDERKEY_F7,
549+ [KEY_F8] = RENDERKEY_F8,
550+ [KEY_F9] = RENDERKEY_F9,
551+ [KEY_F10] = RENDERKEY_F10,
552+ [KEY_F11] = RENDERKEY_F11,
553+ [KEY_F12] = RENDERKEY_F12,
554+ [KEY_LEFTCTRL] = RENDERKEY_LCTRL,
555+ [KEY_LEFTSHIFT] = RENDERKEY_LSHIFT,
556+ [KEY_LEFTALT] = RENDERKEY_LALT,
557+ [KEY_RIGHTCTRL] = RENDERKEY_RCTRL,
558+ [KEY_RIGHTSHIFT] = RENDERKEY_RSHIFT,
559+ [KEY_RIGHTALT] = RENDERKEY_RALT,
560+ [KEY_DELETE] = RENDERKEY_DEL,
561+ [KEY_LEFT] = RENDERKEY_LEFT,
562+ [KEY_HOME] = RENDERKEY_HOME,
563+ [KEY_END] = RENDERKEY_END,
564+ [KEY_UP] = RENDERKEY_UP,
565+ [KEY_DOWN] = RENDERKEY_DOWN,
566+ [KEY_PAGEUP] = RENDERKEY_PAGEUP,
567+ [KEY_PAGEDOWN] = RENDERKEY_PAGEDOWN,
568+ [KEY_RIGHT] = RENDERKEY_RIGHT,
569+ [KEY_KPSLASH] = 0x80,
570+ [KEY_KPASTERISK] = 0x7C,
571+ [KEY_KPMINUS] = 0x7B,
572+ [KEY_KPPLUS] = 0x79,
573+ [KEY_KPENTER] = 0x19,
574+ [KEY_KP1] = 0x69,
575+ [KEY_KP2] = 0x72,
576+ [KEY_KP3] = 0x7A,
577+ [KEY_KP4] = 0x6B,
578+ [KEY_KP5] = 0x73,
579+ [KEY_KP6] = 0x74,
580+ [KEY_KP7] = 0x6C,
581+ [KEY_KP8] = 0x75,
582+ [KEY_KP9] = 0x7D,
583+ [KEY_KP0] = 0x70,
584+ [KEY_KPDOT] = 0x71,
585+};
586+
587+char* render_joystick_type_id(int index)
588+{
589+ return strdup("");
590+}
591+
592+static uint32_t overscan_top[NUM_VID_STD] = {2, 21};
593+static uint32_t overscan_bot[NUM_VID_STD] = {1, 17};
594+static uint32_t overscan_left[NUM_VID_STD] = {13, 13};
595+static uint32_t overscan_right[NUM_VID_STD] = {14, 14};
596+static vid_std video_standard = VID_NTSC;
597+
598+typedef enum {
599+ DEV_NONE,
600+ DEV_KEYBOARD,
601+ DEV_MOUSE,
602+ DEV_GAMEPAD
603+} device_type;
604+
605+static int32_t mouse_x, mouse_y, mouse_accum_x, mouse_accum_y;
606+static int32_t handle_event(device_type dtype, int device_index, struct input_event *event)
607+{
608+ switch (event->type) {
609+ case EV_KEY:
610+ //code is key, value is 1 for keydown, 0 for keyup
611+ if (dtype == DEV_KEYBOARD && event->code < 128) {
612+ //keyboard key that we might have a mapping for
613+ if (event->value) {
614+ handle_keydown(sym_map[event->code], scancode_map[event->code]);
615+ } else {
616+ handle_keyup(sym_map[event->code], scancode_map[event->code]);
617+ }
618+ } else if (dtype == DEV_MOUSE && event->code >= BTN_MOUSE && event->code < BTN_JOYSTICK) {
619+ //mosue button
620+ if (event->value) {
621+ handle_mousedown(device_index, event->code - BTN_LEFT);
622+ } else {
623+ handle_mouseup(device_index, event->code - BTN_LEFT);
624+ }
625+ } else if (dtype == DEV_GAMEPAD && event->code >= BTN_GAMEPAD && event->code < BTN_DIGI) {
626+ //gamepad button
627+ if (event->value) {
628+ handle_joydown(device_index, event->code - BTN_SOUTH);
629+ } else {
630+ handle_joyup(device_index, event->code - BTN_SOUTH);
631+ }
632+ }
633+ break;
634+ case EV_REL:
635+ if (dtype == DEV_MOUSE) {
636+ switch(event->code)
637+ {
638+ case REL_X:
639+ mouse_accum_x += event->value;
640+ break;
641+ case REL_Y:
642+ mouse_accum_y += event->value;
643+ break;
644+ }
645+ }
646+ break;
647+ case EV_ABS:
648+ //TODO: Handle joystick axis/hat motion, absolute mouse movement
649+ break;
650+ case EV_SYN:
651+ if (dtype == DEV_MOUSE && (mouse_accum_x || mouse_accum_y)) {
652+ mouse_x += mouse_accum_x;
653+ mouse_y += mouse_accum_y;
654+ if (mouse_x < 0) {
655+ mouse_x = 0;
656+ } else if (mouse_x >= main_width) {
657+ mouse_x = main_width - 1;
658+ }
659+ if (mouse_y < 0) {
660+ mouse_y = 0;
661+ } else if (mouse_y >= main_height) {
662+ mouse_y = main_height - 1;
663+ }
664+ handle_mouse_moved(device_index, mouse_x, mouse_y, mouse_accum_x, mouse_accum_y);
665+ mouse_accum_x = mouse_accum_y = 0;
666+ }
667+ break;
668+ }
669+ return 0;
670+}
671+
672+#define MAX_DEVICES 16
673+static int device_fds[MAX_DEVICES];
674+static device_type device_types[MAX_DEVICES];
675+static int cur_devices;
676+
677+static void drain_events()
678+{
679+ struct input_event events[64];
680+ int index_by_type[3] = {0,0,0};
681+ for (int i = 0; i < cur_devices; i++)
682+ {
683+ int bytes = sizeof(events);
684+ int device_index = index_by_type[device_types[i]-1]++;
685+ while (bytes == sizeof(events))
686+ {
687+ bytes = read(device_fds[i], events, sizeof(events));
688+ if (bytes > 0) {
689+ int num_events = bytes / sizeof(events[0]);
690+ for (int j = 0; j < num_events; j++)
691+ {
692+ handle_event(device_types[i], device_index, events + j);
693+ }
694+ } else if (bytes < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
695+ perror("Failed to read evdev events");
696+ }
697+ }
698+ }
699+}
700+
701+static char *vid_std_names[NUM_VID_STD] = {"ntsc", "pal"};
702+
703+static void init_audio()
704+{
705+ char *device_name = tern_find_path_default(config, "audio\0alsa_device\0", (tern_val){.ptrval="default"}, TVAL_PTR).ptrval;
706+ int res = snd_pcm_open(&audio_handle, device_name, SND_PCM_STREAM_PLAYBACK, 0);
707+ if (res < 0) {
708+ fatal_error("Failed to open ALSA device: %s\n", snd_strerror(res));
709+ }
710+
711+ snd_pcm_hw_params_t *params;
712+ snd_pcm_hw_params_alloca(¶ms);
713+ res = snd_pcm_hw_params_any(audio_handle, params);
714+ if (res < 0) {
715+ fatal_error("No playback configurations available: %s\n", snd_strerror(res));
716+ }
717+ res = snd_pcm_hw_params_set_access(audio_handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
718+ if (res < 0) {
719+ fatal_error("Failed to set access type: %s\n", snd_strerror(res));
720+ }
721+ res = snd_pcm_hw_params_set_format(audio_handle, params, SND_PCM_FORMAT_S16_LE);
722+ if (res < 0) {
723+ //failed to set, signed 16-bit integer, try floating point
724+ res = snd_pcm_hw_params_set_format(audio_handle, params, SND_PCM_FORMAT_FLOAT_LE);
725+ if (res < 0) {
726+ fatal_error("Failed to set an acceptable format: %s\n", snd_strerror(res));
727+ }
728+ mix = mix_f32;
729+ } else {
730+ mix = mix_s16;
731+ }
732+
733+ char * rate_str = tern_find_path(config, "audio\0rate\0", TVAL_PTR).ptrval;
734+ sample_rate = rate_str ? atoi(rate_str) : 0;
735+ if (!sample_rate) {
736+ sample_rate = 48000;
737+ }
738+ snd_pcm_hw_params_set_rate_near(audio_handle, params, &sample_rate, NULL);
739+ output_channels = 2;
740+ snd_pcm_hw_params_set_channels_near(audio_handle, params, &output_channels);
741+
742+ char * samples_str = tern_find_path(config, "audio\0buffer\0", TVAL_PTR).ptrval;
743+ buffer_samples = samples_str ? atoi(samples_str) : 0;
744+ if (!buffer_samples) {
745+ buffer_samples = 512;
746+ }
747+ snd_pcm_hw_params_set_period_size_near(audio_handle, params, &buffer_samples, NULL);
748+
749+ int dir = 1;
750+ unsigned int periods = 2;
751+ snd_pcm_hw_params_set_periods_near(audio_handle, params, &periods, &dir);
752+
753+ res = snd_pcm_hw_params(audio_handle, params);
754+ if (res < 0) {
755+ fatal_error("Failed to set ALSA hardware params: %s\n", snd_strerror(res));
756+ }
757+
758+ printf("Initialized audio at frequency %d with a %d sample buffer, ", (int)sample_rate, (int)buffer_samples);
759+ if (mix == mix_s16) {
760+ puts("signed 16-bit int format");
761+ } else {
762+ puts("32-bit float format");
763+ }
764+}
765+
766+struct wayland_buffer {
767+ struct wl_buffer *buffer;
768+ uint32_t *pixels;
769+ uint8_t busy;
770+};
771+
772+static struct wl_display *wl_display_handle;
773+static struct wl_compositor *wl_compositor_handle;
774+static struct wl_shm *wl_shm_handle;
775+static struct wl_seat *wl_seat_handle;
776+static struct wl_keyboard *wl_keyboard_handle;
777+static struct wl_pointer *wl_pointer_handle;
778+static struct xdg_wm_base *xdg_wm_base_handle;
779+static struct wl_surface *wl_surface_handle;
780+static struct xdg_surface *xdg_surface_handle;
781+static struct xdg_toplevel *xdg_toplevel_handle;
782+static struct wl_callback *frame_callback;
783+static struct wayland_buffer wl_buffers[2];
784+static uint8_t wl_cur_buffer;
785+static uint8_t wl_configured;
786+static uint8_t frame_pending;
787+static uint32_t wl_stride;
788+static int32_t wl_pointer_x, wl_pointer_y;
789+static uint32_t *copy_buffer;
790+static uint32_t last_width, last_width_scale, last_height, last_height_scale;
791+static uint32_t max_multiple;
792+
793+static void wl_buffer_release(void *data, struct wl_buffer *buffer)
794+{
795+ ((struct wayland_buffer *)data)->busy = 0;
796+}
797+
798+static const struct wl_buffer_listener wl_buffer_listener = {
799+ .release = wl_buffer_release
800+};
801+
802+static void dispatch_wayland_pending(uint32_t timeout)
803+{
804+ if (!wl_display_handle) {
805+ return;
806+ }
807+ while (wl_display_prepare_read(wl_display_handle) != 0)
808+ {
809+ wl_display_dispatch_pending(wl_display_handle);
810+ }
811+ wl_display_flush(wl_display_handle);
812+ struct pollfd pfd = {
813+ .fd = wl_display_get_fd(wl_display_handle),
814+ .events = POLLIN
815+ };
816+ if (poll(&pfd, 1, timeout) > 0 && (pfd.revents & POLLIN)) {
817+ wl_display_read_events(wl_display_handle);
818+ } else {
819+ wl_display_cancel_read(wl_display_handle);
820+ }
821+ wl_display_dispatch_pending(wl_display_handle);
822+}
823+
824+static void frame_done(void *data, struct wl_callback *callback, uint32_t time)
825+{
826+ wl_callback_destroy(callback);
827+ if (callback == frame_callback) {
828+ frame_callback = NULL;
829+ frame_pending = 0;
830+ }
831+}
832+
833+static const struct wl_callback_listener frame_listener = {
834+ .done = frame_done
835+};
836+
837+static int create_shm_file(size_t size)
838+{
839+#ifdef SYS_memfd_create
840+ int fd = syscall(SYS_memfd_create, "blastem-wayland", 0);
841+ if (fd >= 0) {
842+ if (ftruncate(fd, size) == 0) {
843+ return fd;
844+ }
845+ close(fd);
846+ }
847+#endif
848+ char template[] = "/blastem-wayland-XXXXXX";
849+ const char *runtime_dir = getenv("XDG_RUNTIME_DIR");
850+ if (!runtime_dir) {
851+ return -1;
852+ }
853+ char *name = alloc_concat(runtime_dir, template);
854+ fd = mkostemp(name, O_CLOEXEC);
855+ if (fd >= 0) {
856+ unlink(name);
857+ if (ftruncate(fd, size) == 0) {
858+ free(name);
859+ return fd;
860+ }
861+ close(fd);
862+ }
863+ free(name);
864+ return -1;
865+}
866+
867+static void create_wayland_buffer(struct wayland_buffer *buf);
868+static void destroy_wayland_buffer(struct wayland_buffer *buf);
869+
870+static void xdg_wm_base_ping(void *data, struct xdg_wm_base *xdg_wm_base, uint32_t serial)
871+{
872+ xdg_wm_base_pong(xdg_wm_base, serial);
873+}
874+
875+static const struct xdg_wm_base_listener xdg_wm_base_listener = {
876+ .ping = xdg_wm_base_ping
877+};
878+
879+static void xdg_surface_configure(void *data, struct xdg_surface *xdg_surface, uint32_t serial)
880+{
881+ xdg_surface_ack_configure(xdg_surface, serial);
882+ wl_configured = 1;
883+}
884+
885+static const struct xdg_surface_listener xdg_surface_listener = {
886+ .configure = xdg_surface_configure
887+};
888+
889+static void xdg_toplevel_configure(void *data, struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height, struct wl_array *states)
890+{
891+ if (width > 0 && height > 0 && (width != main_width || height != main_height)) {
892+ destroy_wayland_buffer(&wl_buffers[0]);
893+ destroy_wayland_buffer(&wl_buffers[1]);
894+ main_width = width;
895+ main_height = height;
896+ wl_stride = main_width * sizeof(uint32_t);
897+ create_wayland_buffer(&wl_buffers[0]);
898+ create_wayland_buffer(&wl_buffers[1]);
899+ }
900+}
901+
902+static void xdg_toplevel_close(void *data, struct xdg_toplevel *xdg_toplevel)
903+{
904+ if (current_system) {
905+ current_system->request_exit(current_system);
906+ } else {
907+ exit(0);
908+ }
909+}
910+
911+static const struct xdg_toplevel_listener xdg_toplevel_listener = {
912+ .configure = xdg_toplevel_configure,
913+ .close = xdg_toplevel_close
914+};
915+
916+static void wl_keyboard_keymap(void *data, struct wl_keyboard *keyboard, uint32_t format, int32_t fd, uint32_t size)
917+{
918+ close(fd);
919+}
920+
921+static void wl_keyboard_enter(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys)
922+{
923+}
924+
925+static void wl_keyboard_leave(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface)
926+{
927+}
928+
929+static void wl_keyboard_key(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state)
930+{
931+ if (key >= 128) {
932+ return;
933+ }
934+ if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
935+ handle_keydown(sym_map[key], scancode_map[key]);
936+ } else {
937+ handle_keyup(sym_map[key], scancode_map[key]);
938+ }
939+}
940+
941+static void wl_keyboard_modifiers(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group)
942+{
943+}
944+
945+static void wl_keyboard_repeat_info(void *data, struct wl_keyboard *keyboard, int32_t rate, int32_t delay)
946+{
947+}
948+
949+static const struct wl_keyboard_listener wl_keyboard_listener = {
950+ .keymap = wl_keyboard_keymap,
951+ .enter = wl_keyboard_enter,
952+ .leave = wl_keyboard_leave,
953+ .key = wl_keyboard_key,
954+ .modifiers = wl_keyboard_modifiers,
955+ .repeat_info = wl_keyboard_repeat_info
956+};
957+
958+static void wl_pointer_enter(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y)
959+{
960+ wl_pointer_x = wl_fixed_to_int(surface_x);
961+ wl_pointer_y = wl_fixed_to_int(surface_y);
962+ handle_mouse_moved(0, wl_pointer_x, wl_pointer_y, 0, 0);
963+}
964+
965+static void wl_pointer_leave(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface)
966+{
967+}
968+
969+static void wl_pointer_motion(void *data, struct wl_pointer *pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y)
970+{
971+ int32_t x = wl_fixed_to_int(surface_x);
972+ int32_t y = wl_fixed_to_int(surface_y);
973+ handle_mouse_moved(0, x, y, x - wl_pointer_x, y - wl_pointer_y);
974+ wl_pointer_x = x;
975+ wl_pointer_y = y;
976+}
977+
978+static void wl_pointer_button(void *data, struct wl_pointer *pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state)
979+{
980+ if (button < BTN_MOUSE || button >= BTN_JOYSTICK) {
981+ return;
982+ }
983+ if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
984+ handle_mousedown(0, button - BTN_LEFT);
985+ } else {
986+ handle_mouseup(0, button - BTN_LEFT);
987+ }
988+}
989+
990+static void wl_pointer_axis(void *data, struct wl_pointer *pointer, uint32_t time, uint32_t axis, wl_fixed_t value)
991+{
992+}
993+
994+static const struct wl_pointer_listener wl_pointer_listener = {
995+ .enter = wl_pointer_enter,
996+ .leave = wl_pointer_leave,
997+ .motion = wl_pointer_motion,
998+ .button = wl_pointer_button,
999+ .axis = wl_pointer_axis
1000+};
1001+
1002+static void seat_capabilities(void *data, struct wl_seat *seat, uint32_t capabilities)
1003+{
1004+ if ((capabilities & WL_SEAT_CAPABILITY_KEYBOARD) && !wl_keyboard_handle) {
1005+ wl_keyboard_handle = wl_seat_get_keyboard(seat);
1006+ wl_keyboard_add_listener(wl_keyboard_handle, &wl_keyboard_listener, NULL);
1007+ } else if (!(capabilities & WL_SEAT_CAPABILITY_KEYBOARD) && wl_keyboard_handle) {
1008+ wl_keyboard_destroy(wl_keyboard_handle);
1009+ wl_keyboard_handle = NULL;
1010+ }
1011+ if ((capabilities & WL_SEAT_CAPABILITY_POINTER) && !wl_pointer_handle) {
1012+ wl_pointer_handle = wl_seat_get_pointer(seat);
1013+ wl_pointer_add_listener(wl_pointer_handle, &wl_pointer_listener, NULL);
1014+ } else if (!(capabilities & WL_SEAT_CAPABILITY_POINTER) && wl_pointer_handle) {
1015+ wl_pointer_destroy(wl_pointer_handle);
1016+ wl_pointer_handle = NULL;
1017+ }
1018+}
1019+
1020+static void seat_name(void *data, struct wl_seat *seat, const char *name)
1021+{
1022+}
1023+
1024+static const struct wl_seat_listener wl_seat_listener = {
1025+ .capabilities = seat_capabilities,
1026+ .name = seat_name
1027+};
1028+
1029+static void registry_global(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version)
1030+{
1031+ if (!strcmp(interface, wl_compositor_interface.name)) {
1032+ wl_compositor_handle = wl_registry_bind(registry, name, &wl_compositor_interface, version < 4 ? version : 4);
1033+ } else if (!strcmp(interface, wl_shm_interface.name)) {
1034+ wl_shm_handle = wl_registry_bind(registry, name, &wl_shm_interface, 1);
1035+ } else if (!strcmp(interface, wl_seat_interface.name)) {
1036+ wl_seat_handle = wl_registry_bind(registry, name, &wl_seat_interface, 1);
1037+ wl_seat_add_listener(wl_seat_handle, &wl_seat_listener, NULL);
1038+ } else if (!strcmp(interface, xdg_wm_base_interface.name)) {
1039+ xdg_wm_base_handle = wl_registry_bind(registry, name, &xdg_wm_base_interface, 1);
1040+ xdg_wm_base_add_listener(xdg_wm_base_handle, &xdg_wm_base_listener, NULL);
1041+ }
1042+}
1043+
1044+static void registry_global_remove(void *data, struct wl_registry *registry, uint32_t name)
1045+{
1046+}
1047+
1048+static const struct wl_registry_listener registry_listener = {
1049+ .global = registry_global,
1050+ .global_remove = registry_global_remove
1051+};
1052+
1053+static void create_wayland_buffer(struct wayland_buffer *buf)
1054+{
1055+ size_t size = wl_stride * main_height;
1056+ int fd = create_shm_file(size);
1057+ if (fd < 0) {
1058+ fatal_error("Failed to create Wayland shared memory file\n");
1059+ }
1060+ buf->pixels = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
1061+ if (buf->pixels == MAP_FAILED) {
1062+ close(fd);
1063+ fatal_error("Failed to mmap Wayland shared memory buffer\n");
1064+ }
1065+ struct wl_shm_pool *pool = wl_shm_create_pool(wl_shm_handle, fd, size);
1066+ buf->buffer = wl_shm_pool_create_buffer(pool, 0, main_width, main_height, wl_stride, WL_SHM_FORMAT_XRGB8888);
1067+ wl_buffer_add_listener(buf->buffer, &wl_buffer_listener, buf);
1068+ wl_shm_pool_destroy(pool);
1069+ close(fd);
1070+}
1071+
1072+static void destroy_wayland_buffer(struct wayland_buffer *buf)
1073+{
1074+ size_t size = wl_stride * main_height;
1075+ if (buf->buffer) {
1076+ wl_buffer_destroy(buf->buffer);
1077+ buf->buffer = NULL;
1078+ }
1079+ if (buf->pixels) {
1080+ munmap(buf->pixels, size);
1081+ buf->pixels = NULL;
1082+ }
1083+ buf->busy = 0;
1084+}
1085+
1086+static void destroy_wayland(void)
1087+{
1088+ destroy_wayland_buffer(&wl_buffers[0]);
1089+ destroy_wayland_buffer(&wl_buffers[1]);
1090+ if (xdg_toplevel_handle) {
1091+ xdg_toplevel_destroy(xdg_toplevel_handle);
1092+ xdg_toplevel_handle = NULL;
1093+ }
1094+ if (xdg_surface_handle) {
1095+ xdg_surface_destroy(xdg_surface_handle);
1096+ xdg_surface_handle = NULL;
1097+ }
1098+ if (frame_callback) {
1099+ wl_callback_destroy(frame_callback);
1100+ frame_callback = NULL;
1101+ frame_pending = 0;
1102+ }
1103+ if (wl_surface_handle) {
1104+ wl_surface_destroy(wl_surface_handle);
1105+ wl_surface_handle = NULL;
1106+ }
1107+ if (wl_keyboard_handle) {
1108+ wl_keyboard_destroy(wl_keyboard_handle);
1109+ wl_keyboard_handle = NULL;
1110+ }
1111+ if (wl_pointer_handle) {
1112+ wl_pointer_destroy(wl_pointer_handle);
1113+ wl_pointer_handle = NULL;
1114+ }
1115+ if (wl_seat_handle) {
1116+ wl_seat_destroy(wl_seat_handle);
1117+ wl_seat_handle = NULL;
1118+ }
1119+ if (xdg_wm_base_handle) {
1120+ xdg_wm_base_destroy(xdg_wm_base_handle);
1121+ xdg_wm_base_handle = NULL;
1122+ }
1123+ if (wl_shm_handle) {
1124+ wl_shm_destroy(wl_shm_handle);
1125+ wl_shm_handle = NULL;
1126+ }
1127+ if (wl_compositor_handle) {
1128+ wl_compositor_destroy(wl_compositor_handle);
1129+ wl_compositor_handle = NULL;
1130+ }
1131+ if (wl_display_handle) {
1132+ wl_display_disconnect(wl_display_handle);
1133+ wl_display_handle = NULL;
1134+ }
1135+ wl_configured = 0;
1136+}
1137+
1138+static uint32_t mix_pixel(uint32_t last, uint32_t cur, float ratio)
1139+{
1140+ float a,b,c,d;
1141+ a = (last & 255) * ratio;
1142+ b = (last >> 8 & 255) * ratio;
1143+ c = (last >> 16 & 255) * ratio;
1144+ d = (last >> 24 & 255) * ratio;
1145+ ratio = 1.0f - ratio;
1146+ a += (cur & 255) * ratio;
1147+ b += (cur >> 8 & 255) * ratio;
1148+ c += (cur >> 16 & 255) * ratio;
1149+ d += (cur >> 24 & 255) * ratio;
1150+ return ((int)d) << 24 | ((int)c) << 16 | ((int)b) << 8 | ((int)a);
1151+}
1152+static void do_buffer_copy(void)
1153+{
1154+ while (frame_pending && wl_display_handle)
1155+ {
1156+ wl_display_dispatch(wl_display_handle);
1157+ }
1158+ struct wayland_buffer *target = &wl_buffers[wl_cur_buffer];
1159+ if (target->busy) {
1160+ target = &wl_buffers[wl_cur_buffer ^ 1];
1161+ while (target->busy && wl_display_handle)
1162+ {
1163+ wl_display_dispatch(wl_display_handle);
1164+ }
1165+ }
1166+ wl_cur_buffer = target == &wl_buffers[0] ? 1 : 0;
1167+ uint32_t *pixels = target->pixels;
1168+ uint32_t width_multiple = main_width / last_width_scale;
1169+ uint32_t height_multiple = main_height / last_height_scale;
1170+ uint32_t multiple = width_multiple < height_multiple ? width_multiple : height_multiple;
1171+ if (max_multiple && multiple > max_multiple) {
1172+ multiple = max_multiple;
1173+ }
1174+ height_multiple = last_height_scale * multiple / last_height;
1175+ uint32_t *cur_line = pixels + (main_width - last_width_scale * multiple)/2;
1176+ cur_line += wl_stride * (main_height - last_height_scale * multiple) / (2 * sizeof(uint32_t));
1177+ uint32_t *src_line = copy_buffer;
1178+ memset(pixels, 0, wl_stride * main_height);
1179+ if (height_multiple * last_height == multiple * last_height_scale) {
1180+ if (last_width == last_width_scale) {
1181+ for (uint32_t y = 0; y < last_height; y++)
1182+ {
1183+ for (uint32_t i = 0; i < height_multiple; i++)
1184+ {
1185+ uint32_t *cur = cur_line;
1186+ uint32_t *src = src_line;
1187+ for (uint32_t x = 0; x < last_width ; x++)
1188+ {
1189+ uint32_t pixel = *(src++);
1190+ for (uint32_t j = 0; j < multiple; j++)
1191+ {
1192+ *(cur++) = pixel;
1193+ }
1194+ }
1195+
1196+ cur_line += wl_stride / sizeof(uint32_t);
1197+ }
1198+ src_line += LINEBUF_SIZE;
1199+ }
1200+ } else {
1201+ float scale_multiple = ((float)(last_width_scale * multiple)) / (float)last_width;
1202+ float remaining = 0.0f;
1203+ uint32_t last_pixel = 0;
1204+ for (uint32_t y = 0; y < last_height; y++)
1205+ {
1206+ for (uint32_t i = 0; i < height_multiple; i++)
1207+ {
1208+ uint32_t *cur = cur_line;
1209+ uint32_t *src = src_line;
1210+ for (uint32_t x = 0; x < last_width ; x++)
1211+ {
1212+ uint32_t pixel = *(src++);
1213+ float count = scale_multiple;
1214+ if (remaining > 0.0f) {
1215+ *(cur++) = mix_pixel(last_pixel, pixel, remaining);
1216+ count -= 1.0f - remaining;
1217+ }
1218+ for (; count >= 1; count -= 1.0f)
1219+ {
1220+ *(cur++) = pixel;
1221+ }
1222+ remaining = count;
1223+ last_pixel = pixel;
1224+ }
1225+
1226+ cur_line += wl_stride / sizeof(uint32_t);
1227+ }
1228+ src_line += LINEBUF_SIZE;
1229+ }
1230+ }
1231+ } else {
1232+ float height_scale = ((float)(last_height_scale * multiple)) / (float)last_height;
1233+ float height_remaining = 0.0f;
1234+ uint32_t *last_line;
1235+ if (last_width == last_width_scale) {
1236+ for (uint32_t y = 0; y < last_height; y++)
1237+ {
1238+ float hcount = height_scale;
1239+ if (height_remaining > 0.0f) {
1240+ uint32_t *cur = cur_line;
1241+ uint32_t *src = src_line;
1242+ uint32_t *last = last_line;
1243+ for (uint32_t x = 0; x < last_width ; x++)
1244+ {
1245+ uint32_t mixed = mix_pixel(*(last++), *(src++), height_remaining);
1246+ for (uint32_t j = 0; j < multiple; j++)
1247+ {
1248+ *(cur++) = mixed;
1249+ }
1250+ }
1251+ hcount -= 1.0f - height_remaining;
1252+ cur_line += wl_stride / sizeof(uint32_t);
1253+ }
1254+ for(; hcount >= 1; hcount -= 1.0f)
1255+ {
1256+ uint32_t *cur = cur_line;
1257+ uint32_t *src = src_line;
1258+ for (uint32_t x = 0; x < last_width ; x++)
1259+ {
1260+ uint32_t pixel = *(src++);
1261+ for (uint32_t j = 0; j < multiple; j++)
1262+ {
1263+ *(cur++) = pixel;
1264+ }
1265+ }
1266+
1267+ cur_line += wl_stride / sizeof(uint32_t);
1268+ }
1269+ height_remaining = hcount;
1270+ last_line = src_line;
1271+ src_line += LINEBUF_SIZE;
1272+ }
1273+ } else {
1274+ float scale_multiple = ((float)(last_width_scale * multiple)) / (float)last_width;
1275+ float remaining = 0.0f;
1276+ uint32_t last_pixel = 0;
1277+ for (uint32_t y = 0; y < last_height; y++)
1278+ {
1279+ float hcount = height_scale;
1280+ if (height_remaining > 0.0f) {
1281+ uint32_t *cur = cur_line;
1282+ uint32_t *src = src_line;
1283+ uint32_t *last = last_line;
1284+
1285+ for (uint32_t x = 0; x < last_width; x++)
1286+ {
1287+ uint32_t pixel = mix_pixel(*(last++), *(src++), height_remaining);
1288+ float count = scale_multiple;
1289+ if (remaining > 0.0f) {
1290+ *(cur++) = mix_pixel(last_pixel, pixel, remaining);
1291+ count -= 1.0f - remaining;
1292+ }
1293+ for (; count >= 1.0f; count -= 1.0f)
1294+ {
1295+ *(cur++) = pixel;
1296+ }
1297+ remaining = count;
1298+ last_pixel = pixel;
1299+ }
1300+ hcount -= 1.0f - height_remaining;
1301+ cur_line += wl_stride / sizeof(uint32_t);
1302+ }
1303+
1304+ for (; hcount >= 1.0f; hcount -= 1.0f)
1305+ {
1306+ uint32_t *cur = cur_line;
1307+ uint32_t *src = src_line;
1308+ for (uint32_t x = 0; x < last_width ; x++)
1309+ {
1310+ uint32_t pixel = *(src++);
1311+ float count = scale_multiple;
1312+ if (remaining > 0.0f) {
1313+ *(cur++) = mix_pixel(last_pixel, pixel, remaining);
1314+ count -= 1.0f - remaining;
1315+ }
1316+ for (; count >= 1; count -= 1.0f)
1317+ {
1318+ *(cur++) = pixel;
1319+ }
1320+ remaining = count;
1321+ last_pixel = pixel;
1322+ }
1323+
1324+ cur_line += wl_stride / sizeof(uint32_t);
1325+ }
1326+ height_remaining = hcount;
1327+ last_line = src_line;
1328+ src_line += LINEBUF_SIZE;
1329+ }
1330+ }
1331+ }
1332+ wl_surface_attach(wl_surface_handle, target->buffer, 0, 0);
1333+ wl_surface_damage(wl_surface_handle, 0, 0, main_width, main_height);
1334+ frame_callback = wl_surface_frame(wl_surface_handle);
1335+ wl_callback_add_listener(frame_callback, &frame_listener, NULL);
1336+ frame_pending = 1;
1337+ wl_surface_commit(wl_surface_handle);
1338+ target->busy = 1;
1339+ wl_display_flush(wl_display_handle);
1340+}
1341+
1342+void window_setup(void)
1343+{
1344+ tern_val def = {.ptrval = "audio"};
1345+ tern_node *video = tern_find_node(config, "video");
1346+ if (video)
1347+ {
1348+ for (int i = 0; i < NUM_VID_STD; i++)
1349+ {
1350+ tern_node *std_settings = tern_find_node(video, vid_std_names[i]);
1351+ if (std_settings) {
1352+ char *val = tern_find_path_default(std_settings, "overscan\0top\0", (tern_val){.ptrval = NULL}, TVAL_PTR).ptrval;
1353+ if (val) {
1354+ overscan_top[i] = atoi(val);
1355+ }
1356+ val = tern_find_path_default(std_settings, "overscan\0bottom\0", (tern_val){.ptrval = NULL}, TVAL_PTR).ptrval;
1357+ if (val) {
1358+ overscan_bot[i] = atoi(val);
1359+ }
1360+ val = tern_find_path_default(std_settings, "overscan\0left\0", (tern_val){.ptrval = NULL}, TVAL_PTR).ptrval;
1361+ if (val) {
1362+ overscan_left[i] = atoi(val);
1363+ }
1364+ val = tern_find_path_default(std_settings, "overscan\0right\0", (tern_val){.ptrval = NULL}, TVAL_PTR).ptrval;
1365+ if (val) {
1366+ overscan_right[i] = atoi(val);
1367+ }
1368+ }
1369+ }
1370+ }
1371+ wl_display_handle = wl_display_connect(NULL);
1372+ if (!wl_display_handle) {
1373+ fatal_error("Failed to connect to Wayland display\n");
1374+ }
1375+ struct wl_registry *registry = wl_display_get_registry(wl_display_handle);
1376+ wl_registry_add_listener(registry, ®istry_listener, NULL);
1377+ wl_display_roundtrip(wl_display_handle);
1378+ if (!wl_compositor_handle || !wl_shm_handle || !xdg_wm_base_handle) {
1379+ fatal_error("Wayland compositor is missing wl_compositor, wl_shm or xdg_wm_base support\n");
1380+ }
1381+ wl_display_roundtrip(wl_display_handle);
1382+ wl_surface_handle = wl_compositor_create_surface(wl_compositor_handle);
1383+ xdg_surface_handle = xdg_wm_base_get_xdg_surface(xdg_wm_base_handle, wl_surface_handle);
1384+ xdg_surface_add_listener(xdg_surface_handle, &xdg_surface_listener, NULL);
1385+ xdg_toplevel_handle = xdg_surface_get_toplevel(xdg_surface_handle);
1386+ xdg_toplevel_add_listener(xdg_toplevel_handle, &xdg_toplevel_listener, NULL);
1387+ if (caption) {
1388+ xdg_toplevel_set_title(xdg_toplevel_handle, caption);
1389+ }
1390+ wl_surface_commit(wl_surface_handle);
1391+ while (!wl_configured && wl_display_dispatch(wl_display_handle) != -1)
1392+ {
1393+ }
1394+ wl_stride = main_width * sizeof(uint32_t);
1395+ create_wayland_buffer(&wl_buffers[0]);
1396+ create_wayland_buffer(&wl_buffers[1]);
1397+ printf("Wayland shm window: %d x %d\n", main_width, main_height);
1398+
1399+ def.ptrval = "0";
1400+ max_multiple = atoi(tern_find_path_default(config, "video\0wayland\0max_multiple\0", def, TVAL_PTR).ptrval);
1401+
1402+}
1403+
1404+void restore_tty(void)
1405+{
1406+ ioctl(STDIN_FILENO, KDSETMODE, KD_TEXT);
1407+ for (int i = 0; i < cur_devices; i++)
1408+ {
1409+ if (device_types[i] == DEV_KEYBOARD) {
1410+ ioctl(device_fds[i], EVIOCGRAB, 0);
1411+ }
1412+ }
1413+}
1414+
1415+static void init_evdev(void)
1416+{
1417+ tern_val def = {.ptrval = "off"};
1418+ if (strcmp(tern_find_path_default(config, "video\0wayland\0evdev\0", def, TVAL_PTR).ptrval, "on")) {
1419+ return;
1420+ }
1421+ DIR *d = opendir("/dev/input");
1422+ if (!d) {
1423+ warning("Failed to open /dev/input for reading: %s\n", strerror(errno));
1424+ return;
1425+ }
1426+ struct dirent* entry;
1427+ int joystick_counter = 0;
1428+ while ((entry = readdir(d)) && cur_devices < MAX_DEVICES)
1429+ {
1430+ if (!strncmp("event", entry->d_name, strlen("event"))) {
1431+ char *filename = alloc_concat("/dev/input/", entry->d_name);
1432+ int fd = open(filename, O_RDONLY);
1433+ if (fd == -1) {
1434+ int errnum = errno;
1435+ warning("Failed to open evdev device %s for reading: %s\n", filename, strerror(errnum));
1436+ free(filename);
1437+ continue;
1438+ }
1439+
1440+ unsigned long bits;
1441+ if (-1 == ioctl(fd, EVIOCGBIT(0, sizeof(bits)), &bits)) {
1442+ int errnum = errno;
1443+ warning("Failed get capability bits from evdev device %s: %s\n", filename, strerror(errnum));
1444+ free(filename);
1445+ close(fd);
1446+ continue;
1447+ }
1448+ if (!(1 & bits >> EV_KEY)) {
1449+ free(filename);
1450+ close(fd);
1451+ continue;
1452+ }
1453+ unsigned long button_bits[(BTN_THUMBR+8*sizeof(long))/(8*sizeof(long))];
1454+ int res = ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(button_bits)), button_bits);
1455+ if (-1 == res) {
1456+ int errnum = errno;
1457+ warning("Failed get capability bits from evdev device %s: %s\n", filename, strerror(errnum));
1458+ free(filename);
1459+ close(fd);
1460+ continue;
1461+ }
1462+ int to_check[] = {KEY_ENTER, BTN_MOUSE, BTN_GAMEPAD};
1463+ device_type dtype = DEV_NONE;
1464+ for (int i = 0; i < 3; i++)
1465+ {
1466+ if (1 & button_bits[to_check[i]/(8*sizeof(button_bits[0]))] >> to_check[i]%(8*sizeof(button_bits[0]))) {
1467+ dtype = i + 1;
1468+ }
1469+ }
1470+ if (dtype == DEV_NONE) {
1471+ close(fd);
1472+ } else {
1473+ device_fds[cur_devices] = fd;
1474+ device_types[cur_devices] = dtype;
1475+ char name[1024];
1476+ char *names[] = {"Keyboard", "Mouse", "Gamepad"};
1477+ ioctl(fd, EVIOCGNAME(sizeof(name)), name);
1478+ printf("%s is a %s\n%s\n", filename, names[dtype - 1], name);
1479+
1480+ if (dtype == DEV_GAMEPAD) {
1481+ handle_joy_added(joystick_counter++);
1482+ } else if (dtype == DEV_KEYBOARD && isatty(STDIN_FILENO)) {
1483+ ioctl(fd, EVIOCGRAB, 1);
1484+ }
1485+
1486+ fcntl(fd, F_SETFL, O_NONBLOCK);
1487+ cur_devices++;
1488+ }
1489+ free(filename);
1490+ }
1491+ }
1492+ closedir(d);
1493+}
1494+
1495+void render_init(int width, int height, char * title)
1496+{
1497+ if (height <= 0) {
1498+ float aspect = config_aspect() > 0.0f ? config_aspect() : 4.0f/3.0f;
1499+ height = ((float)width / aspect) + 0.5f;
1500+ }
1501+ printf("width: %d, height: %d\n", width, height);
1502+ main_width = width;
1503+ main_height = height;
1504+
1505+ caption = title;
1506+
1507+ if (isatty(STDIN_FILENO)) {
1508+ ioctl(STDIN_FILENO, KDSETMODE, KD_GRAPHICS);
1509+ atexit(restore_tty);
1510+ }
1511+
1512+ window_setup();
1513+
1514+ init_audio();
1515+
1516+ render_set_video_standard(VID_NTSC);
1517+ init_evdev();
1518+
1519+ atexit(render_quit);
1520+}
1521+static void update_source(audio_source *src, double rc, uint8_t sync_changed)
1522+{
1523+ double alpha = src->dt / (src->dt + rc);
1524+ int32_t lowpass_alpha = (int32_t)(((double)0x10000) * alpha);
1525+ src->lowpass_alpha = lowpass_alpha;
1526+}
1527+
1528+void render_config_updated(void)
1529+{
1530+
1531+ destroy_wayland();
1532+ drain_events();
1533+
1534+ window_setup();
1535+
1536+ render_close_audio();
1537+ init_audio();
1538+ render_set_video_standard(video_standard);
1539+
1540+ double lowpass_cutoff = get_lowpass_cutoff(config);
1541+ double rc = (1.0 / lowpass_cutoff) / (2.0 * M_PI);
1542+ for (uint8_t i = 0; i < num_audio_sources; i++)
1543+ {
1544+ update_source(audio_sources[i], rc, 0);
1545+ }
1546+ for (uint8_t i = 0; i < num_inactive_audio_sources; i++)
1547+ {
1548+ update_source(inactive_audio_sources[i], rc, 0);
1549+ }
1550+ drain_events();
1551+}
1552+
1553+void render_set_video_standard(vid_std std)
1554+{
1555+ video_standard = std;
1556+}
1557+
1558+void render_update_caption(char *title)
1559+{
1560+ caption = title;
1561+ if (xdg_toplevel_handle) {
1562+ xdg_toplevel_set_title(xdg_toplevel_handle, title);
1563+ }
1564+ free(fps_caption);
1565+ fps_caption = NULL;
1566+}
1567+
1568+static char *screenshot_path;
1569+void render_save_screenshot(char *path)
1570+{
1571+ if (screenshot_path) {
1572+ free(screenshot_path);
1573+ }
1574+ screenshot_path = path;
1575+}
1576+
1577+uint8_t render_create_window(char *caption, uint32_t width, uint32_t height, window_close_handler close_handler)
1578+{
1579+ //no op
1580+ return 0;
1581+}
1582+
1583+void render_destroy_window(uint8_t which)
1584+{
1585+ //no op
1586+}
1587+
1588+static uint8_t last_video_buffer;
1589+static uint32_t video_buffer_offset;
1590+uint32_t *render_get_video_buffer(uint8_t which, int *pitch)
1591+{
1592+ if (last_video_buffer != which) {
1593+ *pitch = LINEBUF_SIZE * sizeof(uint32_t) * 2;
1594+ return video_buffer + video_buffer_offset + (which == VIDEO_BUFFER_EVEN ? LINEBUF_SIZE : 0);
1595+ }
1596+ *pitch = LINEBUF_SIZE * sizeof(uint32_t);
1597+ return video_buffer + video_buffer_offset;
1598+}
1599+
1600+uint8_t events_processed;
1601+#define FPS_INTERVAL 1000
1602+
1603+void render_video_buffer_updated(uint8_t which, int width)
1604+{
1605+ uint32_t height = which <= VIDEO_BUFFER_EVEN
1606+ ? (video_standard == VID_NTSC ? 243 : 294) - (overscan_top[video_standard] + overscan_bot[video_standard])
1607+ : 240;
1608+ width -= overscan_left[video_standard] + overscan_right[video_standard];
1609+ last_width = width;
1610+ last_width_scale = LINEBUF_SIZE - (overscan_left[video_standard] + overscan_right[video_standard]);
1611+ last_height = last_height_scale = height;
1612+ copy_buffer = video_buffer + video_buffer_offset + overscan_left[video_standard] + LINEBUF_SIZE * overscan_top[video_standard];
1613+ if (which != last_video_buffer) {
1614+ last_height *= 2;
1615+ copy_buffer += LINEBUF_SIZE * overscan_top[video_standard];
1616+ uint32_t *src = video_buffer + (video_buffer_offset ? 0 : LINEBUF_SIZE * MAX_VIDEO_BUFFER_LINES) + overscan_left[video_standard] + LINEBUF_SIZE * overscan_top[video_standard] + LINEBUF_SIZE * overscan_top[video_standard];
1617+ uint32_t *dst = copy_buffer;
1618+ if (which == VIDEO_BUFFER_ODD) {
1619+ src += LINEBUF_SIZE;
1620+ dst += LINEBUF_SIZE;
1621+ }
1622+ for (int i = 0; i < height; i++)
1623+ {
1624+ memcpy(dst, src, width * sizeof(uint32_t));
1625+ src += LINEBUF_SIZE * 2;
1626+ dst += LINEBUF_SIZE * 2;
1627+ }
1628+ video_buffer_offset = video_buffer_offset ? 0 : LINEBUF_SIZE * MAX_VIDEO_BUFFER_LINES;
1629+ }
1630+ do_buffer_copy();
1631+ last_video_buffer = which;
1632+ if (!events_processed) {
1633+ process_events();
1634+ }
1635+ events_processed = 0;
1636+}
1637+
1638+uint32_t render_emulated_width()
1639+{
1640+ return last_width - overscan_left[video_standard] - overscan_right[video_standard];
1641+}
1642+
1643+uint32_t render_emulated_height()
1644+{
1645+ return (video_standard == VID_NTSC ? 243 : 294) - overscan_top[video_standard] - overscan_bot[video_standard];
1646+}
1647+
1648+uint32_t render_overscan_left()
1649+{
1650+ return overscan_left[video_standard];
1651+}
1652+
1653+uint32_t render_overscan_top()
1654+{
1655+ return overscan_top[video_standard];
1656+}
1657+
1658+void render_wait_quit(vdp_context * context)
1659+{
1660+ for(;;)
1661+ {
1662+ drain_events();
1663+ sleep(1);
1664+ }
1665+}
1666+
1667+int render_lookup_button(char *name)
1668+{
1669+ static tern_node *button_lookup;
1670+ if (!button_lookup) {
1671+ //xbox names
1672+ button_lookup = tern_insert_int(button_lookup, "a", BTN_SOUTH);
1673+ button_lookup = tern_insert_int(button_lookup, "b", BTN_EAST);
1674+ button_lookup = tern_insert_int(button_lookup, "x", BTN_WEST);
1675+ button_lookup = tern_insert_int(button_lookup, "y", BTN_NORTH);
1676+ button_lookup = tern_insert_int(button_lookup, "back", BTN_SELECT);
1677+ button_lookup = tern_insert_int(button_lookup, "start", BTN_START);
1678+ button_lookup = tern_insert_int(button_lookup, "guid", BTN_MODE);
1679+ button_lookup = tern_insert_int(button_lookup, "leftshoulder", BTN_TL);
1680+ button_lookup = tern_insert_int(button_lookup, "rightshoulder", BTN_TR);
1681+ button_lookup = tern_insert_int(button_lookup, "leftstick", BTN_THUMBL);
1682+ button_lookup = tern_insert_int(button_lookup, "rightstick", BTN_THUMBR);
1683+ //ps names
1684+ button_lookup = tern_insert_int(button_lookup, "cross", BTN_SOUTH);
1685+ button_lookup = tern_insert_int(button_lookup, "circle", BTN_EAST);
1686+ button_lookup = tern_insert_int(button_lookup, "square", BTN_WEST);
1687+ button_lookup = tern_insert_int(button_lookup, "triangle", BTN_NORTH);
1688+ button_lookup = tern_insert_int(button_lookup, "share", BTN_SELECT);
1689+ button_lookup = tern_insert_int(button_lookup, "select", BTN_SELECT);
1690+ button_lookup = tern_insert_int(button_lookup, "options", BTN_START);
1691+ button_lookup = tern_insert_int(button_lookup, "l1", BTN_TL);
1692+ button_lookup = tern_insert_int(button_lookup, "r1", BTN_TR);
1693+ button_lookup = tern_insert_int(button_lookup, "l3", BTN_THUMBL);
1694+ button_lookup = tern_insert_int(button_lookup, "r3", BTN_THUMBR);
1695+ }
1696+ return (int)tern_find_int(button_lookup, name, KEY_CNT);
1697+}
1698+
1699+int render_lookup_axis(char *name)
1700+{
1701+ static tern_node *axis_lookup;
1702+ if (!axis_lookup) {
1703+ //xbox names
1704+ axis_lookup = tern_insert_int(axis_lookup, "leftx", ABS_X);
1705+ axis_lookup = tern_insert_int(axis_lookup, "lefty", ABS_Y);
1706+ axis_lookup = tern_insert_int(axis_lookup, "lefttrigger", ABS_Z);
1707+ axis_lookup = tern_insert_int(axis_lookup, "rightx", ABS_RX);
1708+ axis_lookup = tern_insert_int(axis_lookup, "righty", ABS_RY);
1709+ axis_lookup = tern_insert_int(axis_lookup, "righttrigger", ABS_RZ);
1710+ //ps names
1711+ axis_lookup = tern_insert_int(axis_lookup, "l2", ABS_Z);
1712+ axis_lookup = tern_insert_int(axis_lookup, "r2", ABS_RZ);
1713+ }
1714+ return (int)tern_find_int(axis_lookup, name, ABS_CNT);
1715+}
1716+
1717+int32_t render_translate_input_name(int32_t controller, char *name, uint8_t is_axis)
1718+{
1719+ if (is_axis) {
1720+ int axis = render_lookup_axis(name);
1721+ if (axis == ABS_CNT) {
1722+ return RENDER_INVALID_NAME;
1723+ }
1724+ return RENDER_AXIS_BIT | axis;
1725+ } else {
1726+ int button = render_lookup_button(name);
1727+ if (button != KEY_CNT) {
1728+ return button;
1729+ }
1730+ if (!strcmp("dpup", name)) {
1731+ return RENDER_DPAD_BIT | 1;
1732+ }
1733+ if (!strcmp("dpdown", name)) {
1734+ return RENDER_DPAD_BIT | 4;
1735+ }
1736+ if (!strcmp("dpdleft", name)) {
1737+ return RENDER_DPAD_BIT | 8;
1738+ }
1739+ if (!strcmp("dpright", name)) {
1740+ return RENDER_DPAD_BIT | 2;
1741+ }
1742+ return RENDER_INVALID_NAME;
1743+ }
1744+}
1745+
1746+int32_t render_dpad_part(int32_t input)
1747+{
1748+ return input >> 4 & 0xFFFFFF;
1749+}
1750+
1751+uint8_t render_direction_part(int32_t input)
1752+{
1753+ return input & 0xF;
1754+}
1755+
1756+int32_t render_axis_part(int32_t input)
1757+{
1758+ return input & 0xFFFFFFF;
1759+}
1760+
1761+void process_events()
1762+{
1763+ if (events_processed > MAX_EVENT_POLL_PER_FRAME) {
1764+ return;
1765+ }
1766+ if (wl_display_handle) {
1767+ dispatch_wayland_pending(0);
1768+ }
1769+ drain_events();
1770+ events_processed++;
1771+}
1772+
1773+uint32_t render_audio_buffer()
1774+{
1775+ return buffer_samples;
1776+}
1777+
1778+uint32_t render_sample_rate()
1779+{
1780+ return sample_rate;
1781+}
1782+
1783+void render_errorbox(char *title, char *message)
1784+{
1785+
1786+}
1787+
1788+void render_warnbox(char *title, char *message)
1789+{
1790+
1791+}
1792+
1793+void render_infobox(char *title, char *message)
1794+{
1795+
1796+}
1797+
1798+uint8_t render_get_active_video_buffer(void)
1799+{
1800+ return VIDEO_BUFFER_ODD;
1801+}
A
rom.db
+1379,
-0
1@@ -0,0 +1,1379 @@
2+T-081326 {
3+ name NBA Jam
4+ EEPROM {
5+ type i2c
6+ size 256
7+ }
8+ map {
9+ 0 {
10+ device ROM
11+ last 1FFFFF
12+ }
13+ 200000 {
14+ device EEPROM
15+ last 3FFFFF
16+ bits_read {
17+ 1 sda
18+ }
19+ bits_write {
20+ 0 sda
21+ 1 scl
22+ }
23+ }
24+ }
25+}
26+T-81033 {
27+ name NBA Jam
28+ EEPROM {
29+ type i2c
30+ size 256
31+ }
32+ map {
33+ 0 {
34+ device ROM
35+ last 1FFFFF
36+ }
37+ 200000 {
38+ device EEPROM
39+ last 3FFFFF
40+ bits_read {
41+ 1 sda
42+ }
43+ bits_write {
44+ 0 sda
45+ 1 scl
46+ }
47+ }
48+ }
49+}
50+T-081276 {
51+ name NFL Quarterback Club
52+ EEPROM {
53+ type i2c
54+ size 256
55+ }
56+ map {
57+ 0 {
58+ device ROM
59+ last 1FFFFF
60+ }
61+ 200000 {
62+ device EEPROM
63+ #This is almost certainly not correct based on the address pins
64+ #available to the Acclaim mapper. It's probably available up to
65+ #2FFFFF at least and just fights with D0 from the mask ROM
66+ last 200001
67+ bits_read {
68+ 0 sda
69+ }
70+ bits_write {
71+ 0 sda
72+ 8 scl
73+ }
74+ }
75+ 200002 {
76+ device ROM
77+ offset 200000
78+ last 2FFFFF
79+ }
80+ }
81+}
82+T-81406 {
83+ name NBA Jam TE
84+ EEPROM {
85+ type i2c
86+ size 512
87+ }
88+ map {
89+ 0 {
90+ device ROM
91+ last 1FFFFF
92+ }
93+ 200000 {
94+ device EEPROM
95+ #This is almost certainly not correct based on the address pins
96+ #available to the Acclaim mapper. It's probably available up to
97+ #2FFFFF at least and just fights with D0 from the mask ROM
98+ last 200001
99+ bits_read {
100+ 0 sda
101+ }
102+ bits_write {
103+ 0 sda
104+ 8 scl
105+ }
106+ }
107+ 200002 {
108+ device ROM
109+ offset 200000
110+ last 2FFFFF
111+ }
112+ }
113+}
114+T-081586 {
115+ name NFL Quarterback Club '96
116+ EEPROM {
117+ type i2c
118+ size 2048
119+ }
120+ map {
121+ 0 {
122+ device ROM
123+ last 1FFFFF
124+ }
125+ 200000 {
126+ device EEPROM
127+ #This is almost certainly not correct based on the address pins
128+ #available to the Acclaim mapper. It's probably available up to
129+ #2FFFFF at least and just fights with D0 from the mask ROM
130+ last 200001
131+ bits_read {
132+ 0 sda
133+ }
134+ bits_write {
135+ 0 sda
136+ 8 scl
137+ }
138+ }
139+ 200002 {
140+ device ROM
141+ last 3FFFFF
142+ offset 200000
143+ }
144+ }
145+}
146+T-81576 {
147+ name College Slam
148+ EEPROM {
149+ type i2c
150+ size 8192
151+ }
152+ map {
153+ 0 {
154+ device ROM
155+ last 1FFFFF
156+ }
157+ 200000 {
158+ device EEPROM
159+ #This is almost certainly not correct based on the address pins
160+ #available to the Acclaim mapper. It's probably available up to
161+ #2FFFFF at least and just fights with D0 from the mask ROM
162+ last 200001
163+ bits_read {
164+ 0 sda
165+ }
166+ bits_write {
167+ 0 sda
168+ 8 scl
169+ }
170+ }
171+ 200002 {
172+ device ROM
173+ offset 200000
174+ last 2FFFFF
175+ }
176+ }
177+}
178+T-81476 {
179+ name Frank Thomas Big Hurt Baseball
180+ EEPROM {
181+ type i2c
182+ size 8192
183+ }
184+ map {
185+ 0 {
186+ device ROM
187+ last 1FFFFF
188+ }
189+ 200000 {
190+ device EEPROM
191+ #This is almost certainly not correct based on the address pins
192+ #available to the Acclaim mapper. It's probably available up to
193+ #2FFFFF at least and just fights with D0 from the mask ROM
194+ last 200001
195+ bits_read {
196+ 0 sda
197+ }
198+ bits_write {
199+ 0 sda
200+ 8 scl
201+ }
202+ }
203+ 200002 {
204+ device ROM
205+ last 3FFFFF
206+ offset 200000
207+ }
208+ }
209+}
210+T-50176 {
211+ name Rings of Power
212+ EEPROM {
213+ type i2c
214+ size 128
215+ }
216+ map {
217+ 0 {
218+ device ROM
219+ last FFFFF
220+ }
221+ 200000 {
222+ device EEPROM
223+ last 3FFFFF
224+ bits_read {
225+ 7 sda
226+ }
227+ bits_write {
228+ 6 scl
229+ 7 sda
230+ }
231+ }
232+ }
233+}
234+T-50396 {
235+ name NHLPA Hockey '93
236+ EEPROM {
237+ type i2c
238+ size 128
239+ }
240+ map {
241+ 0 {
242+ device ROM
243+ last 7FFFF
244+ }
245+ 200000 {
246+ device EEPROM
247+ last 3FFFFF
248+ bits_read {
249+ 7 sda
250+ }
251+ bits_write {
252+ 6 scl
253+ 7 sda
254+ }
255+ }
256+ }
257+}
258+T-50446 {
259+ name John Madden Football '93
260+ EEPROM {
261+ type i2c
262+ size 128
263+ }
264+ map {
265+ 0 {
266+ device ROM
267+ last FFFFF
268+ }
269+ 200000 {
270+ device EEPROM
271+ last 3FFFFF
272+ bits_read {
273+ 7 sda
274+ }
275+ bits_write {
276+ 6 scl
277+ 7 sda
278+ }
279+ }
280+ }
281+}
282+T-50516 {
283+ name John Madden Football '93: Championship Edition
284+ EEPROM {
285+ type i2c
286+ size 128
287+ }
288+ map {
289+ 0 {
290+ device ROM
291+ last FFFFF
292+ }
293+ 200000 {
294+ device EEPROM
295+ last 3FFFFF
296+ bits_read {
297+ 7 sda
298+ }
299+ bits_write {
300+ 6 scl
301+ 7 sda
302+ }
303+ }
304+ }
305+}
306+T-172196 {
307+ name Madden NFL 98
308+ SRAM {
309+ size 16318
310+ bus odd
311+ }
312+ map {
313+ 0 {
314+ device ROM
315+ last 1FFFFF
316+ }
317+ 200000 {
318+ device SRAM
319+ last 3FFFFF
320+ }
321+ }
322+}
323+T-50606 {
324+ name Bill Walsh College Football
325+ EEPROM {
326+ type i2c
327+ size 128
328+ }
329+ map {
330+ 0 {
331+ device ROM
332+ last FFFFF
333+ }
334+ 200000 {
335+ device EEPROM
336+ last 3FFFFF
337+ bits_read {
338+ 7 sda
339+ }
340+ bits_write {
341+ 6 scl
342+ 7 sda
343+ }
344+ }
345+ }
346+}
347+MK-1228 {
348+ name Greatest Heavyweights of the Ring
349+ EEPROM {
350+ type i2c
351+ size 128
352+ }
353+ map {
354+ 0 {
355+ device ROM
356+ last 1FFFFF
357+ }
358+ 200000 {
359+ device EEPROM
360+ last 3FFFFF
361+ bits_read {
362+ 0 sda
363+ }
364+ bits_write {
365+ 0 sda
366+ 1 scl
367+ }
368+ }
369+ }
370+}
371+G-5538 {
372+ name Greatest Heavyweights of the Ring
373+ EEPROM {
374+ type i2c
375+ size 128
376+ }
377+ map {
378+ 0 {
379+ device ROM
380+ last 1FFFFF
381+ }
382+ 200000 {
383+ device EEPROM
384+ last 3FFFFF
385+ bits_read {
386+ 0 sda
387+ }
388+ bits_write {
389+ 0 sda
390+ 1 scl
391+ }
392+ }
393+ }
394+}
395+PR-1993 {
396+ name Greatest Heavyweights of the Ring (Prototype)
397+ EEPROM {
398+ type i2c
399+ size 128
400+ }
401+ map {
402+ 0 {
403+ device ROM
404+ last 1FFFFF
405+ }
406+ 200000 {
407+ device EEPROM
408+ last 3FFFFF
409+ bits_read {
410+ 0 sda
411+ }
412+ bits_write {
413+ 0 sda
414+ 1 scl
415+ }
416+ }
417+ }
418+}
419+00001211 {
420+ name Sports Talk Baseball
421+ EEPROM {
422+ type i2c
423+ size 128
424+ }
425+ map {
426+ 0 {
427+ device ROM
428+ last 1FFFFF
429+ }
430+ 200000 {
431+ device EEPROM
432+ last 3FFFFF
433+ bits_read {
434+ 0 sda
435+ }
436+ bits_write {
437+ 0 sda
438+ 1 scl
439+ }
440+ }
441+ }
442+}
443+00004076 {
444+ name Honoo no Toukyuuji Dodge Danpei
445+ EEPROM {
446+ type i2c
447+ size 128
448+ }
449+ map {
450+ 0 {
451+ device ROM
452+ last 1FFFFF
453+ }
454+ 200000 {
455+ device EEPROM
456+ last 3FFFFF
457+ bits_read {
458+ 0 sda
459+ }
460+ bits_write {
461+ 0 sda
462+ 1 scl
463+ }
464+ }
465+ }
466+}
467+00054503 {
468+ name Game Toshokan
469+ EEPROM {
470+ type i2c
471+ size 128
472+ }
473+ map {
474+ 0 {
475+ device ROM
476+ last 1FFFFF
477+ }
478+ 200000 {
479+ device EEPROM
480+ last 3FFFFF
481+ bits_read {
482+ 0 sda
483+ }
484+ bits_write {
485+ 0 sda
486+ 1 scl
487+ }
488+ }
489+ }
490+}
491+T-120106 {
492+ name Brian Lara Cricket
493+ EEPROM {
494+ type i2c
495+ size 1024
496+ }
497+ map {
498+ 0 {
499+ device ROM
500+ last 2FFFFF
501+ }
502+ 300000 {
503+ device EEPROM
504+ last 37FFFF
505+ bits_write {
506+ 0 sda
507+ 1 scl
508+ }
509+ }
510+ 380000 {
511+ device EEPROM
512+ last 3FFFFF
513+ bits_read {
514+ 7 sda
515+ }
516+ }
517+ }
518+}
519+T-120146 {
520+ name Brian Lara Cricket 96
521+ EEPROM {
522+ type i2c
523+ size 8192
524+ }
525+ map {
526+ 0 {
527+ device ROM
528+ last 2FFFFF
529+ }
530+ 300000 {
531+ device EEPROM
532+ last 37FFFF
533+ bits_write {
534+ 0 sda
535+ 1 scl
536+ }
537+ }
538+ 380000 {
539+ device EEPROM
540+ last 3FFFFF
541+ bits_read {
542+ 7 sda
543+ }
544+ }
545+ }
546+}
547+e8ff759679a0df2b3f9ece37ef686f248d3cf37b {
548+ name Micro Machines: Turbo Tournament '96
549+ EEPROM {
550+ type i2c
551+ size 2048
552+ }
553+ #TODO: J-Cart
554+ map {
555+ 0 {
556+ device ROM
557+ last 2FFFFF
558+ }
559+ 300000 {
560+ device EEPROM
561+ last 37FFFF
562+ bits_write {
563+ 0 sda
564+ 1 scl
565+ }
566+ }
567+ 380000 {
568+ device EEPROM
569+ last 387FFF
570+ bits_read {
571+ 7 sda
572+ }
573+ }
574+ 388000 {
575+ device jcart
576+ last 38FFFF
577+ }
578+ }
579+}
580+9f47fcc7bb2f5921cb1c3beb06b668ffb292cb08 {
581+ name Micro Machines: Turbo Tournament '96
582+ EEPROM {
583+ type i2c
584+ size 2048
585+ }
586+ #TODO: J-Cart
587+ map {
588+ 0 {
589+ device ROM
590+ last 2FFFFF
591+ }
592+ 300000 {
593+ device EEPROM
594+ last 37FFFF
595+ bits_write {
596+ 0 sda
597+ 1 scl
598+ }
599+ }
600+ 380000 {
601+ device EEPROM
602+ last 3FFFFF
603+ bits_read {
604+ 7 sda
605+ }
606+ }
607+ }
608+}
609+6d3df64ab8bb0b559f216adca62d1cdd74704a26 {
610+ name Micro Machines: Military
611+ EEPROM {
612+ type i2c
613+ size 1024
614+ }
615+ #TODO: J-Cart
616+ map {
617+ 0 {
618+ device ROM
619+ last 2FFFFF
620+ }
621+ 300000 {
622+ device EEPROM
623+ last 37FFFF
624+ bits_write {
625+ 0 sda
626+ 1 scl
627+ }
628+ }
629+ 380000 {
630+ device EEPROM
631+ last 387FFF
632+ bits_read {
633+ 7 sda
634+ }
635+ }
636+ 388000 {
637+ device jcart
638+ last 38FFFF
639+ }
640+ }
641+}
642+T-120096 {
643+ name Micro Machines 2: Turbo Tournament
644+ EEPROM {
645+ type i2c
646+ size 2048
647+ }
648+ #TODO: J-Cart
649+ map {
650+ 0 {
651+ device ROM
652+ last 2FFFFF
653+ }
654+ 300000 {
655+ device EEPROM
656+ last 37FFFF
657+ bits_write {
658+ 0 sda
659+ 1 scl
660+ }
661+ }
662+ 380000 {
663+ device EEPROM
664+ last 387FFF
665+ bits_read {
666+ 7 sda
667+ }
668+ }
669+ 388000 {
670+ device jcart
671+ last 38FFFF
672+ }
673+ }
674+}
675+MK-12056 {
676+ name Super Street Fighter 2: The New Challengers
677+ map {
678+ 0 {
679+ device ROM
680+ last 7FFFF
681+ }
682+ 80000 {
683+ device Sega mapper
684+ last 3FFFFF
685+ offset 80000
686+ }
687+ }
688+}
689+T-12056 {
690+ name Super Street Fighter 2: The New Challengers
691+ map {
692+ 0 {
693+ device ROM
694+ last 7FFFF
695+ }
696+ 80000 {
697+ device Sega mapper
698+ last 3FFFFF
699+ offset 80000
700+ }
701+ }
702+}
703+T-12043 {
704+ name Super Street Fighter 2: The New Challengers
705+ map {
706+ 0 {
707+ device ROM
708+ last 7FFFF
709+ }
710+ 80000 {
711+ device Sega mapper
712+ last 3FFFFF
713+ offset 80000
714+ }
715+ }
716+}
717+T-12046 {
718+ name Mega Man - The Wily Wars
719+ EEPROM {
720+ type i2c
721+ size 128
722+ }
723+ map {
724+ 0 {
725+ device ROM
726+ last 1FFFFF
727+ }
728+ 200000 {
729+ device EEPROM
730+ last 3FFFFF
731+ bits_read {
732+ 0 sda
733+ }
734+ bits_write {
735+ 0 sda
736+ 1 scl
737+ }
738+ }
739+ }
740+}
741+T-12053 {
742+ name Rockman Mega World
743+ EEPROM {
744+ type i2c
745+ size 128
746+ }
747+ map {
748+ 0 {
749+ device ROM
750+ last 1FFFFF
751+ }
752+ 200000 {
753+ device EEPROM
754+ last 3FFFFF
755+ bits_read {
756+ 0 sda
757+ }
758+ bits_write {
759+ 0 sda
760+ 1 scl
761+ }
762+ }
763+ }
764+}
765+MK-1079 {
766+ #This entry is needed only to make this play nicely with
767+ #S&K lock-on support. Normal 2MB cartridges with SRAM won't
768+ #work right, but Sonic 3 has the limited SRAM-only variant
769+ #of Sega's mapper commonly found on 4MB carts with SRAM
770+ name Sonic the Hedgehog 3
771+ map {
772+ 0 {
773+ device ROM
774+ last 1FFFFF
775+ }
776+ 200000 {
777+ device Sega mapper
778+ variant save-only
779+ offset 200000
780+ last 3FFFFF
781+ }
782+ }
783+
784+}
785+MK-1563 {
786+ name Sonic & Knuckles
787+ map {
788+ 0 {
789+ device ROM
790+ last 1FFFFF
791+ }
792+ 200000 {
793+ device LOCK-ON
794+ last 3FFFFF
795+ offset 200000
796+ }
797+ }
798+}
799+G-4060 {
800+ name Wonder Boy in Monster World
801+ EEPROM {
802+ type i2c
803+ size 128
804+ }
805+ map {
806+ 0 {
807+ device ROM
808+ last 1FFFFF
809+ }
810+ 200000 {
811+ device EEPROM
812+ last 3FFFFF
813+ bits_read {
814+ 0 sda
815+ }
816+ bits_write {
817+ 0 sda
818+ 1 scl
819+ }
820+ }
821+ }
822+}
823+G-4524 {
824+ name Ninja Burai Densetsu
825+ EEPROM {
826+ type i2c
827+ size 128
828+ }
829+ map {
830+ 0 {
831+ device ROM
832+ last 1FFFFF
833+ }
834+ 200000 {
835+ device EEPROM
836+ last 3FFFFF
837+ bits_read {
838+ 0 sda
839+ }
840+ bits_write {
841+ 0 sda
842+ 1 scl
843+ }
844+ }
845+ }
846+}
847+T-70106- {
848+ name Another World
849+ #European version of this game has EUROPE in the region field rather than just E
850+ regions E
851+}
852+G-004130 {
853+ name Alien Soldier
854+ #Japanese version of this game seems to indicate support for European consoles in
855+ #the header. While the game does indeed run, most people probably expect 60Hz
856+ #if they are running the Japanese version rather than the European one
857+ regions J
858+}
859+G-005545 {
860+ name Light Crusader
861+ #Japanese version of this game seems to indicate support for European consoles in
862+ #the header. While the game does indeed run, most people probably expect 60Hz
863+ #if they are running the Japanese version rather than the European one
864+ regions J
865+}
866+
867+00004042 {
868+ name Castle of Illusion: Fushigi no Oshiro Daibouken
869+ #Has JAPAN in header rather than J, A gets interpreted as a "new-style" code
870+ regions J
871+}
872+T-48036 {
873+ name Ms. Pac-Man
874+ #Ms. Pac-Man doesn't like 6-button controllers
875+ device_overrides {
876+ 1 gamepad3.1
877+ 2 gamepad3.2
878+ }
879+}
880+T-103026 {
881+ name King of the Monsters
882+ #This game won't work at all with a properly emualted 6-button controller
883+ device_overrides {
884+ 1 gamepad3.1
885+ 2 gamepad3.2
886+ }
887+}
888+T-119106 {
889+ name Combat Cars
890+ #Routine in the main game seems to work fine with 6-button controllers,
891+ #but options menu has problems.
892+ device_overrides {
893+ 1 gamepad3.1
894+ 2 gamepad3.2
895+ }
896+}
897+T-113106 {
898+ name Second Samurai
899+ #Pause doesn't work right with a 6-button controller
900+ device_overrides {
901+ 1 gamepad3.1
902+ 2 gamepad3.2
903+ }
904+}
905+MK-1304 {
906+ name Dungeons & Dragons - Warriors of the Eternal Sun
907+ #Switching characters cycles too fast with a 6-button controller
908+ device_overrides {
909+ 1 gamepad3.1
910+ 2 gamepad3.2
911+ }
912+}
913+#Automatically hook up the mouse in the appropriate port for the games I've tested
914+T-76076 {
915+ name Nobunaga's Ambition
916+ device_overrides {
917+ 2 mouse.1
918+ }
919+}
920+T-97056 {
921+ name Fun 'N' Games
922+ device_overrides {
923+ 2 mouse.1
924+ }
925+}
926+MK-1552 {
927+ name Richard Scarry's Busytown
928+ device_overrides {
929+ 1 mouse.1
930+ }
931+}
932+MK-1713 {
933+ name Wacky Worlds
934+ device_overrides {
935+ 2 mouse.1
936+ }
937+}
938+T-97056- {
939+ name Fun 'n' Games
940+ device_overrides {
941+ 2 mouse.1
942+ }
943+}
944+T-130016 {
945+ name Shanghai II: Dragon's Eye
946+ device_overrides {
947+ 1 mouse.1
948+ }
949+}
950+T-50286 {
951+ name Buck Rogers: Countdown to Doomsday
952+ SRAM {
953+ size 8192
954+ bus odd
955+ }
956+ map {
957+ 0 {
958+ device ROM
959+ last 1FFFFF
960+ }
961+ 200000 {
962+ device SRAM
963+ last 3FFFFF
964+ }
965+ }
966+}
967+MK-1215 {
968+ name Evander 'Real Deal' Holyfield's Boxing
969+ EEPROM {
970+ type i2c
971+ size 128
972+ }
973+ map {
974+ 0 {
975+ device ROM
976+ last 1FFFFF
977+ }
978+ 200000 {
979+ device EEPROM
980+ last 3FFFFF
981+ bits_read {
982+ 0 sda
983+ }
984+ bits_write {
985+ 0 sda
986+ 1 scl
987+ }
988+ }
989+ }
990+}
991+ACLD012 {
992+ name Hardball III
993+ SRAM {
994+ size 32768
995+ bus odd
996+ }
997+ map {
998+ 0 {
999+ device ROM
1000+ last 1FFFFF
1001+ }
1002+ 200000 {
1003+ device SRAM
1004+ last 3FFFFF
1005+ }
1006+ }
1007+}
1008+T-50166 {
1009+ name Might and Magic - Gates to Another World
1010+ SRAM {
1011+ size 32768
1012+ bus odd
1013+ }
1014+ map {
1015+ 0 {
1016+ device ROM
1017+ last 1FFFFF
1018+ }
1019+ 200000 {
1020+ device SRAM
1021+ last 3FFFFF
1022+ }
1023+ }
1024+}
1025+9bed099693c27a6575b394bdd150efb7cc53c5c6 {
1026+ name Atomic Robo-Kid
1027+ regions J
1028+}
1029+d366d05644eb59a14baf3c2e7281c1584630c021 {
1030+ name Might and Magic III - Isles of Terra
1031+ SRAM {
1032+ size 32768
1033+ bus odd
1034+ }
1035+ map {
1036+ 0 {
1037+ device ROM
1038+ last 1FFFFF
1039+ }
1040+ 200000 {
1041+ device SRAM
1042+ last 3FFFFF
1043+ }
1044+ }
1045+}
1046+8fe0806427e123717ba20478ab1410c25fa942e6 {
1047+ name Ya Se Chuan Shuo
1048+ map {
1049+ 0 {
1050+ device ROM
1051+ last 3FFFFF
1052+ }
1053+ 400000 {
1054+ device fixed
1055+ value 6300
1056+ last 400001
1057+ }
1058+ 400002 {
1059+ device fixed
1060+ value 9800
1061+ last 400003
1062+ }
1063+ 400004 {
1064+ device fixed
1065+ value C900
1066+ last 400005
1067+ }
1068+ 400006 {
1069+ device fixed
1070+ value 1800
1071+ last 400007
1072+ }
1073+ }
1074+}
1075+7857c797245b52641a3d1d4512089bccb0ed5359 {
1076+ name 16 Zhang Ma Jiang
1077+ map {
1078+ 0 {
1079+ device ROM
1080+ last 3FFFFF
1081+ }
1082+ 400002 {
1083+ device fixed
1084+ value AA00
1085+ last 400003
1086+ }
1087+ 400006 {
1088+ device fixed
1089+ value F000
1090+ last 400007
1091+ }
1092+ }
1093+}
1094+5fc4591fbb1acc64e184466c7b6287c7f64e0b7a {
1095+ name Elf Wor
1096+ map {
1097+ 0 {
1098+ device ROM
1099+ last 3FFFFF
1100+ }
1101+ 400000 {
1102+ device fixed
1103+ value 5500
1104+ last 400001
1105+ }
1106+ 400002 {
1107+ device fixed
1108+ value 0F00
1109+ last 400003
1110+ }
1111+ 400004 {
1112+ device fixed
1113+ value C900
1114+ last 400005
1115+ }
1116+ 400006 {
1117+ device fixed
1118+ value 1800
1119+ last 400007
1120+ }
1121+ }
1122+}
1123+df7a2527875317406b466175f0614d343dd32117 {
1124+ name Huan Le Tao Qi Shu: Smart Mouse
1125+ map {
1126+ 0 {
1127+ device ROM
1128+ last 3FFFFF
1129+ }
1130+ 400000 {
1131+ device fixed
1132+ value 5500
1133+ last 400001
1134+ }
1135+ 400002 {
1136+ device fixed
1137+ value 0F00
1138+ last 400003
1139+ }
1140+ 400004 {
1141+ device fixed
1142+ value AA00
1143+ last 400005
1144+ }
1145+ 400006 {
1146+ device fixed
1147+ value F000
1148+ last 400007
1149+ }
1150+ }
1151+}
1152+25d2d6a5ab20e16b8b42b67e5fb338421b64b29b {
1153+ name Mighty Morphin' Power Rangers: The Fighting Edition
1154+ map {
1155+ 0 {
1156+ device ROM
1157+ last 3FFFFF
1158+ }
1159+ 400000 {
1160+ device fixed
1161+ value 5500
1162+ last 400001
1163+ }
1164+ 400002 {
1165+ device fixed
1166+ value 0F00
1167+ last 400003
1168+ }
1169+ 400004 {
1170+ device fixed
1171+ value C900
1172+ last 400005
1173+ }
1174+ 400006 {
1175+ device fixed
1176+ value 1800
1177+ last 400007
1178+ }
1179+ }
1180+}
1181+03f40c14624f1522d6e3105997d14e8eaba12257 {
1182+ name Super Bubble Bobble MD
1183+ map {
1184+ 0 {
1185+ device ROM
1186+ last 3FFFFF
1187+ }
1188+ 400000 {
1189+ device fixed
1190+ value 5500
1191+ last 400001
1192+ }
1193+ 400002 {
1194+ device fixed
1195+ value 0F00
1196+ last 400003
1197+ }
1198+ }
1199+}
1200+3dca68795b6c9a16cafa5e71218d5ce83aa465fc {
1201+ name Thunderbolt II
1202+ map {
1203+ 0 {
1204+ device ROM
1205+ last 3FFFFF
1206+ }
1207+ 400000 {
1208+ device fixed
1209+ value 5500
1210+ last 400001
1211+ }
1212+ 400006 {
1213+ device fixed
1214+ value F000
1215+ last 400007
1216+ }
1217+ }
1218+}
1219+2a561b6e47c93272fe5947084837d9f6f514ed38 {
1220+ name Squirrel King
1221+ map {
1222+ 0 {
1223+ device ROM
1224+ last 3FFFFF
1225+ }
1226+ 400000 {
1227+ device RAM
1228+ size 2
1229+ bus both
1230+ last 7FFFFF
1231+ }
1232+ }
1233+}
1234+
1235+#This entry is used by the GUI ROM
1236+BlstMenu {
1237+ map {
1238+ 0 {
1239+ device ROM
1240+ last FFFFF
1241+ }
1242+ 100000 {
1243+ device RAM
1244+ size 80000
1245+ last 17FFFF
1246+ }
1247+ 180000 {
1248+ device MENU
1249+ last 1FFFFF
1250+ }
1251+ }
1252+ device_overrides {
1253+ 1 gamepad3.1
1254+ 2 mouse.1
1255+ ext none
1256+ }
1257+ mouse_mode absolute
1258+}
1259+
1260+6568b3a4e096159776ef8687a80d43589741fd60 {
1261+ name Magistr 16 BIOS
1262+ NOR {
1263+ size 262144
1264+ page_size 128
1265+ product_id DA45
1266+ bus even
1267+ }
1268+ map {
1269+ 0 {
1270+ device ROM
1271+ last 3FFFFF
1272+ }
1273+ 400000 {
1274+ device NOR
1275+ last 5FFFFF
1276+ }
1277+# 600000 {
1278+# device Super IO
1279+# last 7FFFFF
1280+# }
1281+ E00000 {
1282+ device RAM
1283+ size 40000
1284+ last FFFFFF
1285+ bus both
1286+ }
1287+ }
1288+}
1289+
1290+7313c20071de0ab1cd84ac1352cb0ed1c4a4afa8 {
1291+ #This appears to be an underdump, but it seems to be the only copy floating around
1292+ name 12-in-1
1293+ map {
1294+ 0 {
1295+ device multi-game
1296+ last 3FFFFF
1297+ }
1298+ }
1299+}
1300+6b2a6de2622735f6d56c6c9c01f74daa90e355cb {
1301+ name Super 15-in-1
1302+ map {
1303+ 0 {
1304+ device multi-game
1305+ last 3FFFFF
1306+ }
1307+ }
1308+}
1309+e1c041ba69da087c428dcda16850159f3caebd4b {
1310+ name Super 19-in-1
1311+ map {
1312+ 0 {
1313+ device multi-game
1314+ last 3FFFFF
1315+ }
1316+ }
1317+}
1318+31c66bd13abf4ae8271c09ec5286a0ee0289dbbc {
1319+ #Designed to run on Sega Channel hardware which is RAM-based
1320+ #writes to the this RAM qutie a bit to select games
1321+ name Game no Kanzume Otokuyou
1322+ map {
1323+ 0 {
1324+ device ROM
1325+ last 3FFFFF
1326+ writeable yes
1327+ }
1328+ }
1329+}
1330+cda73e4caf53cbc8f0750b69e5e7f394ad3735d1 {
1331+ name MegaWiFi Bootloader
1332+ NOR {
1333+ size 4194304
1334+ page_size 128
1335+ product_id DA45
1336+ bus both
1337+ init ROM
1338+ cmd_address1 AAB
1339+ cmd_address2 555
1340+ }
1341+ map {
1342+ 0 {
1343+ device NOR
1344+ last 3FFFFF
1345+ }
1346+ A130C0 {
1347+ device megawifi
1348+ last A130CF
1349+ }
1350+ }
1351+}
1352+222a66cdb8865a7f89e5a72418413888bb400176 {
1353+ #I've personally confirmed this version had a J-Cart
1354+ #release, but unlike the other revision it runs without it
1355+ name Pete Sampras Tennis
1356+ map {
1357+ 0 {
1358+ device ROM
1359+ last 1FFFFF
1360+ }
1361+ 200000 {
1362+ device jcart
1363+ last 3FFFFF
1364+ }
1365+ }
1366+}
1367+4c830ace4590294bb374b4cab71ebebf44d9a07a {
1368+ #This version will not accept input if J-Cart hardware is missing
1369+ name Pete Sampras Tennis
1370+ map {
1371+ 0 {
1372+ device ROM
1373+ last 1FFFFF
1374+ }
1375+ 200000 {
1376+ device jcart
1377+ last 3FFFFF
1378+ }
1379+ }
1380+}
A
romdb.c
+981,
-0
1@@ -0,0 +1,981 @@
2+#include <stdlib.h>
3+#include <string.h>
4+#include "config.h"
5+#include "romdb.h"
6+#include "util.h"
7+#include "hash.h"
8+#include "genesis.h"
9+#include "menu.h"
10+#include "xband.h"
11+#include "realtec.h"
12+#include "nor.h"
13+#include "sega_mapper.h"
14+#include "multi_game.h"
15+#include "megawifi.h"
16+#include "jcart.h"
17+#include "blastem.h"
18+
19+#define DOM_TITLE_START 0x120
20+#define DOM_TITLE_END 0x150
21+#define TITLE_START DOM_TITLE_END
22+#define TITLE_END (TITLE_START+48)
23+#define ROM_END 0x1A4
24+#define RAM_ID 0x1B0
25+#define RAM_FLAGS 0x1B2
26+#define RAM_START 0x1B4
27+#define RAM_END 0x1B8
28+#define REGION_START 0x1F0
29+
30+char const *save_type_name(uint8_t save_type)
31+{
32+ if (save_type == SAVE_I2C) {
33+ return "EEPROM";
34+ } else if(save_type == SAVE_NOR) {
35+ return "NOR Flash";
36+ }
37+ return "SRAM";
38+}
39+
40+tern_node *load_rom_db()
41+{
42+ tern_node *db = parse_bundled_config("rom.db");
43+ if (!db) {
44+ fatal_error("Failed to load ROM DB\n");
45+ }
46+ return db;
47+}
48+
49+void free_rom_info(rom_info *info)
50+{
51+ free(info->name);
52+ if (info->save_type != SAVE_NONE) {
53+ free(info->save_buffer);
54+ if (info->save_type == SAVE_I2C) {
55+ free(info->eeprom_map);
56+ } else if (info->save_type == SAVE_NOR) {
57+ free(info->nor);
58+ }
59+ }
60+ free(info->map);
61+ free(info->port1_override);
62+ free(info->port2_override);
63+ free(info->ext_override);
64+ free(info->mouse_mode);
65+}
66+
67+void cart_serialize(system_header *sys, serialize_buffer *buf)
68+{
69+ if (sys->type != SYSTEM_GENESIS) {
70+ return;
71+ }
72+ genesis_context *gen = (genesis_context *)sys;
73+ if (gen->mapper_type == MAPPER_NONE) {
74+ return;
75+ }
76+ start_section(buf, SECTION_MAPPER);
77+ save_int8(buf, gen->mapper_type);
78+ switch(gen->mapper_type)
79+ {
80+ case MAPPER_SEGA:
81+ sega_mapper_serialize(gen, buf);
82+ break;
83+ case MAPPER_REALTEC:
84+ realtec_serialize(gen, buf);
85+ break;
86+ case MAPPER_XBAND:
87+ xband_serialize(gen, buf);
88+ break;
89+ case MAPPER_MULTI_GAME:
90+ multi_game_serialize(gen, buf);
91+ break;
92+ }
93+ end_section(buf);
94+}
95+
96+void cart_deserialize(deserialize_buffer *buf, void *vcontext)
97+{
98+ genesis_context *gen = vcontext;
99+ uint8_t mapper_type = load_int8(buf);
100+ if (mapper_type != gen->mapper_type) {
101+ warning("Mapper type mismatch, skipping load of mapper state");
102+ return;
103+ }
104+ switch(gen->mapper_type)
105+ {
106+ case MAPPER_SEGA:
107+ sega_mapper_deserialize(buf, gen);
108+ break;
109+ case MAPPER_REALTEC:
110+ realtec_deserialize(buf, gen);
111+ break;
112+ case MAPPER_XBAND:
113+ xband_deserialize(buf, gen);
114+ break;
115+ case MAPPER_MULTI_GAME:
116+ multi_game_deserialize(buf, gen);
117+ break;
118+ }
119+}
120+
121+char *get_header_name(uint8_t *rom)
122+{
123+ //TODO: Should probably prefer the title field that corresponds to the user's region preference
124+ uint8_t *last = rom + TITLE_END - 1;
125+ uint8_t *src = rom + TITLE_START;
126+
127+ for (;;)
128+ {
129+ while (last > src && (*last <= 0x20 || *last >= 0x80))
130+ {
131+ last--;
132+ }
133+ if (last == src) {
134+ if (src == rom + TITLE_START) {
135+ src = rom + DOM_TITLE_START;
136+ last = rom + DOM_TITLE_END - 1;
137+ } else {
138+ return strdup("UNKNOWN");
139+ }
140+ } else {
141+ last++;
142+ char *ret = malloc(last - src + 1);
143+ uint8_t *dst;
144+ uint8_t last_was_space = 1;
145+ for (dst = ret; src < last; src++)
146+ {
147+ if (*src >= 0x20 && *src < 0x80) {
148+ if (*src == ' ') {
149+ if (last_was_space) {
150+ continue;
151+ }
152+ last_was_space = 1;
153+ } else {
154+ last_was_space = 0;
155+ }
156+ *(dst++) = *src;
157+ }
158+ }
159+ *dst = 0;
160+ return ret;
161+ }
162+ }
163+}
164+
165+char *region_chars = "JUEW";
166+uint8_t region_bits[] = {REGION_J, REGION_U, REGION_E, REGION_J|REGION_U|REGION_E};
167+
168+uint8_t translate_region_char(uint8_t c)
169+{
170+ for (int i = 0; i < sizeof(region_bits); i++)
171+ {
172+ if (c == region_chars[i]) {
173+ return region_bits[i];
174+ }
175+ }
176+ uint8_t bin_region = 0;
177+ if (c >= '0' && c <= '9') {
178+ bin_region = c - '0';
179+ } else if (c >= 'A' && c <= 'F') {
180+ bin_region = c - 'A' + 0xA;
181+ } else if (c >= 'a' && c <= 'f') {
182+ bin_region = c - 'a' + 0xA;
183+ }
184+ uint8_t ret = 0;
185+ if (bin_region & 8) {
186+ ret |= REGION_E;
187+ }
188+ if (bin_region & 4) {
189+ ret |= REGION_U;
190+ }
191+ if (bin_region & 1) {
192+ ret |= REGION_J;
193+ }
194+ return ret;
195+}
196+
197+uint8_t get_header_regions(uint8_t *rom)
198+{
199+ uint8_t regions = 0;
200+ for (int i = 0; i < 3; i++)
201+ {
202+ regions |= translate_region_char(rom[REGION_START + i]);
203+ }
204+ return regions;
205+}
206+
207+uint32_t get_u32be(uint8_t *data)
208+{
209+ return *data << 24 | data[1] << 16 | data[2] << 8 | data[3];
210+}
211+
212+uint32_t calc_mask(uint32_t src_size, uint32_t start, uint32_t end)
213+{
214+ uint32_t map_size = end-start+1;
215+ if (src_size < map_size) {
216+ return nearest_pow2(src_size)-1;
217+ } else if (!start) {
218+ return 0xFFFFFF;
219+ } else {
220+ return nearest_pow2(map_size)-1;
221+ }
222+}
223+
224+uint8_t has_ram_header(uint8_t *rom, uint32_t rom_size)
225+{
226+ return rom_size >= (RAM_END + 4) && rom[RAM_ID] == 'R' && rom[RAM_ID + 1] == 'A';
227+}
228+
229+uint32_t read_ram_header(rom_info *info, uint8_t *rom)
230+{
231+ uint32_t ram_start = get_u32be(rom + RAM_START);
232+ uint32_t ram_end = get_u32be(rom + RAM_END);
233+ uint32_t ram_flags = info->save_type = rom[RAM_FLAGS] & RAM_FLAG_MASK;
234+ ram_start &= 0xFFFFFE;
235+ ram_end |= 1;
236+ if (ram_start >= 0x800000) {
237+ info->save_buffer = NULL;
238+ return ram_start;
239+ }
240+ info->save_mask = ram_end - ram_start;
241+ uint32_t save_size = info->save_mask + 1;
242+ if (ram_flags != RAM_FLAG_BOTH) {
243+ save_size /= 2;
244+ }
245+ info->save_size = save_size;
246+ info->save_buffer = malloc(save_size);
247+ return ram_start;
248+}
249+
250+void add_memmap_header(rom_info *info, uint8_t *rom, uint32_t size, memmap_chunk const *base_map, int base_chunks)
251+{
252+ uint32_t rom_end = get_u32be(rom + ROM_END) + 1;
253+ if (size > rom_end) {
254+ rom_end = size;
255+ } else if (rom_end > nearest_pow2(size)) {
256+ rom_end = nearest_pow2(size);
257+ }
258+ if (size >= 0x80000 && !memcmp("SEGA SSF", rom + 0x100, 8)) {
259+ info->mapper_start_index = 0;
260+ info->mapper_type = MAPPER_SEGA;
261+ info->map_chunks = base_chunks + 9;
262+ info->map = malloc(sizeof(memmap_chunk) * info->map_chunks);
263+ memset(info->map, 0, sizeof(memmap_chunk)*9);
264+ memcpy(info->map+9, base_map, sizeof(memmap_chunk) * base_chunks);
265+
266+ info->map[0].start = 0;
267+ info->map[0].end = 0x80000;
268+ info->map[0].mask = 0xFFFFFF;
269+ info->map[0].flags = MMAP_READ;
270+ info->map[0].buffer = rom;
271+
272+ if (has_ram_header(rom, size)){
273+ read_ram_header(info, rom);
274+ }
275+
276+ for (int i = 1; i < 8; i++)
277+ {
278+ info->map[i].start = i * 0x80000;
279+ info->map[i].end = (i + 1) * 0x80000;
280+ info->map[i].mask = 0x7FFFF;
281+ info->map[i].buffer = (i + 1) * 0x80000 <= size ? rom + i * 0x80000 : rom;
282+ info->map[i].ptr_index = i;
283+ info->map[i].flags = MMAP_READ | MMAP_PTR_IDX | MMAP_CODE | MMAP_FUNC_NULL;
284+
285+ info->map[i].read_16 = (read_16_fun)read_sram_w;//these will only be called when mem_pointers[i] == NULL
286+ info->map[i].read_8 = (read_8_fun)read_sram_b;
287+ info->map[i].write_16 = (write_16_fun)write_sram_area_w;//these will be called all writes to the area
288+ info->map[i].write_8 = (write_8_fun)write_sram_area_b;
289+
290+ }
291+ info->map[8].start = 0xA13000;
292+ info->map[8].end = 0xA13100;
293+ info->map[8].mask = 0xFF;
294+ info->map[8].write_16 = (write_16_fun)write_bank_reg_w;
295+ info->map[8].write_8 = (write_8_fun)write_bank_reg_b;
296+ return;
297+ } else if(!memcmp("SEGA MEGAWIFI", rom + 0x100, strlen("SEGA MEGAWIFI"))) {
298+ info->mapper_type = MAPPER_NONE;
299+ info->map_chunks = base_chunks + 2;
300+ info->map = malloc(sizeof(memmap_chunk) * info->map_chunks);
301+ memset(info->map, 0, sizeof(memmap_chunk)*2);
302+ memcpy(info->map+2, base_map, sizeof(memmap_chunk) * base_chunks);
303+ info->save_size = 0x400000;
304+ info->save_bus = RAM_FLAG_BOTH;
305+ info->save_type = SAVE_NOR;
306+ info->map[0].start = 0;
307+ info->map[0].end = 0x400000;
308+ info->map[0].mask = 0xFFFFFF;
309+ info->map[0].write_16 = nor_flash_write_w;
310+ info->map[0].write_8 = nor_flash_write_b;
311+ info->map[0].read_16 = nor_flash_read_w;
312+ info->map[0].read_8 = nor_flash_read_b;
313+ info->map[0].flags = MMAP_READ_CODE | MMAP_CODE;
314+ info->map[0].buffer = info->save_buffer = malloc(info->save_size);
315+ uint32_t init_size = size < info->save_size ? size : info->save_size;
316+ memcpy(info->save_buffer, rom, init_size);
317+ byteswap_rom(info->save_size, (uint16_t *)info->save_buffer);
318+ info->nor = calloc(1, sizeof(nor_state));
319+ nor_flash_init(info->nor, info->save_buffer, info->save_size, 128, 0xDA45, RAM_FLAG_BOTH);
320+ info->nor->cmd_address1 = 0xAAB;
321+ info->nor->cmd_address2 = 0x555;
322+ info->map[1].start = 0xA130C0;
323+ info->map[1].end = 0xA130D0;
324+ info->map[1].mask = 0xFFFFFF;
325+ if (!strcmp(
326+ "on",
327+ tern_find_path_default(config, "system\0megawifi\0", (tern_val){.ptrval="off"}, TVAL_PTR).ptrval)
328+ ) {
329+ info->map[1].write_16 = megawifi_write_w;
330+ info->map[1].write_8 = megawifi_write_b;
331+ info->map[1].read_16 = megawifi_read_w;
332+ info->map[1].read_8 = megawifi_read_b;
333+ } else {
334+ warning("ROM uses MegaWiFi, but it is disabled\n");
335+ }
336+ return;
337+ } else if (has_ram_header(rom, size)) {
338+ uint32_t ram_start = read_ram_header(info, rom);
339+
340+ if (info->save_buffer) {
341+ info->map_chunks = base_chunks + (ram_start >= rom_end ? 2 : 3);
342+ info->map = malloc(sizeof(memmap_chunk) * info->map_chunks);
343+ memset(info->map, 0, sizeof(memmap_chunk)*2);
344+ memcpy(info->map+2, base_map, sizeof(memmap_chunk) * base_chunks);
345+
346+ if (ram_start >= rom_end) {
347+ info->map[0].end = rom_end < 0x400000 ? nearest_pow2(rom_end) - 1 : 0xFFFFFF;
348+ if (info->map[0].end > ram_start) {
349+ info->map[0].end = ram_start;
350+ }
351+ //TODO: ROM mirroring
352+ info->map[0].mask = 0xFFFFFF;
353+ info->map[0].flags = MMAP_READ;
354+ info->map[0].buffer = rom;
355+
356+ info->map[1].start = ram_start;
357+ info->map[1].mask = info->save_mask;
358+ info->map[1].end = ram_start + info->save_mask + 1;
359+ info->map[1].flags = MMAP_READ | MMAP_WRITE;
360+
361+ if (info->save_type == RAM_FLAG_ODD) {
362+ info->map[1].flags |= MMAP_ONLY_ODD;
363+ } else if (info->save_type == RAM_FLAG_EVEN) {
364+ info->map[1].flags |= MMAP_ONLY_EVEN;
365+ }
366+ info->map[1].buffer = info->save_buffer;
367+ } else {
368+ //Assume the standard Sega mapper
369+ info->mapper_type = MAPPER_SEGA;
370+ info->map[0].end = 0x200000;
371+ info->map[0].mask = 0xFFFFFF;
372+ info->map[0].flags = MMAP_READ;
373+ info->map[0].buffer = rom;
374+
375+ info->map[1].start = 0x200000;
376+ info->map[1].end = 0x400000;
377+ info->map[1].mask = 0x1FFFFF;
378+ info->map[1].flags = MMAP_READ | MMAP_PTR_IDX | MMAP_FUNC_NULL;
379+ info->map[1].ptr_index = info->mapper_start_index = 0;
380+ info->map[1].read_16 = (read_16_fun)read_sram_w;//these will only be called when mem_pointers[2] == NULL
381+ info->map[1].read_8 = (read_8_fun)read_sram_b;
382+ info->map[1].write_16 = (write_16_fun)write_sram_area_w;//these will be called all writes to the area
383+ info->map[1].write_8 = (write_8_fun)write_sram_area_b;
384+ info->map[1].buffer = rom + 0x200000;
385+
386+ memmap_chunk *last = info->map + info->map_chunks - 1;
387+ memset(last, 0, sizeof(memmap_chunk));
388+ last->start = 0xA13000;
389+ last->end = 0xA13100;
390+ last->mask = 0xFF;
391+ last->write_16 = (write_16_fun)write_bank_reg_w;
392+ last->write_8 = (write_8_fun)write_bank_reg_b;
393+ }
394+ return;
395+ }
396+ }
397+
398+ info->map_chunks = base_chunks + 1;
399+ info->map = malloc(sizeof(memmap_chunk) * info->map_chunks);
400+ memset(info->map, 0, sizeof(memmap_chunk));
401+ memcpy(info->map+1, base_map, sizeof(memmap_chunk) * base_chunks);
402+
403+ info->map[0].end = rom_end > 0x400000 ? rom_end : 0x400000;
404+ info->map[0].mask = rom_end < 0x400000 ? nearest_pow2(rom_end) - 1 : 0xFFFFFF;
405+ info->map[0].flags = MMAP_READ;
406+ info->map[0].buffer = rom;
407+ info->save_type = SAVE_NONE;
408+}
409+
410+rom_info configure_rom_heuristics(uint8_t *rom, uint32_t rom_size, memmap_chunk const *base_map, uint32_t base_chunks)
411+{
412+ rom_info info;
413+ info.mapper_type = MAPPER_NONE;
414+ info.name = get_header_name(rom);
415+ info.regions = get_header_regions(rom);
416+ info.is_save_lock_on = 0;
417+ info.rom = rom;
418+ info.rom_size = rom_size;
419+ add_memmap_header(&info, rom, rom_size, base_map, base_chunks);
420+ info.port1_override = info.port2_override = info.ext_override = info.mouse_mode = NULL;
421+ return info;
422+}
423+
424+typedef struct {
425+ rom_info *info;
426+ uint8_t *rom;
427+ uint8_t *lock_on;
428+ tern_node *root;
429+ tern_node *rom_db;
430+ uint32_t rom_size;
431+ uint32_t lock_on_size;
432+ int index;
433+ int num_els;
434+ uint16_t ptr_index;
435+} map_iter_state;
436+
437+void eeprom_read_fun(char *key, tern_val val, uint8_t valtype, void *data)
438+{
439+ int bit = atoi(key);
440+ if (bit < 0 || bit > 15) {
441+ fprintf(stderr, "bit %s is out of range", key);
442+ return;
443+ }
444+ if (valtype != TVAL_PTR) {
445+ fprintf(stderr, "bit %s has a non-scalar value", key);
446+ return;
447+ }
448+ char *pin = val.ptrval;
449+ if (strcmp(pin, "sda")) {
450+ fprintf(stderr, "bit %s is connected to unrecognized read pin %s", key, pin);
451+ return;
452+ }
453+ eeprom_map *map = data;
454+ map->sda_read_bit = bit;
455+}
456+
457+void eeprom_write_fun(char *key, tern_val val, uint8_t valtype, void *data)
458+{
459+ int bit = atoi(key);
460+ if (bit < 0 || bit > 15) {
461+ fprintf(stderr, "bit %s is out of range", key);
462+ return;
463+ }
464+ if (valtype != TVAL_PTR) {
465+ fprintf(stderr, "bit %s has a non-scalar value", key);
466+ return;
467+ }
468+ char *pin = val.ptrval;
469+ eeprom_map *map = data;
470+ if (!strcmp(pin, "sda")) {
471+ map->sda_write_mask = 1 << bit;
472+ return;
473+ }
474+ if (!strcmp(pin, "scl")) {
475+ map->scl_mask = 1 << bit;
476+ return;
477+ }
478+ fprintf(stderr, "bit %s is connected to unrecognized write pin %s", key, pin);
479+}
480+
481+void process_sram_def(char *key, map_iter_state *state)
482+{
483+ if (!state->info->save_size) {
484+ char * size = tern_find_path(state->root, "SRAM\0size\0", TVAL_PTR).ptrval;
485+ if (!size) {
486+ fatal_error("ROM DB map entry %d with address %s has device type SRAM, but the SRAM size is not defined\n", state->index, key);
487+ }
488+ state->info->save_size = atoi(size);
489+ if (!state->info->save_size) {
490+ fatal_error("SRAM size %s is invalid\n", size);
491+ }
492+ state->info->save_mask = nearest_pow2(state->info->save_size)-1;
493+ state->info->save_buffer = malloc(state->info->save_size);
494+ memset(state->info->save_buffer, 0, state->info->save_size);
495+ char *bus = tern_find_path(state->root, "SRAM\0bus\0", TVAL_PTR).ptrval;
496+ if (!strcmp(bus, "odd")) {
497+ state->info->save_type = RAM_FLAG_ODD;
498+ } else if(!strcmp(bus, "even")) {
499+ state->info->save_type = RAM_FLAG_EVEN;
500+ } else {
501+ state->info->save_type = RAM_FLAG_BOTH;
502+ }
503+ }
504+}
505+
506+void process_eeprom_def(char * key, map_iter_state *state)
507+{
508+ if (!state->info->save_size) {
509+ char * size = tern_find_path(state->root, "EEPROM\0size\0", TVAL_PTR).ptrval;
510+ if (!size) {
511+ fatal_error("ROM DB map entry %d with address %s has device type EEPROM, but the EEPROM size is not defined\n", state->index, key);
512+ }
513+ state->info->save_size = atoi(size);
514+ if (!state->info->save_size) {
515+ fatal_error("EEPROM size %s is invalid\n", size);
516+ }
517+ char *etype = tern_find_path(state->root, "EEPROM\0type\0", TVAL_PTR).ptrval;
518+ if (!etype) {
519+ etype = "i2c";
520+ }
521+ if (!strcmp(etype, "i2c")) {
522+ state->info->save_type = SAVE_I2C;
523+ } else {
524+ fatal_error("EEPROM type %s is invalid\n", etype);
525+ }
526+ state->info->save_buffer = malloc(state->info->save_size);
527+ memset(state->info->save_buffer, 0xFF, state->info->save_size);
528+ state->info->eeprom_map = malloc(sizeof(eeprom_map) * state->num_els);
529+ memset(state->info->eeprom_map, 0, sizeof(eeprom_map) * state->num_els);
530+ }
531+}
532+
533+void process_nor_def(char *key, map_iter_state *state)
534+{
535+ if (!state->info->save_size) {
536+ char *size = tern_find_path(state->root, "NOR\0size\0", TVAL_PTR).ptrval;
537+ if (!size) {
538+ fatal_error("ROM DB map entry %d with address %s has device type NOR, but the NOR size is not defined\n", state->index, key);
539+ }
540+ state->info->save_size = atoi(size);
541+ if (!state->info->save_size) {
542+ fatal_error("NOR size %s is invalid\n", size);
543+ }
544+ char *page_size = tern_find_path(state->root, "NOR\0page_size\0", TVAL_PTR).ptrval;
545+ if (!page_size) {
546+ fatal_error("ROM DB map entry %d with address %s has device type NOR, but the NOR page size is not defined\n", state->index, key);
547+ }
548+ uint32_t save_page_size = atoi(page_size);
549+ if (!save_page_size) {
550+ fatal_error("NOR page size %s is invalid\n", page_size);
551+ }
552+ char *product_id = tern_find_path(state->root, "NOR\0product_id\0", TVAL_PTR).ptrval;
553+ if (!product_id) {
554+ fatal_error("ROM DB map entry %d with address %s has device type NOR, but the NOR product ID is not defined\n", state->index, key);
555+ }
556+ uint16_t save_product_id = strtol(product_id, NULL, 16);
557+ char *bus = tern_find_path(state->root, "NOR\0bus\0", TVAL_PTR).ptrval;
558+ if (!strcmp(bus, "odd")) {
559+ state->info->save_bus = RAM_FLAG_ODD;
560+ } else if(!strcmp(bus, "even")) {
561+ state->info->save_bus = RAM_FLAG_EVEN;
562+ } else {
563+ state->info->save_bus = RAM_FLAG_BOTH;
564+ }
565+ state->info->save_type = SAVE_NOR;
566+ state->info->save_buffer = malloc(state->info->save_size);
567+ char *init = tern_find_path_default(state->root, "NOR\0init\0", (tern_val){.ptrval="FF"}, TVAL_PTR).ptrval;
568+ if (!strcmp(init, "ROM")) {
569+ uint32_t init_size = state->rom_size > state->info->save_size ? state->info->save_size : state->rom_size;
570+ memcpy(state->info->save_buffer, state->rom, init_size);
571+ if (state->info->save_bus == RAM_FLAG_BOTH) {
572+ byteswap_rom(state->info->save_size, (uint16_t *)state->info->save_buffer);
573+ }
574+ } else {
575+ memset(state->info->save_buffer, strtol(init, NULL, 16), state->info->save_size);
576+ }
577+ state->info->nor = calloc(1, sizeof(nor_state));
578+ nor_flash_init(state->info->nor, state->info->save_buffer, state->info->save_size, save_page_size, save_product_id, state->info->save_bus);
579+ char *cmd1 = tern_find_path(state->root, "NOR\0cmd_address1\0", TVAL_PTR).ptrval;
580+ if (cmd1) {
581+ state->info->nor->cmd_address1 = strtol(cmd1, NULL, 16);
582+ }
583+ char *cmd2 = tern_find_path(state->root, "NOR\0cmd_address2\0", TVAL_PTR).ptrval;
584+ if (cmd2) {
585+ state->info->nor->cmd_address2 = strtol(cmd2, NULL, 16);
586+ }
587+ }
588+}
589+
590+void add_eeprom_map(tern_node *node, uint32_t start, uint32_t end, map_iter_state *state)
591+{
592+ eeprom_map *eep_map = state->info->eeprom_map + state->info->num_eeprom;
593+ eep_map->start = start;
594+ eep_map->end = end;
595+ eep_map->sda_read_bit = 0xFF;
596+ tern_node * bits_read = tern_find_node(node, "bits_read");
597+ if (bits_read) {
598+ tern_foreach(bits_read, eeprom_read_fun, eep_map);
599+ }
600+ tern_node * bits_write = tern_find_node(node, "bits_write");
601+ if (bits_write) {
602+ tern_foreach(bits_write, eeprom_write_fun, eep_map);
603+ }
604+ debug_message("EEPROM address %X: sda read: %X, sda write: %X, scl: %X\n", start, eep_map->sda_read_bit, eep_map->sda_write_mask, eep_map->scl_mask);
605+ state->info->num_eeprom++;
606+}
607+
608+void map_iter_fun(char *key, tern_val val, uint8_t valtype, void *data)
609+{
610+ map_iter_state *state = data;
611+ if (valtype != TVAL_NODE) {
612+ fatal_error("ROM DB map entry %d with address %s is not a node\n", state->index, key);
613+ }
614+ tern_node *node = val.ptrval;
615+ uint32_t start = strtol(key, NULL, 16);
616+ uint32_t end = strtol(tern_find_ptr_default(node, "last", "0"), NULL, 16);
617+ if (!end || end < start) {
618+ fatal_error("'last' value is missing or invalid for ROM DB map entry %d with address %s\n", state->index, key);
619+ }
620+ char * dtype = tern_find_ptr_default(node, "device", "ROM");
621+ uint32_t offset = strtol(tern_find_ptr_default(node, "offset", "0"), NULL, 16);
622+ memmap_chunk *map = state->info->map + state->index;
623+ map->start = start;
624+ map->end = end + 1;
625+ if (!strcmp(dtype, "ROM")) {
626+ map->buffer = state->rom + offset;
627+ map->mask = calc_mask(state->rom_size - offset, start, end);
628+ if (strcmp(tern_find_ptr_default(node, "writeable", "no"), "yes")) {
629+ map->flags = MMAP_READ;
630+ } else {
631+ map->flags = MMAP_READ | MMAP_WRITE | MMAP_CODE;
632+ }
633+ } else if (!strcmp(dtype, "LOCK-ON")) {
634+ rom_info lock_info;
635+ if (state->lock_on) {
636+ lock_info = configure_rom(state->rom_db, state->lock_on, state->lock_on_size, NULL, 0, NULL, 0);
637+ } else if (state->rom_size > start) {
638+ //This is a bit of a hack to deal with pre-combined S3&K/S2&K ROMs and S&K ROM hacks
639+ lock_info = configure_rom(state->rom_db, state->rom + start, state->rom_size - start, NULL, 0, NULL, 0);
640+ } else {
641+ //skip this entry if there is no lock on cartridge attached
642+ return;
643+ }
644+ uint32_t matching_chunks = 0;
645+ for (int i = 0; i < lock_info.map_chunks; i++)
646+ {
647+ if (lock_info.map[i].start < 0xC00000 && lock_info.map[i].end > 0x200000) {
648+ matching_chunks++;
649+ }
650+ }
651+ if (matching_chunks == 0) {
652+ //Nothing mapped in the relevant range for the lock-on cart, ignore this mapping
653+ free_rom_info(&lock_info);
654+ return;
655+ } else if (matching_chunks > 1) {
656+ state->info->map_chunks += matching_chunks - 1;
657+ state->info->map = realloc(state->info->map, sizeof(memmap_chunk) * state->info->map_chunks);
658+ memset(state->info->map + state->info->map_chunks - (matching_chunks - 1), 0, sizeof(memmap_chunk) * (matching_chunks - 1));
659+ map = state->info->map + state->index;
660+ }
661+ for (int i = 0; i < lock_info.map_chunks; i++)
662+ {
663+ if (lock_info.map[i].start >= 0xC00000 || lock_info.map[i].end <= 0x200000) {
664+ continue;
665+ }
666+ *map = lock_info.map[i];
667+ if (map->start < 0x200000) {
668+ if (map->buffer) {
669+ map->buffer += (0x200000 - map->start) & ((map->flags & MMAP_AUX_BUFF) ? map->aux_mask : map->mask);
670+ }
671+ map->start = 0x200000;
672+ }
673+ map++;
674+ state->index++;
675+ }
676+ if (state->info->save_type == SAVE_NONE && lock_info.save_type != SAVE_NONE) {
677+ //main cart has no save device, but lock-on cart does
678+ if (state->lock_on) {
679+ state->info->is_save_lock_on = 1;
680+ }
681+ state->info->save_buffer = lock_info.save_buffer;
682+ state->info->save_size = lock_info.save_size;
683+ state->info->save_mask = lock_info.save_mask;
684+ state->info->nor = lock_info.nor;
685+ state->info->save_type = lock_info.save_type;
686+ state->info->save_bus = lock_info.save_bus;
687+ lock_info.save_buffer = NULL;
688+ lock_info.save_type = SAVE_NONE;
689+ }
690+ free_rom_info(&lock_info);
691+ return;
692+ } else if (!strcmp(dtype, "EEPROM")) {
693+ process_eeprom_def(key, state);
694+ add_eeprom_map(node, start, end, state);
695+
696+ map->write_16 = write_eeprom_i2c_w;
697+ map->write_8 = write_eeprom_i2c_b;
698+ map->read_16 = read_eeprom_i2c_w;
699+ map->read_8 = read_eeprom_i2c_b;
700+ map->mask = 0xFFFFFF;
701+ } else if (!strcmp(dtype, "SRAM")) {
702+ process_sram_def(key, state);
703+ map->buffer = state->info->save_buffer + offset;
704+ map->flags = MMAP_READ | MMAP_WRITE;
705+ if (state->info->save_type == RAM_FLAG_ODD) {
706+ map->flags |= MMAP_ONLY_ODD;
707+ } else if(state->info->save_type == RAM_FLAG_EVEN) {
708+ map->flags |= MMAP_ONLY_EVEN;
709+ }
710+ map->mask = calc_mask(state->info->save_size, start, end);
711+ } else if (!strcmp(dtype, "RAM")) {
712+ uint32_t size = strtol(tern_find_ptr_default(node, "size", "0"), NULL, 16);
713+ if (!size || size > map->end - map->start) {
714+ size = map->end - map->start;
715+ }
716+ map->buffer = malloc(size);
717+ map->mask = calc_mask(size, start, end);
718+ map->flags = MMAP_READ | MMAP_WRITE;
719+ char *bus = tern_find_ptr_default(node, "bus", "both");
720+ if (!strcmp(bus, "odd")) {
721+ map->flags |= MMAP_ONLY_ODD;
722+ } else if (!strcmp(bus, "even")) {
723+ map->flags |= MMAP_ONLY_EVEN;
724+ } else {
725+ map->flags |= MMAP_CODE;
726+ }
727+ } else if (!strcmp(dtype, "NOR")) {
728+ process_nor_def(key, state);
729+
730+ map->write_16 = nor_flash_write_w;
731+ map->write_8 = nor_flash_write_b;
732+ map->read_16 = nor_flash_read_w;
733+ map->read_8 = nor_flash_read_b;
734+ if (state->info->save_bus == RAM_FLAG_BOTH) {
735+ map->flags |= MMAP_READ_CODE | MMAP_CODE;
736+ map->buffer = state->info->save_buffer;
737+ }
738+ map->mask = 0xFFFFFF;
739+ } else if (!strcmp(dtype, "Sega mapper")) {
740+ state->info->mapper_type = MAPPER_SEGA;
741+ state->info->mapper_start_index = state->ptr_index++;
742+ char *variant = tern_find_ptr_default(node, "variant", "full");
743+ char *save_device = tern_find_path(node, "save\0device\0", TVAL_PTR).ptrval;
744+ if (save_device && !strcmp(save_device, "EEPROM")) {
745+ process_eeprom_def(key, state);
746+ add_eeprom_map(node, start & map->mask, end & map->mask, state);
747+ } else if (save_device && !strcmp(save_device, "SRAM")) {
748+ process_sram_def(key, state);
749+ } else if(has_ram_header(state->rom, state->rom_size)) {
750+ //no save definition in ROM DB entry, but there is an SRAM header
751+ //this support is mostly to handle homebrew that uses the SSF2 product ID
752+ //in an attempt to signal desire for the full Sega/SSF2 mapper, but also uses SRAM unlike SSF2
753+ read_ram_header(state->info, state->rom);
754+ }
755+ if (!strcmp(variant, "save-only")) {
756+ state->info->map_chunks+=1;
757+ state->info->map = realloc(state->info->map, sizeof(memmap_chunk) * state->info->map_chunks);
758+ memset(state->info->map + state->info->map_chunks - 1, 0, sizeof(memmap_chunk) * 1);
759+ map = state->info->map + state->index;
760+ map->start = start;
761+ map->end = end;
762+ offset &= nearest_pow2(state->rom_size) - 1;
763+ map->buffer = state->rom + offset;
764+ map->mask = calc_mask(state->rom_size - offset, start, end);
765+ map->ptr_index = state->info->mapper_start_index;
766+ map->flags = MMAP_READ | MMAP_PTR_IDX | MMAP_CODE | MMAP_FUNC_NULL;
767+ if (save_device && !strcmp(save_device, "EEPROM")) {
768+ map->write_16 = write_eeprom_i2c_w;
769+ map->write_8 = write_eeprom_i2c_b;
770+ map->read_16 = read_eeprom_i2c_w;
771+ map->read_8 = read_eeprom_i2c_b;
772+ } else {
773+ map->read_16 = (read_16_fun)read_sram_w;//these will only be called when mem_pointers[ptr_idx] == NULL
774+ map->read_8 = (read_8_fun)read_sram_b;
775+ map->write_16 = (write_16_fun)write_sram_area_w;//these will be called all writes to the area
776+ map->write_8 = (write_8_fun)write_sram_area_b;
777+ }
778+ state->index++;
779+ map++;
780+ } else {
781+ state->info->map_chunks+=7;
782+ state->info->map = realloc(state->info->map, sizeof(memmap_chunk) * state->info->map_chunks);
783+ memset(state->info->map + state->info->map_chunks - 7, 0, sizeof(memmap_chunk) * 7);
784+ map = state->info->map + state->index;
785+ for (int i = 0; i < 7; i++, state->index++, map++)
786+ {
787+ map->start = start + i * 0x80000;
788+ map->end = start + (i + 1) * 0x80000;
789+ map->mask = 0x7FFFF;
790+ map->buffer = state->rom + offset + i * 0x80000;
791+ map->ptr_index = state->ptr_index++;
792+ if (i < 3) {
793+ map->flags = MMAP_READ | MMAP_PTR_IDX | MMAP_CODE;
794+ } else {
795+ map->flags = MMAP_READ | MMAP_PTR_IDX | MMAP_CODE | MMAP_FUNC_NULL;
796+ if (save_device && !strcmp(save_device, "EEPROM")) {
797+ map->write_16 = write_eeprom_i2c_w;
798+ map->write_8 = write_eeprom_i2c_b;
799+ map->read_16 = read_eeprom_i2c_w;
800+ map->read_8 = read_eeprom_i2c_b;
801+ } else {
802+ map->read_16 = (read_16_fun)read_sram_w;//these will only be called when mem_pointers[2] == NULL
803+ map->read_8 = (read_8_fun)read_sram_b;
804+ map->write_16 = (write_16_fun)write_sram_area_w;//these will be called all writes to the area
805+ map->write_8 = (write_8_fun)write_sram_area_b;
806+ }
807+ }
808+ }
809+ }
810+ map->start = 0xA13000;
811+ map->end = 0xA13100;
812+ map->mask = 0xFF;
813+ map->write_16 = (write_16_fun)write_bank_reg_w;
814+ map->write_8 = (write_8_fun)write_bank_reg_b;
815+ } else if (!strcmp(dtype, "MENU")) {
816+ //fake hardware for supporting menu
817+ map->buffer = NULL;
818+ map->mask = 0xFF;
819+ map->write_16 = menu_write_w;
820+ map->read_16 = menu_read_w;
821+ } else if (!strcmp(dtype, "fixed")) {
822+ uint16_t *value = malloc(2);
823+ map->buffer = value;
824+ map->mask = 0;
825+ map->flags = MMAP_READ;
826+ *value = strtol(tern_find_ptr_default(node, "value", "0"), NULL, 16);
827+ } else if (!strcmp(dtype, "multi-game")) {
828+ state->info->mapper_type = MAPPER_MULTI_GAME;
829+ state->info->mapper_start_index = state->ptr_index++;
830+ //make a mirror copy of the ROM so we can efficiently support arbitrary start offsets
831+ state->rom = realloc(state->rom, state->rom_size * 2);
832+ memcpy(state->rom + state->rom_size, state->rom, state->rom_size);
833+ state->rom_size *= 2;
834+ //make room for an extra map entry
835+ state->info->map_chunks+=1;
836+ state->info->map = realloc(state->info->map, sizeof(memmap_chunk) * state->info->map_chunks);
837+ memset(state->info->map + state->info->map_chunks - 1, 0, sizeof(memmap_chunk) * 1);
838+ map = state->info->map + state->index;
839+ map->buffer = state->rom;
840+ map->mask = calc_mask(state->rom_size, start, end);
841+ map->flags = MMAP_READ | MMAP_PTR_IDX | MMAP_CODE;
842+ map->ptr_index = state->info->mapper_start_index;
843+ map++;
844+ state->index++;
845+ map->start = 0xA13000;
846+ map->end = 0xA13100;
847+ map->mask = 0xFF;
848+ map->write_16 = write_multi_game_w;
849+ map->write_8 = write_multi_game_b;
850+ } else if (!strcmp(dtype, "megawifi")) {
851+ if (!strcmp(
852+ "on",
853+ tern_find_path_default(config, "system\0megawifi\0", (tern_val){.ptrval="off"}, TVAL_PTR).ptrval)
854+ ) {
855+ map->write_16 = megawifi_write_w;
856+ map->write_8 = megawifi_write_b;
857+ map->read_16 = megawifi_read_w;
858+ map->read_8 = megawifi_read_b;
859+ map->mask = 0xFFFFFF;
860+ } else {
861+ warning("ROM uses MegaWiFi, but it is disabled\n");
862+ return;
863+ }
864+ } else if (!strcmp(dtype, "jcart")) {
865+ state->info->mapper_type = MAPPER_JCART;
866+ map->write_16 = jcart_write_w;
867+ map->write_8 = jcart_write_b;
868+ map->read_16 = jcart_read_w;
869+ map->read_8 = jcart_read_b;
870+ map->mask = 0xFFFFFF;
871+ } else {
872+ fatal_error("Invalid device type %s for ROM DB map entry %d with address %s\n", dtype, state->index, key);
873+ }
874+ state->index++;
875+}
876+
877+rom_info configure_rom(tern_node *rom_db, void *vrom, uint32_t rom_size, void *lock_on, uint32_t lock_on_size, memmap_chunk const *base_map, uint32_t base_chunks)
878+{
879+ uint8_t product_id[GAME_ID_LEN+1];
880+ uint8_t *rom = vrom;
881+ product_id[GAME_ID_LEN] = 0;
882+ for (int i = 0; i < GAME_ID_LEN; i++)
883+ {
884+ if (rom[GAME_ID_OFF + i] <= ' ') {
885+ product_id[i] = 0;
886+ break;
887+ }
888+ product_id[i] = rom[GAME_ID_OFF + i];
889+
890+ }
891+ debug_message("Product ID: %s\n", product_id);
892+ uint8_t raw_hash[20];
893+ sha1(vrom, rom_size, raw_hash);
894+ uint8_t hex_hash[41];
895+ bin_to_hex(hex_hash, raw_hash, 20);
896+ debug_message("SHA1: %s\n", hex_hash);
897+ tern_node * entry = tern_find_node(rom_db, hex_hash);
898+ if (!entry) {
899+ entry = tern_find_node(rom_db, product_id);
900+ }
901+ if (!entry) {
902+ debug_message("Not found in ROM DB, examining header\n\n");
903+ if (xband_detect(rom, rom_size)) {
904+ return xband_configure_rom(rom_db, rom, rom_size, lock_on, lock_on_size, base_map, base_chunks);
905+ }
906+ if (realtec_detect(rom, rom_size)) {
907+ return realtec_configure_rom(rom, rom_size, base_map, base_chunks);
908+ }
909+ return configure_rom_heuristics(rom, rom_size, base_map, base_chunks);
910+ }
911+ rom_info info;
912+ info.mapper_type = MAPPER_NONE;
913+ info.name = tern_find_ptr(entry, "name");
914+ if (info.name) {
915+ debug_message("Found name: %s\n\n", info.name);
916+ info.name = strdup(info.name);
917+ } else {
918+ info.name = get_header_name(rom);
919+ }
920+
921+ char *dbreg = tern_find_ptr(entry, "regions");
922+ info.regions = 0;
923+ if (dbreg) {
924+ while (*dbreg != 0)
925+ {
926+ info.regions |= translate_region_char(*(dbreg++));
927+ }
928+ }
929+ if (!info.regions) {
930+ info.regions = get_header_regions(rom);
931+ }
932+
933+ info.is_save_lock_on = 0;
934+ info.rom = vrom;
935+ info.rom_size = rom_size;
936+ tern_node *map = tern_find_node(entry, "map");
937+ if (map) {
938+ info.save_type = SAVE_NONE;
939+ info.map_chunks = tern_count(map);
940+ if (info.map_chunks) {
941+ info.map_chunks += base_chunks;
942+ info.save_buffer = NULL;
943+ info.save_size = 0;
944+ info.map = malloc(sizeof(memmap_chunk) * info.map_chunks);
945+ info.eeprom_map = NULL;
946+ info.num_eeprom = 0;
947+ memset(info.map, 0, sizeof(memmap_chunk) * info.map_chunks);
948+ map_iter_state state = {
949+ .info = &info,
950+ .rom = rom,
951+ .lock_on = lock_on,
952+ .root = entry,
953+ .rom_db = rom_db,
954+ .rom_size = rom_size,
955+ .lock_on_size = lock_on_size,
956+ .index = 0,
957+ .num_els = info.map_chunks - base_chunks,
958+ .ptr_index = 0
959+ };
960+ tern_foreach(map, map_iter_fun, &state);
961+ memcpy(info.map + state.index, base_map, sizeof(memmap_chunk) * base_chunks);
962+ info.rom = state.rom;
963+ info.rom_size = state.rom_size;
964+ } else {
965+ add_memmap_header(&info, rom, rom_size, base_map, base_chunks);
966+ }
967+ } else {
968+ add_memmap_header(&info, rom, rom_size, base_map, base_chunks);
969+ }
970+
971+ tern_node *device_overrides = tern_find_node(entry, "device_overrides");
972+ if (device_overrides) {
973+ info.port1_override = tern_find_ptr(device_overrides, "1");
974+ info.port2_override = tern_find_ptr(device_overrides, "2");
975+ info.ext_override = tern_find_ptr(device_overrides, "ext");
976+ } else {
977+ info.port1_override = info.port2_override = info.ext_override = NULL;
978+ }
979+ info.mouse_mode = tern_find_ptr(entry, "mouse_mode");
980+
981+ return info;
982+}
A
romdb.h
+96,
-0
1@@ -0,0 +1,96 @@
2+#ifndef ROMDB_H_
3+#define ROMDB_H_
4+
5+#define REGION_J 1
6+#define REGION_U 2
7+#define REGION_E 4
8+
9+#define RAM_FLAG_ODD 0x18
10+#define RAM_FLAG_EVEN 0x10
11+#define RAM_FLAG_BOTH 0x00
12+#define RAM_FLAG_MASK RAM_FLAG_ODD
13+#define SAVE_I2C 0x01
14+#define SAVE_NOR 0x02
15+#define SAVE_NONE 0xFF
16+
17+#include "tern.h"
18+#include "serialize.h"
19+
20+typedef struct {
21+ uint32_t start;
22+ uint32_t end;
23+ uint16_t sda_write_mask;
24+ uint16_t scl_mask;
25+ uint8_t sda_read_bit;
26+} eeprom_map;
27+
28+typedef struct {
29+ uint8_t *buffer;
30+ uint8_t *page_buffer;
31+ uint32_t size;
32+ uint32_t page_size;
33+ uint32_t current_page;
34+ uint32_t last_write_cycle;
35+ uint32_t cmd_address1;
36+ uint32_t cmd_address2;
37+ uint16_t product_id;
38+ uint8_t mode;
39+ uint8_t cmd_state;
40+ uint8_t alt_cmd;
41+ uint8_t bus_flags;
42+} nor_state;
43+
44+enum {
45+ MAPPER_NONE,
46+ MAPPER_SEGA,
47+ MAPPER_REALTEC,
48+ MAPPER_XBAND,
49+ MAPPER_MULTI_GAME,
50+ MAPPER_JCART
51+};
52+
53+
54+typedef struct rom_info rom_info;
55+
56+#include "memmap.h"
57+
58+struct rom_info {
59+ char *name;
60+ memmap_chunk *map;
61+ uint8_t *save_buffer;
62+ void *rom;
63+ eeprom_map *eeprom_map;
64+ char *port1_override;
65+ char *port2_override;
66+ char *ext_override;
67+ char *mouse_mode;
68+ nor_state *nor;
69+ uint32_t num_eeprom;
70+ uint32_t map_chunks;
71+ uint32_t rom_size;
72+ uint32_t save_size;
73+ uint32_t save_mask;
74+ uint16_t mapper_start_index;
75+ uint8_t save_type;
76+ uint8_t save_bus; //only used for NOR currently
77+ uint8_t mapper_type;
78+ uint8_t regions;
79+ uint8_t is_save_lock_on; //Does the save buffer actually belong to a lock-on cart?
80+};
81+
82+#define GAME_ID_OFF 0x183
83+#define GAME_ID_LEN 8
84+
85+tern_node *load_rom_db();
86+rom_info configure_rom(tern_node *rom_db, void *vrom, uint32_t rom_size, void *lock_on, uint32_t lock_on_size, memmap_chunk const *base_map, uint32_t base_chunks);
87+rom_info configure_rom_heuristics(uint8_t *rom, uint32_t rom_size, memmap_chunk const *base_map, uint32_t base_chunks);
88+uint8_t translate_region_char(uint8_t c);
89+char const *save_type_name(uint8_t save_type);
90+//Note: free_rom_info only frees things pointed to by a rom_info struct, not the struct itself
91+//this is because rom_info structs are typically stack allocated
92+void free_rom_info(rom_info *info);
93+typedef struct system_header system_header;
94+void cart_serialize(system_header *sys, serialize_buffer *buf);
95+void cart_deserialize(deserialize_buffer *buf, void *vcontext);
96+
97+#endif //ROMDB_H_
A
saves.c
+73,
-0
1@@ -0,0 +1,73 @@
2+#include <string.h>
3+#include <stdlib.h>
4+#include "saves.h"
5+#include "util.h"
6+
7+//0123456789012345678901234678
8+//Slot N - December 31st, XXXX
9+#define MAX_DESC_SIZE 40
10+
11+char *get_slot_name(system_header *system, uint32_t slot_index, char *ext)
12+{
13+ if (!system->save_dir) {
14+ return NULL;
15+ }
16+ char *fname;
17+ if (slot_index < 10) {
18+ size_t name_len = strlen("slot_N.") + strlen(ext) + 1;
19+ fname = malloc(name_len);
20+ snprintf(fname, name_len, "slot_%d.%s", slot_index, ext);
21+ } else {
22+ size_t name_len = strlen("quicksave.") + strlen(ext) + 1;
23+ fname = malloc(name_len);
24+ snprintf(fname, name_len, "quicksave.%s", ext);
25+ }
26+ char const *parts[] = {system->save_dir, PATH_SEP, fname};
27+ char *ret = alloc_concat_m(3, parts);
28+ free(fname);
29+ return ret;
30+}
31+
32+save_slot_info *get_slot_info(system_header *system, uint32_t *num_out)
33+{
34+ save_slot_info *dst = calloc(11, sizeof(save_slot_info));
35+ time_t modtime;
36+ struct tm ltime;
37+ for (uint32_t i = 0; i <= QUICK_SAVE_SLOT; i++)
38+ {
39+ char * cur = dst[i].desc = malloc(MAX_DESC_SIZE);
40+ char * fname = get_slot_name(system, i, "state");
41+ modtime = get_modification_time(fname);
42+ free(fname);
43+ if (!modtime && system->type == SYSTEM_GENESIS) {
44+ fname = get_slot_name(system, i, "gst");
45+ modtime = get_modification_time(fname);
46+ free(fname);
47+ }
48+ if (i == QUICK_SAVE_SLOT) {
49+ cur += snprintf(cur, MAX_DESC_SIZE, "Quick - ");
50+ } else {
51+ cur += snprintf(cur, MAX_DESC_SIZE, "Slot %d - ", i);
52+ }
53+ if (modtime) {
54+ strftime(cur, MAX_DESC_SIZE - (cur - dst->desc), "%c", localtime_r(&modtime, <ime));
55+ } else {
56+ strcpy(cur, "EMPTY");
57+ }
58+ dst[i].modification_time = modtime;
59+ }
60+ *num_out = QUICK_SAVE_SLOT + 1;
61+ return dst;
62+}
63+
64+void free_slot_info(save_slot_info *slots)
65+{
66+ if (!slots) {
67+ return;
68+ }
69+ for (uint32_t i = 0; i <= QUICK_SAVE_SLOT; i++)
70+ {
71+ free(slots[i].desc);
72+ }
73+ free(slots);
74+}
A
saves.h
+20,
-0
1@@ -0,0 +1,20 @@
2+#ifndef SAVES_H_
3+#define SAVES_H_
4+
5+#include <time.h>
6+#include <stdint.h>
7+#include "system.h"
8+
9+#define QUICK_SAVE_SLOT 10
10+#define SERIALIZE_SLOT 11
11+
12+typedef struct {
13+ char *desc;
14+ time_t modification_time;
15+} save_slot_info;
16+
17+char *get_slot_name(system_header *system, uint32_t slot_index, char *ext);
18+save_slot_info *get_slot_info(system_header *system, uint32_t *num_out);
19+void free_slot_info(save_slot_info *slots);
20+
21+#endif //SAVES_H_
+148,
-0
1@@ -0,0 +1,148 @@
2+#include "genesis.h"
3+
4+uint16_t read_sram_w(uint32_t address, m68k_context * context)
5+{
6+ genesis_context * gen = context->system;
7+ address &= gen->save_ram_mask;
8+ switch(gen->save_type)
9+ {
10+ case RAM_FLAG_BOTH:
11+ return gen->save_storage[address] << 8 | gen->save_storage[address+1];
12+ case RAM_FLAG_EVEN:
13+ return gen->save_storage[address >> 1] << 8 | 0xFF;
14+ case RAM_FLAG_ODD:
15+ return gen->save_storage[address >> 1] | 0xFF00;
16+ }
17+ return 0xFFFF;//We should never get here
18+}
19+
20+uint8_t read_sram_b(uint32_t address, m68k_context * context)
21+{
22+ genesis_context * gen = context->system;
23+ address &= gen->save_ram_mask;
24+ switch(gen->save_type)
25+ {
26+ case RAM_FLAG_BOTH:
27+ return gen->save_storage[address];
28+ case RAM_FLAG_EVEN:
29+ if (address & 1) {
30+ return 0xFF;
31+ } else {
32+ return gen->save_storage[address >> 1];
33+ }
34+ case RAM_FLAG_ODD:
35+ if (address & 1) {
36+ return gen->save_storage[address >> 1];
37+ } else {
38+ return 0xFF;
39+ }
40+ }
41+ return 0xFF;//We should never get here
42+}
43+
44+m68k_context * write_sram_area_w(uint32_t address, m68k_context * context, uint16_t value)
45+{
46+ genesis_context * gen = context->system;
47+ if ((gen->bank_regs[0] & 0x3) == 1) {
48+ address &= gen->save_ram_mask;
49+ switch(gen->save_type)
50+ {
51+ case RAM_FLAG_BOTH:
52+ gen->save_storage[address] = value >> 8;
53+ gen->save_storage[address+1] = value;
54+ break;
55+ case RAM_FLAG_EVEN:
56+ gen->save_storage[address >> 1] = value >> 8;
57+ break;
58+ case RAM_FLAG_ODD:
59+ gen->save_storage[address >> 1] = value;
60+ break;
61+ }
62+ }
63+ return context;
64+}
65+
66+m68k_context * write_sram_area_b(uint32_t address, m68k_context * context, uint8_t value)
67+{
68+ genesis_context * gen = context->system;
69+ if ((gen->bank_regs[0] & 0x3) == 1) {
70+ address &= gen->save_ram_mask;
71+ switch(gen->save_type)
72+ {
73+ case RAM_FLAG_BOTH:
74+ gen->save_storage[address] = value;
75+ break;
76+ case RAM_FLAG_EVEN:
77+ if (!(address & 1)) {
78+ gen->save_storage[address >> 1] = value;
79+ }
80+ break;
81+ case RAM_FLAG_ODD:
82+ if (address & 1) {
83+ gen->save_storage[address >> 1] = value;
84+ }
85+ break;
86+ }
87+ }
88+ return context;
89+}
90+
91+m68k_context * write_bank_reg_w(uint32_t address, m68k_context * context, uint16_t value)
92+{
93+ genesis_context * gen = context->system;
94+ address &= 0xE;
95+ address >>= 1;
96+ gen->bank_regs[address] = value;
97+ if (!address) {
98+ if (value & 1) {
99+ //Used for games that only use the mapper for SRAM
100+ if (context->mem_pointers[gen->mapper_start_index]) {
101+ gen->mapper_temp = context->mem_pointers[gen->mapper_start_index];
102+ }
103+ context->mem_pointers[gen->mapper_start_index] = NULL;
104+ //For games that need more than 4MB
105+ for (int i = 4; i < 8; i++)
106+ {
107+ context->mem_pointers[gen->mapper_start_index + i] = NULL;
108+ }
109+ } else {
110+ //Used for games that only use the mapper for SRAM
111+ if (!context->mem_pointers[gen->mapper_start_index]) {
112+ context->mem_pointers[gen->mapper_start_index] = gen->mapper_temp;
113+ }
114+ //For games that need more than 4MB
115+ for (int i = 4; i < 8; i++)
116+ {
117+ context->mem_pointers[gen->mapper_start_index + i] = gen->cart + 0x40000*gen->bank_regs[i];
118+ }
119+ }
120+ } else {
121+ void *new_ptr = gen->cart + 0x40000*value;
122+ if (context->mem_pointers[gen->mapper_start_index + address] != new_ptr) {
123+ m68k_invalidate_code_range(gen->m68k, address * 0x80000, (address + 1) * 0x80000);
124+ context->mem_pointers[gen->mapper_start_index + address] = new_ptr;
125+ }
126+ }
127+ return context;
128+}
129+
130+m68k_context * write_bank_reg_b(uint32_t address, m68k_context * context, uint8_t value)
131+{
132+ if (address & 1) {
133+ write_bank_reg_w(address, context, value);
134+ }
135+ return context;
136+}
137+
138+void sega_mapper_serialize(genesis_context *gen, serialize_buffer *buf)
139+{
140+ save_buffer8(buf, gen->bank_regs, sizeof(gen->bank_regs));
141+}
142+
143+void sega_mapper_deserialize(deserialize_buffer *buf, genesis_context *gen)
144+{
145+ for (int i = 0; i < sizeof(gen->bank_regs); i++)
146+ {
147+ write_bank_reg_w(i * 2, gen->m68k, load_int8(buf));
148+ }
149+}
+14,
-0
1@@ -0,0 +1,14 @@
2+#ifndef SEGA_MAPPER_H_
3+#define SEGA_MAPPER_H_
4+#include "serialize.h"
5+
6+uint16_t read_sram_w(uint32_t address, m68k_context * context);
7+uint8_t read_sram_b(uint32_t address, m68k_context * context);
8+m68k_context * write_sram_area_w(uint32_t address, m68k_context * context, uint16_t value);
9+m68k_context * write_sram_area_b(uint32_t address, m68k_context * context, uint8_t value);
10+m68k_context * write_bank_reg_w(uint32_t address, m68k_context * context, uint16_t value);
11+m68k_context * write_bank_reg_b(uint32_t address, m68k_context * context, uint8_t value);
12+void sega_mapper_serialize(genesis_context *gen, serialize_buffer *buf);
13+void sega_mapper_deserialize(deserialize_buffer *buf, genesis_context *gen);
14+
15+#endif //SEGA_MAPPER_H_
+277,
-0
1@@ -0,0 +1,277 @@
2+#include <string.h>
3+#include <stdlib.h>
4+#include <stdio.h>
5+#include "serialize.h"
6+#include "util.h"
7+
8+#ifndef SERIALIZE_DEFAULT_SIZE
9+#define SERIALIZE_DEFAULT_SIZE (256*1024) //default to enough for a Genesis save state
10+#endif
11+
12+
13+void init_serialize(serialize_buffer *buf)
14+{
15+ buf->storage = SERIALIZE_DEFAULT_SIZE;
16+ buf->size = 0;
17+ buf->current_section_start = 0;
18+ buf->data = malloc(SERIALIZE_DEFAULT_SIZE);
19+}
20+
21+static void reserve(serialize_buffer *buf, size_t amount)
22+{
23+ if (amount > (buf->storage - buf->size)) {
24+ buf->storage *= 2;
25+ buf = realloc(buf, buf->storage + sizeof(*buf));
26+ }
27+}
28+
29+void save_int32(serialize_buffer *buf, uint32_t val)
30+{
31+ reserve(buf, sizeof(val));
32+ buf->data[buf->size++] = val >> 24;
33+ buf->data[buf->size++] = val >> 16;
34+ buf->data[buf->size++] = val >> 8;
35+ buf->data[buf->size++] = val;
36+}
37+
38+void save_int16(serialize_buffer *buf, uint16_t val)
39+{
40+ reserve(buf, sizeof(val));
41+ buf->data[buf->size++] = val >> 8;
42+ buf->data[buf->size++] = val;
43+}
44+
45+void save_int8(serialize_buffer *buf, uint8_t val)
46+{
47+ reserve(buf, sizeof(val));
48+ buf->data[buf->size++] = val;
49+}
50+
51+void save_string(serialize_buffer *buf, char *val)
52+{
53+ size_t len = strlen(val);
54+ save_buffer8(buf, val, len);
55+}
56+
57+void save_buffer8(serialize_buffer *buf, void *val, size_t len)
58+{
59+ reserve(buf, len);
60+ memcpy(&buf->data[buf->size], val, len);
61+ buf->size += len;
62+}
63+
64+void save_buffer16(serialize_buffer *buf, uint16_t *val, size_t len)
65+{
66+ reserve(buf, len * sizeof(*val));
67+ for(; len != 0; len--, val++) {
68+ buf->data[buf->size++] = *val >> 8;
69+ buf->data[buf->size++] = *val;
70+ }
71+}
72+
73+void save_buffer32(serialize_buffer *buf, uint32_t *val, size_t len)
74+{
75+ reserve(buf, len * sizeof(*val));
76+ for(; len != 0; len--, val++) {
77+ buf->data[buf->size++] = *val >> 24;
78+ buf->data[buf->size++] = *val >> 16;
79+ buf->data[buf->size++] = *val >> 8;
80+ buf->data[buf->size++] = *val;
81+ }
82+}
83+
84+void start_section(serialize_buffer *buf, uint16_t section_id)
85+{
86+ save_int16(buf, section_id);
87+ //reserve some space for size once we end this section
88+ reserve(buf, sizeof(uint32_t));
89+ buf->size += sizeof(uint32_t);
90+ //save start point for use in end_device
91+ buf->current_section_start = buf->size;
92+}
93+
94+void end_section(serialize_buffer *buf)
95+{
96+ size_t section_size = buf->size - buf->current_section_start;
97+ if (section_size > 0xFFFFFFFFU) {
98+ fatal_error("Sections larger than 4GB are not supported");
99+ }
100+ uint32_t size = section_size;
101+ uint8_t *field = buf->data + buf->current_section_start - sizeof(uint32_t);
102+ *(field++) = size >> 24;
103+ *(field++) = size >> 16;
104+ *(field++) = size >> 8;
105+ *(field++) = size;
106+ buf->current_section_start = 0;
107+}
108+
109+void register_section_handler(deserialize_buffer *buf, section_handler handler, uint16_t section_id)
110+{
111+ if (section_id > buf->max_handler) {
112+ uint16_t old_max = buf->max_handler;
113+ if (buf->max_handler < 0x8000) {
114+ buf->max_handler *= 2;
115+ } else {
116+ buf->max_handler = 0xFFFF;
117+ }
118+ buf->handlers = realloc(buf->handlers, (buf->max_handler+1) * sizeof(handler));
119+ memset(buf->handlers + old_max + 1, 0, (buf->max_handler - old_max) * sizeof(handler));
120+ }
121+ if (!buf->handlers) {
122+ buf->handlers = calloc(buf->max_handler + 1, sizeof(handler));
123+ }
124+ buf->handlers[section_id] = handler;
125+}
126+
127+void init_deserialize(deserialize_buffer *buf, uint8_t *data, size_t size)
128+{
129+ buf->size = size;
130+ buf->cur_pos = 0;
131+ buf->data = data;
132+ buf->handlers = NULL;
133+ buf->max_handler = 8;
134+}
135+
136+uint32_t load_int32(deserialize_buffer *buf)
137+{
138+ uint32_t val;
139+ if ((buf->size - buf->cur_pos) < sizeof(val)) {
140+ fatal_error("Failed to load required int32 field");
141+ }
142+ val = buf->data[buf->cur_pos++] << 24;
143+ val |= buf->data[buf->cur_pos++] << 16;
144+ val |= buf->data[buf->cur_pos++] << 8;
145+ val |= buf->data[buf->cur_pos++];
146+ return val;
147+}
148+
149+uint16_t load_int16(deserialize_buffer *buf)
150+{
151+ uint16_t val;
152+ if ((buf->size - buf->cur_pos) < sizeof(val)) {
153+ fatal_error("Failed to load required int16 field");
154+ }
155+ val = buf->data[buf->cur_pos++] << 8;
156+ val |= buf->data[buf->cur_pos++];
157+ return val;
158+}
159+
160+uint8_t load_int8(deserialize_buffer *buf)
161+{
162+ uint8_t val;
163+ if ((buf->size - buf->cur_pos) < sizeof(val)) {
164+ fatal_error("Failed to load required int8 field");
165+ }
166+ val = buf->data[buf->cur_pos++];
167+ return val;
168+}
169+
170+void load_buffer8(deserialize_buffer *buf, void *dst, size_t len)
171+{
172+ if ((buf->size - buf->cur_pos) < len) {
173+ fatal_error("Failed to load required buffer of size %d", len);
174+ }
175+ memcpy(dst, buf->data + buf->cur_pos, len);
176+ buf->cur_pos += len;
177+}
178+
179+void load_buffer16(deserialize_buffer *buf, uint16_t *dst, size_t len)
180+{
181+ if ((buf->size - buf->cur_pos) < len * sizeof(uint16_t)) {
182+ fatal_error("Failed to load required buffer of size %d\n", len);
183+ }
184+ for(; len != 0; len--, dst++) {
185+ uint16_t value = buf->data[buf->cur_pos++] << 8;
186+ value |= buf->data[buf->cur_pos++];
187+ *dst = value;
188+ }
189+}
190+void load_buffer32(deserialize_buffer *buf, uint32_t *dst, size_t len)
191+{
192+ if ((buf->size - buf->cur_pos) < len * sizeof(uint32_t)) {
193+ fatal_error("Failed to load required buffer of size %d\n", len);
194+ }
195+ for(; len != 0; len--, dst++) {
196+ uint32_t value = buf->data[buf->cur_pos++] << 24;
197+ value |= buf->data[buf->cur_pos++] << 16;
198+ value |= buf->data[buf->cur_pos++] << 8;
199+ value |= buf->data[buf->cur_pos++];
200+ *dst = value;
201+ }
202+}
203+
204+void load_section(deserialize_buffer *buf)
205+{
206+ if (!buf->handlers) {
207+ fatal_error("load_section called on a deserialize_buffer with no handlers registered\n");
208+ }
209+ uint16_t section_id = load_int16(buf);
210+ uint32_t size = load_int32(buf);
211+ if (size > (buf->size - buf->cur_pos)) {
212+ fatal_error("Section is bigger than remaining space in file");
213+ }
214+ if (section_id > buf->max_handler || !buf->handlers[section_id].fun) {
215+ warning("No handler for section ID %d, save state may be from a newer version\n", section_id);
216+ buf->cur_pos += size;
217+ return;
218+ }
219+ deserialize_buffer section;
220+ init_deserialize(§ion, buf->data + buf->cur_pos, size);
221+ buf->handlers[section_id].fun(§ion, buf->handlers[section_id].data);
222+ buf->cur_pos += size;
223+}
224+
225+static const char sz_ident[] = "BLSTSZ\x01\x07";
226+
227+uint8_t save_to_file(serialize_buffer *buf, char *path)
228+{
229+ FILE *f = fopen(path, "wb");
230+ if (!f) {
231+ return 0;
232+ }
233+ if (fwrite(sz_ident, 1, sizeof(sz_ident)-1, f) != sizeof(sz_ident)-1) {
234+ fclose(f);
235+ return 0;
236+ }
237+ if (fwrite(buf->data, 1, buf->size, f) != buf->size) {
238+ fclose(f);
239+ return 0;
240+ }
241+ fclose(f);
242+ return 1;
243+}
244+
245+uint8_t load_from_file(deserialize_buffer *buf, char *path)
246+{
247+ FILE *f = fopen(path, "rb");
248+ if (!f) {
249+ return 0;
250+ }
251+ char ident[sizeof(sz_ident)-1];
252+ long size = file_size(f);
253+ if (size < sizeof(ident)) {
254+ fclose(f);
255+ return 0;
256+ }
257+ if (fread(ident, 1, sizeof(ident), f) != sizeof(ident)) {
258+ fclose(f);
259+ return 0;
260+ }
261+ if (memcmp(ident, sz_ident, sizeof(ident))) {
262+ return 0;
263+ }
264+ buf->size = size - sizeof(ident);
265+ buf->cur_pos = 0;
266+ buf->data = malloc(buf->size);
267+ buf->handlers = NULL;
268+ buf->max_handler = 8;
269+ if (fread(buf->data, 1, buf->size, f) != buf->size) {
270+ fclose(f);
271+ free(buf->data);
272+ buf->data = NULL;
273+ buf->size = 0;
274+ return 0;
275+ }
276+ fclose(f);
277+ return 1;
278+}
+69,
-0
1@@ -0,0 +1,69 @@
2+#ifndef SERIALIZE_H_
3+#define SERIALIZE_H_
4+
5+#include <stdint.h>
6+#include <stddef.h>
7+
8+typedef struct {
9+ size_t size;
10+ size_t storage;
11+ size_t current_section_start;
12+ uint8_t *data;
13+} serialize_buffer;
14+
15+typedef struct deserialize_buffer deserialize_buffer;
16+typedef void (*section_fun)(deserialize_buffer *buf, void *data);
17+
18+typedef struct {
19+ section_fun fun;
20+ void *data;
21+} section_handler;
22+
23+struct deserialize_buffer {
24+ size_t size;
25+ size_t cur_pos;
26+ uint8_t *data;
27+ section_handler *handlers;
28+ uint16_t max_handler;
29+};
30+
31+enum {
32+ SECTION_HEADER,
33+ SECTION_68000,
34+ SECTION_Z80,
35+ SECTION_VDP,
36+ SECTION_YM2612,
37+ SECTION_PSG,
38+ SECTION_GEN_BUS_ARBITER,
39+ SECTION_SEGA_IO_1,
40+ SECTION_SEGA_IO_2,
41+ SECTION_SEGA_IO_EXT,
42+ SECTION_MAIN_RAM,
43+ SECTION_SOUND_RAM,
44+ SECTION_MAPPER,
45+ SECTION_EEPROM,
46+ SECTION_CART_RAM
47+};
48+
49+void init_serialize(serialize_buffer *buf);
50+void save_int32(serialize_buffer *buf, uint32_t val);
51+void save_int16(serialize_buffer *buf, uint16_t val);
52+void save_int8(serialize_buffer *buf, uint8_t val);
53+void save_string(serialize_buffer *buf, char *val);
54+void save_buffer8(serialize_buffer *buf, void *val, size_t len);
55+void save_buffer16(serialize_buffer *buf, uint16_t *val, size_t len);
56+void save_buffer32(serialize_buffer *buf, uint32_t *val, size_t len);
57+void start_section(serialize_buffer *buf, uint16_t section_id);
58+void end_section(serialize_buffer *buf);
59+void register_section_handler(deserialize_buffer *buf, section_handler handler, uint16_t section_id);
60+void init_deserialize(deserialize_buffer *buf, uint8_t *data, size_t size);
61+uint32_t load_int32(deserialize_buffer *buf);
62+uint16_t load_int16(deserialize_buffer *buf);
63+uint8_t load_int8(deserialize_buffer *buf);
64+void load_buffer8(deserialize_buffer *buf, void *dst, size_t len);
65+void load_buffer16(deserialize_buffer *buf, uint16_t *dst, size_t len);
66+void load_buffer32(deserialize_buffer *buf, uint32_t *dst, size_t len);
67+void load_section(deserialize_buffer *buf);
68+uint8_t save_to_file(serialize_buffer *buf, char *path);
69+uint8_t load_from_file(deserialize_buffer *buf, char *path);
70+#endif //SERIALIZE_H
+173,
-0
1@@ -0,0 +1,173 @@
2+HSYNC End
3+Plane A: D13C
4+??slot??
5+tile
6+tile
7+Plane B: F29C
8+?sprite tile slot?
9+tile
10+tile
11+Plane A: D100
12+68K Slot
13+tile
14+tile
15+Plane B: F2A0
16+?sprite table slot?
17+tile
18+tile
19+Plane A: D104
20+68K slot
21+tile
22+tile
23+Plane B: F2A4
24+?sprite table slot?
25+tile
26+tile
27+Plane A: D108
28+68K slot
29+?tile?
30+?tile?
31+Plane B: F2A8
32+?sprite table slot?
33+tile
34+tile
35+Plane A: D10C
36+refresh
37+?tile?
38+?tile?
39+Plane B: F22C
40+?sprite table slot?
41+tile
42+tile
43+Plane A: D110
44+68K slot
45+?tile?
46+?tile?
47+Plane B: F230
48+?sprite table slot?
49+tile
50+tile
51+Plane A: D114
52+68K slot
53+?tile?
54+?tile?
55+Plane B: F2F4
56+?sprite table slot?
57+tile
58+tile
59+Plane A: D118
60+68K slot
61+?tile?
62+?tile?
63+Plane B: F238
64+?sprite table slot?
65+ttile tile
66+Plane A: D11C
67+refresh
68+?tile?
69+?tile?
70+Plane B: F23C
71+?sprite table slot?
72+tile
73+tile
74+Plane A: D120
75+68K slot
76+?tile?
77+?tile?
78+Plane B: F240
79+?sprite table slot?
80+tile
81+tile
82+Plane A: D124
83+68K Slot
84+?tile?
85+?tile?
86+Plane B: F244
87+?sprite table slot?
88+tile
89+tile
90+Plane A: D128
91+68K Slot
92+?tile?
93+?tile?
94+Plane B: F3C8
95+?sprite table slot?
96+tile
97+tile
98+Plane A: D12C
99+refresh
100+?tile?
101+?tile?
102+Plane B: F24C
103+?sprite table slot?
104+tile
105+tile
106+Plane A: D130
107+68K slot
108+?tile?
109+?tile?
110+Plane B: F250
111+?sprite table slot?
112+tile
113+tile
114+Plane A: D134
115+68K Slot
116+?tile?
117+?tile?
118+Plane B: F254
119+?sprite table slot?
120+tile
121+tile
122+Plane A: D138
123+68K slot
124+?tile?
125+?tile?
126+Plane B: F3D8
127+?sprite table slot?
128+tile
129+tile
130+Plane A: D13C
131+refresh
132+tile
133+tile
134+Plane B: F3DC
135+?sprite table slot?
136+tile
137+tile
138+---------------
139+68K Slot
140+68K Slot
141+sprite tile slot
142+sprite tile slot
143+sprite tile slot
144+sprite tile slot
145+?sprite tile slot?
146+?sprite tile slot?
147+?sprite tile slot?
148+?sprite tile slot?
149+?sprite tile slot?
150+?sprite tile slot?
151+?sprite tile slot?
152+?sprite tile slot?
153+?sprite tile slot?
154+?sprite tile slot?
155+68K Slot
156+?sprite tile slot?
157+?sprite tile slot?
158+?sprite tile slot?
159+?sprite tile slot?
160+?sprite tile slot?
161+HSYNC Start
162+?sprite tile slot?
163+?sprite tile slot?
164+?sprite tile slot?
165+?sprite tile slot?
166+?sprite tile slot?
167+?sprite tile slot?
168+?unkown tile slot?
169+68K Slot
170+Horizontal Scroll
171+?sprite tile slot?
172+?sprite tile slot?
173+?sprite tile slot?
174+?unkown tile slot?
+64,
-0
1@@ -0,0 +1,64 @@
2+0000: single color blocks
3+0200: Random symbols????
4+0400-0C00: Font
5+0C00-0E??: Score font
6+0E??: Player name displays
7+
8+2000-3000: floor (mostly, some garbage around 2800 and 2A00)
9+3000-6C00: background
10+6C00-8000: not graphics
11+8000-~8A00: bat/bird sprites, special attack text
12+8A00-9000: ?????
13+9000-9200: More special attack text
14+9200-9600: another font
15+9800-AA00: special attack effects?
16+AC00-B000: ????
17+B000-B500: character sprite
18+????
19+C000-C500: chracter sprite
20+D000-DA00: window name table
21+DA00-DC00: Sprite attribute table
22+DC00-E000: horizontal scroll data
23+E000-????: plane A&B name table
24+C500-FFFF: not graphics
25+
26+VDP Registers:
27+Mode
28+00 - 14
29+01 - 64
30+Scroll A Name Table Address: E000
31+02 - 38
32+Window Name Table Address: D000
33+03 - 34
34+Scroll B Name Table Address: E000
35+04 - 07
36+Sprite Attribute Table Address: DA00
37+05 - 6D
38+06 - 00
39+Backdrop color - 0
40+07 - 00
41+08 - 00
42+09 - 00
43+HINT Counter
44+0A - AF
45+Mode - Full screen vertical scroll, line horizontal scroll, external ints disabled, 32 cell display, no interlacing
46+0B - 03
47+0C - 00
48+H Scroll Data Address: DC00
49+0D - 37
50+0E - 00
51+Auto increment
52+0F - 02
53+Scroll Size
54+10 - 11
55+Window H Pos
56+11 - 00
57+Window V Pos
58+12 - 05
59+DMA transfer length
60+13 - 00
61+14 - 00
62+DMA source address and mode
63+15 - DB
64+16 - CF
65+17 - 7F
A
sms.c
+641,
-0
1@@ -0,0 +1,641 @@
2+#include <string.h>
3+#include <stdlib.h>
4+#include <stddef.h>
5+#include "sms.h"
6+#include "blastem.h"
7+#include "render.h"
8+#include "util.h"
9+#include "debug.h"
10+#include "saves.h"
11+#include "bindings.h"
12+
13+#define Z80_CYCLE current_cycle
14+#define Z80_OPTS options
15+
16+static void *memory_io_write(uint32_t location, void *vcontext, uint8_t value)
17+{
18+ z80_context *z80 = vcontext;
19+ sms_context *sms = z80->system;
20+ if (location & 1) {
21+ uint8_t fuzzy_ctrl_0 = sms->io.ports[0].control, fuzzy_ctrl_1 = sms->io.ports[1].control;
22+ io_control_write(sms->io.ports, (~value) << 5 & 0x60, z80->Z80_CYCLE);
23+ fuzzy_ctrl_0 |= sms->io.ports[0].control;
24+ io_control_write(sms->io.ports+1, (~value) << 3 & 0x60, z80->Z80_CYCLE);
25+ fuzzy_ctrl_1 |= sms->io.ports[1].control;
26+ if (
27+ (fuzzy_ctrl_0 & 0x40 & (sms->io.ports[0].output ^ (value << 1)) & (value << 1))
28+ || (fuzzy_ctrl_0 & 0x40 & (sms->io.ports[1].output ^ (value >> 1)) & (value >> 1))
29+ ) {
30+ //TH is an output and it went from 0 -> 1
31+ vdp_run_context(sms->vdp, z80->Z80_CYCLE);
32+ vdp_latch_hv(sms->vdp);
33+ }
34+ io_data_write(sms->io.ports, value << 1, z80->Z80_CYCLE);
35+ io_data_write(sms->io.ports + 1, value >> 1, z80->Z80_CYCLE);
36+ } else {
37+ //TODO: memory control write
38+ }
39+ return vcontext;
40+}
41+
42+static uint8_t hv_read(uint32_t location, void *vcontext)
43+{
44+ z80_context *z80 = vcontext;
45+ sms_context *sms = z80->system;
46+ vdp_run_context(sms->vdp, z80->Z80_CYCLE);
47+ uint16_t hv = vdp_hv_counter_read(sms->vdp);
48+ if (location & 1) {
49+ return hv;
50+ } else {
51+ return hv >> 8;
52+ }
53+}
54+
55+static void *sms_psg_write(uint32_t location, void *vcontext, uint8_t value)
56+{
57+ z80_context *z80 = vcontext;
58+ sms_context *sms = z80->system;
59+ psg_run(sms->psg, z80->Z80_CYCLE);
60+ psg_write(sms->psg, value);
61+ return vcontext;
62+}
63+
64+static void update_interrupts(sms_context *sms)
65+{
66+ uint32_t vint = vdp_next_vint(sms->vdp);
67+ uint32_t hint = vdp_next_hint(sms->vdp);
68+ sms->z80->int_pulse_start = vint < hint ? vint : hint;
69+}
70+
71+static uint8_t vdp_read(uint32_t location, void *vcontext)
72+{
73+ z80_context *z80 = vcontext;
74+ sms_context *sms = z80->system;
75+ vdp_run_context(sms->vdp, z80->Z80_CYCLE);
76+ if (location & 1) {
77+ uint8_t ret = vdp_control_port_read(sms->vdp);
78+ sms->vdp->flags2 &= ~(FLAG2_VINT_PENDING|FLAG2_HINT_PENDING);
79+ update_interrupts(sms);
80+ return ret;
81+ } else {
82+ return vdp_data_port_read_pbc(sms->vdp);
83+ }
84+}
85+
86+static void *vdp_write(uint32_t location, void *vcontext, uint8_t value)
87+{
88+ z80_context *z80 = vcontext;
89+ sms_context *sms = z80->system;
90+ if (location & 1) {
91+ vdp_run_context_full(sms->vdp, z80->Z80_CYCLE);
92+ vdp_control_port_write_pbc(sms->vdp, value);
93+ update_interrupts(sms);
94+ } else {
95+ vdp_run_context(sms->vdp, z80->Z80_CYCLE);
96+ vdp_data_port_write_pbc(sms->vdp, value);
97+ }
98+ return vcontext;
99+}
100+
101+static uint8_t io_read(uint32_t location, void *vcontext)
102+{
103+ z80_context *z80 = vcontext;
104+ sms_context *sms = z80->system;
105+ if (location == 0xC0 || location == 0xDC) {
106+ uint8_t port_a = io_data_read(sms->io.ports, z80->Z80_CYCLE);
107+ uint8_t port_b = io_data_read(sms->io.ports+1, z80->Z80_CYCLE);
108+ return (port_a & 0x3F) | (port_b << 6);
109+ }
110+ if (location == 0xC1 || location == 0xDD) {
111+ uint8_t port_a = io_data_read(sms->io.ports, z80->Z80_CYCLE);
112+ uint8_t port_b = io_data_read(sms->io.ports+1, z80->Z80_CYCLE);
113+ return (port_a & 0x40) | (port_b >> 2 & 0xF) | (port_b << 1 & 0x80) | 0x10;
114+ }
115+ return 0xFF;
116+}
117+
118+static void update_mem_map(uint32_t location, sms_context *sms, uint8_t value)
119+{
120+ z80_context *z80 = sms->z80;
121+ void *old_value;
122+ if (location) {
123+ uint32_t idx = location - 1;
124+ old_value = z80->mem_pointers[idx];
125+ z80->mem_pointers[idx] = sms->rom + (value << 14 & (sms->rom_size-1));
126+ if (old_value != z80->mem_pointers[idx]) {
127+ //invalidate any code we translated for the relevant bank
128+ z80_invalidate_code_range(z80, idx ? idx * 0x4000 : 0x400, idx * 0x4000 + 0x4000);
129+ }
130+ } else {
131+ old_value = z80->mem_pointers[2];
132+ if (value & 8) {
133+ //cartridge RAM is enabled
134+ z80->mem_pointers[2] = sms->cart_ram + (value & 4 ? (SMS_CART_RAM_SIZE/2) : 0);
135+ } else {
136+ //cartridge RAM is disabled
137+ z80->mem_pointers[2] = sms->rom + (sms->bank_regs[3] << 14 & (sms->rom_size-1));
138+ }
139+ if (old_value != z80->mem_pointers[2]) {
140+ //invalidate any code we translated for the relevant bank
141+ z80_invalidate_code_range(z80, 0x8000, 0xC000);
142+ }
143+ }
144+}
145+
146+static void *mapper_write(uint32_t location, void *vcontext, uint8_t value)
147+{
148+ z80_context *z80 = vcontext;
149+ sms_context *sms = z80->system;
150+ location &= 3;
151+ sms->ram[0x1FFC + location] = value;
152+ sms->bank_regs[location] = value;
153+ update_mem_map(location, sms, value);
154+ return vcontext;
155+}
156+
157+static void *cart_ram_write(uint32_t location, void *vcontext, uint8_t value)
158+{
159+ z80_context *z80 = vcontext;
160+ sms_context *sms = z80->system;
161+ if (sms->bank_regs[0] & 8) {
162+ //cartridge RAM is enabled
163+ location &= 0x3FFF;
164+ z80->mem_pointers[2][location] = value;
165+ z80_handle_code_write(0x8000 + location, z80);
166+ }
167+ return vcontext;
168+}
169+
170+uint8_t debug_commands(system_header *system, char *input_buf)
171+{
172+ sms_context *sms = (sms_context *)system;
173+ switch(input_buf[0])
174+ {
175+ case 'v':
176+ if (input_buf[1] == 'r') {
177+ vdp_print_reg_explain(sms->vdp);
178+ } else if (input_buf[1] == 's') {
179+ vdp_print_sprite_table(sms->vdp);
180+ } else {
181+ return 0;
182+ }
183+ break;
184+ }
185+ return 1;
186+}
187+
188+static memmap_chunk io_map[] = {
189+ {0x00, 0x40, 0xFF, 0, 0, 0, NULL, NULL, NULL, NULL, memory_io_write},
190+ {0x40, 0x80, 0xFF, 0, 0, 0, NULL, NULL, NULL, hv_read, sms_psg_write},
191+ {0x80, 0xC0, 0xFF, 0, 0, 0, NULL, NULL, NULL, vdp_read, vdp_write},
192+ {0xC0, 0x100,0xFF, 0, 0, 0, NULL, NULL, NULL, io_read, NULL}
193+};
194+
195+static void set_speed_percent(system_header * system, uint32_t percent)
196+{
197+ sms_context *context = (sms_context *)system;
198+ uint32_t old_clock = context->master_clock;
199+ context->master_clock = ((uint64_t)context->normal_clock * (uint64_t)percent) / 100;
200+
201+ psg_adjust_master_clock(context->psg, context->master_clock);
202+}
203+
204+void sms_serialize(sms_context *sms, serialize_buffer *buf)
205+{
206+ start_section(buf, SECTION_Z80);
207+ z80_serialize(sms->z80, buf);
208+ end_section(buf);
209+
210+ start_section(buf, SECTION_VDP);
211+ vdp_serialize(sms->vdp, buf);
212+ end_section(buf);
213+
214+ start_section(buf, SECTION_PSG);
215+ psg_serialize(sms->psg, buf);
216+ end_section(buf);
217+
218+ start_section(buf, SECTION_SEGA_IO_1);
219+ io_serialize(sms->io.ports, buf);
220+ end_section(buf);
221+
222+ start_section(buf, SECTION_SEGA_IO_2);
223+ io_serialize(sms->io.ports + 1, buf);
224+ end_section(buf);
225+
226+ start_section(buf, SECTION_MAIN_RAM);
227+ save_int8(buf, sizeof(sms->ram) / 1024);
228+ save_buffer8(buf, sms->ram, sizeof(sms->ram));
229+ end_section(buf);
230+
231+ start_section(buf, SECTION_MAPPER);
232+ save_int8(buf, 1);//mapper type, 1 for Sega mapper
233+ save_buffer8(buf, sms->bank_regs, sizeof(sms->bank_regs));
234+ end_section(buf);
235+
236+ start_section(buf, SECTION_CART_RAM);
237+ save_int8(buf, SMS_CART_RAM_SIZE / 1024);
238+ save_buffer8(buf, sms->cart_ram, SMS_CART_RAM_SIZE);
239+ end_section(buf);
240+}
241+
242+static uint8_t *serialize(system_header *sys, size_t *size_out)
243+{
244+ sms_context *sms = (sms_context *)sys;
245+ serialize_buffer state;
246+ init_serialize(&state);
247+ sms_serialize(sms, &state);
248+ if (size_out) {
249+ *size_out = state.size;
250+ }
251+ return state.data;
252+}
253+
254+static void ram_deserialize(deserialize_buffer *buf, void *vsms)
255+{
256+ sms_context *sms = vsms;
257+ uint32_t ram_size = load_int8(buf) * 1024;
258+ if (ram_size > sizeof(sms->ram)) {
259+ fatal_error("State has a RAM size of %d bytes", ram_size);
260+ }
261+ load_buffer8(buf, sms->ram, ram_size);
262+}
263+
264+static void cart_ram_deserialize(deserialize_buffer *buf, void *vsms)
265+{
266+ sms_context *sms = vsms;
267+ uint32_t ram_size = load_int8(buf) * 1024;
268+ if (ram_size > SMS_CART_RAM_SIZE) {
269+ fatal_error("State has a cart RAM size of %d bytes", ram_size);
270+ }
271+ load_buffer8(buf, sms->cart_ram, ram_size);
272+}
273+
274+static void mapper_deserialize(deserialize_buffer *buf, void *vsms)
275+{
276+ sms_context *sms = vsms;
277+ uint8_t mapper_type = load_int8(buf);
278+ if (mapper_type != 1) {
279+ warning("State contains an unrecognized mapper type %d, it may be from a newer version of BlastEm\n", mapper_type);
280+ return;
281+ }
282+ for (int i = 0; i < sizeof(sms->bank_regs); i++)
283+ {
284+ sms->bank_regs[i] = load_int8(buf);
285+ update_mem_map(i, sms, sms->bank_regs[i]);
286+ }
287+}
288+
289+void sms_deserialize(deserialize_buffer *buf, sms_context *sms)
290+{
291+ register_section_handler(buf, (section_handler){.fun = z80_deserialize, .data = sms->z80}, SECTION_Z80);
292+ register_section_handler(buf, (section_handler){.fun = vdp_deserialize, .data = sms->vdp}, SECTION_VDP);
293+ register_section_handler(buf, (section_handler){.fun = psg_deserialize, .data = sms->psg}, SECTION_PSG);
294+ register_section_handler(buf, (section_handler){.fun = io_deserialize, .data = sms->io.ports}, SECTION_SEGA_IO_1);
295+ register_section_handler(buf, (section_handler){.fun = io_deserialize, .data = sms->io.ports + 1}, SECTION_SEGA_IO_2);
296+ register_section_handler(buf, (section_handler){.fun = ram_deserialize, .data = sms}, SECTION_MAIN_RAM);
297+ register_section_handler(buf, (section_handler){.fun = mapper_deserialize, .data = sms}, SECTION_MAPPER);
298+ register_section_handler(buf, (section_handler){.fun = cart_ram_deserialize, .data = sms}, SECTION_CART_RAM);
299+ //TODO: cart RAM
300+ while (buf->cur_pos < buf->size)
301+ {
302+ load_section(buf);
303+ }
304+ z80_invalidate_code_range(sms->z80, 0xC000, 0x10000);
305+ if (sms->bank_regs[0] & 8) {
306+ //cart RAM is enabled, invalidate the region in case there is any code there
307+ z80_invalidate_code_range(sms->z80, 0x8000, 0xC000);
308+ }
309+ free(buf->handlers);
310+ buf->handlers = NULL;
311+}
312+
313+static void deserialize(system_header *sys, uint8_t *data, size_t size)
314+{
315+ sms_context *sms = (sms_context *)sys;
316+ deserialize_buffer buffer;
317+ init_deserialize(&buffer, data, size);
318+ sms_deserialize(&buffer, sms);
319+}
320+
321+static void save_state(sms_context *sms, uint8_t slot)
322+{
323+ char *save_path = get_slot_name(&sms->header, slot, "state");
324+ serialize_buffer state;
325+ init_serialize(&state);
326+ sms_serialize(sms, &state);
327+ save_to_file(&state, save_path);
328+ printf("Saved state to %s\n", save_path);
329+ free(save_path);
330+ free(state.data);
331+}
332+
333+static uint8_t load_state_path(sms_context *sms, char *path)
334+{
335+ deserialize_buffer state;
336+ uint8_t ret;
337+ if ((ret = load_from_file(&state, path))) {
338+ sms_deserialize(&state, sms);
339+ free(state.data);
340+ printf("Loaded %s\n", path);
341+ }
342+ return ret;
343+}
344+
345+static uint8_t load_state(system_header *system, uint8_t slot)
346+{
347+ sms_context *sms = (sms_context *)system;
348+ char *statepath = get_slot_name(system, slot, "state");
349+ uint8_t ret;
350+ if (!sms->z80->native_pc) {
351+ ret = get_modification_time(statepath) != 0;
352+ if (ret) {
353+ system->delayed_load_slot = slot + 1;
354+ }
355+ goto done;
356+
357+ }
358+ ret = load_state_path(sms, statepath);
359+done:
360+ free(statepath);
361+ return ret;
362+}
363+
364+static void run_sms(system_header *system)
365+{
366+ sms_context *sms = (sms_context *)system;
367+ uint32_t target_cycle = sms->z80->Z80_CYCLE + 3420*16;
368+ //TODO: PAL support
369+ render_set_video_standard(VID_NTSC);
370+ while (!sms->should_return)
371+ {
372+ if (system->delayed_load_slot) {
373+ load_state(system, system->delayed_load_slot - 1);
374+ system->delayed_load_slot = 0;
375+
376+ }
377+ if (system->enter_debugger && sms->z80->pc) {
378+ system->enter_debugger = 0;
379+ zdebugger(sms->z80, sms->z80->pc);
380+ }
381+ if (sms->z80->nmi_start == CYCLE_NEVER) {
382+ uint32_t nmi = vdp_next_nmi(sms->vdp);
383+ if (nmi != CYCLE_NEVER) {
384+ z80_assert_nmi(sms->z80, nmi);
385+ }
386+ }
387+ z80_run(sms->z80, target_cycle);
388+ if (sms->z80->reset) {
389+ z80_clear_reset(sms->z80, sms->z80->Z80_CYCLE + 128*15);
390+ }
391+ target_cycle = sms->z80->Z80_CYCLE;
392+ vdp_run_context(sms->vdp, target_cycle);
393+ psg_run(sms->psg, target_cycle);
394+
395+ if (system->save_state) {
396+ while (!sms->z80->pc) {
397+ //advance Z80 to an instruction boundary
398+ z80_run(sms->z80, sms->z80->Z80_CYCLE + 1);
399+ }
400+ save_state(sms, system->save_state - 1);
401+ system->save_state = 0;
402+ }
403+
404+ target_cycle += 3420*16;
405+ if (target_cycle > 0x10000000) {
406+ uint32_t adjust = sms->z80->Z80_CYCLE - 3420*262*2;
407+ io_adjust_cycles(sms->io.ports, sms->z80->Z80_CYCLE, adjust);
408+ io_adjust_cycles(sms->io.ports+1, sms->z80->Z80_CYCLE, adjust);
409+ z80_adjust_cycles(sms->z80, adjust);
410+ vdp_adjust_cycles(sms->vdp, adjust);
411+ sms->psg->cycles -= adjust;
412+ target_cycle -= adjust;
413+ }
414+ }
415+ bindings_release_capture();
416+ vdp_release_framebuffer(sms->vdp);
417+ render_pause_source(sms->psg->audio);
418+ sms->should_return = 0;
419+}
420+
421+static void resume_sms(system_header *system)
422+{
423+ sms_context *sms = (sms_context *)system;
424+ bindings_reacquire_capture();
425+ vdp_reacquire_framebuffer(sms->vdp);
426+ render_resume_source(sms->psg->audio);
427+ run_sms(system);
428+}
429+
430+static void start_sms(system_header *system, char *statefile)
431+{
432+ sms_context *sms = (sms_context *)system;
433+
434+ z80_assert_reset(sms->z80, 0);
435+ z80_clear_reset(sms->z80, 128*15);
436+
437+ if (statefile) {
438+ load_state_path(sms, statefile);
439+ }
440+
441+ if (system->enter_debugger) {
442+ system->enter_debugger = 0;
443+ zinsert_breakpoint(sms->z80, sms->z80->pc, (uint8_t *)zdebugger);
444+ }
445+
446+ run_sms(system);
447+}
448+
449+static void soft_reset(system_header *system)
450+{
451+ sms_context *sms = (sms_context *)system;
452+ z80_assert_reset(sms->z80, sms->z80->Z80_CYCLE);
453+ sms->z80->target_cycle = sms->z80->sync_cycle = sms->z80->Z80_CYCLE;
454+}
455+
456+static void free_sms(system_header *system)
457+{
458+ sms_context *sms = (sms_context *)system;
459+ vdp_free(sms->vdp);
460+ z80_options_free(sms->z80->Z80_OPTS);
461+ free(sms->z80);
462+ psg_free(sms->psg);
463+ free(sms);
464+}
465+
466+static uint16_t get_open_bus_value(system_header *system)
467+{
468+ return 0xFFFF;
469+}
470+
471+static void request_exit(system_header *system)
472+{
473+ sms_context *sms = (sms_context *)system;
474+ sms->should_return = 1;
475+ sms->z80->target_cycle = sms->z80->sync_cycle = sms->z80->Z80_CYCLE;
476+}
477+
478+static void inc_debug_mode(system_header *system)
479+{
480+ sms_context *sms = (sms_context *)system;
481+ vdp_inc_debug_mode(sms->vdp);
482+}
483+
484+static void load_save(system_header *system)
485+{
486+ //TODO: Implement me
487+}
488+
489+static void persist_save(system_header *system)
490+{
491+ //TODO: Implement me
492+}
493+
494+static void gamepad_down(system_header *system, uint8_t gamepad_num, uint8_t button)
495+{
496+ sms_context *sms = (sms_context *)system;
497+ if (gamepad_num == GAMEPAD_MAIN_UNIT) {
498+ if (button == MAIN_UNIT_PAUSE) {
499+ vdp_pbc_pause(sms->vdp);
500+ }
501+ } else {
502+ io_gamepad_down(&sms->io, gamepad_num, button);
503+ }
504+}
505+
506+static void gamepad_up(system_header *system, uint8_t gamepad_num, uint8_t button)
507+{
508+ sms_context *sms = (sms_context *)system;
509+ io_gamepad_up(&sms->io, gamepad_num, button);
510+}
511+
512+static void mouse_down(system_header *system, uint8_t mouse_num, uint8_t button)
513+{
514+ sms_context *sms = (sms_context *)system;
515+ io_mouse_down(&sms->io, mouse_num, button);
516+}
517+
518+static void mouse_up(system_header *system, uint8_t mouse_num, uint8_t button)
519+{
520+ sms_context *sms = (sms_context *)system;
521+ io_mouse_up(&sms->io, mouse_num, button);
522+}
523+
524+static void mouse_motion_absolute(system_header *system, uint8_t mouse_num, uint16_t x, uint16_t y)
525+{
526+ sms_context *sms = (sms_context *)system;
527+ io_mouse_motion_absolute(&sms->io, mouse_num, x, y);
528+}
529+
530+static void mouse_motion_relative(system_header *system, uint8_t mouse_num, int32_t x, int32_t y)
531+{
532+ sms_context *sms = (sms_context *)system;
533+ io_mouse_motion_relative(&sms->io, mouse_num, x, y);
534+}
535+
536+static void keyboard_down(system_header *system, uint8_t scancode)
537+{
538+ sms_context *sms = (sms_context *)system;
539+ io_keyboard_down(&sms->io, scancode);
540+}
541+
542+static void keyboard_up(system_header *system, uint8_t scancode)
543+{
544+ sms_context *sms = (sms_context *)system;
545+ io_keyboard_up(&sms->io, scancode);
546+}
547+
548+static void set_gain_config(sms_context *sms)
549+{
550+ char *config_gain;
551+ config_gain = tern_find_path(config, "audio\0psg_gain\0", TVAL_PTR).ptrval;
552+ render_audio_source_gaindb(sms->psg->audio, config_gain ? atof(config_gain) : 0.0f);
553+}
554+
555+static void config_updated(system_header *system)
556+{
557+ sms_context *sms = (sms_context *)system;
558+ setup_io_devices(config, &system->info, &sms->io);
559+}
560+
561+
562+sms_context *alloc_configure_sms(system_media *media, uint32_t opts, uint8_t force_region)
563+{
564+ sms_context *sms = calloc(1, sizeof(sms_context));
565+ uint32_t rom_size = nearest_pow2(media->size);
566+ memmap_chunk memory_map[6];
567+ if (media->size > 0xC000) {
568+ sms->header.info.map_chunks = 6;
569+ uint8_t *ram_reg_overlap = sms->ram + sizeof(sms->ram) - 4;
570+ memory_map[0] = (memmap_chunk){0x0000, 0x0400, 0xFFFF, 0, 0, MMAP_READ, media->buffer, NULL, NULL, NULL, NULL};
571+ memory_map[1] = (memmap_chunk){0x0400, 0x4000, 0xFFFF, 0, 0, MMAP_READ|MMAP_PTR_IDX|MMAP_CODE, NULL, NULL, NULL, NULL, NULL};
572+ memory_map[2] = (memmap_chunk){0x4000, 0x8000, 0x3FFF, 0, 1, MMAP_READ|MMAP_PTR_IDX|MMAP_CODE, NULL, NULL, NULL, NULL, NULL};
573+ memory_map[3] = (memmap_chunk){0x8000, 0xC000, 0x3FFF, 0, 2, MMAP_READ|MMAP_PTR_IDX|MMAP_CODE, NULL, NULL, NULL, NULL, cart_ram_write};
574+ memory_map[4] = (memmap_chunk){0xC000, 0xFFFC, sizeof(sms->ram)-1, 0, 0, MMAP_READ|MMAP_WRITE|MMAP_CODE, sms->ram, NULL, NULL, NULL, NULL};
575+ memory_map[5] = (memmap_chunk){0xFFFC, 0x10000, 0x0003, 0, 0, MMAP_READ, ram_reg_overlap, NULL, NULL, NULL, mapper_write};
576+ } else {
577+ sms->header.info.map_chunks = 2;
578+ memory_map[0] = (memmap_chunk){0x0000, 0xC000, rom_size-1, 0, 0, MMAP_READ, media->buffer, NULL, NULL, NULL, NULL};
579+ memory_map[1] = (memmap_chunk){0xC000, 0x10000, sizeof(sms->ram)-1, 0, 0, MMAP_READ|MMAP_WRITE|MMAP_CODE, sms->ram, NULL, NULL, NULL, NULL};
580+ };
581+ sms->header.info.map = malloc(sizeof(memmap_chunk) * sms->header.info.map_chunks);
582+ memcpy(sms->header.info.map, memory_map, sizeof(memmap_chunk) * sms->header.info.map_chunks);
583+ z80_options *zopts = malloc(sizeof(z80_options));
584+ init_z80_opts(zopts, sms->header.info.map, sms->header.info.map_chunks, io_map, 4, 15, 0xFF);
585+ sms->z80 = init_z80_context(zopts);
586+ sms->z80->system = sms;
587+ sms->z80->Z80_OPTS->gen.debug_cmd_handler = debug_commands;
588+
589+ sms->rom = media->buffer;
590+ sms->rom_size = rom_size;
591+ if (sms->header.info.map_chunks > 2) {
592+ sms->z80->mem_pointers[0] = sms->rom;
593+ sms->z80->mem_pointers[1] = sms->rom + 0x4000;
594+ sms->z80->mem_pointers[2] = sms->rom + 0x8000;
595+ sms->bank_regs[1] = 0;
596+ sms->bank_regs[2] = 0x4000 >> 14;
597+ sms->bank_regs[3] = 0x8000 >> 14;
598+ }
599+
600+ //TODO: Detect region and pick master clock based off of that
601+ sms->normal_clock = sms->master_clock = 53693175;
602+
603+ sms->psg = malloc(sizeof(psg_context));
604+ psg_init(sms->psg, sms->master_clock, 15*16);
605+
606+ set_gain_config(sms);
607+
608+ sms->vdp = init_vdp_context(0);
609+ sms->vdp->system = &sms->header;
610+
611+ sms->header.info.save_type = SAVE_NONE;
612+ sms->header.info.name = strdup(media->name);
613+
614+ setup_io_devices(config, &sms->header.info, &sms->io);
615+ sms->header.has_keyboard = io_has_keyboard(&sms->io);
616+
617+ sms->header.set_speed_percent = set_speed_percent;
618+ sms->header.start_context = start_sms;
619+ sms->header.resume_context = resume_sms;
620+ sms->header.load_save = load_save;
621+ sms->header.persist_save = persist_save;
622+ sms->header.load_state = load_state;
623+ sms->header.free_context = free_sms;
624+ sms->header.get_open_bus_value = get_open_bus_value;
625+ sms->header.request_exit = request_exit;
626+ sms->header.soft_reset = soft_reset;
627+ sms->header.inc_debug_mode = inc_debug_mode;
628+ sms->header.gamepad_down = gamepad_down;
629+ sms->header.gamepad_up = gamepad_up;
630+ sms->header.mouse_down = mouse_down;
631+ sms->header.mouse_up = mouse_up;
632+ sms->header.mouse_motion_absolute = mouse_motion_absolute;
633+ sms->header.mouse_motion_relative = mouse_motion_relative;
634+ sms->header.keyboard_down = keyboard_down;
635+ sms->header.keyboard_up = keyboard_up;
636+ sms->header.config_updated = config_updated;
637+ sms->header.serialize = serialize;
638+ sms->header.deserialize = deserialize;
639+ sms->header.type = SYSTEM_SMS;
640+
641+ return sms;
642+}
A
sms.h
+31,
-0
1@@ -0,0 +1,31 @@
2+#ifndef SMS_H_
3+#define SMS_H_
4+
5+#include "system.h"
6+#include "vdp.h"
7+#include "psg.h"
8+#include "z80_to_x86.h"
9+#include "io.h"
10+
11+#define SMS_RAM_SIZE (8*1024)
12+#define SMS_CART_RAM_SIZE (32*1024)
13+
14+typedef struct {
15+ system_header header;
16+ z80_context *z80;
17+ vdp_context *vdp;
18+ psg_context *psg;
19+ sega_io io;
20+ uint8_t *rom;
21+ uint32_t rom_size;
22+ uint32_t master_clock;
23+ uint32_t normal_clock;
24+ uint8_t should_return;
25+ uint8_t ram[SMS_RAM_SIZE];
26+ uint8_t bank_regs[4];
27+ uint8_t cart_ram[SMS_CART_RAM_SIZE];
28+} sms_context;
29+
30+sms_context *alloc_configure_sms(system_media *media, uint32_t opts, uint8_t force_region);
31+
32+#endif //SMS_H_
+59,
-0
1@@ -0,0 +1,59 @@
2+#ifndef SPECIAL_KEYS_EVDEV_H_
3+#define SPECIAL_KEYS_EVDEV_H_
4+
5+enum {
6+ RENDERKEY_DOWN = 128,
7+ RENDERKEY_UP,
8+ RENDERKEY_LEFT,
9+ RENDERKEY_RIGHT,
10+ RENDERKEY_ESC,
11+ RENDERKEY_DEL,
12+ RENDERKEY_LSHIFT,
13+ RENDERKEY_RSHIFT,
14+ RENDERKEY_LCTRL,
15+ RENDERKEY_RCTRL,
16+ RENDERKEY_LALT,
17+ RENDERKEY_RALT,
18+ RENDERKEY_HOME,
19+ RENDERKEY_END,
20+ RENDERKEY_PAGEUP,
21+ RENDERKEY_PAGEDOWN,
22+ RENDERKEY_F1,
23+ RENDERKEY_F2,
24+ RENDERKEY_F3,
25+ RENDERKEY_F4,
26+ RENDERKEY_F5,
27+ RENDERKEY_F6,
28+ RENDERKEY_F7,
29+ RENDERKEY_F8,
30+ RENDERKEY_F9,
31+ RENDERKEY_F10,
32+ RENDERKEY_F11,
33+ RENDERKEY_F12,
34+ RENDERKEY_SELECT,
35+ RENDERKEY_PLAY,
36+ RENDERKEY_SEARCH,
37+ RENDERKEY_BACK,
38+ RENDERKEY_NP0,
39+ RENDERKEY_NP1,
40+ RENDERKEY_NP2,
41+ RENDERKEY_NP3,
42+ RENDERKEY_NP4,
43+ RENDERKEY_NP5,
44+ RENDERKEY_NP6,
45+ RENDERKEY_NP7,
46+ RENDERKEY_NP8,
47+ RENDERKEY_NP9,
48+ RENDERKEY_NP_DIV,
49+ RENDERKEY_NP_MUL,
50+ RENDERKEY_NP_MIN,
51+ RENDERKEY_NP_PLUS,
52+ RENDERKEY_NP_ENTER,
53+ RENDERKEY_NP_STOP,
54+ RENDER_DPAD_UP,
55+ RENDER_DPAD_DOWN,
56+ RENDER_DPAD_LEFT,
57+ RENDER_DPAD_RIGHT
58+};
59+
60+#endif //SPECIAL_KEYS_EVDEV_H_
+127,
-0
1@@ -0,0 +1,127 @@
2+/*
3+ Copyright 2013 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#include <stdlib.h>
8+#include <stdio.h>
9+#include "vdp.h"
10+#include "render.h"
11+#include "util.h"
12+#include "genesis.h"
13+#include "config.h"
14+
15+
16+uint16_t read_dma_value(uint32_t address)
17+{
18+ return 0;
19+}
20+
21+m68k_context *m68k_handle_code_write(uint32_t address, m68k_context *context)
22+{
23+ return NULL;
24+}
25+
26+z80_context *z80_handle_code_write(uint32_t address, z80_context *context)
27+{
28+ return NULL;
29+}
30+
31+void ym_data_write(ym2612_context * context, uint8_t value)
32+{
33+}
34+
35+void ym_address_write_part1(ym2612_context * context, uint8_t address)
36+{
37+}
38+
39+void ym_address_write_part2(ym2612_context * context, uint8_t address)
40+{
41+}
42+
43+void handle_keydown(int keycode, uint8_t scancode)
44+{
45+}
46+
47+void handle_keyup(int keycode, uint8_t scancode)
48+{
49+}
50+
51+void handle_joydown(int joystick, int button)
52+{
53+}
54+
55+void handle_joyup(int joystick, int button)
56+{
57+}
58+
59+void handle_joy_dpad(int joystick, int dpadnum, uint8_t value)
60+{
61+}
62+
63+void handle_joy_axis(int joystick, int axis, int16_t value)
64+{
65+}
66+
67+void handle_joy_added(int joystick)
68+{
69+}
70+
71+void handle_mousedown(int mouse, int button)
72+{
73+}
74+
75+void handle_mouseup(int mouse, int button)
76+{
77+}
78+
79+void handle_mouse_moved(int mouse, uint16_t x, uint16_t y, int16_t deltax, int16_t deltay)
80+{
81+}
82+
83+tern_node * config;
84+int headless = 0;
85+
86+int main(int argc, char ** argv)
87+{
88+ if (argc < 2) {
89+ fatal_error("Usage: stateview FILENAME\n");
90+ }
91+ FILE * state_file = fopen(argv[1], "rb");
92+ if (!state_file) {
93+ fatal_error("Failed to open %s\n", argv[1]);
94+ }
95+ set_exe_str(argv[0]);
96+ config = load_config(argv[0]);
97+ int width = -1;
98+ int height = -1;
99+ if (argc > 2) {
100+ width = atoi(argv[2]);
101+ if (argc > 3) {
102+ height = atoi(argv[3]);
103+ }
104+ }
105+ int def_width = 0;
106+ char *config_width = tern_find_ptr(config, "videowidth");
107+ if (config_width) {
108+ def_width = atoi(config_width);
109+ }
110+ if (!def_width) {
111+ def_width = 640;
112+ }
113+ width = width < 320 ? def_width : width;
114+ height = height < 240 ? (width/320) * 240 : height;
115+
116+ render_init(width, height, "GST State Viewer", 0);
117+ vdp_context *context = init_vdp_context(0);
118+ vdp_load_gst(context, state_file);
119+ vdp_run_to_vblank(context);
120+ vdp_print_sprite_table(context);
121+ printf("Display %s\n", (context->regs[REG_MODE_2] & DISPLAY_ENABLE) ? "enabled" : "disabled");
122+ if (!(context->regs[REG_MODE_2] & DISPLAY_ENABLE)) {
123+ puts("Forcing display on");
124+ vdp_control_port_write(context, 0x8000 | REG_MODE_2 << 8 | context->regs[REG_MODE_2] | DISPLAY_ENABLE);
125+ }
126+ render_wait_quit(context);
127+ return 0;
128+}
+7383,
-0
1@@ -0,0 +1,7383 @@
2+;Size: 7375
3+;Rate: 100000000
4+;Channels: 16
5+;EnabledChannels: 65535
6+;TriggerPosition: 119
7+;Compressed: true
8+;AbsoluteLength: 12287
9+;CursorEnabled: true
10+000077f6@0
11+0000f7f6@2
12+0000fd1a@4
13+0000b91a@5
14+0000b99a@6
15+0000399a@10
16+0000a99a@11
17+0000a91a@12
18+0000adf2@13
19+0000a5f2@14
20+00002572@19
21+00002570@20
22+0000a5f0@21
23+0000a5f4@22
24+0000e7f4@23
25+0000e5f4@25
26+0000e774@26
27+000067f4@28
28+000065f0@29
29+0000e7f4@30
30+0000e5f0@32
31+0000f7f4@33
32+0000f774@34
33+0000f770@35
34+0000f7f4@36
35+000077f4@37
36+000075f6@38
37+0000f7f6@39
38+0000fd3e@41
39+0000b93a@42
40+0000b9ba@43
41+000039ba@47
42+000029ba@48
43+0000a93a@49
44+0000adfa@50
45+0000a5f2@51
46+00002572@56
47+00002570@57
48+0000a5f0@58
49+0000e5f4@60
50+0000e7f4@61
51+0000e5f4@62
52+0000e7f4@63
53+0000e774@64
54+000067f4@65
55+000065f0@66
56+0000e5f4@67
57+0000e7f4@68
58+0000e5f4@69
59+0000f7f4@70
60+0000f774@71
61+0000f570@72
62+0000f7f4@73
63+000077f6@75
64+0000f7f6@77
65+0000fffe@78
66+0000fb1a@79
67+0000bb9a@80
68+00003b9a@84
69+0000ab1a@86
70+0000ab9a@87
71+0000a5f2@88
72+00002572@93
73+00002570@94
74+0000a570@95
75+0000a5f0@96
76+0000e7f4@98
77+0000e774@101
78+000065f4@103
79+0000e7f4@104
80+0000f7f4@107
81+0000f774@108
82+0000f7f4@110
83+000077f6@112
84+0000f7f6@114
85+0000f81a@116
86+0000b81a@117
87+0000b89a@118
88+0000389a@121
89+0000a81a@123
90+0000a4f2@125
91+00002470@131
92+0000a470@132
93+0000a674@134
94+0000e6f0@135
95+0000e6f4@136
96+00006674@140
97+00006474@141
98+0000e674@142
99+0000f6f4@144
100+000076f6@149
101+00007676@150
102+0000f676@151
103+0000f83a@153
104+0000b8ba@154
105+0000383a@159
106+0000a83a@160
107+0000acf2@162
108+0000a4f2@163
109+00002472@168
110+00002470@169
111+0000a470@170
112+0000a474@171
113+0000e6f4@172
114+000066f4@177
115+00006470@178
116+0000e674@179
117+0000f474@181
118+0000f6f4@182
119+000076f6@186
120+00007476@187
121+0000f676@188
122+0000fe3e@190
123+0000ba9a@191
124+00003a1a@196
125+0000aa1a@198
126+0000ae7a@199
127+0000a4f2@200
128+000024f2@205
129+00002470@206
130+0000a470@207
131+0000e4f4@209
132+0000e6f4@210
133+000066f4@214
134+00006470@215
135+0000e474@216
136+0000e674@217
137+0000e474@218
138+0000f6f4@219
139+00007676@224
140+0000f676@226
141+0000f67e@227
142+0000f21a@228
143+0000b29a@229
144+0000329a@233
145+0000321a@234
146+0000a21a@235
147+0000a4f2@237
148+000024f2@242
149+00002470@243
150+0000a470@244
151+0000e6f4@247
152+00006474@252
153+0000e474@253
154+0000e674@254
155+0000f6f4@256
156+00007676@261
157+0000f676@263
158+0000f21a@265
159+0000b29a@266
160+0000329a@270
161+0000321a@271
162+0000a29a@272
163+0000a4f2@274
164+0000a472@278
165+0000a4f2@279
166+000024f0@280
167+0000a4f0@281
168+0000a6f4@283
169+0000e6f4@284
170+0000e674@285
171+000066f4@289
172+000064f4@290
173+0000e6f4@291
174+0000f6f4@293
175+0000f674@295
176+00007676@298
177+000076f6@299
178+0000f6f6@300
179+0000f69a@302
180+0000b21a@303
181+0000329a@308
182+0000a29a@309
183+0000a6f2@311
184+0000a4f2@312
185+0000a472@314
186+00002472@317
187+000024f0@318
188+0000a4f0@319
189+0000a6f4@320
190+0000e6f4@321
191+0000e674@323
192+00006674@326
193+000064f0@327
194+0000e6f4@328
195+0000e4f0@330
196+0000f6f4@331
197+0000f674@332
198+00007676@335
199+000076f6@336
200+0000f6f6@337
201+0000f6be@339
202+0000b2ae@340
203+0000b22e@341
204+000032ae@345
205+0000a2ae@347
206+0000a082@349
207+0000a002@351
208+00002082@354
209+00002080@355
210+0000a080@356
211+0000e0a4@358
212+0000e284@359
213+0000e004@360
214+0000e204@362
215+00006224@363
216+00006084@364
217+0000e0a4@365
218+0000e2a4@366
219+0000e284@367
220+0000f2a4@368
221+0000f224@369
222+0000f204@370
223+000070a6@373
224+000072a6@374
225+0000f2a6@375
226+0000f2ae@376
227+0000f22e@379
228+0000722e@382
229+000072ae@383
230+0000e2ae@384
231+0000e082@386
232+0000e002@388
233+00006082@391
234+00006080@392
235+0000e080@393
236+0000e2a4@395
237+0000a2a4@396
238+0000a60c@398
239+0000268c@401
240+0000a68c@402
241+0000b68c@405
242+0000b60c@407
243+0000360e@410
244+0000768e@411
245+0000f68e@412
246+0000f49a@414
247+0000b49a@415
248+0000b41a@416
249+0000349a@419
250+0000a49a@421
251+0000aef2@423
252+0000aaf2@424
253+0000aa72@425
254+0000aaf2@426
255+00002af0@429
256+0000aaf0@430
257+0000aa74@432
258+0000ea70@433
259+0000eaf4@434
260+00006af4@438
261+0000ea74@440
262+0000fa74@442
263+0000faf4@444
264+00007af6@447
265+0000faf6@449
266+0000fa76@450
267+0000fe26@451
268+0000b426@452
269+0000b4a6@453
270+000034a6@457
271+0000a4a6@458
272+0000a426@459
273+0000a472@460
274+0000a4f2@462
275+000024f2@466
276+000024f0@467
277+0000a470@468
278+0000a674@469
279+0000e674@470
280+0000e6f4@472
281+000066f4@475
282+000064f4@476
283+0000e674@477
284+0000f474@479
285+0000f674@480
286+0000f6f4@481
287+000076f6@484
288+000074f6@485
289+0000f4f6@486
290+0000f676@487
291+0000f606@488
292+0000b606@489
293+0000b686@490
294+00003686@494
295+0000a606@496
296+0000a676@497
297+0000a472@498
298+0000a4f2@500
299+000024f2@503
300+000024f0@504
301+0000a470@505
302+0000e474@507
303+0000e674@508
304+0000e6f4@509
305+000066f4@512
306+000064f4@513
307+0000e4f4@514
308+0000e674@515
309+0000e474@516
310+0000f674@517
311+0000f6f4@519
312+000074f6@522
313+000076f6@523
314+0000f676@524
315+0000f626@526
316+0000b6a6@527
317+000036a6@531
318+0000a626@533
319+0000a472@535
320+0000a4f2@537
321+000024f2@540
322+000024f0@541
323+0000a470@542
324+0000e674@545
325+0000e6f4@546
326+000064f4@550
327+0000e4f4@551
328+0000e674@552
329+0000f674@554
330+0000f6f4@556
331+000076f6@559
332+0000f676@561
333+0000f226@563
334+0000b226@564
335+0000b2a6@565
336+000032a6@568
337+0000a2a6@570
338+0000a226@571
339+0000a002@572
340+0000a082@574
341+00002080@578
342+0000a080@579
343+0000a000@580
344+0000a2a4@581
345+0000e2a0@582
346+0000e2a4@583
347+00006224@587
348+00006000@588
349+0000e2a4@589
350+0000f2a4@591
351+0000f224@594
352+00007226@596
353+00007206@597
354+0000f2a6@598
355+0000f8be@600
356+0000f9be@601
357+0000b9be@602
358+0000b93e@604
359+0000393e@605
360+0000a93e@607
361+0000a9be@608
362+0000abc2@609
363+0000ab42@613
364+00002b42@615
365+00002b40@616
366+0000abc0@617
367+0000abe4@618
368+0000ebe0@619
369+0000ebe4@620
370+0000eb64@623
371+00006b64@624
372+00006b44@625
373+0000ebe4@626
374+0000fbe4@629
375+0000fb64@632
376+00007b46@633
377+0000fb66@635
378+0000fbe6@636
379+0000f3a6@638
380+0000b3a6@639
381+0000b326@641
382+00003326@643
383+00002326@644
384+0000a3a6@645
385+0000a182@647
386+0000a102@651
387+00002102@652
388+00002100@653
389+0000a180@654
390+0000e1a4@656
391+0000e3a4@657
392+0000e1a4@658
393+0000e3a4@659
394+0000e324@660
395+00006324@661
396+00006104@662
397+0000e124@663
398+0000e3a4@664
399+0000f3a4@666
400+0000f324@669
401+0000f304@670
402+00007326@671
403+0000f3a6@673
404+0000f3be@674
405+0000f19a@675
406+0000b19a@676
407+0000b11a@679
408+0000311a@680
409+0000a19a@682
410+0000a182@684
411+0000a102@688
412+00002102@689
413+00002100@690
414+0000a100@691
415+0000a180@692
416+0000e3a4@694
417+0000e324@697
418+00006104@699
419+0000e104@700
420+0000e3a4@701
421+0000e1a4@702
422+0000f3a4@703
423+0000f184@705
424+0000f3a4@706
425+0000f304@707
426+00007326@708
427+00007306@709
428+0000f3a6@710
429+0000f19a@712
430+0000b19a@714
431+0000b11a@716
432+0000311a@717
433+0000a11a@719
434+0000a19a@720
435+0000a182@721
436+0000a102@725
437+00002100@727
438+0000a100@728
439+0000a180@729
440+0000a3a4@730
441+0000e3a4@731
442+0000e384@733
443+0000e324@734
444+0000e104@735
445+000061a4@736
446+000063a4@737
447+0000e3a4@738
448+0000f384@740
449+0000f3a4@741
450+0000f304@742
451+0000f3a4@743
452+000073a6@745
453+0000f3a6@747
454+0000f17e@749
455+0000f15e@750
456+0000b1de@751
457+000031de@754
458+0000a15e@756
459+0000afc2@758
460+00002f42@764
461+00002f40@765
462+0000afc0@766
463+0000afe4@767
464+0000efe0@768
465+0000efe4@769
466+0000efc4@770
467+0000ef64@771
468+0000ef44@772
469+00006fe4@773
470+00006fc4@774
471+0000efe4@775
472+0000efc4@777
473+0000ffe4@778
474+0000ff64@779
475+0000ff44@780
476+0000ffe4@781
477+00007fe6@782
478+0000ffe6@784
479+0000fb56@786
480+0000b356@787
481+0000b3d6@788
482+000033d6@792
483+00002356@793
484+0000a356@794
485+0000a7f6@795
486+0000a7f2@796
487+00002772@801
488+00002770@802
489+0000a7f0@803
490+0000e7f4@805
491+0000e774@809
492+000067f4@810
493+0000e7f4@812
494+0000f7f4@815
495+0000f774@816
496+0000f7f4@818
497+000077f6@820
498+0000f7f6@822
499+0000f7fe@823
500+0000f53a@824
501+0000b5ba@825
502+000035ba@829
503+0000a53a@831
504+0000a5ba@832
505+0000ab02@833
506+0000ab82@834
507+00002b82@838
508+00002b00@839
509+0000ab80@840
510+0000aba4@842
511+0000eba4@843
512+0000eb24@846
513+00006ba4@848
514+0000eba4@849
515+0000fba4@852
516+0000fb24@853
517+0000fb04@854
518+0000fba4@855
519+00007ba6@857
520+0000fba6@859
521+0000f71a@861
522+0000b79a@863
523+0000379a@866
524+0000a71a@868
525+0000ab82@870
526+00002b00@876
527+0000ab80@877
528+0000aba4@879
529+0000eba4@880
530+0000eb84@882
531+0000eb24@883
532+0000eb04@884
533+00006ba4@885
534+0000eba4@887
535+0000fb84@889
536+0000fba4@890
537+0000fb24@891
538+0000fba4@892
539+00007ba6@894
540+0000fba6@896
541+0000f902@898
542+0000b902@899
543+0000b982@900
544+00003982@904
545+0000a902@905
546+0000abc2@907
547+00002b42@913
548+00002b40@914
549+0000abc0@915
550+0000abe4@916
551+0000ebe0@917
552+0000ebe4@918
553+0000ebc4@919
554+0000eb64@920
555+0000eb44@921
556+00006be4@922
557+00006bc4@923
558+0000ebe4@924
559+0000ebc0@926
560+0000fbe4@927
561+0000fb64@928
562+0000fbc4@929
563+0000fbe4@930
564+00007be6@931
565+0000fbe6@933
566+0000fb02@935
567+0000f902@936
568+0000f982@937
569+00007982@941
570+00006982@942
571+0000e902@943
572+0000ebc2@944
573+00006b42@950
574+00006b40@951
575+0000ebc0@952
576+0000ebe4@954
577+0000abc0@956
578+0000a100@957
579+00002180@959
580+0000a180@961
581+0000b180@963
582+0000b100@965
583+0000b180@967
584+00007182@969
585+0000f182@971
586+0000f11a@972
587+0000b19a@974
588+0000319a@978
589+0000a11a@980
590+0000a182@982
591+00002182@987
592+00002100@988
593+0000a180@989
594+0000e3a4@992
595+0000e3a0@993
596+0000e384@994
597+0000e324@995
598+0000e304@996
599+00006184@997
600+0000e3a4@998
601+0000f3a4@1001
602+0000f304@1002
603+0000f104@1003
604+0000f3a4@1004
605+000073a6@1006
606+0000f3a6@1008
607+0000f11a@1010
608+0000b11a@1011
609+0000b19a@1012
610+0000319a@1015
611+0000a11a@1017
612+0000a182@1019
613+00002100@1025
614+0000a100@1026
615+0000a180@1027
616+0000a3a4@1028
617+0000e3a4@1029
618+0000e384@1031
619+0000e324@1032
620+0000e104@1033
621+000063a4@1034
622+000061a4@1035
623+0000e3a4@1036
624+0000f184@1038
625+0000f3a4@1039
626+0000f304@1040
627+0000f3a4@1041
628+000073a6@1043
629+0000f3a6@1045
630+0000f162@1047
631+0000b1e2@1049
632+000031e2@1052
633+0000a162@1054
634+0000af42@1056
635+0000afc2@1057
636+00002f42@1062
637+00002fc0@1063
638+0000afc0@1064
639+0000afe4@1065
640+0000efe0@1066
641+0000efe4@1067
642+0000efc4@1068
643+0000ef64@1069
644+0000ef40@1070
645+00006fe4@1071
646+00006fc0@1072
647+0000efe4@1073
648+0000efc0@1075
649+0000ffe4@1076
650+0000ff64@1077
651+0000ff40@1078
652+0000ffe4@1079
653+00007fe6@1080
654+0000ffe6@1082
655+0000fb46@1084
656+0000b346@1085
657+0000b3c6@1086
658+000033c6@1090
659+00002346@1091
660+0000a346@1092
661+0000abe6@1093
662+0000abe2@1094
663+00002b62@1099
664+00002b60@1100
665+0000abe0@1101
666+0000ebe4@1103
667+0000eb64@1107
668+00006be4@1108
669+0000ebe4@1110
670+0000fbe4@1113
671+0000fb64@1114
672+0000fbe4@1116
673+00007be6@1118
674+0000fbe6@1120
675+0000ff7e@1121
676+0000f73a@1122
677+0000b7ba@1123
678+000037ba@1127
679+0000a73a@1129
680+0000a7ba@1130
681+0000ab02@1131
682+0000ab82@1132
683+00002b82@1136
684+00002b00@1137
685+0000ab80@1138
686+0000aba4@1140
687+0000eba4@1141
688+0000eb24@1144
689+00006ba4@1146
690+0000eba4@1147
691+0000fba4@1150
692+0000fb24@1151
693+0000fba4@1153
694+00007ba6@1155
695+0000fba6@1157
696+0000f91a@1159
697+0000b91a@1160
698+0000b99a@1161
699+0000399a@1164
700+0000a91a@1166
701+0000ab82@1168
702+00002b00@1174
703+0000ab80@1175
704+0000aba4@1177
705+0000eba4@1178
706+0000eb84@1180
707+0000eb24@1181
708+0000eb04@1182
709+00006ba4@1183
710+0000eba4@1185
711+0000fb84@1187
712+0000fba4@1188
713+0000fb04@1189
714+0000fba4@1190
715+00007ba6@1192
716+0000fba6@1194
717+0000f906@1196
718+0000b906@1197
719+0000b986@1198
720+00003986@1202
721+0000a906@1203
722+0000abc2@1205
723+00002b42@1211
724+00002b40@1212
725+0000abc0@1213
726+0000abe4@1214
727+0000ebe0@1215
728+0000ebe4@1216
729+0000ebc4@1217
730+0000eb64@1218
731+0000eb44@1219
732+00006be4@1220
733+00006bc4@1221
734+0000ebe4@1222
735+0000fbc4@1224
736+0000fbe4@1225
737+0000fb64@1226
738+0000fb44@1227
739+0000fbe4@1228
740+00007be6@1229
741+0000fbe6@1231
742+0000fb06@1233
743+0000f906@1234
744+0000f986@1235
745+00007986@1239
746+00006986@1240
747+0000e906@1241
748+0000ebc6@1242
749+0000ebc2@1243
750+00006b42@1248
751+00006b40@1249
752+0000ebc0@1250
753+0000ebe4@1252
754+0000abc4@1254
755+0000a100@1255
756+00002180@1257
757+0000a180@1259
758+0000b180@1262
759+0000b100@1263
760+0000b180@1265
761+00007182@1267
762+0000f182@1269
763+0000f11a@1270
764+0000b19a@1272
765+0000319a@1276
766+0000a11a@1278
767+0000a19a@1279
768+0000a182@1280
769+00002182@1285
770+00002100@1286
771+0000a100@1287
772+0000a180@1288
773+0000e3a4@1290
774+0000e184@1292
775+0000e324@1293
776+0000e304@1294
777+000061a4@1295
778+0000e1a4@1296
779+0000e3a4@1297
780+0000f3a4@1299
781+0000f324@1300
782+0000f104@1301
783+0000f3a4@1302
784+000073a6@1304
785+0000f3a6@1306
786+0000f97a@1308
787+0000f9fa@1309
788+0000b9fa@1310
789+000039fa@1313
790+0000a97a@1315
791+0000a982@1317
792+0000a182@1318
793+00002100@1323
794+0000a180@1324
795+0000a3a4@1326
796+0000e3a4@1327
797+0000e384@1329
798+0000e324@1330
799+0000e104@1331
800+000061a4@1332
801+0000e3a4@1334
802+0000f180@1336
803+0000f3a4@1337
804+0000f104@1338
805+0000f3a4@1339
806+000073a6@1341
807+0000f3a6@1343
808+0000f166@1345
809+0000b1e6@1347
810+000031e6@1351
811+0000a166@1352
812+0000afc2@1354
813+00002f42@1360
814+00002f40@1361
815+0000afc0@1362
816+0000afe4@1363
817+0000efe0@1364
818+0000efe4@1365
819+0000efc4@1366
820+0000ef64@1367
821+00006fe4@1369
822+00006fc4@1370
823+0000efe4@1371
824+0000efc4@1373
825+0000ffe4@1374
826+0000ff64@1375
827+0000ffe4@1377
828+00007fe6@1378
829+0000ffe6@1380
830+0000fb46@1382
831+0000b346@1383
832+0000b3c6@1384
833+000033c6@1388
834+000023c6@1389
835+0000a346@1390
836+0000abe6@1391
837+0000abe2@1392
838+00002b62@1397
839+00002b60@1398
840+0000abe0@1399
841+0000ebe4@1401
842+0000eb64@1405
843+00006be4@1406
844+0000ebe4@1408
845+0000fbe4@1411
846+0000fb64@1412
847+0000fbe4@1414
848+00007be6@1416
849+0000fbe6@1418
850+0000fb7e@1419
851+0000f93a@1420
852+0000b9ba@1421
853+000039ba@1425
854+0000a93a@1427
855+0000a9ba@1428
856+0000ab02@1429
857+0000ab82@1430
858+00002b82@1434
859+00002b00@1435
860+0000ab80@1436
861+0000aba4@1438
862+0000eba4@1439
863+0000eb24@1442
864+00006ba4@1444
865+0000eba4@1445
866+0000fba4@1448
867+0000fb24@1449
868+0000fb04@1450
869+0000fba4@1451
870+00007ba6@1453
871+0000fba6@1455
872+0000f31a@1457
873+0000b31a@1458
874+0000b39a@1459
875+0000339a@1462
876+0000a31a@1464
877+0000af22@1466
878+0000ada2@1467
879+00002d20@1472
880+0000ada0@1473
881+0000afa4@1475
882+0000efa4@1476
883+0000ef24@1479
884+00006fa4@1481
885+0000efa4@1483
886+0000ffa4@1485
887+0000ff24@1487
888+0000ffa4@1488
889+00007fa6@1490
890+0000ffa6@1492
891+0000f90a@1494
892+0000b90a@1495
893+0000b98a@1496
894+0000398a@1500
895+0000a90a@1501
896+0000abc2@1503
897+00002b42@1509
898+00002b40@1510
899+0000abc0@1511
900+0000abe4@1512
901+0000ebe0@1513
902+0000ebe4@1514
903+0000ebc4@1515
904+0000eb64@1516
905+0000eb44@1517
906+00006be4@1518
907+00006bc4@1519
908+0000ebe4@1520
909+0000fbc0@1522
910+0000fbe4@1523
911+0000fb44@1524
912+0000fbe4@1526
913+00007be6@1527
914+0000fbe6@1529
915+0000fb0e@1531
916+0000f90a@1532
917+0000f98a@1533
918+0000798a@1537
919+0000698a@1538
920+0000e90a@1539
921+0000ebca@1540
922+0000ebc2@1541
923+00006b42@1546
924+00006b40@1547
925+0000ebc0@1548
926+0000ebe4@1550
927+0000afe0@1552
928+0000a5e0@1553
929+0000a560@1554
930+000025e0@1555
931+0000a5e0@1557
932+0000b5e0@1559
933+0000b560@1561
934+0000b5e0@1563
935+000075e2@1565
936+0000f5e2@1567
937+0000fd7a@1568
938+0000f91a@1569
939+0000b99a@1570
940+0000399a@1574
941+0000a91a@1576
942+0000a99a@1577
943+0000abd2@1578
944+00002bd2@1583
945+00002b50@1584
946+0000abd0@1585
947+0000abf4@1587
948+0000ebf4@1588
949+0000ebd4@1590
950+0000eb74@1591
951+00006bf4@1593
952+0000ebf4@1594
953+0000fbf4@1597
954+0000fb74@1598
955+0000fb54@1599
956+0000fbf4@1600
957+00007bf6@1602
958+0000fbf6@1604
959+0000f91a@1606
960+0000b91a@1607
961+0000b99a@1608
962+0000399a@1611
963+0000a91a@1613
964+0000a99a@1614
965+0000abd2@1615
966+00002b50@1621
967+0000ab50@1622
968+0000abd0@1623
969+0000abf4@1624
970+0000ebf4@1625
971+0000ebd4@1627
972+0000eb74@1628
973+0000eb54@1629
974+00006bf4@1630
975+0000ebf4@1632
976+0000fbf4@1634
977+0000fb54@1636
978+0000fbf4@1637
979+00007bf6@1639
980+00007bd6@1640
981+0000fbf6@1641
982+0000f17a@1643
983+0000b16a@1644
984+0000b1ea@1645
985+000031ea@1649
986+0000a1ea@1650
987+0000a16a@1651
988+0000afc2@1652
989+00002f42@1658
990+00002f40@1659
991+0000afc0@1660
992+0000afe4@1661
993+0000efe0@1662
994+0000efe4@1663
995+0000efc4@1664
996+0000ef64@1665
997+0000ef44@1666
998+00006fe4@1667
999+0000efe4@1669
1000+0000efc0@1671
1001+0000ffe4@1672
1002+0000ff64@1673
1003+0000ff44@1674
1004+0000ffe4@1675
1005+00007fe6@1676
1006+0000ffe6@1678
1007+0000fb46@1680
1008+0000b346@1681
1009+0000b3c6@1682
1010+000033c6@1686
1011+00002346@1687
1012+0000a346@1688
1013+0000abe6@1689
1014+0000abe2@1690
1015+00002b62@1695
1016+00002b60@1696
1017+0000abe0@1697
1018+0000ebe4@1699
1019+0000eb64@1703
1020+00006be4@1704
1021+0000ebe4@1706
1022+0000fbe4@1709
1023+0000fb64@1710
1024+0000fbe4@1712
1025+00007be6@1714
1026+0000fbe6@1715
1027+0000fb7e@1717
1028+0000f33a@1718
1029+0000b3ba@1719
1030+000033ba@1723
1031+0000a33a@1725
1032+0000a3ba@1726
1033+0000ada2@1727
1034+00002da2@1732
1035+00002d20@1733
1036+0000ada0@1734
1037+0000efa4@1737
1038+0000efa0@1738
1039+0000efa4@1739
1040+0000ef24@1740
1041+00006da4@1742
1042+0000efa4@1743
1043+0000ffa4@1746
1044+0000ff24@1747
1045+0000ffa4@1749
1046+00007fa6@1751
1047+0000ffa6@1753
1048+0000f51a@1755
1049+0000b51a@1756
1050+0000b59a@1757
1051+0000359a@1760
1052+0000a51a@1762
1053+0000ad22@1764
1054+0000ada2@1765
1055+00002d20@1770
1056+0000ada0@1771
1057+0000afa4@1773
1058+0000efa4@1774
1059+0000ef24@1777
1060+00006da4@1779
1061+0000efa4@1781
1062+0000ffa0@1783
1063+0000ffa4@1784
1064+0000ff24@1785
1065+0000ffa4@1786
1066+00007fa6@1788
1067+0000ffa6@1790
1068+0000f90e@1792
1069+0000b98e@1794
1070+0000398e@1798
1071+0000a90e@1799
1072+0000abc2@1801
1073+00002b42@1807
1074+00002b40@1808
1075+0000abc0@1809
1076+0000abe4@1810
1077+0000ebe0@1811
1078+0000ebe4@1812
1079+0000ebc4@1813
1080+0000eb64@1814
1081+0000eb44@1815
1082+00006be4@1816
1083+00006bc4@1817
1084+0000ebe4@1818
1085+0000ebc4@1820
1086+0000fbe4@1821
1087+0000fb64@1822
1088+0000fbc4@1823
1089+0000fbe4@1824
1090+00007be6@1825
1091+0000fbe6@1827
1092+0000fb0e@1829
1093+0000f90e@1830
1094+0000f98e@1831
1095+0000798e@1835
1096+0000798c@1836
1097+0000f90c@1837
1098+0000fbcc@1838
1099+0000fbc0@1839
1100+0000ebc0@1841
1101+00006b40@1844
1102+0000ebc0@1846
1103+0000ebe4@1848
1104+0000eb44@1852
1105+00006be4@1853
1106+00006bc4@1854
1107+0000ebe4@1855
1108+0000ebc4@1857
1109+0000fbe4@1858
1110+0000fb64@1859
1111+0000fb44@1860
1112+0000fbe4@1861
1113+00007be6@1863
1114+0000fbe6@1864
1115+0000fb7e@1866
1116+0000f91a@1867
1117+0000b99a@1868
1118+0000399a@1872
1119+0000a91a@1874
1120+0000a99a@1875
1121+0000abd2@1876
1122+00002bd2@1881
1123+00002b50@1882
1124+0000abd0@1883
1125+0000abf4@1885
1126+0000ebf4@1886
1127+0000eb74@1889
1128+00006bf4@1891
1129+0000ebf4@1892
1130+0000fbf4@1895
1131+0000fb74@1896
1132+0000fb54@1897
1133+0000fbf4@1898
1134+00007bf6@1900
1135+0000fbf6@1902
1136+0000f91a@1904
1137+0000b91a@1905
1138+0000b99a@1906
1139+0000399a@1909
1140+0000a91a@1911
1141+0000abd2@1913
1142+00002b50@1919
1143+0000ab50@1920
1144+0000abd0@1921
1145+0000abf4@1922
1146+0000ebf4@1923
1147+0000ebd4@1925
1148+0000eb74@1926
1149+0000eb54@1927
1150+00006bf4@1928
1151+0000ebf4@1930
1152+0000fbd4@1932
1153+0000fbf4@1933
1154+0000fb54@1934
1155+0000fbf4@1935
1156+00007bf6@1937
1157+0000fbf6@1939
1158+0000f17e@1941
1159+0000b16e@1942
1160+0000b1ee@1943
1161+000031ee@1946
1162+0000a16e@1948
1163+0000afc2@1950
1164+00002f42@1956
1165+00002f40@1957
1166+0000afc0@1958
1167+0000afe4@1959
1168+0000efe0@1960
1169+0000efe4@1961
1170+0000efc4@1962
1171+0000ef64@1963
1172+0000ef44@1964
1173+00006fe4@1965
1174+0000efe4@1967
1175+0000efc0@1969
1176+0000ffe4@1970
1177+0000ff64@1971
1178+0000ff44@1972
1179+0000ffe4@1973
1180+00007fe6@1974
1181+0000ffe6@1976
1182+0000fb46@1978
1183+0000b346@1979
1184+0000b3c6@1980
1185+000033c6@1984
1186+00002346@1985
1187+0000a346@1986
1188+0000abe6@1987
1189+0000abe2@1988
1190+00002b62@1993
1191+00002b60@1994
1192+0000abe0@1995
1193+0000ebe4@1997
1194+0000eb64@2001
1195+00006be4@2002
1196+0000ebe4@2004
1197+0000fbe4@2007
1198+0000fb64@2008
1199+0000fbe4@2010
1200+00007be6@2012
1201+0000fbe6@2013
1202+0000ff7e@2015
1203+0000f53a@2016
1204+0000b5ba@2017
1205+000035ba@2021
1206+0000a53a@2023
1207+0000a5ba@2024
1208+0000ad22@2025
1209+0000ada2@2026
1210+00002da2@2030
1211+00002d20@2031
1212+0000ada0@2032
1213+0000efa4@2035
1214+0000eda4@2037
1215+0000ef24@2038
1216+0000efa4@2039
1217+00006da4@2040
1218+0000efa4@2041
1219+0000ffa4@2044
1220+0000ff24@2045
1221+0000ffa4@2047
1222+00007fa6@2049
1223+0000ffa6@2051
1224+0000f71a@2053
1225+0000b71a@2054
1226+0000b79a@2055
1227+0000379a@2058
1228+0000a71a@2060
1229+0000ada2@2062
1230+00002d20@2068
1231+0000ada0@2069
1232+0000afa4@2071
1233+0000efa4@2072
1234+0000ef24@2075
1235+00006fa4@2077
1236+0000efa4@2079
1237+0000ffa4@2081
1238+0000ff24@2083
1239+0000ffa4@2084
1240+00007fa6@2086
1241+0000ffa6@2088
1242+0000f932@2090
1243+0000b912@2091
1244+0000b992@2092
1245+00003992@2096
1246+0000a912@2097
1247+0000abc2@2099
1248+00002b42@2105
1249+00002b40@2106
1250+0000abc0@2107
1251+0000abe4@2108
1252+0000ebe0@2109
1253+0000ebe4@2110
1254+0000ebc4@2111
1255+0000eb64@2112
1256+0000eb44@2113
1257+00006be4@2114
1258+00006bc4@2115
1259+0000ebe4@2116
1260+0000fbc0@2118
1261+0000fbe4@2119
1262+0000fb64@2120
1263+0000fbc4@2121
1264+0000fbe4@2122
1265+00007be6@2123
1266+0000fbe6@2125
1267+0000fb12@2127
1268+0000f912@2128
1269+0000f992@2129
1270+00007992@2133
1271+00006992@2134
1272+0000e912@2135
1273+0000ebd2@2136
1274+0000ebc2@2137
1275+00006b42@2142
1276+00006b40@2143
1277+0000ebc0@2144
1278+0000ebe4@2146
1279+0000afe0@2148
1280+0000a5e0@2149
1281+0000a560@2150
1282+000025e0@2151
1283+0000a5e0@2153
1284+0000b5e0@2156
1285+0000b560@2157
1286+0000b5e0@2159
1287+000075e2@2161
1288+0000f5e2@2162
1289+0000fd7a@2164
1290+0000f91a@2165
1291+0000b99a@2166
1292+0000399a@2170
1293+0000a91a@2172
1294+0000a99a@2173
1295+0000abd2@2174
1296+00002bd2@2179
1297+00002b50@2180
1298+0000abd0@2181
1299+0000abf4@2183
1300+0000ebf4@2184
1301+0000eb74@2187
1302+00006bf4@2189
1303+0000ebf4@2190
1304+0000fbf4@2193
1305+0000fb74@2194
1306+0000fb54@2195
1307+0000fbf4@2196
1308+00007bf6@2198
1309+0000fbf6@2200
1310+0000f91a@2202
1311+0000b91a@2203
1312+0000b99a@2204
1313+0000399a@2207
1314+0000a91a@2209
1315+0000a99a@2210
1316+0000abd2@2211
1317+00002b50@2217
1318+0000ab50@2218
1319+0000abd0@2219
1320+0000abf4@2220
1321+0000ebf4@2221
1322+0000ebd4@2223
1323+0000eb74@2224
1324+0000eb54@2225
1325+00006bf4@2226
1326+0000ebf4@2228
1327+0000fbd4@2230
1328+0000fbf4@2231
1329+0000fb54@2232
1330+0000fbf4@2233
1331+00007bf6@2235
1332+0000fbf6@2237
1333+0000f172@2239
1334+0000b172@2240
1335+0000b1f2@2241
1336+000031f2@2244
1337+0000a172@2246
1338+0000afc2@2248
1339+00002f42@2254
1340+00002f40@2255
1341+0000afc0@2256
1342+0000afe4@2257
1343+0000efe0@2258
1344+0000efe4@2259
1345+0000ef64@2261
1346+00006fe4@2263
1347+0000efe4@2265
1348+0000ffc0@2267
1349+0000ffe4@2268
1350+0000ff64@2269
1351+0000ffe4@2271
1352+00007fe6@2272
1353+0000ffe6@2274
1354+0000f346@2276
1355+0000b346@2277
1356+0000b3c6@2278
1357+000033c6@2282
1358+00002346@2283
1359+0000a346@2284
1360+0000abe6@2285
1361+0000abe2@2286
1362+00002b62@2291
1363+00002b60@2292
1364+0000abe0@2293
1365+0000ebe4@2295
1366+0000eb64@2299
1367+00006be4@2300
1368+0000ebe4@2302
1369+0000fbe4@2304
1370+0000fb64@2306
1371+0000fbe4@2308
1372+00007be6@2310
1373+0000fbe6@2311
1374+0000fb7e@2313
1375+0000fb1a@2314
1376+0000bb9a@2315
1377+00003b9a@2319
1378+0000ab1a@2321
1379+0000ab9a@2322
1380+0000ab82@2323
1381+00002b82@2328
1382+00002b00@2329
1383+0000ab80@2330
1384+0000aba4@2332
1385+0000eba4@2333
1386+0000eb24@2336
1387+00006ba4@2338
1388+0000eba4@2339
1389+0000fba4@2342
1390+0000fb24@2343
1391+0000fb04@2344
1392+0000fba4@2345
1393+00007ba6@2347
1394+0000fba6@2349
1395+0000fb3a@2351
1396+0000bbba@2353
1397+00003bba@2356
1398+0000ab3a@2358
1399+0000ab82@2360
1400+00002b00@2366
1401+0000ab80@2367
1402+0000aba4@2369
1403+0000eba4@2370
1404+0000eb24@2373
1405+00006ba4@2375
1406+0000eba4@2377
1407+0000fba4@2379
1408+0000fb24@2381
1409+0000fba4@2382
1410+00007ba6@2384
1411+0000fba6@2386
1412+0000f916@2388
1413+0000b996@2390
1414+00003996@2393
1415+0000a916@2395
1416+0000abc2@2397
1417+00002b42@2403
1418+00002b40@2404
1419+0000abc0@2405
1420+0000abe4@2406
1421+0000ebe0@2407
1422+0000ebe4@2408
1423+0000ebc4@2409
1424+0000eb64@2410
1425+0000eb44@2411
1426+00006be4@2412
1427+00006bc4@2413
1428+0000ebe4@2414
1429+0000fbc0@2416
1430+0000fbe4@2417
1431+0000fb64@2418
1432+0000fb44@2419
1433+0000fbe4@2420
1434+00007be6@2421
1435+0000fbe6@2423
1436+0000fb16@2425
1437+0000f916@2426
1438+0000f996@2427
1439+00007996@2431
1440+0000e996@2432
1441+0000e916@2433
1442+0000ebd6@2434
1443+0000ebc2@2435
1444+00006b42@2440
1445+00006b40@2441
1446+0000ebc0@2442
1447+0000ebe4@2444
1448+0000afe0@2446
1449+0000a5e0@2447
1450+0000a560@2448
1451+000025e0@2449
1452+0000a5e0@2451
1453+0000b5e0@2454
1454+0000b560@2455
1455+0000b5e0@2457
1456+000075e2@2459
1457+0000f5e2@2460
1458+0000fd7a@2462
1459+0000f91a@2463
1460+0000b99a@2464
1461+0000399a@2468
1462+0000a91a@2470
1463+0000a99a@2471
1464+0000abd2@2472
1465+00002bd2@2477
1466+00002b50@2478
1467+0000abd0@2479
1468+0000abf4@2481
1469+0000ebf4@2482
1470+0000eb74@2485
1471+00006bf4@2487
1472+0000ebf4@2488
1473+0000fbf4@2491
1474+0000fb74@2492
1475+0000fb54@2493
1476+0000fbf4@2494
1477+00007bf6@2496
1478+0000fbf6@2498
1479+0000f91a@2500
1480+0000b91a@2501
1481+0000b99a@2502
1482+0000399a@2505
1483+0000a91a@2507
1484+0000a99a@2508
1485+0000abd2@2509
1486+00002b50@2515
1487+0000ab50@2516
1488+0000abd0@2517
1489+0000abf4@2518
1490+0000ebf4@2519
1491+0000ebd4@2521
1492+0000eb74@2522
1493+00006bf4@2524
1494+0000ebf4@2526
1495+0000fbd4@2528
1496+0000fbf4@2529
1497+0000fb54@2530
1498+0000fbf4@2531
1499+00007bf6@2533
1500+0000fbf6@2535
1501+0000f176@2537
1502+0000b1f6@2539
1503+000031f6@2542
1504+0000a176@2544
1505+0000afc2@2546
1506+00002f42@2552
1507+00002f40@2553
1508+0000afc0@2554
1509+0000afe4@2555
1510+0000efe0@2556
1511+0000efe4@2557
1512+0000efc4@2558
1513+0000ef64@2559
1514+00006fe4@2561
1515+00006fc4@2562
1516+0000efe4@2563
1517+0000ffc4@2565
1518+0000ffe4@2566
1519+0000ff64@2567
1520+0000ffe4@2569
1521+00007fe6@2570
1522+0000ffe6@2572
1523+0000f346@2574
1524+0000b346@2575
1525+0000b3c6@2576
1526+000033c6@2580
1527+0000a3c6@2581
1528+0000a346@2582
1529+0000abe6@2583
1530+0000abe2@2584
1531+00002b62@2589
1532+00002b60@2590
1533+0000abe0@2591
1534+0000ebe4@2593
1535+0000eb64@2597
1536+00006be4@2598
1537+0000ebe4@2600
1538+0000fbe4@2603
1539+0000fb64@2604
1540+0000fbe4@2606
1541+00007be6@2608
1542+0000fbe6@2609
1543+0000ff7e@2611
1544+0000fd1a@2612
1545+0000bd9a@2613
1546+00003d9a@2617
1547+0000ad1a@2619
1548+0000ad9a@2620
1549+0000ab82@2621
1550+00002b82@2626
1551+00002b00@2627
1552+0000ab80@2628
1553+0000aba4@2630
1554+0000eba4@2631
1555+0000eb04@2634
1556+0000eb24@2635
1557+00006ba4@2636
1558+0000eba4@2637
1559+0000fba4@2640
1560+0000fb24@2641
1561+0000fb04@2642
1562+0000fba4@2643
1563+00007ba6@2645
1564+0000fba6@2647
1565+0000fd3a@2649
1566+0000bdba@2651
1567+00003dba@2654
1568+0000ad3a@2656
1569+0000af82@2658
1570+0000ab82@2659
1571+00002b00@2664
1572+0000ab80@2665
1573+0000aba4@2667
1574+0000eba4@2668
1575+0000eb84@2670
1576+0000eb24@2671
1577+00006ba4@2673
1578+0000eba4@2675
1579+0000fba4@2677
1580+0000fb24@2679
1581+0000fba4@2680
1582+00007ba6@2682
1583+0000fba6@2684
1584+0000f91a@2686
1585+0000b99a@2688
1586+0000399a@2691
1587+0000a91a@2693
1588+0000abc2@2695
1589+00002b42@2701
1590+00002b40@2702
1591+0000abc0@2703
1592+0000abe4@2704
1593+0000ebe0@2705
1594+0000ebe4@2706
1595+0000ebc4@2707
1596+0000eb64@2708
1597+0000eb44@2709
1598+00006be4@2710
1599+0000ebe4@2712
1600+0000fbc0@2714
1601+0000fbe4@2715
1602+0000fb64@2716
1603+0000fb44@2717
1604+0000fbe4@2718
1605+00007be6@2719
1606+0000fbe6@2721
1607+0000fb1e@2723
1608+0000f91a@2724
1609+0000f99a@2725
1610+0000799a@2729
1611+0000f99a@2730
1612+0000e91a@2731
1613+0000ebda@2732
1614+0000ebc2@2733
1615+00006b42@2738
1616+00006b40@2739
1617+0000ebc0@2740
1618+0000ebe4@2742
1619+0000afe0@2744
1620+0000a5e0@2745
1621+0000a560@2746
1622+000025e0@2747
1623+0000a5e0@2749
1624+0000b5e0@2752
1625+0000b560@2753
1626+0000b5e0@2755
1627+000075e2@2757
1628+0000f5e2@2758
1629+0000fd7a@2760
1630+0000f91a@2761
1631+0000b99a@2762
1632+0000399a@2766
1633+0000a91a@2768
1634+0000a99a@2769
1635+0000abd2@2770
1636+00002bd2@2775
1637+00002b50@2776
1638+0000abd0@2777
1639+0000abf4@2779
1640+0000ebf4@2780
1641+0000eb54@2783
1642+0000ebf4@2784
1643+00006bf4@2785
1644+0000ebf4@2786
1645+0000fbf4@2789
1646+0000fb74@2790
1647+0000fb54@2791
1648+0000fbf4@2792
1649+00007bf6@2794
1650+0000fbf6@2796
1651+0000f91a@2798
1652+0000b91a@2799
1653+0000b99a@2800
1654+0000399a@2803
1655+0000a91a@2805
1656+0000a99a@2806
1657+0000abd2@2807
1658+00002b50@2813
1659+0000abd0@2814
1660+0000abf4@2816
1661+0000ebf4@2817
1662+0000ebd4@2819
1663+0000eb74@2820
1664+0000eb54@2821
1665+00006bf4@2822
1666+0000ebf4@2824
1667+0000fbf4@2826
1668+0000fb54@2828
1669+0000fbf4@2829
1670+00007bf6@2831
1671+0000fbf6@2833
1672+0000f17a@2835
1673+0000b1fa@2837
1674+000031fa@2840
1675+0000a17a@2842
1676+0000afc2@2844
1677+00002f42@2850
1678+00002f40@2851
1679+0000afc0@2852
1680+0000afe4@2853
1681+0000efe0@2854
1682+0000efe4@2855
1683+0000efc4@2856
1684+0000ef64@2857
1685+0000ef44@2858
1686+00006fe4@2859
1687+0000efe4@2861
1688+0000ffc0@2863
1689+0000ffe4@2864
1690+0000ff64@2865
1691+0000ffc4@2866
1692+0000ffe4@2867
1693+00007fe6@2868
1694+0000ffe6@2870
1695+0000f346@2872
1696+0000b346@2873
1697+0000b3c6@2874
1698+000033c6@2878
1699+0000a346@2879
1700+0000abe6@2881
1701+0000abe2@2882
1702+00002b62@2887
1703+00002b60@2888
1704+0000abe0@2889
1705+0000ebe4@2891
1706+0000eb64@2895
1707+00006be4@2896
1708+0000ebe4@2898
1709+0000fbe4@2900
1710+0000fb64@2902
1711+0000fbe4@2904
1712+00007be6@2906
1713+0000fbe6@2907
1714+0000ff7e@2909
1715+0000ff1a@2910
1716+0000bf9a@2911
1717+00003f9a@2915
1718+0000af1a@2917
1719+0000af9a@2918
1720+0000ab82@2919
1721+00002b82@2924
1722+00002b00@2925
1723+0000ab80@2926
1724+0000aba4@2928
1725+0000eba4@2929
1726+0000eb24@2932
1727+00006ba4@2934
1728+0000eba4@2935
1729+0000fba4@2938
1730+0000fb24@2939
1731+0000fb04@2940
1732+0000fba4@2941
1733+00007ba6@2943
1734+0000fba6@2945
1735+0000ff3a@2947
1736+0000bfba@2949
1737+00003fba@2952
1738+0000af3a@2954
1739+0000ab82@2956
1740+00002b00@2962
1741+0000ab80@2963
1742+0000aba4@2965
1743+0000eba4@2966
1744+0000eb84@2968
1745+0000eb24@2969
1746+00006ba4@2971
1747+0000eba4@2973
1748+0000fba4@2975
1749+0000fb24@2977
1750+0000fba4@2978
1751+00007ba6@2980
1752+0000fba6@2982
1753+0000f91e@2984
1754+0000b99e@2986
1755+0000399e@2989
1756+0000a91e@2991
1757+0000abc2@2993
1758+00002b42@2999
1759+00002b40@3000
1760+0000abc0@3001
1761+0000abe4@3002
1762+0000ebe0@3003
1763+0000ebe4@3004
1764+0000ebc4@3005
1765+0000eb64@3006
1766+0000eb44@3007
1767+00006be4@3008
1768+0000ebe4@3010
1769+0000fbc4@3012
1770+0000fbe4@3013
1771+0000fb64@3014
1772+0000fb44@3015
1773+0000fbe4@3016
1774+00007be6@3017
1775+0000fbe6@3019
1776+0000fb1e@3021
1777+0000f91e@3022
1778+0000f99e@3023
1779+0000799e@3027
1780+0000f99c@3028
1781+0000f91c@3029
1782+0000fbdc@3030
1783+0000fbc0@3031
1784+0000ebc0@3032
1785+00006b40@3036
1786+0000ebc0@3038
1787+0000ebe4@3040
1788+0000eb44@3044
1789+00006be4@3045
1790+00006bc4@3046
1791+0000ebe4@3047
1792+0000ebc4@3049
1793+0000fbe4@3050
1794+0000fb64@3051
1795+0000fb44@3052
1796+0000fbe4@3053
1797+00007be6@3055
1798+0000fbe6@3056
1799+0000fb7e@3058
1800+0000f91a@3059
1801+0000b99a@3060
1802+0000399a@3064
1803+0000a91a@3066
1804+0000a99a@3067
1805+0000abd2@3068
1806+00002bd2@3073
1807+00002b50@3074
1808+0000abd0@3075
1809+0000abf4@3077
1810+0000ebf4@3078
1811+0000eb74@3081
1812+00006bf4@3083
1813+0000ebf4@3084
1814+0000fbf4@3087
1815+0000fb74@3088
1816+0000fb54@3089
1817+0000fbf4@3090
1818+00007bf6@3092
1819+0000fbf6@3094
1820+0000fb1a@3096
1821+0000bb1a@3097
1822+0000bb9a@3098
1823+00003b9a@3101
1824+0000ab1a@3103
1825+0000ab9a@3104
1826+0000abe2@3105
1827+00002b60@3111
1828+0000ab60@3112
1829+0000abe0@3113
1830+0000abe4@3114
1831+0000ebe4@3115
1832+0000eb64@3118
1833+00006be4@3120
1834+0000ebe4@3122
1835+0000fbe4@3124
1836+0000fb64@3126
1837+0000fbe4@3127
1838+00007be6@3129
1839+0000fbe6@3131
1840+0000f17e@3133
1841+0000b1fe@3135
1842+000031fe@3138
1843+0000a17e@3140
1844+0000afc2@3142
1845+00002f42@3148
1846+00002f40@3149
1847+0000afc0@3150
1848+0000afe4@3151
1849+0000efe0@3152
1850+0000efe4@3153
1851+0000ef64@3155
1852+0000ef44@3156
1853+00006fe4@3157
1854+0000efe4@3159
1855+0000ffc4@3161
1856+0000ffe4@3162
1857+0000ff64@3163
1858+0000ffc4@3164
1859+0000ffe4@3165
1860+00007fe6@3166
1861+0000ffe6@3168
1862+0000f346@3170
1863+0000b346@3171
1864+0000b3c6@3172
1865+000033c6@3176
1866+0000a346@3177
1867+0000abe6@3179
1868+0000abe2@3180
1869+00002b62@3185
1870+00002b60@3186
1871+0000abe0@3187
1872+0000ebe4@3189
1873+0000eb64@3193
1874+00006be4@3194
1875+0000ebe4@3196
1876+0000fbe4@3199
1877+0000fb64@3200
1878+0000fbe4@3202
1879+00007be6@3204
1880+0000fbe6@3205
1881+0000ff7e@3207
1882+0000f71a@3208
1883+0000b79a@3209
1884+0000379a@3213
1885+0000a71a@3215
1886+0000a79a@3216
1887+0000a992@3217
1888+00002992@3222
1889+00002910@3223
1890+0000a990@3224
1891+0000e994@3226
1892+0000ebb4@3227
1893+0000eb90@3228
1894+0000e9b4@3229
1895+0000eb14@3230
1896+000069b4@3232
1897+0000ebb4@3233
1898+0000fbb4@3236
1899+0000fb34@3237
1900+0000fb14@3238
1901+0000fbb4@3239
1902+00007bb6@3241
1903+0000fbb6@3243
1904+0000ffb6@3244
1905+0000f73a@3245
1906+0000b7ba@3247
1907+000037ba@3250
1908+0000a73a@3252
1909+0000a992@3254
1910+00002910@3260
1911+0000a990@3261
1912+0000abb4@3263
1913+0000ebb4@3264
1914+0000eb34@3267
1915+0000e914@3268
1916+00006bb4@3269
1917+000069b4@3270
1918+0000ebb4@3271
1919+0000fb90@3273
1920+0000fbb4@3274
1921+0000fb14@3275
1922+0000fbb4@3276
1923+00007bb6@3278
1924+0000fbb6@3280
1925+0000f922@3282
1926+0000b922@3283
1927+0000b9a2@3284
1928+000039a2@3287
1929+0000a922@3289
1930+0000abc2@3291
1931+00002b42@3297
1932+00002b40@3298
1933+0000abc0@3299
1934+0000abe4@3300
1935+0000ebe0@3301
1936+0000ebe4@3302
1937+0000eb64@3304
1938+0000eb44@3305
1939+00006be4@3306
1940+0000ebe4@3308
1941+0000fbc0@3310
1942+0000fbe4@3311
1943+0000fb64@3312
1944+0000fbe4@3313
1945+00007be6@3315
1946+0000fbe6@3317
1947+0000fb62@3319
1948+0000f922@3320
1949+0000f9a2@3321
1950+000079a2@3325
1951+0000e9a2@3326
1952+0000e922@3327
1953+0000ebe2@3328
1954+0000ebc2@3329
1955+00006b42@3334
1956+00006b40@3335
1957+0000ebc0@3336
1958+0000ebe4@3338
1959+0000abec@3340
1960+0000a9ec@3341
1961+0000a96c@3342
1962+000029ec@3343
1963+0000a9ec@3345
1964+0000b9ec@3348
1965+0000b96c@3349
1966+0000b9ec@3351
1967+000079ee@3353
1968+0000f9ee@3354
1969+0000fb7e@3356
1970+0000fb3a@3357
1971+0000bbba@3358
1972+00003bba@3362
1973+0000ab3a@3364
1974+0000abba@3365
1975+0000abe2@3366
1976+00002be2@3371
1977+00002b60@3372
1978+0000abe0@3373
1979+0000ebe4@3376
1980+0000eb64@3379
1981+00006be4@3381
1982+0000ebe4@3382
1983+0000fbe4@3385
1984+0000fb64@3386
1985+0000fbe4@3388
1986+00007be6@3390
1987+0000fbe6@3392
1988+0000fbee@3393
1989+0000f91a@3394
1990+0000b91a@3395
1991+0000b99a@3396
1992+0000399a@3399
1993+0000a91a@3401
1994+0000a99a@3402
1995+0000abd2@3403
1996+00002bd2@3408
1997+00002b50@3409
1998+0000ab50@3410
1999+0000abd0@3411
2000+0000abf4@3412
2001+0000ebf4@3413
2002+0000ebd4@3415
2003+0000eb74@3416
2004+0000eb54@3417
2005+00006bf4@3418
2006+0000ebf4@3420
2007+0000fbf4@3422
2008+0000fb54@3424
2009+0000fbf4@3425
2010+00007bf6@3427
2011+0000fbf6@3429
2012+0000fb42@3431
2013+0000b342@3432
2014+0000b3c2@3433
2015+000033c2@3436
2016+0000a342@3438
2017+0000af42@3440
2018+0000afc2@3441
2019+00002f42@3446
2020+00002f40@3447
2021+0000afc0@3448
2022+0000afe4@3449
2023+0000efc0@3450
2024+0000efe4@3451
2025+0000efc4@3452
2026+0000ef64@3453
2027+0000ef44@3454
2028+00006fe4@3455
2029+00006fc4@3456
2030+0000efe4@3457
2031+0000ffc0@3459
2032+0000ffe4@3460
2033+0000ff64@3461
2034+0000ff44@3462
2035+0000ffe4@3463
2036+00007fe6@3464
2037+0000ffe6@3466
2038+0000f346@3468
2039+0000b346@3469
2040+0000b3c6@3470
2041+000033c6@3474
2042+0000a3c6@3475
2043+0000a346@3476
2044+0000abe6@3477
2045+0000abe2@3478
2046+00002b62@3483
2047+00002b60@3484
2048+0000abe0@3485
2049+0000ebe4@3487
2050+0000eb64@3491
2051+00006be4@3492
2052+0000ebe4@3494
2053+0000fbe4@3497
2054+0000fb64@3498
2055+0000fbe4@3500
2056+00007be6@3502
2057+0000fbe6@3503
2058+0000ff7e@3505
2059+0000ff1a@3506
2060+0000bf9a@3507
2061+00003f9a@3511
2062+0000af1a@3513
2063+0000af9a@3514
2064+0000aba2@3515
2065+00002ba2@3520
2066+00002b20@3521
2067+0000aba0@3522
2068+0000aba4@3524
2069+0000eba4@3525
2070+0000eb24@3528
2071+00006ba4@3530
2072+0000eba4@3531
2073+0000fba4@3534
2074+0000fb24@3535
2075+0000fba4@3537
2076+00007ba6@3539
2077+0000fba6@3541
2078+0000fbae@3542
2079+0000f53a@3543
2080+0000b5ba@3545
2081+000035ba@3548
2082+0000a53a@3550
2083+0000a182@3552
2084+00002100@3558
2085+0000a180@3559
2086+0000a3a4@3561
2087+0000e3a4@3562
2088+0000e384@3564
2089+0000e324@3565
2090+000061a4@3567
2091+0000e3a4@3569
2092+0000f184@3571
2093+0000f3a4@3572
2094+0000f304@3573
2095+0000f3a4@3574
2096+000073a6@3576
2097+0000f3a6@3578
2098+0000f926@3580
2099+0000b9a6@3582
2100+000039a6@3585
2101+0000a926@3587
2102+0000abc2@3589
2103+00002b42@3595
2104+00002b40@3596
2105+0000abc0@3597
2106+0000abe4@3598
2107+0000ebe0@3599
2108+0000ebe4@3600
2109+0000eb64@3602
2110+00006be4@3604
2111+0000ebe4@3606
2112+0000fbc4@3608
2113+0000fbe4@3609
2114+0000fb64@3610
2115+0000fbe4@3612
2116+00007be6@3613
2117+0000fbe6@3615
2118+0000f926@3617
2119+0000f9a6@3619
2120+000079a6@3623
2121+0000e9a6@3624
2122+0000e926@3625
2123+0000ebe6@3626
2124+0000ebc2@3627
2125+00006b42@3632
2126+00006b40@3633
2127+0000ebc0@3634
2128+0000ebe4@3636
2129+0000afe0@3638
2130+0000a5e0@3639
2131+0000a560@3640
2132+000025e0@3641
2133+0000a5e0@3643
2134+0000b5e0@3646
2135+0000b560@3647
2136+0000b5e0@3649
2137+000075e2@3651
2138+0000f5e2@3652
2139+0000fd7a@3654
2140+0000f91a@3655
2141+0000b99a@3656
2142+0000399a@3660
2143+0000a91a@3662
2144+0000a99a@3663
2145+0000abd2@3664
2146+00002bd2@3669
2147+00002b50@3670
2148+0000abd0@3671
2149+0000abf4@3673
2150+0000ebf4@3674
2151+0000eb54@3677
2152+0000ebf4@3678
2153+00006bd4@3679
2154+0000ebf4@3680
2155+0000fbf4@3683
2156+0000fb74@3684
2157+0000fb54@3685
2158+0000fbf4@3686
2159+00007bf6@3688
2160+0000fbf6@3690
2161+0000f91a@3692
2162+0000b91a@3693
2163+0000b99a@3694
2164+0000399a@3697
2165+0000a91a@3699
2166+0000a99a@3700
2167+0000abd2@3701
2168+00002bd2@3706
2169+00002b50@3707
2170+0000abd0@3708
2171+0000abf4@3710
2172+0000ebf4@3711
2173+0000ebd4@3713
2174+0000eb74@3714
2175+0000eb54@3715
2176+00006bf4@3716
2177+0000ebf4@3718
2178+0000fbd4@3720
2179+0000fbf4@3721
2180+0000fb54@3722
2181+0000fbf4@3723
2182+00007bf6@3725
2183+0000fbf6@3727
2184+0000f346@3729
2185+0000b346@3730
2186+0000b3c6@3731
2187+000033c6@3734
2188+0000a346@3736
2189+0000afc2@3738
2190+00002f42@3744
2191+00002f40@3745
2192+0000afc0@3746
2193+0000afe4@3747
2194+0000efe0@3748
2195+0000efe4@3749
2196+0000efc4@3750
2197+0000ef64@3751
2198+0000ef44@3752
2199+00006fe4@3753
2200+00006fc4@3754
2201+0000efe4@3755
2202+0000ffc0@3757
2203+0000ffe4@3758
2204+0000ff44@3759
2205+0000ffe4@3761
2206+00007fe6@3762
2207+0000ffe6@3764
2208+0000f346@3766
2209+0000b346@3767
2210+0000b3c6@3768
2211+000033c6@3772
2212+0000b3c6@3773
2213+0000a346@3774
2214+0000abe6@3775
2215+0000abe2@3776
2216+00002b62@3781
2217+00002b60@3782
2218+0000abe0@3783
2219+0000ebe4@3785
2220+0000eb64@3789
2221+00006be4@3790
2222+0000ebe4@3792
2223+0000fbe4@3795
2224+0000fb64@3796
2225+0000fbe4@3798
2226+00007be6@3800
2227+0000fbe6@3801
2228+0000ff7e@3803
2229+0000f53a@3804
2230+0000b5ba@3805
2231+000035ba@3809
2232+0000a53a@3811
2233+0000a5ba@3812
2234+0000a102@3813
2235+0000a182@3814
2236+00002182@3818
2237+00002100@3819
2238+0000a180@3820
2239+0000e1a4@3822
2240+0000e3a4@3823
2241+0000e1a4@3824
2242+0000e324@3826
2243+000061a4@3828
2244+0000e3a4@3829
2245+0000f3a4@3832
2246+0000f324@3833
2247+0000f304@3834
2248+0000f3a4@3835
2249+000073a6@3837
2250+0000f3a6@3839
2251+0000f7b6@3840
2252+0000f53a@3841
2253+0000b5ba@3843
2254+000035ba@3846
2255+0000a53a@3848
2256+0000a182@3850
2257+00002100@3856
2258+0000a180@3857
2259+0000a3a4@3859
2260+0000e3a4@3860
2261+0000e380@3862
2262+0000e324@3863
2263+0000e304@3864
2264+000061a4@3865
2265+0000e3a4@3867
2266+0000f3a4@3869
2267+0000f304@3871
2268+0000f3a4@3872
2269+000073a6@3874
2270+0000f3a6@3876
2271+0000f92a@3878
2272+0000b9aa@3880
2273+000039aa@3883
2274+0000a92a@3885
2275+0000abc2@3887
2276+00002b42@3893
2277+00002b40@3894
2278+0000abc0@3895
2279+0000abe4@3896
2280+0000ebe0@3897
2281+0000ebe4@3898
2282+0000eb64@3900
2283+00006be4@3902
2284+0000ebe4@3904
2285+0000fbc0@3906
2286+0000fbe4@3907
2287+0000fb64@3908
2288+0000fbe4@3909
2289+00007be6@3911
2290+0000fbe6@3913
2291+0000f92a@3915
2292+0000f9aa@3917
2293+000079aa@3921
2294+0000e9aa@3922
2295+0000e92a@3923
2296+0000ebea@3924
2297+0000ebc2@3925
2298+00006b42@3930
2299+00006b40@3931
2300+0000ebc0@3932
2301+0000ebe4@3934
2302+0000afe0@3936
2303+0000a5e0@3937
2304+0000a560@3938
2305+000025e0@3939
2306+0000a5e0@3941
2307+0000b5e0@3943
2308+0000b560@3945
2309+0000b5e0@3947
2310+000075e2@3949
2311+0000f5e2@3950
2312+0000fd7a@3952
2313+0000f91a@3953
2314+0000b99a@3954
2315+0000399a@3958
2316+0000a91a@3960
2317+0000a99a@3961
2318+0000abd2@3962
2319+00002bd2@3967
2320+00002b50@3968
2321+0000ab50@3969
2322+0000abd0@3970
2323+0000abf4@3971
2324+0000ebf4@3972
2325+0000eb74@3975
2326+00006b74@3976
2327+00006bf4@3977
2328+0000ebf4@3978
2329+0000fbf4@3981
2330+0000fb74@3982
2331+0000fb54@3983
2332+0000fbf4@3984
2333+00007bf6@3986
2334+0000fbf6@3988
2335+0000fbfe@3989
2336+0000f91a@3990
2337+0000b91a@3991
2338+0000b99a@3992
2339+0000399a@3995
2340+0000a91a@3997
2341+0000a99a@3998
2342+0000abd2@3999
2343+00002bd2@4004
2344+00002b50@4005
2345+0000abd0@4006
2346+0000abf4@4008
2347+0000ebf4@4009
2348+0000ebd4@4011
2349+0000eb74@4012
2350+0000eb54@4013
2351+00006bf4@4014
2352+0000ebf4@4016
2353+0000fbd4@4018
2354+0000fbf4@4019
2355+0000fb54@4020
2356+0000fbf4@4021
2357+00007bf6@4023
2358+0000fbf6@4025
2359+0000fb4a@4027
2360+0000b34a@4028
2361+0000b3ca@4029
2362+000033ca@4032
2363+0000a34a@4034
2364+0000afc2@4036
2365+00002f42@4042
2366+00002f40@4043
2367+0000afc0@4044
2368+0000afe4@4045
2369+0000efc0@4046
2370+0000efe4@4047
2371+0000efc4@4048
2372+0000ef64@4049
2373+0000ef44@4050
2374+00006fe4@4051
2375+00006fc4@4052
2376+0000efe4@4053
2377+0000ffc0@4055
2378+0000ffe4@4056
2379+0000ff44@4057
2380+0000ffc0@4058
2381+0000ffe4@4059
2382+00007fe6@4060
2383+0000ffe6@4062
2384+0000f346@4064
2385+0000b346@4065
2386+0000b3c6@4066
2387+000033c6@4070
2388+0000a3c6@4071
2389+0000a346@4072
2390+0000abe6@4073
2391+0000abe2@4074
2392+00002b62@4079
2393+00002b60@4080
2394+0000abe0@4081
2395+0000ebe4@4083
2396+0000eb64@4087
2397+00006be4@4088
2398+0000ebe4@4090
2399+0000fbe4@4093
2400+0000fb64@4094
2401+0000fbe4@4096
2402+00007be6@4098
2403+0000fbe6@4099
2404+0000ff7e@4101
2405+0000f53a@4102
2406+0000b5ba@4103
2407+000035ba@4107
2408+0000a53a@4109
2409+0000a5ba@4110
2410+0000a102@4111
2411+0000a182@4112
2412+00002182@4116
2413+00002100@4117
2414+0000a180@4118
2415+0000e1a4@4120
2416+0000e3a4@4121
2417+0000e1a4@4122
2418+0000e3a4@4123
2419+0000e324@4124
2420+00006324@4125
2421+000061a4@4126
2422+0000e3a4@4127
2423+0000f3a4@4130
2424+0000f324@4131
2425+0000f304@4132
2426+0000f3a4@4133
2427+000073a6@4135
2428+0000f3a6@4137
2429+0000f7b6@4138
2430+0000f53a@4139
2431+0000b5ba@4141
2432+000035ba@4144
2433+0000a53a@4146
2434+0000a182@4148
2435+00002100@4154
2436+0000a180@4155
2437+0000a3a4@4157
2438+0000e3a4@4158
2439+0000e324@4161
2440+0000e104@4162
2441+000061a4@4163
2442+0000e3a4@4165
2443+0000f1a4@4167
2444+0000f3a4@4168
2445+0000f104@4169
2446+0000f3a4@4170
2447+000073a6@4172
2448+0000f3a6@4174
2449+0000f92e@4176
2450+0000b9ae@4178
2451+000039ae@4181
2452+0000a92e@4183
2453+0000abc2@4185
2454+00002b42@4191
2455+00002b40@4192
2456+0000abc0@4193
2457+0000abe4@4194
2458+0000ebe0@4195
2459+0000ebe4@4196
2460+0000ebc4@4197
2461+0000eb64@4198
2462+0000eb44@4199
2463+00006be4@4200
2464+0000ebe4@4202
2465+0000fbc4@4204
2466+0000fbe4@4205
2467+0000fb64@4206
2468+0000fbe4@4207
2469+00007be6@4209
2470+0000fbe6@4211
2471+0000f92e@4213
2472+0000f9ae@4215
2473+000079ac@4219
2474+0000f9ac@4220
2475+0000f92c@4221
2476+0000fbe8@4222
2477+0000fbc0@4223
2478+0000ebc0@4224
2479+00006b40@4228
2480+0000ebc0@4230
2481+0000ebe4@4232
2482+0000eb44@4236
2483+00006be4@4237
2484+00006bc4@4238
2485+0000ebe4@4239
2486+0000ebc4@4241
2487+0000fbe4@4242
2488+0000fb64@4243
2489+0000fb44@4244
2490+0000fbe4@4245
2491+00007be6@4247
2492+0000fbe6@4248
2493+0000fb7e@4250
2494+0000f91a@4251
2495+0000b99a@4252
2496+0000399a@4256
2497+0000a91a@4258
2498+0000a99a@4259
2499+0000abd2@4260
2500+00002bd2@4265
2501+00002b50@4266
2502+0000abd0@4267
2503+0000abf4@4269
2504+0000ebf4@4270
2505+0000eb74@4273
2506+00006b74@4274
2507+00006bf4@4275
2508+0000ebf4@4276
2509+0000fbf4@4279
2510+0000fb74@4280
2511+0000fb54@4281
2512+0000fbf4@4282
2513+00007bf6@4284
2514+0000fbf6@4286
2515+0000f91a@4288
2516+0000b91a@4289
2517+0000b99a@4290
2518+0000399a@4293
2519+0000a91a@4295
2520+0000a99a@4296
2521+0000abd2@4297
2522+00002bd2@4302
2523+00002b50@4303
2524+0000ab50@4304
2525+0000abd0@4305
2526+0000abf4@4306
2527+0000ebf4@4307
2528+0000ebd4@4309
2529+0000eb74@4310
2530+0000eb54@4311
2531+00006bf4@4312
2532+0000ebf4@4314
2533+0000fbf4@4316
2534+0000fb74@4317
2535+0000fb54@4318
2536+0000fbf4@4319
2537+00007bf6@4321
2538+0000fbf6@4323
2539+0000f35e@4325
2540+0000b34e@4326
2541+0000b3ce@4327
2542+000033ce@4330
2543+0000a34e@4332
2544+0000afc2@4334
2545+00002f42@4340
2546+00002fc0@4341
2547+0000afc0@4342
2548+0000afe4@4343
2549+0000efc0@4344
2550+0000efe4@4345
2551+0000ef64@4347
2552+0000ef44@4348
2553+00006fe4@4349
2554+00006fc4@4350
2555+0000efe4@4351
2556+0000ffc0@4353
2557+0000ffe4@4354
2558+0000ff44@4355
2559+0000ffc4@4356
2560+0000ffe4@4357
2561+00007fe6@4358
2562+0000ffe6@4360
2563+0000f346@4362
2564+0000b346@4363
2565+0000b3c6@4364
2566+000033c6@4368
2567+0000a346@4369
2568+0000abe6@4371
2569+0000abe2@4372
2570+00002b62@4377
2571+00002b60@4378
2572+0000abe0@4379
2573+0000ebe4@4381
2574+0000eb64@4385
2575+00006be4@4386
2576+0000ebe4@4388
2577+0000fbe4@4391
2578+0000fb64@4392
2579+0000fbe4@4394
2580+00007be6@4396
2581+0000fbe6@4397
2582+0000ff7e@4399
2583+0000f53a@4400
2584+0000b5ba@4401
2585+000035ba@4405
2586+0000a53a@4407
2587+0000a5ba@4408
2588+0000a102@4409
2589+0000a182@4410
2590+00002182@4414
2591+00002100@4415
2592+0000a180@4416
2593+0000e1a4@4418
2594+0000e3a4@4419
2595+0000e1a4@4420
2596+0000e3a4@4421
2597+0000e324@4422
2598+000063a4@4423
2599+000061a4@4424
2600+0000e1a4@4425
2601+0000e3a4@4426
2602+0000f3a4@4428
2603+0000f324@4429
2604+0000f304@4430
2605+0000f3a4@4431
2606+000073a6@4433
2607+0000f3a6@4435
2608+0000f7be@4436
2609+0000f53a@4437
2610+0000b5ba@4439
2611+000035ba@4442
2612+0000a53a@4444
2613+0000a182@4446
2614+00002100@4452
2615+0000a180@4453
2616+0000a3a4@4455
2617+0000e3a4@4456
2618+0000e324@4459
2619+0000e104@4460
2620+000061a4@4461
2621+0000e3a4@4463
2622+0000f3a4@4465
2623+0000f324@4466
2624+0000f104@4467
2625+0000f3a4@4468
2626+000073a6@4470
2627+0000f3a6@4472
2628+0000f932@4474
2629+0000b9b2@4476
2630+000039b2@4479
2631+0000a932@4481
2632+0000abc2@4483
2633+00002b42@4489
2634+00002b40@4490
2635+0000abc0@4491
2636+0000abe4@4492
2637+0000ebc0@4493
2638+0000ebe4@4494
2639+0000eb64@4496
2640+00006be4@4498
2641+0000ebe4@4500
2642+0000fbc0@4502
2643+0000fbe4@4503
2644+0000fb64@4504
2645+0000fbe4@4505
2646+00007be6@4507
2647+0000fbe6@4509
2648+0000f972@4511
2649+0000f932@4512
2650+0000f9b2@4513
2651+000079b2@4517
2652+0000e9b2@4518
2653+0000e932@4519
2654+0000ebe2@4520
2655+0000ebc2@4521
2656+00006b42@4526
2657+00006b40@4527
2658+0000ebc0@4528
2659+0000ebe4@4530
2660+0000afe0@4532
2661+0000a5e0@4533
2662+0000a560@4534
2663+000025e0@4535
2664+0000a5e0@4537
2665+0000b5e0@4540
2666+0000b560@4541
2667+0000b5e0@4543
2668+000075e2@4545
2669+0000f5e2@4546
2670+0000fd3a@4548
2671+0000f91a@4549
2672+0000b99a@4550
2673+0000399a@4554
2674+0000a91a@4556
2675+0000a99a@4557
2676+0000abd2@4558
2677+00002b52@4563
2678+00002b50@4564
2679+0000abd0@4565
2680+0000abf4@4567
2681+0000ebf4@4568
2682+0000eb74@4571
2683+00006b74@4572
2684+00006bf4@4573
2685+0000ebf4@4574
2686+0000fbf4@4577
2687+0000fb74@4578
2688+0000fb54@4579
2689+0000fbf4@4580
2690+00007bf6@4582
2691+0000fbf6@4584
2692+0000fbfe@4585
2693+0000f91a@4586
2694+0000b91a@4587
2695+0000b99a@4588
2696+0000399a@4591
2697+0000a91a@4593
2698+0000a99a@4594
2699+0000abd2@4595
2700+00002bd2@4600
2701+00002b50@4601
2702+0000ab50@4602
2703+0000abd0@4603
2704+0000abf0@4604
2705+0000ebf4@4605
2706+0000ebd4@4607
2707+0000eb74@4608
2708+0000eb54@4609
2709+00006bf4@4610
2710+0000ebf4@4612
2711+0000fbf4@4614
2712+0000fb54@4616
2713+0000fbf4@4617
2714+00007bf6@4619
2715+0000fbf6@4621
2716+0000f352@4623
2717+0000b352@4624
2718+0000b3d2@4625
2719+000033d2@4628
2720+0000a352@4630
2721+0000afc2@4632
2722+00002f42@4638
2723+00002fc0@4639
2724+0000afc0@4640
2725+0000afe4@4641
2726+0000efc0@4642
2727+0000efe4@4643
2728+0000efc4@4644
2729+0000ef64@4645
2730+0000ef44@4646
2731+00006fe4@4647
2732+00006fc4@4648
2733+0000efe4@4649
2734+0000ffc0@4651
2735+0000ffe4@4652
2736+0000ff44@4653
2737+0000ffc4@4654
2738+0000ffe4@4655
2739+00007fe6@4656
2740+0000ffe6@4658
2741+0000f346@4660
2742+0000b346@4661
2743+0000b3c6@4662
2744+000033c6@4666
2745+0000a346@4667
2746+0000abe6@4669
2747+0000abe2@4670
2748+00002b62@4675
2749+00002b60@4676
2750+0000abe0@4677
2751+0000ebe4@4679
2752+0000eb64@4683
2753+00006be4@4684
2754+0000ebe4@4686
2755+0000fbe4@4689
2756+0000fb64@4690
2757+0000fbe4@4692
2758+00007be6@4694
2759+0000fbe6@4695
2760+0000ff7e@4697
2761+0000b53a@4698
2762+0000b5ba@4699
2763+000035ba@4703
2764+0000a53a@4705
2765+0000a5ba@4706
2766+0000a102@4707
2767+0000a182@4708
2768+00002182@4712
2769+00002100@4713
2770+0000a180@4714
2771+0000e1a4@4716
2772+0000e3a4@4717
2773+0000e1a4@4718
2774+0000e3a4@4719
2775+0000e304@4720
2776+000063a4@4721
2777+00006184@4722
2778+0000e1a4@4723
2779+0000e3a4@4724
2780+0000e1a4@4725
2781+0000f3a4@4726
2782+0000f324@4727
2783+0000f100@4728
2784+0000f3a4@4729
2785+000073a6@4731
2786+0000f3a6@4733
2787+0000f7be@4734
2788+0000f53a@4735
2789+0000b5ba@4737
2790+000035ba@4740
2791+0000a53a@4742
2792+0000a182@4744
2793+00002182@4749
2794+00002100@4750
2795+0000a180@4751
2796+0000a3a4@4753
2797+0000e3a4@4754
2798+0000e384@4756
2799+0000e324@4757
2800+0000e104@4758
2801+000061a4@4759
2802+0000e3a4@4761
2803+0000f3a4@4763
2804+0000f324@4764
2805+0000f104@4765
2806+0000f3a4@4766
2807+000073a6@4768
2808+0000f3a6@4770
2809+0000f936@4772
2810+0000b9b6@4774
2811+000039b6@4777
2812+0000a9b6@4779
2813+0000a936@4780
2814+0000abc2@4781
2815+00002b42@4787
2816+00002b40@4788
2817+0000abc0@4789
2818+0000abe4@4790
2819+0000ebe0@4791
2820+0000ebe4@4792
2821+0000eb64@4794
2822+00006be4@4796
2823+0000ebe4@4798
2824+0000fbc4@4800
2825+0000fbe4@4801
2826+0000fb64@4802
2827+0000fbe4@4803
2828+00007be6@4805
2829+0000fbe6@4807
2830+0000f936@4809
2831+0000f9b6@4811
2832+000079b6@4815
2833+0000e9b6@4816
2834+0000e936@4817
2835+0000ebf6@4818
2836+0000ebc2@4819
2837+00006b42@4824
2838+00006b40@4825
2839+0000ebc0@4826
2840+0000ebe4@4828
2841+0000afe0@4830
2842+0000a5e0@4831
2843+0000a560@4832
2844+000025e0@4833
2845+0000a5e0@4835
2846+0000b5e0@4838
2847+0000b560@4839
2848+0000b5e0@4841
2849+000075e2@4843
2850+0000f5e2@4844
2851+0000fd3a@4846
2852+0000f91a@4847
2853+0000b99a@4848
2854+0000399a@4852
2855+0000a91a@4854
2856+0000a9da@4855
2857+0000abd2@4856
2858+00002bd2@4861
2859+00002b50@4862
2860+0000abd0@4863
2861+0000abf4@4865
2862+0000ebf4@4866
2863+0000eb74@4869
2864+00006bf4@4870
2865+00006bd4@4871
2866+0000ebf4@4872
2867+0000fbf4@4875
2868+0000fb74@4876
2869+0000fb54@4877
2870+0000fbf4@4878
2871+00007bf6@4880
2872+0000fbf6@4882
2873+0000fbfe@4883
2874+0000f33a@4884
2875+0000b3ba@4885
2876+000033ba@4889
2877+0000a33a@4891
2878+0000a3ba@4892
2879+0000abd2@4893
2880+00002bd2@4898
2881+00002b50@4899
2882+0000ab50@4900
2883+0000abd0@4901
2884+0000abf0@4902
2885+0000ebf4@4903
2886+0000eb74@4906
2887+00006bf4@4908
2888+0000ebf4@4910
2889+0000fbf4@4912
2890+0000fb74@4914
2891+0000fbf4@4915
2892+00007bf6@4917
2893+0000fbf6@4919
2894+0000f356@4921
2895+0000b356@4922
2896+0000b3d6@4923
2897+000033d6@4926
2898+0000a356@4928
2899+0000afc2@4930
2900+00002f42@4936
2901+00002fc0@4937
2902+0000afc0@4938
2903+0000afe4@4939
2904+0000efc0@4940
2905+0000efe4@4941
2906+0000efc4@4942
2907+0000ef64@4943
2908+0000ef44@4944
2909+00006fe4@4945
2910+0000efe4@4947
2911+0000ffc4@4949
2912+0000ffe4@4950
2913+0000ff64@4951
2914+0000ffc4@4952
2915+0000ffe4@4953
2916+00007fe6@4954
2917+0000ffe6@4956
2918+0000f346@4958
2919+0000b346@4959
2920+0000b3c6@4960
2921+000033c6@4964
2922+0000a346@4965
2923+0000abe2@4967
2924+00002b62@4973
2925+00002b60@4974
2926+0000abe0@4975
2927+0000ebe4@4977
2928+0000eb64@4981
2929+00006be4@4982
2930+0000ebe4@4984
2931+0000fbe4@4987
2932+0000fb64@4988
2933+0000fbe4@4990
2934+00007be6@4992
2935+0000fbe6@4993
2936+0000ff7e@4995
2937+0000b53a@4996
2938+0000b5ba@4997
2939+000035ba@5001
2940+000025ba@5002
2941+0000a53a@5003
2942+0000a5ba@5004
2943+0000a102@5005
2944+0000a182@5006
2945+00002182@5010
2946+00002100@5011
2947+0000a180@5012
2948+0000e1a4@5014
2949+0000e3a4@5015
2950+0000e1a4@5016
2951+0000e324@5018
2952+00006324@5019
2953+00006184@5020
2954+0000e1a4@5021
2955+0000e3a4@5022
2956+0000f3a4@5024
2957+0000f324@5025
2958+0000f304@5026
2959+0000f3a4@5027
2960+000073a6@5029
2961+0000f3a6@5031
2962+0000f7be@5032
2963+0000f53a@5033
2964+0000b5ba@5035
2965+000035ba@5038
2966+0000a53a@5040
2967+0000a5ba@5041
2968+0000a102@5042
2969+0000a182@5043
2970+00002182@5047
2971+00002100@5048
2972+0000a180@5049
2973+0000a3a0@5051
2974+0000e3a4@5052
2975+0000e324@5055
2976+0000e104@5056
2977+000061a4@5057
2978+0000e3a4@5059
2979+0000f3a4@5061
2980+0000f324@5062
2981+0000f3a4@5064
2982+000073a6@5066
2983+0000f3a6@5068
2984+0000f93a@5070
2985+0000b9ba@5072
2986+000039ba@5075
2987+0000a93a@5077
2988+0000abc2@5079
2989+00002b42@5085
2990+00002b40@5086
2991+0000abc0@5087
2992+0000abe4@5088
2993+0000ebe0@5089
2994+0000ebe4@5090
2995+0000ebc4@5091
2996+0000eb64@5092
2997+0000eb44@5093
2998+00006be4@5094
2999+0000ebe4@5096
3000+0000fbc0@5098
3001+0000fbe4@5099
3002+0000fb64@5100
3003+0000fbe4@5101
3004+00007be6@5103
3005+0000fbe6@5105
3006+0000f97e@5107
3007+0000f93a@5108
3008+0000f9ba@5109
3009+000079ba@5113
3010+0000e9ba@5114
3011+0000e93a@5115
3012+0000ebe2@5116
3013+0000ebc2@5117
3014+00006b42@5122
3015+00006b40@5123
3016+0000ebc0@5124
3017+0000ebe4@5126
3018+0000ab24@5128
3019+0000a324@5129
3020+000023a4@5131
3021+0000a3a4@5133
3022+0000b3a4@5136
3023+0000b324@5137
3024+0000b3a4@5139
3025+000073a6@5141
3026+0000f3a6@5142
3027+0000fb7e@5144
3028+0000f97a@5145
3029+0000b9fa@5146
3030+000039fa@5150
3031+0000397a@5151
3032+0000a97a@5152
3033+0000a9fa@5153
3034+0000a102@5154
3035+0000a182@5155
3036+00002182@5159
3037+00002100@5160
3038+0000a180@5161
3039+0000e1a4@5163
3040+0000e3a4@5164
3041+0000e1a4@5165
3042+0000e3a4@5166
3043+0000e324@5167
3044+000063a4@5168
3045+000061a4@5169
3046+0000e1a4@5170
3047+0000e3a4@5171
3048+0000f3a4@5173
3049+0000f324@5174
3050+0000f304@5175
3051+0000f3a4@5176
3052+000073a6@5178
3053+0000f3a6@5180
3054+0000f3be@5181
3055+0000f11a@5182
3056+0000b11a@5183
3057+0000b19a@5184
3058+0000319a@5187
3059+0000a11a@5189
3060+0000a19a@5190
3061+0000a182@5191
3062+00002182@5196
3063+00002100@5197
3064+0000a180@5198
3065+0000a3a0@5200
3066+0000e3a4@5201
3067+0000e184@5203
3068+0000e324@5204
3069+0000e124@5205
3070+000061a4@5206
3071+0000e3a4@5208
3072+0000f184@5210
3073+0000f3a4@5211
3074+0000f104@5212
3075+0000f3a4@5213
3076+000073a6@5215
3077+0000f3a6@5217
3078+0000f35a@5219
3079+0000b3da@5221
3080+000033da@5224
3081+0000a35a@5226
3082+0000afc2@5228
3083+00002f42@5234
3084+00002fc0@5235
3085+0000afc0@5236
3086+0000afe4@5237
3087+0000efc0@5238
3088+0000efe4@5239
3089+0000efc0@5240
3090+0000ef64@5241
3091+0000ef44@5242
3092+00006fe4@5243
3093+00006fc4@5244
3094+0000efe4@5245
3095+0000ffc0@5247
3096+0000ffe4@5248
3097+0000ff44@5249
3098+0000ffc4@5250
3099+0000ffe4@5251
3100+00007fe6@5252
3101+0000ffe6@5254
3102+0000f346@5256
3103+0000b346@5257
3104+0000b3c6@5258
3105+000033c6@5262
3106+0000a346@5263
3107+0000abe2@5265
3108+00002b62@5271
3109+00002b60@5272
3110+0000abe0@5273
3111+0000abe4@5274
3112+0000ebe4@5275
3113+0000eb64@5279
3114+00006be4@5280
3115+0000ebe4@5282
3116+0000fbe4@5285
3117+0000fb64@5286
3118+0000fbe4@5288
3119+00007be6@5290
3120+0000fbe6@5291
3121+0000ff7e@5293
3122+0000b53a@5294
3123+0000b5ba@5295
3124+000035ba@5299
3125+0000a53a@5301
3126+0000a5ba@5302
3127+0000a102@5303
3128+0000a182@5304
3129+00002182@5308
3130+00002100@5309
3131+0000a180@5310
3132+0000e1a4@5312
3133+0000e3a4@5313
3134+0000e1a4@5314
3135+0000e324@5316
3136+000063a4@5317
3137+00006184@5318
3138+0000e1a4@5319
3139+0000e3a4@5320
3140+0000f3a4@5322
3141+0000f324@5323
3142+0000f304@5324
3143+0000f3a4@5325
3144+000073a6@5327
3145+0000f3a6@5329
3146+0000f7be@5330
3147+0000f53a@5331
3148+0000b5ba@5333
3149+000035ba@5336
3150+0000a53a@5338
3151+0000a182@5340
3152+00002182@5345
3153+00002100@5346
3154+0000a180@5347
3155+0000a3a0@5349
3156+0000e3a4@5350
3157+0000e324@5353
3158+0000e104@5354
3159+000061a4@5355
3160+0000e3a4@5357
3161+0000f3a4@5359
3162+0000f104@5361
3163+0000f3a4@5362
3164+000073a6@5364
3165+0000f3a6@5366
3166+0000f93e@5368
3167+0000b9be@5370
3168+000039be@5373
3169+0000a93e@5375
3170+0000abc2@5377
3171+00002b42@5383
3172+00002b40@5384
3173+0000abc0@5385
3174+0000abe4@5386
3175+0000ebe0@5387
3176+0000ebe4@5388
3177+0000eb64@5390
3178+00006be4@5392
3179+0000ebe4@5394
3180+0000fbc4@5396
3181+0000fbe4@5397
3182+0000fb64@5398
3183+0000fbe4@5399
3184+00007be6@5401
3185+0000fbe6@5403
3186+0000f97e@5405
3187+0000f93e@5406
3188+0000f9be@5407
3189+000079bc@5411
3190+0000f9bc@5412
3191+0000f93c@5413
3192+0000fbe0@5414
3193+0000fbc0@5415
3194+0000ebc0@5416
3195+00006b40@5420
3196+0000ebc0@5422
3197+0000ebe4@5424
3198+0000eb44@5428
3199+00006be4@5429
3200+00006bc4@5430
3201+0000ebe4@5431
3202+0000fbc4@5433
3203+0000fbe4@5434
3204+0000fb64@5435
3205+0000fb44@5436
3206+0000fbe4@5437
3207+00007be6@5439
3208+0000fbe6@5440
3209+0000fb5e@5442
3210+0000b11a@5443
3211+0000b19a@5444
3212+0000319a@5448
3213+0000a11a@5450
3214+0000a19a@5451
3215+0000a182@5452
3216+00002182@5457
3217+00002100@5458
3218+0000a180@5459
3219+0000e1a4@5461
3220+0000e3a4@5462
3221+0000e184@5463
3222+0000e3a4@5464
3223+0000e304@5465
3224+000063a4@5466
3225+00006184@5467
3226+0000e3a4@5468
3227+0000e1a4@5470
3228+0000f3a4@5471
3229+0000f324@5472
3230+0000f304@5473
3231+0000f3a4@5474
3232+000073a6@5476
3233+0000f3a6@5478
3234+0000f3be@5479
3235+0000f11a@5480
3236+0000b11a@5481
3237+0000b19a@5482
3238+0000319a@5485
3239+0000a11a@5487
3240+0000a19a@5488
3241+0000a182@5489
3242+00002182@5494
3243+00002100@5495
3244+0000a180@5496
3245+0000a3a0@5498
3246+0000e3a4@5499
3247+0000e384@5501
3248+0000e324@5502
3249+0000e104@5503
3250+000061a4@5504
3251+0000e3a4@5506
3252+0000f384@5508
3253+0000f3a4@5509
3254+0000f104@5510
3255+0000f3a4@5511
3256+000073a6@5513
3257+0000f3a6@5515
3258+0000f37e@5517
3259+0000f35e@5518
3260+0000b3de@5519
3261+000033de@5522
3262+0000a35e@5524
3263+0000afc2@5526
3264+00002f42@5532
3265+00002fc0@5533
3266+0000afc0@5534
3267+0000afe4@5535
3268+0000efc0@5536
3269+0000efe4@5537
3270+0000efc4@5538
3271+0000ef64@5539
3272+0000ef44@5540
3273+00006fe4@5541
3274+00006fc4@5542
3275+0000efe4@5543
3276+0000ffc4@5545
3277+0000ffe4@5546
3278+0000ff44@5547
3279+0000ffc4@5548
3280+0000ffe4@5549
3281+00007fe6@5550
3282+0000ffe6@5552
3283+0000f346@5554
3284+0000b346@5555
3285+0000b3c6@5556
3286+000033c6@5560
3287+0000a346@5561
3288+0000abe2@5563
3289+00002b62@5569
3290+00002b60@5570
3291+0000abe0@5571
3292+0000abe4@5572
3293+0000ebe4@5573
3294+0000eb64@5577
3295+00006be4@5578
3296+0000ebe4@5580
3297+0000fbe4@5583
3298+0000fb64@5584
3299+0000fbe4@5586
3300+00007be6@5588
3301+0000fbe6@5589
3302+0000fb7e@5591
3303+0000b91a@5592
3304+0000b99a@5593
3305+0000399a@5597
3306+0000a91a@5599
3307+0000abba@5600
3308+0000a7a2@5601
3309+000027a2@5606
3310+00002720@5607
3311+0000a7a0@5608
3312+0000a7a4@5610
3313+0000e7a4@5611
3314+0000e724@5614
3315+000067a4@5615
3316+0000e7a4@5617
3317+0000f7a4@5620
3318+0000f724@5621
3319+0000f7a4@5623
3320+000077a6@5625
3321+0000f7a6@5627
3322+0000ffbe@5628
3323+0000f93a@5629
3324+0000b93a@5630
3325+0000b9ba@5631
3326+000039ba@5634
3327+0000a93a@5636
3328+0000a9ba@5637
3329+0000af22@5638
3330+0000a7a2@5639
3331+000027a2@5643
3332+00002720@5644
3333+0000a7a0@5645
3334+0000a7a4@5647
3335+0000e7a4@5648
3336+0000e724@5651
3337+000067a4@5653
3338+0000e7a4@5655
3339+0000f7a4@5657
3340+0000f724@5658
3341+0000f7a4@5660
3342+000077a6@5662
3343+0000f7a6@5664
3344+0000f93a@5666
3345+0000f9ba@5668
3346+000079ba@5671
3347+0000e93a@5673
3348+0000efa2@5675
3349+0000e7a2@5676
3350+00006722@5681
3351+000067a0@5682
3352+0000e7a0@5683
3353+0000e7a4@5684
3354+0000e7a0@5685
3355+0000e7a4@5686
3356+0000a5e8@5687
3357+0000a568@5688
3358+0000a5e8@5689
3359+000025e8@5690
3360+0000a5e8@5692
3361+0000b5e8@5694
3362+0000b568@5696
3363+0000b5e8@5698
3364+000035ea@5699
3365+000075ea@5700
3366+0000f5ea@5701
3367+0000f93a@5703
3368+0000f9ba@5705
3369+000079ba@5709
3370+0000e9ba@5710
3371+0000e93a@5711
3372+0000efa2@5712
3373+0000e7a2@5713
3374+00006722@5718
3375+00006720@5719
3376+0000e7a0@5720
3377+0000e7a4@5721
3378+0000a7e8@5724
3379+0000a5e8@5725
3380+0000a568@5726
3381+000025e8@5727
3382+0000a5e8@5729
3383+0000b5e8@5732
3384+0000b568@5733
3385+0000b5e8@5735
3386+000075ea@5737
3387+0000f5ea@5738
3388+0000f53e@5740
3389+0000b11e@5741
3390+0000b19e@5742
3391+0000319e@5746
3392+0000a11e@5748
3393+0000a1de@5749
3394+0000a9d2@5750
3395+000029d2@5755
3396+00002950@5756
3397+0000a9d0@5757
3398+0000e9f4@5759
3399+0000ebf4@5760
3400+0000e9d4@5761
3401+0000eb54@5763
3402+00006bf4@5764
3403+000069d4@5765
3404+0000e9f4@5766
3405+0000ebf4@5767
3406+0000e9d4@5768
3407+0000fbf4@5769
3408+0000fb74@5770
3409+0000f954@5771
3410+0000fbf4@5772
3411+000079f6@5774
3412+00007bf6@5775
3413+0000fbf6@5776
3414+0000fbfe@5777
3415+0000f31e@5778
3416+0000b31e@5779
3417+0000b39e@5780
3418+0000339e@5783
3419+0000a31e@5785
3420+0000a39e@5786
3421+0000a9d2@5787
3422+000029d2@5792
3423+00002950@5793
3424+0000a950@5794
3425+0000a9d0@5795
3426+0000abf0@5796
3427+0000ebf4@5797
3428+0000ebd4@5799
3429+0000eb74@5800
3430+0000eb54@5801
3431+000069f4@5802
3432+00006bf4@5803
3433+0000ebf4@5804
3434+0000e9f4@5805
3435+0000fbf4@5806
3436+0000f954@5808
3437+0000fbf4@5809
3438+00007bf6@5811
3439+0000fbf6@5813
3440+0000f51e@5815
3441+0000b51e@5816
3442+0000b59e@5817
3443+0000359e@5820
3444+0000a59e@5822
3445+0000a51e@5823
3446+0000a9d2@5824
3447+00002952@5830
3448+00002950@5831
3449+0000a9d0@5832
3450+0000abf4@5833
3451+0000ebd0@5834
3452+0000ebf4@5835
3453+0000ebd4@5836
3454+0000eb74@5837
3455+0000eb54@5838
3456+00006bf4@5839
3457+000069d4@5840
3458+0000ebf4@5841
3459+0000f9d0@5843
3460+0000fbf4@5844
3461+0000fb54@5845
3462+0000fbd4@5846
3463+0000fbf4@5847
3464+00007bf6@5848
3465+0000fbf6@5850
3466+0000ff1e@5852
3467+0000b71e@5853
3468+0000b79e@5854
3469+0000379e@5858
3470+0000a79e@5859
3471+0000a71e@5860
3472+0000afd2@5861
3473+0000a9d2@5862
3474+00002952@5867
3475+00002950@5868
3476+0000a9d0@5869
3477+0000a9d4@5870
3478+0000ebf4@5871
3479+0000e9d4@5873
3480+0000ebf4@5874
3481+0000eb54@5875
3482+00006bf4@5876
3483+000069d4@5877
3484+0000e9f4@5878
3485+0000ebf4@5879
3486+0000e9d0@5880
3487+0000fbf4@5881
3488+0000fb74@5882
3489+0000f950@5883
3490+0000fbf4@5884
3491+000079f6@5886
3492+0000fbf6@5887
3493+0000fbd6@5888
3494+0000f95e@5889
3495+0000f91e@5890
3496+0000b99e@5891
3497+0000399e@5895
3498+0000a91e@5897
3499+0000a9fe@5898
3500+0000a5f2@5899
3501+00002572@5904
3502+00002570@5905
3503+0000a5f0@5906
3504+0000e5f4@5908
3505+0000e7f4@5909
3506+0000e5f4@5910
3507+0000e7f4@5911
3508+0000e774@5912
3509+000067f4@5913
3510+000065f4@5914
3511+0000e5f4@5915
3512+0000e7f4@5916
3513+0000f7f4@5918
3514+0000f774@5919
3515+0000f7f4@5921
3516+000077f6@5923
3517+0000f7f6@5925
3518+0000fffe@5926
3519+0000f93e@5927
3520+0000b9be@5928
3521+000039be@5932
3522+0000a93e@5934
3523+0000a9be@5935
3524+0000a5f2@5936
3525+000025f2@5941
3526+00002570@5942
3527+0000a5f0@5943
3528+0000a7f0@5945
3529+0000e7f4@5946
3530+0000e774@5949
3531+000065f4@5951
3532+0000e7f4@5952
3533+0000f7f4@5955
3534+0000f774@5956
3535+0000f7f4@5958
3536+000077f6@5960
3537+0000f7f6@5962
3538+0000fb1e@5964
3539+0000bb1e@5965
3540+0000bb9e@5966
3541+00003b9e@5969
3542+0000ab9e@5971
3543+0000ab1e@5972
3544+0000a5f2@5973
3545+00002572@5979
3546+00002570@5980
3547+0000a5f0@5981
3548+0000a7f4@5982
3549+0000e7f0@5983
3550+0000e7f4@5984
3551+0000e774@5986
3552+000067f4@5988
3553+0000e7f4@5990
3554+0000f7f0@5992
3555+0000f7f4@5993
3556+0000f774@5994
3557+0000f7f4@5995
3558+000077f6@5997
3559+0000f7f6@5999
3560+0000fd1e@6001
3561+0000b91e@6002
3562+0000b99e@6003
3563+0000399e@6007
3564+0000a99e@6008
3565+0000a91e@6009
3566+0000adf2@6010
3567+0000a5f2@6011
3568+00002572@6016
3569+00002570@6017
3570+0000a5f0@6018
3571+0000a5f4@6019
3572+0000e7f4@6020
3573+0000e5f4@6022
3574+0000e7f4@6023
3575+0000e774@6024
3576+000067f4@6025
3577+000065f4@6026
3578+0000e5f4@6027
3579+0000e7f4@6028
3580+0000f5f4@6029
3581+0000f7f4@6030
3582+0000f774@6031
3583+0000f7f4@6033
3584+000077f6@6035
3585+0000f7f6@6036
3586+0000fd3e@6038
3587+0000f93e@6039
3588+0000b9be@6040
3589+000039be@6044
3590+0000a93e@6046
3591+0000a9fe@6047
3592+0000a5f2@6048
3593+000025f2@6053
3594+00002570@6054
3595+0000a5f0@6055
3596+0000e5f4@6057
3597+0000e7f4@6058
3598+0000e5f4@6059
3599+0000e7f4@6060
3600+0000e774@6061
3601+000067f4@6062
3602+000065f4@6063
3603+0000e7f4@6064
3604+0000f7f4@6067
3605+0000f774@6068
3606+0000f7f4@6070
3607+000077f6@6072
3608+0000f7f6@6074
3609+0000f7fe@6075
3610+0000fb1e@6076
3611+0000bb9e@6077
3612+00003b9e@6081
3613+0000ab1e@6083
3614+0000ab9e@6084
3615+0000a5f2@6085
3616+000025f2@6090
3617+00002570@6091
3618+0000a5f0@6092
3619+0000a7f0@6094
3620+0000e7f4@6095
3621+0000e774@6098
3622+000065f4@6100
3623+000067f4@6101
3624+0000e7f4@6102
3625+0000f7f4@6104
3626+0000f774@6106
3627+0000f7f4@6107
3628+000077f6@6109
3629+0000f7f6@6111
3630+0000f91e@6113
3631+0000b91e@6114
3632+0000b99e@6115
3633+0000399e@6118
3634+0000a91e@6120
3635+0000a5f2@6122
3636+00002572@6128
3637+00002570@6129
3638+0000a5f0@6130
3639+0000a7f4@6131
3640+0000e7f0@6132
3641+0000e7f4@6133
3642+0000e774@6135
3643+000067f4@6137
3644+000065f4@6138
3645+0000e7f4@6139
3646+0000f5f4@6141
3647+0000f7f4@6142
3648+0000f774@6143
3649+0000f7f4@6144
3650+000077f6@6146
3651+0000f7f6@6148
3652+0000fd3e@6150
3653+0000b93e@6151
3654+0000b9be@6152
3655+000039be@6156
3656+0000a9be@6157
3657+0000a93e@6158
3658+0000adf2@6159
3659+0000a5f2@6160
3660+00002572@6165
3661+00002570@6166
3662+0000a5f0@6167
3663+0000a5f4@6168
3664+0000e7f4@6169
3665+0000e774@6173
3666+000067f4@6174
3667+000065f0@6175
3668+0000e7f4@6176
3669+0000e5f0@6178
3670+0000f7f4@6179
3671+0000f774@6180
3672+0000f7f4@6182
3673+000075f6@6184
3674+0000f7f6@6185
3675+0000ff3e@6187
3676+0000fb1e@6188
3677+0000bb9e@6189
3678+00003b9e@6193
3679+0000ab1e@6195
3680+0000abfe@6196
3681+0000a5f2@6197
3682+000025f2@6202
3683+00002570@6203
3684+0000a5f0@6204
3685+0000e5f4@6206
3686+0000e7f4@6207
3687+0000e5f4@6208
3688+0000e7f4@6209
3689+0000e774@6210
3690+000067f4@6211
3691+0000e5f4@6213
3692+0000e7f4@6214
3693+0000f7f4@6216
3694+0000f774@6217
3695+0000f7f4@6219
3696+000077f6@6221
3697+0000f7f6@6223
3698+0000fffe@6224
3699+0000f91e@6225
3700+0000b99e@6226
3701+0000399e@6230
3702+0000a91e@6232
3703+0000a99e@6233
3704+0000a5f2@6234
3705+000025f2@6239
3706+00002570@6240
3707+0000a570@6241
3708+0000a5f0@6242
3709+0000a7f0@6243
3710+0000e7f4@6244
3711+0000e774@6247
3712+000065f4@6249
3713+000067f4@6250
3714+0000e7f4@6251
3715+0000f7f4@6253
3716+0000f774@6255
3717+0000f7f4@6256
3718+000077f6@6258
3719+0000f7f6@6260
3720+0000f91e@6262
3721+0000f99e@6264
3722+0000799e@6267
3723+0000e99e@6269
3724+0000e91e@6270
3725+0000e5f2@6271
3726+00006570@6277
3727+0000e570@6278
3728+0000e5f0@6279
3729+0000e7f4@6280
3730+0000e7f0@6281
3731+0000a7f4@6282
3732+0000e188@6283
3733+0000a100@6284
3734+00002180@6286
3735+0000a180@6288
3736+0000b180@6290
3737+0000b100@6292
3738+0000b180@6293
3739+00003182@6295
3740+00007182@6296
3741+0000f182@6297
3742+0000f93e@6299
3743+0000f9be@6300
3744+0000b9be@6301
3745+000039be@6305
3746+0000a9be@6306
3747+0000a93e@6307
3748+0000adf2@6308
3749+0000a5f2@6309
3750+00002572@6314
3751+00002570@6315
3752+0000a5f0@6316
3753+0000a5f4@6317
3754+0000e7f4@6318
3755+0000e5f4@6320
3756+0000e7f4@6321
3757+0000e774@6322
3758+000067f4@6323
3759+000065f4@6324
3760+0000e5f4@6325
3761+0000e7f4@6326
3762+0000e5f0@6327
3763+0000f7f4@6328
3764+0000f774@6329
3765+0000f7f4@6331
3766+000075f6@6333
3767+0000f7f6@6334
3768+0000ff3e@6336
3769+0000fb1e@6337
3770+0000bb9e@6338
3771+00003b9e@6342
3772+0000ab1e@6344
3773+0000abfe@6345
3774+0000a5f2@6346
3775+00002572@6351
3776+00002570@6352
3777+0000a5f0@6353
3778+0000e5f4@6355
3779+0000e7f4@6356
3780+0000e5f4@6357
3781+0000e7f4@6358
3782+0000e774@6359
3783+000067f4@6360
3784+000065f4@6361
3785+0000e5f4@6362
3786+0000e7f4@6363
3787+0000f7f4@6365
3788+0000f774@6366
3789+0000f7f4@6368
3790+000077f6@6370
3791+0000f7f6@6372
3792+0000fffe@6373
3793+0000f91a@6374
3794+0000b99a@6375
3795+0000399a@6379
3796+0000a91a@6381
3797+0000a99a@6382
3798+0000a5f2@6383
3799+000025f2@6388
3800+00002570@6389
3801+0000a5f0@6390
3802+0000a7f0@6392
3803+0000e7f4@6393
3804+0000e774@6396
3805+000065f4@6398
3806+0000e7f4@6400
3807+0000f7f4@6402
3808+0000f774@6404
3809+0000f7f4@6405
3810+000077f6@6407
3811+0000f7f6@6409
3812+0000f93a@6411
3813+0000b93a@6412
3814+0000b9ba@6413
3815+000039ba@6416
3816+0000a93a@6418
3817+0000a5f2@6420
3818+00002572@6426
3819+00002570@6427
3820+0000a5f0@6428
3821+0000a7f4@6429
3822+0000e7f0@6430
3823+0000e7f4@6431
3824+0000e774@6433
3825+000067f4@6435
3826+000065f4@6436
3827+0000e7f4@6437
3828+0000f5f0@6439
3829+0000f7f4@6440
3830+0000f774@6441
3831+0000f7f4@6442
3832+000077f6@6444
3833+0000f7f6@6446
3834+0000ff1e@6448
3835+0000bb1a@6449
3836+0000bb9a@6450
3837+00003b9a@6454
3838+0000ab9a@6455
3839+0000ab1a@6456
3840+0000aff2@6457
3841+0000a5f2@6458
3842+00002572@6463
3843+00002570@6464
3844+0000a5f0@6465
3845+0000a5f4@6466
3846+0000e7f4@6467
3847+0000e774@6471
3848+000067f4@6472
3849+000065f0@6473
3850+0000e7f4@6474
3851+0000f7f0@6476
3852+0000f7f4@6477
3853+0000f774@6478
3854+0000f770@6479
3855+0000f7f4@6480
3856+000077f6@6482
3857+0000f7f6@6483
3858+0000fd7e@6485
3859+0000f81a@6486
3860+0000b89a@6487
3861+0000389a@6491
3862+0000a81a@6493
3863+0000a8fa@6494
3864+0000a4f2@6495
3865+00002472@6500
3866+00002470@6501
3867+0000a470@6502
3868+0000e474@6504
3869+0000e6f4@6505
3870+000066f4@6509
3871+00006474@6510
3872+0000e474@6511
3873+0000e674@6512
3874+0000e474@6513
3875+0000f6f4@6514
3876+00007476@6519
3877+00007676@6520
3878+0000f676@6521
3879+0000fe7e@6522
3880+0000f8ba@6523
3881+0000b8ba@6524
3882+000038ba@6528
3883+0000383a@6529
3884+0000a83a@6530
3885+0000a472@6532
3886+0000a4f2@6533
3887+000024f2@6537
3888+00002470@6538
3889+0000a470@6539
3890+0000a670@6541
3891+0000e6f4@6542
3892+00006474@6547
3893+0000e674@6549
3894+0000f6f4@6551
3895+00007676@6556
3896+0000f676@6558
3897+0000fa1a@6560
3898+0000ba9a@6561
3899+00003a9a@6565
3900+00003a1a@6566
3901+0000aa1a@6567
3902+0000a4f2@6569
3903+00002472@6575
3904+0000a470@6576
3905+0000a674@6578
3906+0000e6f0@6579
3907+0000e6f4@6580
3908+00006674@6584
3909+00006470@6585
3910+0000e674@6586
3911+0000f6f4@6588
3912+000076f6@6593
3913+00007676@6594
3914+0000f676@6595
3915+0000f61e@6597
3916+0000b29a@6598
3917+0000321a@6603
3918+0000a21a@6604
3919+0000a672@6606
3920+0000a4f2@6607
3921+00002472@6612
3922+00002470@6613
3923+0000a470@6614
3924+0000a474@6615
3925+0000e6f4@6616
3926+0000e4f4@6617
3927+0000e6f4@6618
3928+000066f4@6621
3929+00006470@6622
3930+0000e474@6623
3931+0000e674@6624
3932+0000e474@6625
3933+0000f6f4@6626
3934+00007476@6631
3935+0000f676@6632
3936+0000f67e@6634
3937+0000b29a@6635
3938+0000329a@6640
3939+0000221a@6641
3940+0000a29a@6642
3941+0000a6fa@6643
3942+0000a4f2@6644
3943+0000a472@6647
3944+000024f2@6649
3945+000024f0@6650
3946+0000a4f0@6651
3947+0000e4f4@6653
3948+0000e6f4@6654
3949+0000e674@6655
3950+0000e474@6656
3951+0000e674@6657
3952+00006674@6658
3953+000064f4@6659
3954+0000e4f4@6660
3955+0000e6f4@6661
3956+0000f6f4@6663
3957+0000f674@6664
3958+000074f6@6668
3959+000076f6@6669
3960+0000f6f6@6670
3961+0000f6fe@6671
3962+0000f29a@6672
3963+0000b29a@6673
3964+0000b21a@6674
3965+0000329a@6677
3966+0000a29a@6679
3967+0000a4f2@6681
3968+0000a472@6683
3969+00002472@6686
3970+000024f0@6687
3971+0000a4f0@6688
3972+0000a6f0@6690
3973+0000e6f4@6691
3974+0000e674@6692
3975+000064f4@6696
3976+0000e6f4@6698
3977+0000f6f4@6700
3978+0000f674@6702
3979+00007676@6705
3980+000076f6@6706
3981+0000f6f6@6707
3982+0000f2ae@6709
3983+0000b2ae@6710
3984+0000b22e@6711
3985+000032ae@6714
3986+0000a2ae@6716
3987+0000a082@6718
3988+0000a002@6720
3989+00002082@6724
3990+00002080@6725
3991+0000a080@6726
3992+0000a2a4@6727
3993+0000e280@6728
3994+0000e2a4@6729
3995+0000e204@6730
3996+0000e224@6731
3997+0000e204@6732
3998+00006224@6733
3999+000060a4@6734
4000+0000e2a4@6735
4001+0000f284@6737
4002+0000f2a4@6738
4003+0000f224@6739
4004+0000f204@6740
4005+0000f224@6741
4006+00007226@6742
4007+00007286@6743
4008+0000f2a6@6744
4009+0000faa6@6745
4010+0000f2ae@6746
4011+0000f22e@6748
4012+000072ae@6752
4013+0000e2ae@6753
4014+0000e2aa@6755
4015+0000e082@6756
4016+0000e002@6757
4017+00006082@6761
4018+00006080@6762
4019+0000e080@6763
4020+0000e084@6764
4021+0000e2a4@6765
4022+0000e084@6766
4023+0000a60c@6767
4024+0000e60c@6768
4025+0000a60c@6769
4026+0000260c@6770
4027+0000268c@6771
4028+0000a68c@6772
4029+0000b68c@6774
4030+0000b60c@6776
4031+0000768e@6780
4032+0000f68e@6781
4033+0000f69e@6783
4034+0000b49e@6784
4035+0000b41e@6786
4036+0000349e@6789
4037+0000a49e@6791
4038+0000a4fe@6792
4039+0000aaf2@6793
4040+0000aa72@6795
4041+0000aaf2@6796
4042+00002af2@6798
4043+00002af0@6799
4044+0000aaf0@6800
4045+0000ea74@6802
4046+0000eaf4@6804
4047+00006af4@6807
4048+0000eaf4@6809
4049+0000ea74@6810
4050+0000fa74@6812
4051+0000faf4@6813
4052+00007af6@6817
4053+0000fa76@6819
4054+0000fe76@6820
4055+0000f426@6821
4056+0000b426@6822
4057+0000b4a6@6823
4058+000034a6@6826
4059+0000a426@6828
4060+0000a472@6830
4061+0000a4f2@6832
4062+000024f2@6835
4063+000024f0@6836
4064+0000a4f0@6837
4065+0000a470@6838
4066+0000a670@6839
4067+0000e674@6840
4068+0000e6f4@6841
4069+000064f4@6845
4070+0000e674@6847
4071+0000e474@6848
4072+0000f674@6849
4073+0000f6f4@6851
4074+000076f6@6854
4075+0000f676@6856
4076+0000f606@6858
4077+0000b606@6859
4078+0000b686@6860
4079+00003686@6863
4080+0000a686@6865
4081+0000a606@6866
4082+0000a472@6867
4083+0000a4f2@6869
4084+000024f2@6873
4085+0000a4f0@6874
4086+0000a470@6875
4087+0000a674@6876
4088+0000e670@6877
4089+0000e674@6878
4090+0000e6f4@6879
4091+000066f4@6882
4092+000064f4@6883
4093+0000e674@6884
4094+0000f674@6886
4095+0000f6f4@6888
4096+000076f6@6891
4097+0000f6f6@6893
4098+0000f676@6894
4099+0000f626@6895
4100+0000b626@6896
4101+0000b6a6@6897
4102+000036a6@6901
4103+0000a6a6@6902
4104+0000a626@6903
4105+0000a672@6904
4106+0000a472@6905
4107+0000a4f2@6906
4108+000024f2@6910
4109+000024f0@6911
4110+0000a470@6912
4111+0000a474@6913
4112+0000e674@6914
4113+0000e474@6915
4114+0000e6f4@6916
4115+000066f4@6919
4116+000064f4@6920
4117+0000e674@6921
4118+0000f674@6924
4119+0000f6f4@6925
4120+000074f6@6929
4121+0000f6f6@6930
4122+0000f676@6931
4123+0000b226@6933
4124+0000b2a6@6934
4125+000032a6@6938
4126+0000a226@6940
4127+0000a002@6942
4128+0000a082@6944
4129+00002082@6947
4130+00002080@6948
4131+0000a000@6949
4132+0000a080@6950
4133+0000e0a4@6951
4134+0000e2a4@6952
4135+000062a4@6956
4136+00006004@6957
4137+0000e0a4@6958
4138+0000e2a4@6959
4139+0000e0a4@6960
4140+0000f2a4@6961
4141+0000f224@6964
4142+00007026@6966
4143+00007226@6967
4144+0000f2a6@6968
4145+0000fabe@6969
4146+0000f8be@6970
4147+0000f9be@6971
4148+0000b9be@6972
4149+0000b93e@6974
4150+0000393e@6975
4151+0000a9be@6977
4152+0000abc2@6979
4153+0000ab42@6983
4154+00002b42@6984
4155+00002b40@6985
4156+0000ab40@6986
4157+0000abc0@6987
4158+0000abe0@6988
4159+0000ebe4@6989
4160+0000eb64@6992
4161+00006b64@6994
4162+0000eb44@6995
4163+0000ebe4@6996
4164+0000fbe4@6998
4165+0000fb64@7002
4166+00007b66@7003
4167+00007b46@7004
4168+0000fbe6@7005
4169+0000f3a6@7007
4170+0000b3a6@7008
4171+0000b326@7011
4172+00003326@7012
4173+0000a326@7014
4174+0000a3a6@7015
4175+0000a182@7016
4176+0000a102@7020
4177+00002102@7022
4178+0000a100@7023
4179+0000a180@7024
4180+0000a3a4@7025
4181+0000e3a0@7026
4182+0000e3a4@7027
4183+0000e324@7029
4184+0000e304@7030
4185+00006324@7031
4186+00006304@7032
4187+0000e3a4@7033
4188+0000f384@7035
4189+0000f3a4@7036
4190+0000f324@7039
4191+00007326@7040
4192+00007306@7041
4193+0000f3a6@7042
4194+0000f19e@7044
4195+0000b19e@7046
4196+0000b11e@7048
4197+0000311e@7050
4198+0000a11e@7051
4199+0000a19e@7052
4200+0000a182@7053
4201+0000a102@7057
4202+00002102@7059
4203+00002100@7060
4204+0000a180@7061
4205+0000a184@7062
4206+0000e3a4@7063
4207+0000e184@7065
4208+0000e3a4@7066
4209+0000e304@7067
4210+00006304@7068
4211+00006104@7069
4212+0000e1a4@7070
4213+0000e3a4@7071
4214+0000f184@7072
4215+0000f3a4@7073
4216+0000f384@7075
4217+0000f324@7076
4218+00007304@7077
4219+00007106@7078
4220+0000f326@7079
4221+0000f3a6@7080
4222+0000f19e@7081
4223+0000b19e@7083
4224+0000b11e@7085
4225+0000311e@7087
4226+0000211e@7088
4227+0000a19e@7089
4228+0000a182@7091
4229+0000a102@7095
4230+00002102@7096
4231+00002100@7097
4232+0000a180@7098
4233+0000e1a4@7100
4234+0000e3a4@7101
4235+0000e1a4@7102
4236+0000e3a4@7103
4237+0000e304@7104
4238+000063a4@7105
4239+00006184@7106
4240+0000e1a4@7107
4241+0000e3a4@7108
4242+0000e1a4@7109
4243+0000f3a4@7110
4244+0000f324@7111
4245+0000f304@7112
4246+0000f3a4@7113
4247+000073a6@7115
4248+0000f3a6@7117
4249+0000f3fe@7118
4250+0000f15e@7119
4251+0000b1de@7120
4252+000031de@7124
4253+0000a15e@7126
4254+0000bf42@7128
4255+0000afc2@7129
4256+00002fc2@7133
4257+00002f40@7134
4258+0000afc0@7135
4259+0000afe0@7137
4260+0000efe4@7138
4261+0000efc4@7140
4262+0000ef64@7141
4263+0000ef44@7142
4264+00006fe4@7143
4265+0000efe4@7144
4266+0000ffe4@7147
4267+0000ff64@7148
4268+0000ff44@7149
4269+0000ffe4@7150
4270+00007fe6@7152
4271+0000ffe6@7154
4272+0000f356@7156
4273+0000b3d6@7158
4274+000033d6@7161
4275+0000a356@7163
4276+0000a7f2@7165
4277+00002770@7171
4278+0000a7f0@7172
4279+0000a7f4@7174
4280+0000e7f0@7175
4281+0000e7f4@7176
4282+0000e774@7178
4283+000067f4@7180
4284+0000e7f4@7182
4285+0000f7f4@7184
4286+0000f774@7186
4287+0000f7f4@7187
4288+000077f6@7189
4289+0000f7f6@7191
4290+0000f53e@7193
4291+0000b53e@7194
4292+0000b5be@7195
4293+000035be@7199
4294+0000a5be@7200
4295+0000a53e@7201
4296+0000afa2@7202
4297+0000ab82@7203
4298+00002b02@7208
4299+00002b00@7209
4300+0000ab80@7210
4301+0000ab84@7211
4302+0000eba4@7212
4303+0000eb24@7215
4304+00006ba4@7217
4305+00006b84@7218
4306+0000eba4@7219
4307+0000fba4@7222
4308+0000fb24@7223
4309+0000fb04@7224
4310+0000fba4@7225
4311+00007ba4@7226
4312+00007ba6@7227
4313+0000fba6@7228
4314+0000ff1e@7230
4315+0000f71e@7231
4316+0000b79e@7232
4317+0000379e@7236
4318+0000a71e@7238
4319+0000a79e@7239
4320+0000ab02@7240
4321+0000ab82@7241
4322+00002b82@7245
4323+00002b00@7246
4324+0000ab80@7247
4325+0000eba4@7249
4326+0000eb04@7253
4327+00006ba4@7254
4328+00006b84@7255
4329+0000eba4@7256
4330+0000fba4@7259
4331+0000fb24@7260
4332+0000fb04@7261
4333+0000fba4@7262
4334+00007ba6@7264
4335+0000fba6@7266
4336+0000f902@7268
4337+0000b982@7269
4338+00003982@7273
4339+0000a902@7275
4340+0000a982@7276
4341+0000abc2@7277
4342+00002bc2@7282
4343+00002b40@7283
4344+0000abc0@7284
4345+0000abe0@7286
4346+0000ebe4@7287
4347+0000eb64@7290
4348+00006be4@7292
4349+0000ebe4@7293
4350+0000fbe4@7296
4351+0000fb64@7297
4352+0000fb44@7298
4353+0000fbe4@7299
4354+00007be6@7301
4355+0000fbe6@7303
4356+0000f902@7305
4357+0000f982@7307
4358+00007982@7310
4359+0000e902@7312
4360+0000ebc2@7314
4361+00006b40@7320
4362+0000eb40@7321
4363+0000ebc0@7322
4364+0000ebe4@7323
4365+0000ebc0@7324
4366+0000abe4@7325
4367+0000e180@7326
4368+0000a100@7327
4369+00002180@7329
4370+0000a180@7331
4371+0000b180@7333
4372+0000b100@7335
4373+0000b180@7336
4374+00003182@7338
4375+00007182@7339
4376+0000f182@7340
4377+0000f11e@7342
4378+0000b19e@7344
4379+0000319e@7348
4380+0000a19e@7349
4381+0000a11e@7350
4382+0000a182@7351
4383+00002102@7357
4384+00002100@7358
4385+0000a180@7359
4386+0000a184@7360
4387+0000e3a4@7361
4388+0000e184@7363
4389+0000e3a4@7364
4390+0000e304@7365
4391+000063a4@7366
4392+00006184@7367
4393+0000e1a4@7368
4394+0000e3a4@7369
4395+0000f180@7370
4396+0000f3a4@7371
4397+0000f304@7372
4398+0000f3a4@7374
4399+000071a6@7376
4400+0000f3a6@7377
4401+0000f11e@7379
4402+0000b19e@7381
4403+0000319e@7385
4404+0000a11e@7387
4405+0000a19e@7388
4406+0000a182@7389
4407+00002182@7394
4408+00002100@7395
4409+0000a180@7396
4410+0000e1a4@7398
4411+0000e3a4@7399
4412+0000e184@7400
4413+0000e3a4@7401
4414+0000e304@7402
4415+000063a4@7403
4416+00006184@7404
4417+0000e1a4@7405
4418+0000e3a4@7406
4419+0000f3a4@7408
4420+0000f324@7409
4421+0000f104@7410
4422+0000f3a4@7411
4423+000073a6@7413
4424+0000f3a6@7415
4425+0000f3e6@7416
4426+0000f162@7417
4427+0000b1e2@7418
4428+000031e2@7422
4429+00003162@7423
4430+0000a162@7424
4431+0000a1e2@7425
4432+0000bf42@7426
4433+0000afc2@7427
4434+00002fc2@7431
4435+00002f40@7432
4436+0000afc0@7433
4437+0000afe0@7435
4438+0000efe4@7436
4439+0000ef64@7439
4440+00006fe4@7441
4441+0000efe4@7442
4442+0000ffe4@7445
4443+0000ff64@7446
4444+0000ff44@7447
4445+0000ffe4@7448
4446+00007fe6@7450
4447+0000ffe6@7452
4448+0000f346@7454
4449+0000b346@7455
4450+0000b3c6@7456
4451+000033c6@7459
4452+0000a346@7461
4453+0000abe2@7463
4454+00002b60@7469
4455+0000abe0@7470
4456+0000abe4@7472
4457+0000ebe0@7473
4458+0000ebe4@7474
4459+0000eb64@7476
4460+00006be4@7478
4461+0000ebe4@7480
4462+0000fbe4@7482
4463+0000fb64@7484
4464+0000fbe4@7485
4465+00007be6@7487
4466+0000fbe6@7489
4467+0000ff3e@7491
4468+0000f73e@7492
4469+0000b7be@7493
4470+000037be@7497
4471+0000a7be@7498
4472+0000a73e@7499
4473+0000afa2@7500
4474+0000ab82@7501
4475+00002b02@7506
4476+00002b00@7507
4477+0000ab80@7508
4478+0000ab84@7509
4479+0000eba4@7510
4480+0000eb24@7514
4481+00006ba4@7515
4482+0000eba4@7517
4483+0000fba4@7520
4484+0000fb24@7521
4485+0000fba4@7523
4486+00007ba4@7524
4487+00007ba6@7525
4488+0000fba6@7526
4489+0000fb1e@7528
4490+0000f91e@7529
4491+0000b99e@7530
4492+0000399e@7534
4493+0000a91e@7536
4494+0000ab9e@7537
4495+0000ab82@7538
4496+00002b82@7543
4497+00002b00@7544
4498+0000ab80@7545
4499+0000eba4@7547
4500+0000eb24@7551
4501+00006ba4@7552
4502+0000eba4@7554
4503+0000fba4@7557
4504+0000fb24@7558
4505+0000fb04@7559
4506+0000fba4@7560
4507+00007ba6@7562
4508+0000fba6@7564
4509+0000f906@7566
4510+0000b986@7567
4511+00003986@7571
4512+00003906@7572
4513+0000a906@7573
4514+0000a986@7574
4515+0000abc2@7575
4516+00002bc2@7580
4517+00002b40@7581
4518+0000abc0@7582
4519+0000abe0@7584
4520+0000ebe4@7585
4521+0000eb64@7588
4522+00006be4@7590
4523+0000ebe4@7591
4524+0000fbe4@7594
4525+0000fb64@7595
4526+0000fb44@7596
4527+0000fbe4@7597
4528+00007be6@7599
4529+0000fbe6@7601
4530+0000f906@7603
4531+0000f986@7605
4532+00007986@7608
4533+0000e986@7610
4534+0000e906@7611
4535+0000ebc2@7612
4536+00006b40@7618
4537+0000eb40@7619
4538+0000ebc0@7620
4539+0000ebe4@7621
4540+0000ebc0@7622
4541+0000abe4@7623
4542+0000e180@7624
4543+0000a100@7625
4544+00002180@7627
4545+0000a180@7629
4546+0000b180@7631
4547+0000b100@7633
4548+0000b180@7634
4549+00003182@7636
4550+00007182@7637
4551+0000f182@7638
4552+0000f11e@7640
4553+0000b19e@7642
4554+0000319e@7646
4555+0000a11e@7647
4556+0000a182@7649
4557+00002102@7655
4558+00002100@7656
4559+0000a180@7657
4560+0000a184@7658
4561+0000e3a4@7659
4562+0000e184@7661
4563+0000e3a4@7662
4564+0000e304@7663
4565+000063a4@7664
4566+00006184@7665
4567+0000e1a4@7666
4568+0000e3a4@7667
4569+0000e180@7668
4570+0000f3a4@7669
4571+0000f304@7670
4572+0000f3a4@7672
4573+000071a6@7674
4574+0000f3a6@7675
4575+0000f97e@7677
4576+0000f9fe@7678
4577+0000b9fe@7679
4578+000039fe@7683
4579+0000397e@7684
4580+0000a97e@7685
4581+0000a9fe@7686
4582+0000a102@7687
4583+0000a182@7688
4584+00002182@7692
4585+00002100@7693
4586+0000a180@7694
4587+0000e1a4@7696
4588+0000e3a4@7697
4589+0000e1a4@7698
4590+0000e304@7700
4591+000063a4@7701
4592+00006184@7702
4593+0000e1a4@7703
4594+0000e3a4@7704
4595+0000e1a4@7705
4596+0000f3a4@7706
4597+0000f324@7707
4598+0000f104@7708
4599+0000f3a4@7709
4600+000071a6@7711
4601+000073a6@7712
4602+0000f3a6@7713
4603+0000f3e6@7714
4604+0000f166@7715
4605+0000b1e6@7716
4606+000031e6@7720
4607+00003166@7721
4608+0000a166@7722
4609+0000a1e6@7723
4610+0000bf42@7724
4611+0000afc2@7725
4612+00002fc2@7729
4613+00002f40@7730
4614+0000afc0@7731
4615+0000afe0@7733
4616+0000efe4@7734
4617+0000ef64@7737
4618+00006fe4@7739
4619+0000efe4@7740
4620+0000ffe4@7743
4621+0000ff64@7744
4622+0000ff44@7745
4623+0000ffe4@7746
4624+00007fe6@7748
4625+0000ffe6@7750
4626+0000f346@7752
4627+0000b346@7753
4628+0000b3c6@7754
4629+000033c6@7757
4630+0000a346@7759
4631+0000abe2@7761
4632+00002b60@7767
4633+0000abe0@7768
4634+0000abe4@7770
4635+0000ebe0@7771
4636+0000ebe4@7772
4637+0000eb64@7774
4638+00006be4@7776
4639+0000ebe4@7778
4640+0000fbe4@7780
4641+0000fb64@7782
4642+0000fbe4@7783
4643+00007be6@7785
4644+0000fbe6@7787
4645+0000f93e@7789
4646+0000b9be@7791
4647+000039be@7795
4648+0000a9be@7796
4649+0000a93e@7797
4650+0000ab82@7798
4651+00002b02@7804
4652+00002b00@7805
4653+0000ab80@7806
4654+0000ab84@7807
4655+0000eba4@7808
4656+0000eb24@7812
4657+00006ba4@7813
4658+0000eba4@7815
4659+0000fba4@7818
4660+0000fb24@7819
4661+0000fb04@7820
4662+0000fba4@7821
4663+00007ba4@7822
4664+00007ba6@7823
4665+0000fba6@7824
4666+0000fb1e@7826
4667+0000f31e@7827
4668+0000b39e@7828
4669+0000339e@7832
4670+0000331e@7833
4671+0000a31e@7834
4672+0000a7be@7835
4673+0000ada2@7836
4674+00002da2@7841
4675+00002d20@7842
4676+0000ada0@7843
4677+0000eda4@7845
4678+0000efa4@7846
4679+0000eda4@7847
4680+0000efa4@7848
4681+0000ef24@7849
4682+00006fa4@7850
4683+00006da4@7851
4684+0000efa4@7852
4685+0000ffa4@7855
4686+0000ff24@7856
4687+0000ffa4@7858
4688+00007fa6@7860
4689+0000ffa6@7862
4690+0000ffae@7863
4691+0000f90a@7864
4692+0000b98a@7865
4693+0000398a@7869
4694+0000a90a@7871
4695+0000a98a@7872
4696+0000abc2@7873
4697+00002bc2@7878
4698+00002b40@7879
4699+0000abc0@7880
4700+0000abe0@7882
4701+0000ebe4@7883
4702+0000ebc4@7885
4703+0000eb64@7886
4704+00006be4@7888
4705+0000ebe4@7889
4706+0000fbe4@7892
4707+0000fb64@7893
4708+0000fb44@7894
4709+0000fbe4@7895
4710+00007be6@7897
4711+0000fbe6@7899
4712+0000f90a@7901
4713+0000f98a@7903
4714+0000798a@7906
4715+0000e90a@7908
4716+0000ebc2@7910
4717+00006b40@7916
4718+0000eb40@7917
4719+0000ebc0@7918
4720+0000ebe4@7919
4721+0000ebe0@7920
4722+0000abe4@7921
4723+0000a5e0@7922
4724+0000a560@7923
4725+0000a5e0@7924
4726+000025e0@7925
4727+0000a5e0@7927
4728+0000b5e0@7929
4729+0000b560@7931
4730+0000b5e0@7932
4731+000035e2@7934
4732+000075e2@7935
4733+0000f5e2@7936
4734+0000f91e@7938
4735+0000b91e@7939
4736+0000b99e@7940
4737+0000399e@7944
4738+0000a99e@7945
4739+0000a91e@7946
4740+0000abd2@7947
4741+00002b52@7953
4742+00002b50@7954
4743+0000abd0@7955
4744+0000abf4@7956
4745+0000ebf4@7957
4746+0000ebd4@7959
4747+0000ebf4@7960
4748+0000eb54@7961
4749+00006bf4@7962
4750+00006bd4@7963
4751+0000ebf4@7964
4752+0000ebd0@7966
4753+0000fbf4@7967
4754+0000fb74@7968
4755+0000fb54@7969
4756+0000fbf4@7970
4757+00007bf4@7971
4758+00007bf6@7972
4759+0000fbf6@7973
4760+0000fb1e@7975
4761+0000b91e@7976
4762+0000b99e@7977
4763+0000399e@7981
4764+0000299e@7982
4765+0000a91e@7983
4766+0000abde@7984
4767+0000abd2@7985
4768+00002b52@7990
4769+00002b50@7991
4770+0000abd0@7992
4771+0000ebf4@7994
4772+0000ebd4@7997
4773+0000eb54@7998
4774+00006bf4@7999
4775+00006bd4@8000
4776+0000ebf4@8001
4777+0000fbf4@8004
4778+0000fb74@8005
4779+0000fb54@8006
4780+0000fbf4@8007
4781+00007bf6@8009
4782+0000fbf6@8011
4783+0000fbfe@8012
4784+0000f16a@8013
4785+0000b1ea@8014
4786+000031ea@8018
4787+0000a16a@8020
4788+0000a1ea@8021
4789+0000bf42@8022
4790+0000afc2@8023
4791+00002fc2@8027
4792+00002f40@8028
4793+0000afc0@8029
4794+0000afe0@8031
4795+0000efe4@8032
4796+0000ef64@8035
4797+0000ef44@8036
4798+00006fe4@8037
4799+0000efe4@8038
4800+0000ffe4@8041
4801+0000ff64@8042
4802+0000ffe4@8044
4803+00007fe6@8046
4804+0000ffe6@8048
4805+0000f346@8050
4806+0000b346@8051
4807+0000b3c6@8052
4808+000033c6@8055
4809+0000a346@8057
4810+0000abe2@8059
4811+00002b60@8065
4812+0000abe0@8066
4813+0000abe4@8068
4814+0000ebe4@8069
4815+0000eb64@8072
4816+00006be4@8074
4817+0000ebe4@8076
4818+0000fbe4@8078
4819+0000fb64@8080
4820+0000fbe4@8081
4821+00007be6@8083
4822+0000fbe6@8085
4823+0000f33e@8087
4824+0000b3be@8089
4825+000033be@8093
4826+0000a3be@8094
4827+0000a33e@8095
4828+0000afa2@8096
4829+0000ada2@8097
4830+00002d22@8102
4831+00002d20@8103
4832+0000ada0@8104
4833+0000ada4@8105
4834+0000efa4@8106
4835+0000ef24@8110
4836+00006fa4@8111
4837+0000efa4@8113
4838+0000efa0@8115
4839+0000ffa4@8116
4840+0000ff24@8117
4841+0000ffa4@8119
4842+00007fa4@8120
4843+00007fa6@8121
4844+0000ffa6@8122
4845+0000fd3e@8124
4846+0000f51e@8125
4847+0000b59e@8126
4848+0000359e@8130
4849+0000351e@8131
4850+0000a51e@8132
4851+0000a5be@8133
4852+0000ada2@8134
4853+00002da2@8139
4854+00002d20@8140
4855+0000ada0@8141
4856+0000eda4@8143
4857+0000efa4@8144
4858+0000eda4@8145
4859+0000efa4@8146
4860+0000ef24@8147
4861+00006fa4@8148
4862+00006da4@8149
4863+0000eda4@8150
4864+0000efa4@8151
4865+0000eda4@8152
4866+0000ffa4@8153
4867+0000ff24@8154
4868+0000ffa4@8156
4869+00007da6@8158
4870+00007fa6@8159
4871+0000ffa6@8160
4872+0000ffae@8161
4873+0000f90e@8162
4874+0000b98e@8163
4875+0000398e@8167
4876+0000a90e@8169
4877+0000a98e@8170
4878+0000abc2@8171
4879+00002bc2@8176
4880+00002b40@8177
4881+0000abc0@8178
4882+0000abe0@8180
4883+0000ebe4@8181
4884+0000eb64@8184
4885+00006be4@8186
4886+0000ebe4@8187
4887+0000fbe4@8190
4888+0000fb64@8191
4889+0000fb44@8192
4890+0000fbe4@8193
4891+00007be6@8195
4892+0000fbe6@8197
4893+0000f90e@8199
4894+0000f98e@8201
4895+0000798e@8204
4896+0000798c@8205
4897+0000f90c@8206
4898+0000fbc0@8208
4899+0000ebc0@8210
4900+00006b40@8214
4901+0000eb40@8215
4902+0000ebc0@8216
4903+0000ebe4@8217
4904+0000ebe0@8218
4905+0000ebe4@8219
4906+0000ebc4@8220
4907+0000eb64@8221
4908+0000eb44@8222
4909+00006be4@8223
4910+0000ebe4@8225
4911+0000fbc4@8227
4912+0000fbe4@8228
4913+0000fb44@8229
4914+0000fbe4@8230
4915+00007be6@8232
4916+0000fbe6@8234
4917+0000f91e@8236
4918+0000b99e@8238
4919+0000399e@8242
4920+0000a99e@8243
4921+0000a91e@8244
4922+0000abd2@8245
4923+00002b52@8251
4924+00002b50@8252
4925+0000abd0@8253
4926+0000abf4@8254
4927+0000ebf4@8255
4928+0000ebd4@8257
4929+0000eb74@8258
4930+0000eb54@8259
4931+00006bf4@8260
4932+00006bd4@8261
4933+0000ebf4@8262
4934+0000ebd0@8264
4935+0000fbf4@8265
4936+0000fb74@8266
4937+0000fb54@8267
4938+0000fbf4@8268
4939+00007bf4@8269
4940+00007bf6@8270
4941+0000fbf6@8271
4942+0000fb1e@8273
4943+0000b91e@8274
4944+0000b99e@8275
4945+0000399e@8279
4946+0000a91e@8281
4947+0000abde@8282
4948+0000abd2@8283
4949+00002b52@8288
4950+00002b50@8289
4951+0000abd0@8290
4952+0000ebf4@8292
4953+0000eb54@8296
4954+00006bf4@8297
4955+00006bd4@8298
4956+0000ebf4@8299
4957+0000fbf4@8302
4958+0000fb74@8303
4959+0000fb54@8304
4960+0000fbf4@8305
4961+00007bf6@8307
4962+0000fbf6@8309
4963+0000fbfe@8310
4964+0000f16e@8311
4965+0000b1ee@8312
4966+000031ee@8316
4967+0000a16e@8318
4968+0000a1ee@8319
4969+0000bf42@8320
4970+0000afc2@8321
4971+00002fc2@8325
4972+00002f40@8326
4973+0000afc0@8327
4974+0000afe0@8329
4975+0000efe4@8330
4976+0000ef64@8333
4977+00006fe4@8335
4978+0000efe4@8336
4979+0000ffe4@8339
4980+0000ff64@8340
4981+0000ff44@8341
4982+0000ffe4@8342
4983+00007fe6@8344
4984+0000ffe6@8346
4985+0000f346@8348
4986+0000b346@8349
4987+0000b3c6@8350
4988+000033c6@8353
4989+0000a346@8355
4990+0000abe2@8357
4991+00002b60@8363
4992+0000abe0@8364
4993+0000abe4@8366
4994+0000ebe0@8367
4995+0000ebe4@8368
4996+0000eb64@8370
4997+00006be4@8372
4998+0000ebe4@8374
4999+0000fbe4@8376
5000+0000fb64@8378
5001+0000fbe4@8379
5002+00007be6@8381
5003+0000fbe6@8383
5004+0000fd3e@8385
5005+0000b53e@8386
5006+0000b5be@8387
5007+000035be@8391
5008+0000a5be@8392
5009+0000a53e@8393
5010+0000ada2@8394
5011+00002d22@8400
5012+00002d20@8401
5013+0000ada0@8402
5014+0000ada4@8403
5015+0000efa4@8404
5016+0000ef24@8407
5017+00006fa4@8409
5018+00006da4@8410
5019+0000efa4@8411
5020+0000ffa4@8413
5021+0000ff24@8415
5022+0000ffa4@8417
5023+00007fa4@8418
5024+00007fa6@8419
5025+0000ffa6@8420
5026+0000ff3e@8422
5027+0000f71e@8423
5028+0000b79e@8424
5029+0000379e@8428
5030+0000a71e@8430
5031+0000a7be@8431
5032+0000ada2@8432
5033+00002da2@8437
5034+00002d20@8438
5035+0000ada0@8439
5036+0000eda4@8441
5037+0000efa4@8442
5038+0000eda4@8443
5039+0000efa4@8444
5040+0000ef24@8445
5041+00006fa4@8446
5042+00006da4@8447
5043+0000efa4@8448
5044+0000ffa4@8451
5045+0000ff24@8452
5046+0000ffa4@8454
5047+00007fa6@8456
5048+0000ffa6@8458
5049+0000ffb6@8459
5050+0000f912@8460
5051+0000b992@8461
5052+00003992@8465
5053+0000a912@8467
5054+0000a992@8468
5055+0000abc2@8469
5056+00002bc2@8474
5057+00002b40@8475
5058+0000abc0@8476
5059+0000abe0@8478
5060+0000ebe4@8479
5061+0000eb64@8482
5062+00006be4@8484
5063+0000ebe4@8485
5064+0000fbe4@8488
5065+0000fb64@8489
5066+0000fb44@8490
5067+0000fbe4@8491
5068+00007be6@8493
5069+0000fbe6@8495
5070+0000f912@8497
5071+0000f992@8499
5072+00007992@8502
5073+0000e912@8504
5074+0000ebc2@8506
5075+00006b40@8512
5076+0000eb40@8513
5077+0000ebc0@8514
5078+0000ebe4@8515
5079+0000ebc0@8516
5080+0000abe4@8517
5081+0000a5e0@8518
5082+0000a560@8519
5083+0000a5e0@8520
5084+000025e0@8521
5085+0000a5e0@8523
5086+0000b5e0@8525
5087+0000b560@8527
5088+0000b5e0@8528
5089+000035e2@8530
5090+000075e2@8531
5091+0000f5e2@8532
5092+0000f91e@8534
5093+0000b91e@8535
5094+0000b99e@8536
5095+0000399e@8540
5096+0000a99e@8541
5097+0000a91e@8542
5098+0000abd2@8543
5099+00002b52@8549
5100+00002b50@8550
5101+0000abd0@8551
5102+0000abf4@8552
5103+0000ebf4@8553
5104+0000ebd4@8555
5105+0000ebf4@8556
5106+0000eb54@8557
5107+00006bf4@8558
5108+00006bd4@8559
5109+0000ebf4@8560
5110+0000fbd4@8562
5111+0000fbf4@8563
5112+0000fb54@8564
5113+0000fbf4@8566
5114+00007bf4@8567
5115+00007bf6@8568
5116+0000fbf6@8569
5117+0000fb1e@8571
5118+0000b91e@8572
5119+0000b99e@8573
5120+0000399e@8577
5121+0000a91e@8579
5122+0000abde@8580
5123+0000abd2@8581
5124+00002b52@8586
5125+00002b50@8587
5126+0000abd0@8588
5127+0000ebf4@8590
5128+0000eb74@8594
5129+00006bf4@8595
5130+0000ebf4@8597
5131+0000fbf4@8600
5132+0000fb74@8601
5133+0000fb54@8602
5134+0000fbf4@8603
5135+00007bf6@8605
5136+0000fbf6@8607
5137+0000f172@8609
5138+0000b1f2@8610
5139+000031f2@8614
5140+0000a172@8616
5141+0000a1f2@8617
5142+0000bf42@8618
5143+0000afc2@8619
5144+00002fc2@8623
5145+00002f40@8624
5146+0000afc0@8625
5147+0000afe0@8627
5148+0000efe4@8628
5149+0000ef64@8631
5150+00006fe4@8633
5151+0000efe4@8634
5152+0000ffe4@8637
5153+0000ff64@8638
5154+0000ff44@8639
5155+0000ffe4@8640
5156+00007fe6@8642
5157+0000ffe6@8644
5158+0000f346@8646
5159+0000b346@8647
5160+0000b3c6@8648
5161+000033c6@8651
5162+0000a346@8653
5163+0000abe2@8655
5164+00002b60@8661
5165+0000abe0@8662
5166+0000abe4@8664
5167+0000ebe4@8665
5168+0000eb64@8668
5169+00006be4@8670
5170+0000ebe4@8672
5171+0000fbe4@8674
5172+0000fb64@8676
5173+0000fbe4@8677
5174+00007be6@8679
5175+0000fbe6@8681
5176+0000fb1e@8683
5177+0000bb9e@8685
5178+00003b9e@8689
5179+0000ab9e@8690
5180+0000ab1e@8691
5181+0000ab82@8692
5182+00002b02@8698
5183+00002b00@8699
5184+0000ab80@8700
5185+0000aba4@8701
5186+0000eba4@8702
5187+0000eb24@8706
5188+00006ba4@8707
5189+00006b84@8708
5190+0000eba4@8709
5191+0000eb84@8711
5192+0000fba4@8712
5193+0000fb24@8713
5194+0000fb04@8714
5195+0000fba4@8715
5196+00007ba6@8716
5197+0000fba6@8718
5198+0000fb3e@8720
5199+0000bbbe@8722
5200+00003bbe@8726
5201+00003b3e@8727
5202+0000ab3e@8728
5203+0000abbe@8729
5204+0000ab02@8730
5205+0000ab82@8731
5206+00002b82@8735
5207+00002b00@8736
5208+0000ab80@8737
5209+0000eba4@8739
5210+0000eb24@8743
5211+00006ba4@8744
5212+0000eba4@8746
5213+0000fba4@8749
5214+0000fb24@8750
5215+0000fb04@8751
5216+0000fba4@8752
5217+00007ba6@8754
5218+0000fba6@8756
5219+0000fbb6@8757
5220+0000f916@8758
5221+0000b996@8759
5222+00003996@8763
5223+0000a916@8765
5224+0000a996@8766
5225+0000abc2@8767
5226+00002bc2@8772
5227+00002b40@8773
5228+0000abc0@8774
5229+0000abe0@8776
5230+0000ebe4@8777
5231+0000ebc4@8779
5232+0000eb64@8780
5233+00006bc4@8782
5234+0000ebe4@8783
5235+0000fbe4@8786
5236+0000fb64@8787
5237+0000fb44@8788
5238+0000fbe4@8789
5239+00007be6@8791
5240+0000fbe6@8793
5241+0000f916@8795
5242+0000f996@8797
5243+00007996@8800
5244+0000e916@8802
5245+0000ebc2@8804
5246+00006b40@8810
5247+0000eb40@8811
5248+0000ebc0@8812
5249+0000ebe4@8813
5250+0000ebe0@8814
5251+0000abe4@8815
5252+0000a5e0@8816
5253+0000a560@8817
5254+0000a5e0@8818
5255+000025e0@8819
5256+0000a5e0@8821
5257+0000b5e0@8823
5258+0000b560@8825
5259+0000b5e0@8827
5260+000035e2@8828
5261+000075e2@8829
5262+0000f5e2@8830
5263+0000f91e@8832
5264+0000b91e@8833
5265+0000b99e@8834
5266+0000399e@8838
5267+0000a99e@8839
5268+0000a91e@8840
5269+0000abd2@8841
5270+00002b52@8847
5271+00002b50@8848
5272+0000abd0@8849
5273+0000abf4@8850
5274+0000ebf4@8851
5275+0000eb74@8854
5276+0000eb54@8855
5277+00006bf4@8856
5278+0000ebf4@8858
5279+0000ebd4@8860
5280+0000fbf4@8861
5281+0000fb74@8862
5282+0000fb54@8863
5283+0000fbf4@8864
5284+00007bf4@8865
5285+00007bf6@8866
5286+0000fbf6@8867
5287+0000fb1e@8869
5288+0000b91e@8870
5289+0000b99e@8871
5290+0000399e@8875
5291+0000299e@8876
5292+0000a91e@8877
5293+0000abde@8878
5294+0000abd2@8879
5295+00002b52@8884
5296+00002b50@8885
5297+0000abd0@8886
5298+0000ebf4@8888
5299+0000eb54@8892
5300+00006bf4@8893
5301+00006bd4@8894
5302+0000ebf4@8895
5303+0000ebd4@8897
5304+0000fbf4@8898
5305+0000fb74@8899
5306+0000fb54@8900
5307+0000fbf4@8901
5308+00007bf6@8903
5309+0000fbf6@8905
5310+0000f176@8907
5311+0000b1f6@8908
5312+000031f6@8912
5313+0000a176@8914
5314+0000a1f6@8915
5315+0000bf42@8916
5316+0000afc2@8917
5317+00002fc2@8921
5318+00002f40@8922
5319+0000afc0@8923
5320+0000afe0@8925
5321+0000efe4@8926
5322+0000efc4@8928
5323+0000ef64@8929
5324+00006fe4@8931
5325+0000efe4@8932
5326+0000ffe4@8935
5327+0000ff64@8936
5328+0000ff44@8937
5329+0000ffe4@8938
5330+00007fe6@8940
5331+0000ffe6@8942
5332+0000f346@8944
5333+0000b346@8945
5334+0000b3c6@8946
5335+000033c6@8949
5336+0000a346@8951
5337+0000abe2@8953
5338+00002b60@8959
5339+0000ab60@8960
5340+0000abe0@8961
5341+0000abe4@8962
5342+0000ebe4@8963
5343+0000eb64@8966
5344+00006be4@8968
5345+0000ebe4@8970
5346+0000fbe4@8972
5347+0000fb64@8974
5348+0000fbe4@8975
5349+00007be6@8977
5350+0000fbe6@8979
5351+0000ff1e@8981
5352+0000bd1e@8982
5353+0000bd9e@8983
5354+00003d9e@8987
5355+0000ad9e@8988
5356+0000ad1e@8989
5357+0000af82@8990
5358+0000ab82@8991
5359+00002b02@8996
5360+00002b00@8997
5361+0000ab80@8998
5362+0000aba4@8999
5363+0000eba4@9000
5364+0000eb84@9002
5365+0000eba4@9003
5366+0000eb04@9004
5367+00006ba4@9005
5368+0000eba4@9007
5369+0000eb84@9009
5370+0000fba4@9010
5371+0000fb24@9011
5372+0000fb04@9012
5373+0000fba4@9013
5374+00007ba6@9014
5375+0000fba6@9016
5376+0000ff3e@9018
5377+0000fd3e@9019
5378+0000bdbe@9020
5379+00003dbe@9024
5380+0000ad3e@9026
5381+0000afbe@9027
5382+0000ab02@9028
5383+0000ab82@9029
5384+00002b82@9033
5385+00002b00@9034
5386+0000ab80@9035
5387+0000eba4@9037
5388+0000eb24@9041
5389+00006ba4@9042
5390+0000eba4@9044
5391+0000fba4@9047
5392+0000fb24@9048
5393+0000fb04@9049
5394+0000fba4@9050
5395+00007ba6@9052
5396+0000fba6@9054
5397+0000fbbe@9055
5398+0000f91a@9056
5399+0000b99a@9057
5400+0000399a@9061
5401+0000a91a@9063
5402+0000a99a@9064
5403+0000abc2@9065
5404+00002bc2@9070
5405+00002b40@9071
5406+0000abc0@9072
5407+0000abe0@9074
5408+0000ebe4@9075
5409+0000ebc4@9077
5410+0000eb64@9078
5411+00006bc4@9080
5412+0000ebe4@9081
5413+0000fbe4@9084
5414+0000fb64@9085
5415+0000fb44@9086
5416+0000fbe4@9087
5417+00007be6@9089
5418+0000fbe6@9091
5419+0000f91a@9093
5420+0000f99a@9095
5421+0000799a@9098
5422+0000e91a@9100
5423+0000ebc2@9102
5424+00006b40@9108
5425+0000eb40@9109
5426+0000ebc0@9110
5427+0000ebe4@9111
5428+0000ebe0@9112
5429+0000abe4@9113
5430+0000a5e0@9114
5431+0000a560@9115
5432+0000a5e0@9116
5433+000025e0@9117
5434+0000a5e0@9119
5435+0000b5e0@9121
5436+0000b560@9123
5437+0000b5e0@9124
5438+000035e2@9126
5439+000075e2@9127
5440+0000f5e2@9128
5441+0000f91e@9130
5442+0000b91e@9131
5443+0000b99e@9132
5444+0000399e@9136
5445+0000a99e@9137
5446+0000a91e@9138
5447+0000abd2@9139
5448+00002b52@9145
5449+00002b50@9146
5450+0000abd0@9147
5451+0000abf4@9148
5452+0000ebf4@9149
5453+0000ebd4@9151
5454+0000eb74@9152
5455+0000eb54@9153
5456+00006bf4@9154
5457+00006bd4@9155
5458+0000ebf4@9156
5459+0000fbd4@9158
5460+0000fbf4@9159
5461+0000fb74@9160
5462+0000fb54@9161
5463+0000fbf4@9162
5464+00007bf6@9163
5465+0000fbf6@9165
5466+0000fb1e@9167
5467+0000b91e@9168
5468+0000b99e@9169
5469+0000399e@9173
5470+0000299e@9174
5471+0000a91e@9175
5472+0000abde@9176
5473+0000abd2@9177
5474+00002b52@9182
5475+00002b50@9183
5476+0000abd0@9184
5477+0000ebf4@9186
5478+0000eb74@9190
5479+00006bf4@9191
5480+00006bd4@9192
5481+0000ebf4@9193
5482+0000fbf4@9196
5483+0000fb74@9197
5484+0000fb54@9198
5485+0000fbf4@9199
5486+00007bf6@9201
5487+0000fbf6@9203
5488+0000fbfe@9204
5489+0000f17a@9205
5490+0000b1fa@9206
5491+000031fa@9210
5492+0000a17a@9212
5493+0000a1fa@9213
5494+0000bf42@9214
5495+0000afc2@9215
5496+00002fc2@9219
5497+00002f40@9220
5498+0000afc0@9221
5499+0000afe0@9223
5500+0000efe4@9224
5501+0000ef64@9227
5502+00006fe4@9229
5503+0000efe4@9230
5504+0000ffe4@9233
5505+0000ff64@9234
5506+0000ff44@9235
5507+0000ffe4@9236
5508+00007fe6@9238
5509+0000ffe6@9240
5510+0000f346@9242
5511+0000b346@9243
5512+0000b3c6@9244
5513+000033c6@9247
5514+0000a346@9249
5515+0000abe2@9251
5516+00002b60@9257
5517+0000abe0@9258
5518+0000abe4@9260
5519+0000ebe4@9261
5520+0000eb64@9264
5521+00006be4@9266
5522+0000ebe4@9268
5523+0000fbe4@9270
5524+0000fb64@9272
5525+0000fbe4@9273
5526+00007be6@9275
5527+0000fbe6@9277
5528+0000ff1e@9279
5529+0000bf1e@9280
5530+0000bf9e@9281
5531+00003f9e@9285
5532+0000af9e@9286
5533+0000af1e@9287
5534+0000ab82@9288
5535+00002b02@9294
5536+00002b00@9295
5537+0000ab80@9296
5538+0000aba4@9297
5539+0000eba0@9298
5540+0000eba4@9299
5541+0000eb24@9301
5542+0000eb04@9302
5543+00006ba4@9303
5544+00006b84@9304
5545+0000eba4@9305
5546+0000eb84@9307
5547+0000fba4@9308
5548+0000fb24@9309
5549+0000fb04@9310
5550+0000fba4@9311
5551+00007ba6@9312
5552+0000fba6@9314
5553+0000ff3e@9316
5554+0000bfbe@9318
5555+00003fbe@9322
5556+0000af3e@9324
5557+0000afbe@9325
5558+0000ab02@9326
5559+0000ab82@9327
5560+00002b82@9331
5561+00002b00@9332
5562+0000ab80@9333
5563+0000eba4@9335
5564+0000eb24@9339
5565+00006ba4@9340
5566+0000eba4@9342
5567+0000fba4@9345
5568+0000fb24@9346
5569+0000fb04@9347
5570+0000fba4@9348
5571+00007ba6@9350
5572+0000fba6@9352
5573+0000fbbe@9353
5574+0000f91e@9354
5575+0000b99e@9355
5576+0000399e@9359
5577+0000a91e@9361
5578+0000a99e@9362
5579+0000ab42@9363
5580+0000abc2@9364
5581+00002bc2@9368
5582+00002b40@9369
5583+0000ab40@9370
5584+0000abc0@9371
5585+0000abe0@9372
5586+0000ebe4@9373
5587+0000eb64@9376
5588+00006be4@9378
5589+0000ebe4@9379
5590+0000fbe4@9382
5591+0000fb64@9383
5592+0000fb44@9384
5593+0000fbe4@9385
5594+00007be6@9387
5595+0000fbe6@9389
5596+0000f91e@9391
5597+0000f99e@9393
5598+0000799e@9396
5599+0000799c@9397
5600+0000f91c@9398
5601+0000fbc0@9400
5602+0000ebc0@9401
5603+0000fbc0@9402
5604+0000ebc0@9403
5605+00006b40@9406
5606+0000eb40@9407
5607+0000ebc0@9408
5608+0000ebe4@9409
5609+0000ebc4@9412
5610+0000eb64@9413
5611+0000eb44@9414
5612+00006be4@9415
5613+00006bc4@9416
5614+0000ebe4@9417
5615+0000fbc4@9419
5616+0000fbe4@9420
5617+0000fb44@9421
5618+0000fbe4@9422
5619+00007be6@9424
5620+0000fbe6@9426
5621+0000f91e@9428
5622+0000b99e@9430
5623+0000399e@9434
5624+0000a99e@9435
5625+0000a91e@9436
5626+0000abd2@9437
5627+00002b52@9443
5628+00002b50@9444
5629+0000abd0@9445
5630+0000abf4@9446
5631+0000ebf0@9447
5632+0000ebf4@9448
5633+0000ebd4@9449
5634+0000eb74@9450
5635+0000eb54@9451
5636+00006bf4@9452
5637+00006bd4@9453
5638+0000ebf4@9454
5639+0000ebd4@9456
5640+0000fbf4@9457
5641+0000fb54@9458
5642+0000fbf4@9460
5643+00007bf6@9461
5644+0000fbf6@9463
5645+0000fb1e@9465
5646+0000bb9e@9467
5647+00003b9e@9471
5648+00002b9e@9472
5649+0000ab1e@9473
5650+0000abfe@9474
5651+0000abe2@9475
5652+00002b62@9480
5653+00002b60@9481
5654+0000abe0@9482
5655+0000ebe4@9484
5656+0000eb64@9488
5657+00006be4@9489
5658+0000ebe4@9491
5659+0000fbe4@9494
5660+0000fb64@9495
5661+0000fbe4@9497
5662+00007be6@9499
5663+0000fbe6@9501
5664+0000fbfe@9502
5665+0000f17e@9503
5666+0000b1fe@9504
5667+000031fe@9508
5668+0000317e@9509
5669+0000a17e@9510
5670+0000a1fe@9511
5671+0000bf42@9512
5672+0000afc2@9513
5673+00002fc2@9517
5674+00002f40@9518
5675+0000afc0@9519
5676+0000afe0@9521
5677+0000efe4@9522
5678+0000ef64@9525
5679+00006fe4@9527
5680+0000efe4@9528
5681+0000ffe4@9531
5682+0000ff64@9532
5683+0000ffe4@9534
5684+00007fe6@9536
5685+0000ffe6@9538
5686+0000f346@9540
5687+0000b346@9541
5688+0000b3c6@9542
5689+000033c6@9545
5690+0000a346@9547
5691+0000abe2@9549
5692+00002b60@9555
5693+0000abe0@9556
5694+0000abe4@9558
5695+0000ebe4@9559
5696+0000eb64@9562
5697+00006be4@9564
5698+0000ebe4@9566
5699+0000fbe4@9568
5700+0000fb64@9570
5701+0000fbe4@9571
5702+00007be6@9573
5703+0000fbe6@9575
5704+0000ff1e@9577
5705+0000b71e@9578
5706+0000b79e@9579
5707+0000379e@9583
5708+0000a79e@9584
5709+0000a71e@9585
5710+0000a992@9586
5711+00002912@9592
5712+00002910@9593
5713+0000a990@9594
5714+0000abb4@9595
5715+0000ebb0@9596
5716+0000ebb4@9597
5717+0000eb94@9598
5718+0000eb34@9599
5719+0000eb14@9600
5720+00006bb4@9601
5721+00006b90@9602
5722+0000ebb4@9603
5723+0000eb94@9605
5724+0000fbb4@9606
5725+0000fb34@9607
5726+0000fb14@9608
5727+0000fbb4@9609
5728+00007bb6@9610
5729+0000fbb6@9612
5730+0000ff3e@9614
5731+0000f73e@9615
5732+0000b7be@9616
5733+000037be@9620
5734+0000a73e@9622
5735+0000afbe@9623
5736+0000a912@9624
5737+0000a992@9625
5738+00002992@9629
5739+00002910@9630
5740+0000a990@9631
5741+0000e9b4@9633
5742+0000ebb4@9634
5743+0000e9b4@9635
5744+0000ebb4@9636
5745+0000eb14@9637
5746+00006bb4@9638
5747+0000e9b4@9640
5748+0000ebb4@9641
5749+0000fbb4@9643
5750+0000fb34@9644
5751+0000fb14@9645
5752+0000fbb4@9646
5753+000079b6@9648
5754+00007bb6@9649
5755+0000fbb6@9650
5756+0000f922@9652
5757+0000b9a2@9653
5758+000039a2@9657
5759+0000a922@9659
5760+0000a9a2@9660
5761+0000abc2@9661
5762+00002bc2@9666
5763+00002b40@9667
5764+0000abc0@9668
5765+0000abe0@9670
5766+0000ebe4@9671
5767+0000eb64@9674
5768+00006be4@9676
5769+0000ebe4@9677
5770+0000fbe4@9680
5771+0000fb64@9681
5772+0000fb44@9682
5773+0000fbe4@9683
5774+00007be6@9685
5775+0000fbe6@9687
5776+0000f922@9689
5777+0000f9a2@9691
5778+000079a2@9694
5779+0000e922@9696
5780+0000ebc2@9698
5781+00006b40@9704
5782+0000eb40@9705
5783+0000ebc0@9706
5784+0000ebe4@9707
5785+0000ebe0@9708
5786+0000abe4@9709
5787+0000a9ec@9710
5788+0000a96c@9711
5789+0000a9ec@9712
5790+000029ec@9713
5791+0000a9ec@9715
5792+0000b9ec@9717
5793+0000b96c@9719
5794+0000b9ec@9720
5795+000039ee@9722
5796+000079ee@9723
5797+0000f9ee@9724
5798+0000fb3e@9726
5799+0000bb3e@9727
5800+0000bbbe@9728
5801+00003bbe@9732
5802+0000abbe@9733
5803+0000ab3e@9734
5804+0000abe2@9735
5805+00002b62@9741
5806+00002b60@9742
5807+0000abe0@9743
5808+0000abe4@9744
5809+0000ebe4@9745
5810+0000eb64@9748
5811+00006be4@9750
5812+0000ebe4@9752
5813+0000fbe4@9755
5814+0000fb64@9756
5815+0000fbe4@9758
5816+00007be6@9759
5817+0000fbe6@9761
5818+0000fb3e@9763
5819+0000b91e@9764
5820+0000b99e@9765
5821+0000399e@9769
5822+0000299e@9770
5823+0000a91e@9771
5824+0000abde@9772
5825+0000abd2@9773
5826+00002b52@9778
5827+00002b50@9779
5828+0000abd0@9780
5829+0000ebf4@9782
5830+0000eb54@9786
5831+00006bf4@9787
5832+00006bd4@9788
5833+0000ebf4@9789
5834+0000fbf4@9792
5835+0000fb74@9793
5836+0000fb54@9794
5837+0000fbf4@9795
5838+00007bf6@9797
5839+0000fbf6@9799
5840+0000f342@9801
5841+0000b3c2@9802
5842+000033c2@9806
5843+0000a342@9808
5844+0000a3c2@9809
5845+0000afc2@9810
5846+00002fc2@9815
5847+00002f40@9816
5848+0000afc0@9817
5849+0000efe4@9820
5850+0000efe0@9821
5851+0000efc4@9822
5852+0000ef64@9823
5853+0000ef44@9824
5854+00006fe4@9825
5855+0000efe4@9826
5856+0000ffe4@9829
5857+0000ff64@9830
5858+0000ff44@9831
5859+0000ffe4@9832
5860+00007fe6@9834
5861+0000ffe6@9836
5862+0000f346@9838
5863+0000b346@9839
5864+0000b3c6@9840
5865+000033c6@9843
5866+0000a346@9845
5867+0000abe2@9847
5868+00002b60@9853
5869+0000abe0@9854
5870+0000abe4@9856
5871+0000ebe4@9857
5872+0000eb64@9860
5873+00006be4@9862
5874+0000ebe4@9864
5875+0000fbe4@9866
5876+0000fb64@9868
5877+0000fbe4@9869
5878+00007be6@9871
5879+0000fbe6@9873
5880+0000ff1e@9875
5881+0000bf9e@9877
5882+00003f9e@9881
5883+0000af9e@9882
5884+0000af1e@9883
5885+0000aba2@9884
5886+00002b22@9890
5887+00002b20@9891
5888+0000aba0@9892
5889+0000aba4@9893
5890+0000eba4@9894
5891+0000eb24@9897
5892+00006ba4@9899
5893+0000eba4@9901
5894+0000fba4@9904
5895+0000fb24@9905
5896+0000fba4@9907
5897+00007ba6@9908
5898+0000fba6@9910
5899+0000ff3e@9912
5900+0000f53e@9913
5901+0000b5be@9914
5902+000035be@9918
5903+0000253e@9919
5904+0000a53e@9920
5905+0000a5be@9921
5906+0000a102@9922
5907+0000a182@9923
5908+00002182@9927
5909+00002100@9928
5910+0000a180@9929
5911+0000e1a4@9931
5912+0000e3a4@9932
5913+0000e1a4@9933
5914+0000e3a4@9934
5915+0000e304@9935
5916+000063a4@9936
5917+00006184@9937
5918+0000e1a4@9938
5919+0000e3a4@9939
5920+0000e184@9940
5921+0000f3a4@9941
5922+0000f324@9942
5923+0000f104@9943
5924+0000f3a4@9944
5925+000071a6@9946
5926+000073a6@9947
5927+0000f3a6@9948
5928+0000fba6@9949
5929+0000f926@9950
5930+0000b9a6@9951
5931+000039a6@9955
5932+0000a926@9957
5933+0000a9a6@9958
5934+0000abc2@9959
5935+00002bc2@9964
5936+00002b40@9965
5937+0000abc0@9966
5938+0000abe4@9968
5939+0000ebe4@9969
5940+0000eb64@9972
5941+00006be4@9974
5942+0000ebe4@9975
5943+0000fbe4@9978
5944+0000fb64@9979
5945+0000fb44@9980
5946+0000fbe4@9981
5947+00007be6@9983
5948+0000fbe6@9985
5949+0000f926@9987
5950+0000f9a6@9989
5951+000079a6@9992
5952+0000e926@9994
5953+0000ebc2@9996
5954+00006b40@10002
5955+0000eb40@10003
5956+0000ebc0@10004
5957+0000ebe4@10005
5958+0000abe4@10007
5959+0000a5e0@10008
5960+0000a560@10009
5961+0000a5e0@10010
5962+000025e0@10011
5963+0000a5e0@10013
5964+0000b5e0@10015
5965+0000b560@10017
5966+0000b5e0@10018
5967+000035e2@10020
5968+000075e2@10021
5969+0000f5e2@10022
5970+0000f91e@10024
5971+0000b91e@10025
5972+0000b99e@10026
5973+0000399e@10030
5974+0000a99e@10031
5975+0000a91e@10032
5976+0000abd2@10033
5977+00002b52@10039
5978+00002b50@10040
5979+0000abd0@10041
5980+0000abf4@10042
5981+0000ebf0@10043
5982+0000ebf4@10044
5983+0000ebd4@10045
5984+0000eb74@10046
5985+0000eb54@10047
5986+00006bf4@10048
5987+00006bd4@10049
5988+0000ebf4@10050
5989+0000ebd0@10052
5990+0000fbf4@10053
5991+0000fb74@10054
5992+0000fb54@10055
5993+0000fbf4@10056
5994+00007bf6@10057
5995+0000fbf6@10059
5996+0000fb1e@10061
5997+0000b91e@10062
5998+0000b99e@10063
5999+0000399e@10067
6000+0000299e@10068
6001+0000a91e@10069
6002+0000abde@10070
6003+0000abd2@10071
6004+00002b52@10076
6005+00002b50@10077
6006+0000abd0@10078
6007+0000ebf4@10080
6008+0000eb54@10084
6009+00006bf4@10085
6010+00006bd4@10086
6011+0000ebf4@10087
6012+0000fbf4@10090
6013+0000fb74@10091
6014+0000fb54@10092
6015+0000fbf4@10093
6016+00007bf6@10095
6017+0000fbf6@10097
6018+0000fbd6@10098
6019+0000f346@10099
6020+0000b3c6@10100
6021+000033c6@10104
6022+00003346@10105
6023+0000a346@10106
6024+0000a3c6@10107
6025+0000afc2@10108
6026+00002fc2@10113
6027+00002f40@10114
6028+0000afc0@10115
6029+0000afe4@10117
6030+0000efe4@10118
6031+0000efc4@10120
6032+0000ef64@10121
6033+00006fe4@10123
6034+0000efe4@10124
6035+0000ffe4@10127
6036+0000ff64@10128
6037+0000ff44@10129
6038+0000ffe4@10130
6039+00007fe6@10132
6040+0000ffe6@10134
6041+0000f346@10136
6042+0000b346@10137
6043+0000b3c6@10138
6044+000033c6@10141
6045+0000a346@10143
6046+0000abe2@10145
6047+00002b60@10151
6048+0000abe0@10152
6049+0000abe4@10154
6050+0000ebe4@10155
6051+0000eb64@10158
6052+00006be4@10160
6053+0000ebe4@10162
6054+0000fbe4@10164
6055+0000fb64@10166
6056+0000fbe4@10167
6057+00007be6@10169
6058+0000fbe6@10171
6059+0000fd3e@10173
6060+0000f53e@10174
6061+0000b5be@10175
6062+000035be@10179
6063+0000a5be@10180
6064+0000a53e@10181
6065+0000a582@10182
6066+0000a182@10183
6067+00002102@10188
6068+00002100@10189
6069+0000a180@10190
6070+0000a1a4@10191
6071+0000e3a0@10192
6072+0000e3a4@10193
6073+0000e384@10194
6074+0000e324@10195
6075+0000e304@10196
6076+000063a4@10197
6077+00006180@10198
6078+0000e3a4@10199
6079+0000e180@10201
6080+0000f3a4@10202
6081+0000f324@10203
6082+0000f104@10204
6083+0000f3a4@10205
6084+000073a6@10206
6085+000071a6@10207
6086+0000f3a6@10208
6087+0000f53e@10210
6088+0000b5be@10212
6089+000035be@10216
6090+0000a53e@10218
6091+0000a5be@10219
6092+0000a102@10220
6093+0000a182@10221
6094+00002182@10225
6095+00002100@10226
6096+0000a180@10227
6097+0000e1a4@10229
6098+0000e3a4@10230
6099+0000e1a4@10231
6100+0000e3a4@10232
6101+0000e324@10233
6102+000063a4@10234
6103+00006184@10235
6104+0000e1a4@10236
6105+0000e3a4@10237
6106+0000e1a4@10238
6107+0000f3a4@10239
6108+0000f324@10240
6109+0000f304@10241
6110+0000f3a4@10242
6111+000073a6@10244
6112+0000f3a6@10246
6113+0000fbae@10247
6114+0000f92a@10248
6115+0000b9aa@10249
6116+000039aa@10253
6117+0000a92a@10255
6118+0000a9aa@10256
6119+0000abc2@10257
6120+00002bc2@10262
6121+00002b40@10263
6122+0000abc0@10264
6123+0000abe4@10266
6124+0000ebe4@10267
6125+0000eb64@10270
6126+00006be4@10272
6127+0000ebe4@10273
6128+0000fbe4@10276
6129+0000fb64@10277
6130+0000fbe4@10279
6131+00007be6@10281
6132+0000fbe6@10283
6133+0000f92a@10285
6134+0000f9aa@10287
6135+000079aa@10290
6136+0000e92a@10292
6137+0000e9aa@10293
6138+0000ebc2@10294
6139+00006b40@10300
6140+0000eb40@10301
6141+0000ebc0@10302
6142+0000ebe4@10303
6143+0000abe4@10305
6144+0000a5e0@10306
6145+0000a560@10307
6146+0000a5e0@10308
6147+000025e0@10309
6148+0000a5e0@10311
6149+0000b5e0@10313
6150+0000b560@10315
6151+0000b5e0@10316
6152+000035e2@10318
6153+000075e2@10319
6154+0000f5e2@10320
6155+0000f91e@10322
6156+0000b91e@10323
6157+0000b99e@10324
6158+0000399e@10328
6159+0000a99e@10329
6160+0000a91e@10330
6161+0000abd2@10331
6162+00002b52@10337
6163+00002b50@10338
6164+0000abd0@10339
6165+0000abf4@10340
6166+0000ebf0@10341
6167+0000ebf4@10342
6168+0000ebd4@10343
6169+0000eb74@10344
6170+0000eb54@10345
6171+00006bf4@10346
6172+00006bd4@10347
6173+0000ebf4@10348
6174+0000ebd0@10350
6175+0000fbf4@10351
6176+0000fb54@10352
6177+0000fbf4@10354
6178+00007bf6@10355
6179+0000fbf6@10357
6180+0000fb1e@10359
6181+0000b91e@10360
6182+0000b99e@10361
6183+0000399e@10365
6184+0000299e@10366
6185+0000a91e@10367
6186+0000abde@10368
6187+0000abd2@10369
6188+00002b52@10374
6189+00002b50@10375
6190+0000abd0@10376
6191+0000ebf4@10378
6192+0000eb74@10382
6193+00006bf4@10383
6194+00006bd4@10384
6195+0000ebf4@10385
6196+0000fbf4@10388
6197+0000fb74@10389
6198+0000fb54@10390
6199+0000fbf4@10391
6200+00007bf6@10393
6201+0000fbf6@10394
6202+0000fbde@10396
6203+0000f34a@10397
6204+0000b3ca@10398
6205+000033ca@10402
6206+0000334a@10403
6207+0000a34a@10404
6208+0000a3ca@10405
6209+0000afc2@10406
6210+00002fc2@10411
6211+00002f40@10412
6212+0000afc0@10413
6213+0000afe0@10415
6214+0000efe4@10416
6215+0000ef64@10419
6216+0000ef44@10420
6217+00006fe4@10421
6218+0000efe4@10422
6219+0000ffe4@10425
6220+0000ff64@10426
6221+0000ff44@10427
6222+0000ffe4@10428
6223+00007fe6@10430
6224+0000ffe6@10432
6225+0000f346@10434
6226+0000b346@10435
6227+0000b3c6@10436
6228+000033c6@10439
6229+0000a346@10441
6230+0000abe2@10443
6231+00002b60@10449
6232+0000abe0@10450
6233+0000abe4@10452
6234+0000ebe4@10453
6235+0000eb64@10456
6236+00006be4@10458
6237+0000ebe4@10460
6238+0000fbe4@10462
6239+0000fb64@10464
6240+0000fbe4@10465
6241+00007be6@10467
6242+0000fbe6@10469
6243+0000f53e@10471
6244+0000b5be@10473
6245+000035be@10477
6246+0000a5be@10478
6247+0000a53e@10479
6248+0000a582@10480
6249+0000a182@10481
6250+00002102@10486
6251+00002100@10487
6252+0000a180@10488
6253+0000a3a4@10489
6254+0000e3a0@10490
6255+0000e1a4@10491
6256+0000e384@10492
6257+0000e324@10493
6258+0000e304@10494
6259+000063a4@10495
6260+00006180@10496
6261+0000e3a4@10497
6262+0000e180@10499
6263+0000f3a4@10500
6264+0000f304@10501
6265+0000f384@10502
6266+0000f3a4@10503
6267+000073a6@10504
6268+0000f3a6@10506
6269+0000f53e@10508
6270+0000b5be@10510
6271+000035be@10514
6272+0000a53e@10516
6273+0000a5be@10517
6274+0000a102@10518
6275+0000a182@10519
6276+00002182@10523
6277+00002100@10524
6278+0000a180@10525
6279+0000e1a4@10527
6280+0000e3a4@10528
6281+0000e1a4@10529
6282+0000e3a4@10530
6283+0000e304@10531
6284+000063a4@10532
6285+00006184@10533
6286+0000e1a4@10534
6287+0000e3a4@10535
6288+0000e184@10536
6289+0000f3a4@10537
6290+0000f324@10538
6291+0000f104@10539
6292+0000f3a4@10540
6293+000071a6@10542
6294+000073a6@10543
6295+0000f3a6@10544
6296+0000fbae@10545
6297+0000f92e@10546
6298+0000b9ae@10547
6299+000039ae@10551
6300+0000a92e@10553
6301+0000a9ae@10554
6302+0000ab42@10555
6303+0000abc2@10556
6304+00002bc2@10560
6305+00002b40@10561
6306+0000abc0@10562
6307+0000abe4@10564
6308+0000ebe4@10565
6309+0000eb64@10568
6310+00006be4@10570
6311+0000ebe4@10571
6312+0000fbe4@10574
6313+0000fb64@10575
6314+0000fb44@10576
6315+0000fbe4@10577
6316+00007be6@10579
6317+0000fbe6@10581
6318+0000f92e@10583
6319+0000f9ae@10585
6320+000079ae@10588
6321+000079ac@10589
6322+0000f92c@10590
6323+0000fbc0@10592
6324+0000ebc0@10594
6325+00006b40@10598
6326+0000eb40@10599
6327+0000ebc0@10600
6328+0000ebe4@10601
6329+0000eb64@10605
6330+0000eb44@10606
6331+00006be4@10607
6332+0000ebe4@10609
6333+0000fbe4@10611
6334+0000fb64@10613
6335+0000fbe4@10614
6336+00007be6@10616
6337+0000fbe6@10618
6338+0000f91e@10620
6339+0000b99e@10622
6340+0000399e@10626
6341+0000a99e@10627
6342+0000a91e@10628
6343+0000abd2@10629
6344+00002b52@10635
6345+00002b50@10636
6346+0000abd0@10637
6347+0000abf4@10638
6348+0000ebf0@10639
6349+0000ebf4@10640
6350+0000ebd4@10641
6351+0000eb74@10642
6352+0000eb54@10643
6353+00006bf4@10644
6354+0000ebf4@10646
6355+0000fbd4@10648
6356+0000fbf4@10649
6357+0000fb74@10650
6358+0000fb54@10651
6359+0000fbf4@10652
6360+00007bf6@10653
6361+0000fbf6@10655
6362+0000fb1e@10657
6363+0000b91e@10658
6364+0000b99e@10659
6365+0000399e@10663
6366+0000299e@10664
6367+0000a91e@10665
6368+0000abde@10666
6369+0000abd2@10667
6370+00002b52@10672
6371+00002b50@10673
6372+0000abd0@10674
6373+0000ebf4@10676
6374+0000ebd4@10678
6375+0000ebf4@10679
6376+0000eb54@10680
6377+00006bf4@10681
6378+00006bd4@10682
6379+0000ebf4@10683
6380+0000ebd4@10685
6381+0000fbf4@10686
6382+0000fb74@10687
6383+0000fb54@10688
6384+0000fbf4@10689
6385+00007bf6@10691
6386+0000fbf6@10692
6387+0000fbde@10694
6388+0000f34e@10695
6389+0000b3ce@10696
6390+000033ce@10700
6391+0000334e@10701
6392+0000a34e@10702
6393+0000a3ce@10703
6394+0000af42@10704
6395+0000afc2@10705
6396+00002fc2@10709
6397+00002f40@10710
6398+0000afc0@10711
6399+0000afe4@10713
6400+0000efe4@10714
6401+0000ef44@10717
6402+0000ef64@10718
6403+00006fe4@10719
6404+0000efe4@10720
6405+0000ffe4@10723
6406+0000ff64@10724
6407+0000ff44@10725
6408+0000ffe4@10726
6409+00007fe6@10728
6410+0000ffe6@10730
6411+0000f346@10732
6412+0000b346@10733
6413+0000b3c6@10734
6414+000033c6@10737
6415+0000a346@10739
6416+0000a3c6@10740
6417+0000ab62@10741
6418+0000abe2@10742
6419+00002b60@10747
6420+0000abe0@10748
6421+0000abe4@10750
6422+0000ebe4@10751
6423+0000eb64@10754
6424+00006be4@10756
6425+0000ebe4@10758
6426+0000fbe4@10760
6427+0000fb64@10762
6428+0000fbe4@10763
6429+00007be6@10765
6430+0000fbe6@10767
6431+0000f53e@10769
6432+0000b5be@10771
6433+000035be@10775
6434+0000a5be@10776
6435+0000a53e@10777
6436+0000a582@10778
6437+0000a182@10779
6438+00002102@10784
6439+00002100@10785
6440+0000a180@10786
6441+0000a3a4@10787
6442+0000e3a0@10788
6443+0000e3a4@10789
6444+0000e384@10790
6445+0000e324@10791
6446+0000e304@10792
6447+000063a4@10793
6448+00006184@10794
6449+0000e3a4@10795
6450+0000e184@10797
6451+0000f3a4@10798
6452+0000f324@10799
6453+0000f304@10800
6454+0000f3a4@10801
6455+000073a6@10802
6456+0000f3a6@10804
6457+0000f53e@10806
6458+0000b5be@10808
6459+000035be@10812
6460+0000a53e@10814
6461+0000a5be@10815
6462+0000a102@10816
6463+0000a182@10817
6464+00002182@10821
6465+00002100@10822
6466+0000a180@10823
6467+0000e1a4@10825
6468+0000e3a4@10826
6469+0000e1a4@10827
6470+0000e3a4@10828
6471+0000e304@10829
6472+000063a4@10830
6473+00006184@10831
6474+0000e1a4@10832
6475+0000e3a4@10833
6476+0000e184@10834
6477+0000f3a4@10835
6478+0000f324@10836
6479+0000f104@10837
6480+0000f3a4@10838
6481+000071a6@10840
6482+000073a6@10841
6483+0000f3a6@10842
6484+0000fbb6@10843
6485+0000f932@10844
6486+0000b9b2@10845
6487+000039b2@10849
6488+00003932@10850
6489+0000a932@10851
6490+0000a9b2@10852
6491+0000abc2@10853
6492+00002bc2@10858
6493+00002b40@10859
6494+0000abc0@10860
6495+0000abe4@10862
6496+0000ebe4@10863
6497+0000eb64@10866
6498+0000ebe4@10867
6499+00006be4@10868
6500+0000ebe4@10869
6501+0000fbe4@10872
6502+0000fb64@10873
6503+0000fb44@10874
6504+0000fbe4@10875
6505+00007be6@10877
6506+0000fbe6@10879
6507+0000f932@10881
6508+0000f9b2@10883
6509+000079b2@10886
6510+0000e932@10888
6511+0000e9b2@10889
6512+0000ebc2@10890
6513+00006b40@10896
6514+0000eb40@10897
6515+0000ebc0@10898
6516+0000ebe4@10899
6517+0000abe4@10901
6518+0000a5e0@10902
6519+0000a560@10903
6520+0000a5e0@10904
6521+000025e0@10905
6522+0000a5e0@10907
6523+0000b5e0@10909
6524+0000b560@10911
6525+0000b5e0@10912
6526+000035e2@10914
6527+000075e2@10915
6528+0000f5e2@10916
6529+0000f91e@10918
6530+0000b91e@10919
6531+0000b99e@10920
6532+0000399e@10924
6533+0000a99e@10925
6534+0000a91e@10926
6535+0000abd2@10927
6536+00002b52@10933
6537+00002b50@10934
6538+0000abd0@10935
6539+0000abf4@10936
6540+0000ebf0@10937
6541+0000ebf4@10938
6542+0000eb74@10940
6543+0000eb54@10941
6544+00006bf4@10942
6545+0000ebf4@10944
6546+0000ebd0@10946
6547+0000fbf4@10947
6548+0000fb74@10948
6549+0000fb54@10949
6550+0000fbf4@10950
6551+00007bf6@10951
6552+0000fbf6@10953
6553+0000fb1e@10955
6554+0000b91e@10956
6555+0000b99e@10957
6556+0000399e@10961
6557+0000299e@10962
6558+0000a91e@10963
6559+0000abde@10964
6560+0000abd2@10965
6561+00002b52@10970
6562+00002b50@10971
6563+0000abd0@10972
6564+0000ebf4@10974
6565+0000ebd4@10976
6566+0000eb54@10978
6567+00006bf4@10979
6568+00006bd4@10980
6569+0000ebf4@10981
6570+0000ebd0@10983
6571+0000fbf4@10984
6572+0000fb74@10985
6573+0000fb54@10986
6574+0000fbf4@10987
6575+00007bf6@10989
6576+0000fbf6@10990
6577+0000fbd6@10992
6578+0000f352@10993
6579+0000b3d2@10994
6580+000033d2@10998
6581+00003352@10999
6582+0000a352@11000
6583+0000a3d2@11001
6584+0000afc2@11002
6585+00002fc2@11007
6586+00002f40@11008
6587+0000afc0@11009
6588+0000afe4@11011
6589+0000efe4@11012
6590+0000efc4@11014
6591+0000ef64@11015
6592+0000ef44@11016
6593+00006fc4@11017
6594+0000efe4@11018
6595+0000ffe4@11021
6596+0000ff64@11022
6597+0000ff44@11023
6598+0000ffe4@11024
6599+00007fe6@11026
6600+0000ffe6@11028
6601+0000f346@11030
6602+0000b346@11031
6603+0000b3c6@11032
6604+000033c6@11035
6605+0000a346@11037
6606+0000abe2@11039
6607+00002b60@11045
6608+0000abe0@11046
6609+0000abe4@11048
6610+0000ebe4@11049
6611+0000eb64@11052
6612+00006be4@11054
6613+0000ebe4@11056
6614+0000fbe4@11058
6615+0000fb64@11060
6616+0000fbe4@11061
6617+00007be6@11063
6618+0000fbe6@11065
6619+0000f53e@11067
6620+0000b5be@11069
6621+000035be@11072
6622+0000a5be@11074
6623+0000a53e@11075
6624+0000a582@11076
6625+0000a182@11077
6626+00002102@11082
6627+00002100@11083
6628+0000a180@11084
6629+0000a3a4@11085
6630+0000e3a0@11086
6631+0000e3a4@11087
6632+0000e324@11089
6633+0000e304@11090
6634+000063a4@11091
6635+00006184@11092
6636+0000e3a4@11093
6637+0000e180@11095
6638+0000f3a4@11096
6639+0000f324@11097
6640+0000f304@11098
6641+0000f3a4@11099
6642+000073a6@11100
6643+0000f3a6@11102
6644+0000f53e@11104
6645+0000b5be@11106
6646+000035be@11110
6647+0000a53e@11112
6648+0000a5be@11113
6649+0000a102@11114
6650+0000a182@11115
6651+00002182@11119
6652+00002100@11120
6653+0000a180@11121
6654+0000e1a4@11123
6655+0000e3a4@11124
6656+0000e1a4@11125
6657+0000e3a4@11126
6658+0000e304@11127
6659+000063a4@11128
6660+00006184@11129
6661+0000e1a4@11130
6662+0000e3a4@11131
6663+0000e184@11132
6664+0000f3a4@11133
6665+0000f324@11134
6666+0000f304@11135
6667+0000f3a4@11136
6668+000073a6@11138
6669+0000f3a6@11140
6670+0000fbb6@11141
6671+0000f936@11142
6672+0000b9b6@11143
6673+000039b6@11147
6674+00003936@11148
6675+0000a936@11149
6676+0000a9b6@11150
6677+0000ab42@11151
6678+0000abc2@11152
6679+00002bc2@11156
6680+00002b40@11157
6681+0000abc0@11158
6682+0000abe4@11160
6683+0000ebe4@11161
6684+0000eb64@11164
6685+00006be4@11166
6686+0000ebe4@11167
6687+0000fbe4@11170
6688+0000fb64@11171
6689+0000fb44@11172
6690+0000fbe4@11173
6691+00007be6@11175
6692+0000fbe6@11177
6693+0000f936@11179
6694+0000f9b6@11181
6695+000079b6@11184
6696+0000e936@11186
6697+0000ebc2@11188
6698+00006b40@11194
6699+0000eb40@11195
6700+0000ebc0@11196
6701+0000ebe4@11197
6702+0000abe4@11199
6703+0000a5e0@11200
6704+0000a560@11201
6705+0000a5e0@11202
6706+000025e0@11203
6707+0000a5e0@11205
6708+0000b5e0@11207
6709+0000b560@11209
6710+0000b5e0@11211
6711+000035e2@11212
6712+000075e2@11213
6713+0000f5e2@11214
6714+0000f91e@11216
6715+0000b91e@11217
6716+0000b99e@11218
6717+0000399e@11221
6718+0000a99e@11223
6719+0000a91e@11224
6720+0000abd2@11225
6721+00002b52@11231
6722+00002b50@11232
6723+0000abd0@11233
6724+0000abf4@11234
6725+0000ebf0@11235
6726+0000ebf4@11236
6727+0000ebd4@11237
6728+0000eb74@11238
6729+0000eb54@11239
6730+00006bf4@11240
6731+00006bd4@11241
6732+0000ebf4@11242
6733+0000ebd0@11244
6734+0000fbf4@11245
6735+0000fb54@11246
6736+0000fbd4@11247
6737+0000fbf4@11248
6738+00007bf6@11249
6739+0000fbf6@11251
6740+0000fb3e@11253
6741+0000f33e@11254
6742+0000b3be@11255
6743+000033be@11259
6744+000023be@11260
6745+0000a33e@11261
6746+0000abfe@11262
6747+0000abd2@11263
6748+00002b52@11268
6749+00002b50@11269
6750+0000abd0@11270
6751+0000ebf4@11272
6752+0000eb74@11276
6753+00006bf4@11277
6754+00006bd4@11278
6755+0000ebf4@11279
6756+0000fbf4@11282
6757+0000fb74@11283
6758+0000fb54@11284
6759+0000fbf4@11285
6760+00007bf6@11287
6761+0000fbf6@11288
6762+0000fbd6@11290
6763+0000f356@11291
6764+0000b3d6@11292
6765+000033d6@11296
6766+00003356@11297
6767+0000a356@11298
6768+0000a3d6@11299
6769+0000af42@11300
6770+0000afc2@11301
6771+00002fc2@11305
6772+00002f40@11306
6773+0000afc0@11307
6774+0000afe4@11309
6775+0000efe4@11310
6776+0000efc4@11312
6777+0000ef64@11313
6778+00006fc4@11315
6779+0000efe4@11316
6780+0000ffe4@11319
6781+0000ff64@11320
6782+0000ff44@11321
6783+0000ffe4@11322
6784+00007fe6@11324
6785+0000ffe6@11326
6786+0000f346@11328
6787+0000b346@11329
6788+0000b3c6@11330
6789+000033c6@11333
6790+0000a346@11335
6791+0000abe2@11337
6792+00002b60@11343
6793+0000abe0@11344
6794+0000abe4@11346
6795+0000ebe4@11347
6796+0000eb64@11350
6797+00006be4@11352
6798+0000ebe4@11354
6799+0000fbe4@11356
6800+0000fb64@11358
6801+0000fbe4@11359
6802+00007be6@11361
6803+0000fbe6@11363
6804+0000fd3e@11365
6805+0000f53e@11366
6806+0000b5be@11367
6807+000035be@11370
6808+0000a5be@11372
6809+0000a53e@11373
6810+0000a582@11374
6811+0000a182@11375
6812+00002102@11380
6813+00002100@11381
6814+0000a180@11382
6815+0000a3a4@11383
6816+0000e3a0@11384
6817+0000e3a4@11385
6818+0000e324@11387
6819+0000e304@11388
6820+000063a4@11389
6821+00006184@11390
6822+0000e3a4@11391
6823+0000f184@11393
6824+0000f3a4@11394
6825+0000f324@11395
6826+0000f304@11396
6827+0000f3a4@11397
6828+000073a6@11398
6829+0000f3a6@11400
6830+0000f53e@11402
6831+0000b5be@11404
6832+000035be@11408
6833+0000a53e@11410
6834+0000a5be@11411
6835+0000a102@11412
6836+0000a182@11413
6837+00002182@11417
6838+00002100@11418
6839+0000a180@11419
6840+0000e1a4@11421
6841+0000e3a4@11422
6842+0000e1a4@11423
6843+0000e3a4@11424
6844+0000e324@11425
6845+000063a4@11426
6846+00006184@11427
6847+0000e1a4@11428
6848+0000e3a4@11429
6849+0000f3a4@11431
6850+0000f324@11432
6851+0000f304@11433
6852+0000f3a4@11434
6853+000071a6@11436
6854+0000f3a6@11437
6855+0000fb3e@11439
6856+0000f93a@11440
6857+0000b9ba@11441
6858+000039ba@11445
6859+0000393a@11446
6860+0000a93a@11447
6861+0000a9ba@11448
6862+0000ab42@11449
6863+0000abc2@11450
6864+00002bc2@11454
6865+00002b40@11455
6866+0000abc0@11456
6867+0000abe4@11458
6868+0000ebe4@11459
6869+0000eb64@11462
6870+00006be4@11464
6871+0000ebe4@11465
6872+0000fbe4@11468
6873+0000fb64@11469
6874+0000fb44@11470
6875+0000fbe4@11471
6876+00007be6@11473
6877+0000fbe6@11475
6878+0000f93a@11477
6879+0000f9ba@11479
6880+000079ba@11482
6881+0000e93a@11484
6882+0000e9ba@11485
6883+0000eb42@11486
6884+0000ebc2@11487
6885+00006b40@11492
6886+0000ebc0@11493
6887+0000ebe4@11495
6888+0000abe4@11497
6889+0000a3a4@11498
6890+0000a324@11499
6891+000023a4@11501
6892+0000a3a4@11503
6893+0000b3a4@11505
6894+0000b324@11507
6895+0000b3a4@11508
6896+000033a6@11510
6897+000073a6@11511
6898+0000f3a6@11512
6899+0000f97e@11514
6900+0000b9fe@11516
6901+000039fe@11519
6902+0000a97e@11521
6903+0000a982@11523
6904+0000a182@11524
6905+00002102@11529
6906+00002180@11530
6907+0000a180@11531
6908+0000a3a4@11532
6909+0000e3a0@11533
6910+0000e3a4@11534
6911+0000e384@11535
6912+0000e324@11536
6913+0000e304@11537
6914+000063a4@11538
6915+00006184@11539
6916+0000e3a4@11540
6917+0000f184@11542
6918+0000f3a4@11543
6919+0000f304@11544
6920+0000f3a4@11545
6921+000073a6@11547
6922+0000f3a6@11549
6923+0000f11e@11551
6924+0000b19e@11553
6925+0000319e@11557
6926+0000211e@11558
6927+0000a11e@11559
6928+0000a19e@11560
6929+0000a182@11561
6930+00002102@11566
6931+00002100@11567
6932+0000a180@11568
6933+0000e1a4@11570
6934+0000e3a4@11571
6935+0000e184@11572
6936+0000e384@11573
6937+0000e304@11574
6938+000063a4@11575
6939+00006184@11576
6940+0000e1a4@11577
6941+0000e3a4@11578
6942+0000e184@11579
6943+0000f3a4@11580
6944+0000f324@11581
6945+0000f104@11582
6946+0000f3a4@11583
6947+000071a6@11585
6948+0000f3a6@11586
6949+0000f3da@11588
6950+0000f35a@11589
6951+0000b3da@11590
6952+000033da@11594
6953+0000335a@11595
6954+0000a35a@11596
6955+0000a3da@11597
6956+0000af42@11598
6957+0000afc2@11599
6958+00002fc2@11603
6959+00002f40@11604
6960+0000af40@11605
6961+0000afc0@11606
6962+0000afe4@11607
6963+0000efe4@11608
6964+0000ef64@11611
6965+00006fe4@11613
6966+0000efe4@11614
6967+0000ffe4@11617
6968+0000ff64@11618
6969+0000ff44@11619
6970+0000ffe4@11620
6971+00007fe6@11622
6972+0000ffe6@11624
6973+0000f346@11626
6974+0000b346@11627
6975+0000b3c6@11628
6976+000033c6@11631
6977+00003346@11632
6978+0000a346@11633
6979+0000abe2@11635
6980+00002b60@11641
6981+0000abe0@11642
6982+0000abe4@11644
6983+0000ebe4@11645
6984+0000eb64@11648
6985+00006be4@11650
6986+0000ebe4@11652
6987+0000fbe4@11654
6988+0000fb64@11656
6989+0000fbe4@11657
6990+00007be6@11659
6991+0000fbe6@11661
6992+0000f53e@11663
6993+0000b5be@11665
6994+000035be@11668
6995+0000a5be@11670
6996+0000a53e@11671
6997+0000a582@11672
6998+0000a182@11673
6999+00002102@11678
7000+00002100@11679
7001+0000a180@11680
7002+0000a3a4@11681
7003+0000e3a0@11682
7004+0000e3a4@11683
7005+0000e384@11684
7006+0000e324@11685
7007+0000e304@11686
7008+000063a4@11687
7009+000061a4@11688
7010+0000e3a4@11689
7011+0000f184@11691
7012+0000f3a4@11692
7013+0000f324@11693
7014+0000f304@11694
7015+0000f3a4@11695
7016+000073a6@11696
7017+0000f3a6@11698
7018+0000f53e@11700
7019+0000b5be@11702
7020+000035be@11706
7021+0000a53e@11708
7022+0000a5be@11709
7023+0000a102@11710
7024+0000a182@11711
7025+00002182@11715
7026+00002100@11716
7027+0000a180@11717
7028+0000e1a4@11719
7029+0000e3a4@11720
7030+0000e1a4@11721
7031+0000e3a4@11722
7032+0000e304@11723
7033+000063a4@11724
7034+00006184@11725
7035+0000e1a4@11726
7036+0000e3a4@11727
7037+0000e184@11728
7038+0000f3a4@11729
7039+0000f324@11730
7040+0000f104@11731
7041+0000f3a4@11732
7042+000071a6@11734
7043+0000f3a6@11735
7044+0000fb3e@11737
7045+0000f93e@11738
7046+0000b9be@11739
7047+000039be@11743
7048+0000393e@11744
7049+0000a93e@11745
7050+0000a9be@11746
7051+0000ab42@11747
7052+0000abc2@11748
7053+00002bc2@11752
7054+00002b40@11753
7055+0000abc0@11754
7056+0000abe4@11756
7057+0000ebe4@11757
7058+0000ebc4@11759
7059+0000eb64@11760
7060+00006be4@11762
7061+0000ebe4@11763
7062+0000fbe4@11766
7063+0000fb64@11767
7064+0000fb44@11768
7065+0000fbe4@11769
7066+00007be6@11771
7067+0000fbe6@11773
7068+0000f93e@11775
7069+0000f9be@11777
7070+000079be@11780
7071+000079bc@11781
7072+0000f93c@11782
7073+0000fbc0@11784
7074+0000ebc0@11785
7075+0000fbc0@11786
7076+0000ebc0@11787
7077+00006b40@11790
7078+0000eb40@11791
7079+0000ebc0@11792
7080+0000ebe4@11793
7081+0000ebc4@11796
7082+0000eb64@11797
7083+0000eb44@11798
7084+00006be4@11799
7085+0000ebe4@11801
7086+0000fbe4@11803
7087+0000fb64@11805
7088+0000fbe4@11806
7089+00007be6@11808
7090+0000fbe6@11810
7091+0000f11e@11812
7092+0000b19e@11814
7093+0000319e@11817
7094+0000a19e@11819
7095+0000a11e@11820
7096+0000a182@11821
7097+00002102@11827
7098+00002100@11828
7099+0000a180@11829
7100+0000a3a4@11830
7101+0000e3a0@11831
7102+0000e3a4@11832
7103+0000e184@11833
7104+0000e324@11834
7105+0000e304@11835
7106+000063a4@11836
7107+00006184@11837
7108+0000e3a4@11838
7109+0000f180@11840
7110+0000f3a4@11841
7111+0000f304@11842
7112+0000f3a4@11844
7113+000073a6@11845
7114+0000f3a6@11847
7115+0000f11e@11849
7116+0000b19e@11851
7117+0000319e@11855
7118+0000a19e@11856
7119+0000a11e@11857
7120+0000a19e@11858
7121+0000a182@11859
7122+00002102@11864
7123+00002100@11865
7124+0000a180@11866
7125+0000e3a4@11868
7126+0000e184@11870
7127+0000e3a4@11871
7128+0000e304@11872
7129+000063a4@11873
7130+00006184@11874
7131+0000e1a4@11875
7132+0000e3a4@11876
7133+0000e184@11877
7134+0000f3a4@11878
7135+0000f324@11879
7136+0000f304@11880
7137+0000f3a4@11881
7138+000071a6@11883
7139+0000f3a6@11884
7140+0000f3de@11886
7141+0000b3de@11888
7142+000033de@11892
7143+0000a35e@11894
7144+0000a3de@11895
7145+0000af42@11896
7146+0000afc2@11897
7147+00002fc2@11901
7148+00002f40@11902
7149+0000afc0@11903
7150+0000afe4@11905
7151+0000efe4@11906
7152+0000efc4@11908
7153+0000ef64@11909
7154+00006fe4@11911
7155+0000efe4@11912
7156+0000ffe4@11915
7157+0000ff64@11916
7158+0000ff44@11917
7159+0000ffe4@11918
7160+00007fe6@11920
7161+0000ffe6@11922
7162+0000f346@11924
7163+0000b3c6@11925
7164+000033c6@11929
7165+0000a346@11931
7166+0000abe2@11933
7167+00002b60@11939
7168+0000abe0@11940
7169+0000abe4@11942
7170+0000ebe4@11943
7171+0000eb64@11946
7172+00006be4@11948
7173+0000ebe4@11950
7174+0000fbe4@11952
7175+0000fb64@11954
7176+0000fbe4@11955
7177+00007be6@11957
7178+0000fbe6@11959
7179+0000f91e@11961
7180+0000b91e@11962
7181+0000b99e@11963
7182+0000399e@11966
7183+0000a99e@11968
7184+0000a91e@11969
7185+0000afa2@11970
7186+0000a7a2@11971
7187+00002722@11976
7188+00002720@11977
7189+0000a7a0@11978
7190+0000a7a4@11979
7191+0000e7a0@11980
7192+0000e7a4@11981
7193+0000e724@11983
7194+000067a4@11985
7195+0000e7a4@11987
7196+0000f7a4@11989
7197+0000f724@11991
7198+0000f7a4@11993
7199+000077a6@11994
7200+0000f7a6@11996
7201+0000f93e@11998
7202+0000b9be@12000
7203+000039be@12004
7204+0000293e@12005
7205+0000a93e@12006
7206+0000afbe@12007
7207+0000a7a2@12008
7208+00002722@12013
7209+00002720@12014
7210+0000a7a0@12015
7211+0000e7a4@12017
7212+0000e724@12021
7213+000067a4@12022
7214+0000e7a4@12024
7215+0000f7a4@12027
7216+0000f724@12028
7217+0000f7a4@12030
7218+000077a6@12032
7219+0000f7a6@12033
7220+0000ff3e@12035
7221+0000f93e@12036
7222+0000f9be@12037
7223+000079be@12041
7224+0000e93e@12043
7225+0000e9be@12044
7226+0000e722@12045
7227+0000e7a2@12046
7228+000067a2@12050
7229+00006720@12051
7230+0000e7a0@12052
7231+0000e7a4@12054
7232+0000a7a4@12056
7233+0000a5fe@12057
7234+0000a56c@12058
7235+0000a5ec@12059
7236+000025ec@12060
7237+0000a5ec@12061
7238+0000b5ec@12064
7239+0000b56c@12065
7240+0000b5ec@12067
7241+000035ee@12069
7242+000075ee@12070
7243+0000f5ee@12071
7244+0000f93e@12073
7245+0000f9be@12075
7246+000079be@12078
7247+0000e93e@12080
7248+0000ef22@12082
7249+0000e7a2@12083
7250+00006720@12088
7251+0000e7a0@12089
7252+0000e7a4@12091
7253+0000a7a4@12093
7254+0000a5ec@12094
7255+0000a56c@12095
7256+0000a5ec@12096
7257+000025ec@12097
7258+0000a5ec@12099
7259+0000b5ec@12101
7260+0000b56c@12102
7261+0000b5ec@12104
7262+000035ee@12106
7263+000075ee@12107
7264+0000f5ee@12108
7265+0000f11e@12110
7266+0000b11e@12111
7267+0000b19e@12112
7268+0000319e@12115
7269+0000a19e@12117
7270+0000a11e@12118
7271+0000a9d2@12119
7272+00002952@12125
7273+00002950@12126
7274+0000a9d0@12127
7275+0000abf4@12128
7276+0000ebf0@12129
7277+0000ebf4@12130
7278+0000ebd4@12131
7279+0000eb74@12132
7280+0000e950@12133
7281+00006bf4@12134
7282+000069d0@12135
7283+0000ebf4@12136
7284+0000e9d0@12138
7285+0000fbf4@12139
7286+0000fb54@12140
7287+0000f9d4@12141
7288+0000fbf4@12142
7289+00007bf6@12143
7290+000079f6@12144
7291+0000fbf6@12145
7292+0000fb1e@12147
7293+0000b31e@12148
7294+0000b39e@12149
7295+0000339e@12153
7296+0000a39e@12154
7297+0000a31e@12155
7298+0000abda@12156
7299+0000a9d2@12157
7300+00002952@12162
7301+00002950@12163
7302+0000a9d0@12164
7303+0000ebf4@12166
7304+0000e9d4@12168
7305+0000ebf4@12169
7306+0000eb54@12170
7307+00006bf4@12171
7308+000069d4@12172
7309+0000e9f4@12173
7310+0000ebf4@12174
7311+0000e9d4@12175
7312+0000fbf4@12176
7313+0000fb74@12177
7314+0000fb54@12178
7315+0000fbf4@12179
7316+000079f6@12181
7317+0000fbf6@12182
7318+0000ff5e@12184
7319+0000f51e@12185
7320+0000b59e@12186
7321+0000359e@12190
7322+0000a51e@12192
7323+0000a59e@12193
7324+0000a9d2@12194
7325+000029d2@12199
7326+00002950@12200
7327+0000a950@12201
7328+0000a9d0@12202
7329+0000a9d4@12203
7330+0000ebf4@12204
7331+0000e9d4@12205
7332+0000ebf4@12206
7333+0000eb54@12207
7334+000069f4@12209
7335+0000e9f4@12210
7336+0000ebf4@12211
7337+0000fbf4@12213
7338+0000fb74@12214
7339+0000f954@12215
7340+0000fbf4@12216
7341+00007bf6@12218
7342+0000fbf6@12220
7343+0000f71e@12222
7344+0000b71e@12223
7345+0000b79e@12224
7346+0000379e@12227
7347+0000a71e@12229
7348+0000a79e@12230
7349+0000a9d2@12231
7350+00002950@12237
7351+0000a9d0@12238
7352+0000abf4@12240
7353+0000ebf4@12241
7354+0000ebd4@12243
7355+0000eb74@12244
7356+0000eb54@12245
7357+00006bf4@12246
7358+0000ebf4@12248
7359+0000fbd4@12250
7360+0000fbf4@12251
7361+0000fb54@12252
7362+0000fbd4@12253
7363+0000fbf4@12254
7364+00007bf6@12255
7365+0000fbf6@12257
7366+0000f91e@12259
7367+0000b91e@12260
7368+0000b99e@12261
7369+0000399e@12264
7370+0000a99e@12266
7371+0000a91e@12267
7372+0000adf2@12268
7373+0000a5f2@12269
7374+00002572@12274
7375+00002570@12275
7376+0000a5f0@12276
7377+0000a7f4@12277
7378+0000e7f0@12278
7379+0000e7f4@12279
7380+0000e774@12281
7381+000067f4@12283
7382+000065f4@12284
7383+0000e7f4@12285
7384+0000e7f4@12288
+10211,
-0
1@@ -0,0 +1,10211 @@
2+;Size: 10203
3+;Rate: 50000000
4+;Channels: 16
5+;EnabledChannels: 65535
6+;TriggerPosition: 119
7+;Compressed: true
8+;AbsoluteLength: 12287
9+;CursorEnabled: true
10+000065f4@0
11+0000e7f4@1
12+0000f7f4@2
13+0000f574@3
14+0000f7f4@4
15+000077f6@5
16+0000f7fe@6
17+0000f99e@7
18+0000799e@9
19+0000e91e@10
20+0000e5f2@11
21+00006570@14
22+0000e5f0@15
23+0000e7f4@16
24+0000a180@17
25+0000a100@18
26+00002180@19
27+0000a180@20
28+0000b180@21
29+00003182@23
30+0000f182@24
31+0000f93e@25
32+0000b9be@26
33+000039be@28
34+0000a93e@29
35+0000a5f2@30
36+00002570@33
37+0000a7f4@34
38+0000e7f4@35
39+0000e774@36
40+000067f4@37
41+0000e7f4@38
42+0000f5f4@39
43+0000f774@40
44+0000f7f4@41
45+000077f6@42
46+0000f7f6@43
47+0000bb1e@44
48+0000bb9e@45
49+0000ab9e@47
50+0000aff2@48
51+0000a5f2@49
52+00002572@51
53+0000a5f0@52
54+0000e7f4@53
55+0000e5f4@54
56+0000e774@55
57+000067f4@56
58+0000e7f4@57
59+0000f7f4@58
60+0000f774@59
61+0000f7f4@60
62+0000f7f6@61
63+0000fd7e@62
64+0000b99a@63
65+0000399a@65
66+0000a91a@66
67+0000a5f2@67
68+00002570@70
69+0000a5f0@71
70+0000e7f4@72
71+000067f4@74
72+0000e5f4@75
73+0000e7f4@76
74+0000f774@77
75+0000f7f4@78
76+000077f6@79
77+0000f7f6@80
78+0000f93a@81
79+0000b9ba@82
80+000039ba@84
81+0000a9ba@85
82+0000a5f2@86
83+000025f2@88
84+0000a570@89
85+0000a7f0@90
86+0000e7f4@91
87+0000e774@92
88+000065f4@93
89+0000e7f4@94
90+0000f7f4@95
91+0000f774@96
92+0000f7f4@97
93+000077f6@98
94+0000f7f6@99
95+0000bb1a@100
96+0000bb9a@101
97+00003b9a@102
98+0000ab9a@103
99+0000a5f2@104
100+00002572@107
101+0000a5f0@108
102+0000e7f0@109
103+0000e7f4@110
104+0000e774@111
105+000067f4@112
106+0000e7f4@113
107+0000f7f4@114
108+000077f6@116
109+0000f7f6@117
110+0000fd1e@118
111+0000b89a@119
112+0000389a@121
113+0000a81a@122
114+0000a4f2@123
115+00002470@126
116+0000a474@127
117+0000e6f4@128
118+000066f4@130
119+0000e474@131
120+0000f6f4@133
121+00007476@135
122+0000f676@136
123+0000f8ba@137
124+0000b8ba@138
125+0000383a@140
126+0000a8fa@141
127+0000a4f2@142
128+000024f2@144
129+0000a470@145
130+0000e474@146
131+0000e6f4@147
132+00006470@149
133+0000e674@150
134+0000f6f4@151
135+00007676@154
136+0000f67e@155
137+0000ba9a@156
138+00003a9a@158
139+0000aa1a@159
140+0000a4f2@160
141+00002470@163
142+0000a470@164
143+0000e6f4@165
144+00006474@168
145+0000e674@169
146+0000f6f4@170
147+00007676@172
148+0000f676@173
149+0000f29a@174
150+0000b29a@175
151+0000321a@177
152+0000a21a@178
153+0000a4f2@179
154+00002470@182
155+0000a674@183
156+0000e6f4@184
157+00006674@186
158+0000e674@187
159+0000f474@188
160+0000f6f4@189
161+00007676@191
162+0000f676@192
163+0000b29a@193
164+0000a29a@196
165+0000a6f2@197
166+0000a4f2@198
167+0000a472@199
168+000024f2@200
169+0000a4f0@201
170+0000e6f4@202
171+0000e474@203
172+0000e674@204
173+000064f0@205
174+0000e6f4@206
175+0000f6f4@207
176+0000f674@208
177+0000f6f6@210
178+0000f6fe@211
179+0000b21a@212
180+0000329a@214
181+0000a29a@215
182+0000a4f2@216
183+0000a472@217
184+000024f0@219
185+0000a4f0@220
186+0000e6f4@221
187+0000e474@222
188+00006674@223
189+0000e6f4@224
190+0000f674@226
191+000076f6@228
192+0000f6f6@229
193+0000f2ae@230
194+0000b22e@231
195+000032ae@233
196+0000a2ae@234
197+0000a082@235
198+0000a002@236
199+00002002@237
200+0000a080@238
201+0000a2a0@239
202+0000e2a4@240
203+0000e224@241
204+000060a4@242
205+0000e2a4@243
206+0000f2a4@244
207+0000f224@245
208+0000f204@246
209+000072a6@247
210+0000f2a6@248
211+0000f2ae@249
212+0000f22e@250
213+0000722e@251
214+0000e2ae@252
215+0000e082@253
216+0000e002@254
217+00006082@256
218+0000e080@257
219+0000e280@258
220+0000a60c@259
221+0000268c@261
222+0000a68c@262
223+0000b68c@263
224+0000b60c@264
225+0000360e@265
226+0000f68e@266
227+0000f492@267
228+0000b412@268
229+00003492@270
230+0000a492@271
231+0000aaf2@272
232+0000aa72@273
233+0000aaf2@274
234+00002af0@275
235+0000aaf4@276
236+0000eaf4@277
237+00006af4@279
238+0000ea74@280
239+0000fa74@282
240+0000faf4@283
241+00007af6@284
242+0000fa76@285
243+0000b426@286
244+0000b4a6@287
245+000034a6@289
246+0000a476@290
247+0000a472@291
248+0000a4f2@292
249+000024f2@293
250+0000a470@294
251+0000e474@295
252+0000e6f4@296
253+000064f4@298
254+0000e674@299
255+0000f674@300
256+0000f6f4@301
257+000076f6@303
258+0000f676@304
259+0000b606@305
260+0000b686@306
261+00003686@307
262+0000a606@308
263+0000a472@309
264+0000a4f2@310
265+000024f0@312
266+0000a470@313
267+0000e674@314
268+0000e6f4@315
269+000066f4@317
270+0000e674@318
271+0000f6f4@319
272+000076f6@321
273+0000f676@322
274+0000f626@323
275+0000b6a6@324
276+000036a6@326
277+0000a626@327
278+0000a472@328
279+0000a4f2@329
280+000024f0@331
281+0000a674@332
282+0000e674@333
283+0000e6f4@334
284+000066f4@335
285+0000e674@336
286+0000f674@337
287+0000f6f4@338
288+000076f6@340
289+0000f676@341
290+0000b226@342
291+0000b2a6@343
292+0000a2a6@345
293+0000a226@346
294+0000a082@347
295+00002082@349
296+0000a000@350
297+0000e2a4@351
298+00006000@354
299+0000e2a4@355
300+0000f2a4@356
301+0000f224@358
302+0000f226@359
303+0000f8be@360
304+0000b9be@361
305+0000393e@363
306+0000a9be@364
307+0000abc2@365
308+0000ab42@367
309+00002b40@368
310+0000abc0@369
311+0000ebe4@370
312+00006b64@372
313+0000eb64@373
314+0000ebe4@374
315+0000fbe4@375
316+0000fb64@376
317+00007b66@377
318+0000fbe6@378
319+0000f3a6@379
320+0000b3a6@380
321+0000b326@381
322+00003326@382
323+0000a3a6@383
324+0000a182@384
325+00002102@386
326+0000a100@387
327+0000a3a0@388
328+0000e3a4@389
329+0000e324@390
330+00006104@391
331+0000e3a4@392
332+0000f3a4@393
333+0000f324@395
334+00007306@396
335+0000f3a6@397
336+0000b192@398
337+00003112@400
338+0000a112@401
339+0000a182@402
340+0000a102@404
341+00002102@405
342+0000a180@406
343+0000e380@407
344+0000e384@408
345+0000e304@409
346+00006100@410
347+0000e3a4@411
348+0000f3a4@412
349+00007306@414
350+0000f1a6@415
351+0000f192@416
352+0000b192@417
353+0000b112@418
354+00003112@419
355+0000a192@420
356+0000a182@421
357+0000a102@423
358+00002100@424
359+0000a184@425
360+0000e3a4@426
361+000063a4@428
362+0000e3a4@429
363+0000e180@430
364+0000f324@431
365+0000f3a4@432
366+000071a6@433
367+0000f3a6@434
368+0000f1de@435
369+0000b1de@436
370+0000315e@438
371+0000a5de@439
372+0000afc2@440
373+00002fc2@442
374+0000afc0@443
375+0000afe4@444
376+0000efe4@445
377+0000ef44@446
378+00006fc4@447
379+0000efe4@448
380+0000ffe4@449
381+0000ff44@450
382+0000ffe4@451
383+00007fe6@452
384+0000fff6@453
385+0000b3d6@454
386+000033d6@456
387+0000a356@457
388+0000a7f2@458
389+00002770@461
390+0000a7f0@462
391+0000e7f4@463
392+0000e774@465
393+000067f4@466
394+0000e7f4@467
395+0000f774@468
396+0000f7f4@469
397+000077f6@470
398+0000f7f6@471
399+0000f532@472
400+0000b5b2@473
401+000035b2@475
402+0000a532@476
403+0000ab82@477
404+00002b00@480
405+0000aba4@481
406+0000eba4@482
407+0000eb24@483
408+00006ba4@484
409+0000eba4@485
410+0000fba4@486
411+0000fb04@487
412+0000fba4@488
413+00007ba6@489
414+0000fba6@490
415+0000f712@491
416+0000b792@492
417+0000a792@494
418+0000af92@495
419+0000ab82@496
420+00002b02@498
421+0000ab80@499
422+0000eba4@500
423+0000eb24@502
424+00006b84@503
425+0000eba4@504
426+0000fba4@505
427+0000fb04@506
428+0000fba4@507
429+0000fba6@508
430+0000fb82@509
431+0000b982@510
432+00003982@512
433+0000a902@513
434+0000abc2@514
435+00002b40@517
436+0000abc0@518
437+0000ebe4@519
438+00006be4@521
439+0000ebe4@522
440+0000fb64@524
441+0000fbe4@525
442+00007be6@526
443+0000fbe6@527
444+0000f902@528
445+0000f982@529
446+00007982@531
447+0000e982@532
448+0000ebc2@533
449+00006bc2@535
450+0000ebc0@536
451+0000ebe0@537
452+0000abe4@538
453+0000a100@539
454+00002180@540
455+0000a180@541
456+0000b180@542
457+0000b100@543
458+0000b180@544
459+00007182@545
460+0000f182@546
461+0000b112@547
462+0000b192@548
463+00003192@549
464+0000a112@550
465+0000a182@551
466+00002102@554
467+0000a180@555
468+0000e380@556
469+0000e384@557
470+0000e304@558
471+00006384@559
472+0000e3a4@560
473+0000f3a4@561
474+0000f384@562
475+000073a6@563
476+0000f3a6@564
477+0000f112@565
478+0000b192@566
479+00003192@568
480+0000a112@569
481+0000a182@570
482+00002100@573
483+0000a184@574
484+0000e3a4@575
485+000063a4@577
486+0000e1a4@578
487+0000e180@579
488+0000f324@580
489+0000f3a4@581
490+000071a6@582
491+0000f3a6@583
492+0000f162@584
493+0000b1e2@585
494+00003162@587
495+0000a5e2@588
496+0000afc2@589
497+00002fc2@591
498+0000afc0@592
499+0000efe4@593
500+0000ef44@595
501+00006fc4@596
502+0000efe4@597
503+0000ffe4@598
504+0000ff44@599
505+0000ffe4@600
506+00007fe6@601
507+0000ffe6@602
508+0000b3c6@603
509+000033c6@605
510+0000a346@606
511+0000abe2@607
512+00002b60@610
513+0000abe0@611
514+0000ebe4@612
515+0000eb64@614
516+0000ebe4@615
517+0000fb64@617
518+0000fbe4@618
519+00007be6@619
520+0000fbe6@620
521+0000f732@621
522+0000b7b2@622
523+000037b2@624
524+0000a732@625
525+0000ab82@626
526+00002b00@629
527+0000aba4@630
528+0000eba4@631
529+0000eb24@632
530+00006ba4@633
531+0000eba4@634
532+0000fba4@635
533+0000fb24@636
534+0000fba4@637
535+00007ba6@638
536+0000fba6@639
537+0000b912@640
538+0000b992@641
539+0000a912@643
540+0000ab92@644
541+0000ab82@645
542+00002b02@647
543+0000ab80@648
544+0000eba4@649
545+0000eb04@651
546+00006b84@652
547+0000eba4@653
548+0000fba4@654
549+0000fb04@655
550+0000fba4@656
551+0000fba6@657
552+0000fb06@658
553+0000b986@659
554+00003986@661
555+0000a906@662
556+0000abc2@663
557+00002b40@666
558+0000abc0@667
559+0000ebe4@668
560+0000ebc4@669
561+00006be4@670
562+0000ebe4@671
563+0000fb64@673
564+0000fbe4@674
565+00007be6@675
566+0000fbe6@676
567+0000f906@677
568+0000f986@678
569+00007986@680
570+0000e986@681
571+0000ebc2@682
572+00006bc2@684
573+0000eb40@685
574+0000ebe0@686
575+0000abe4@687
576+0000a100@688
577+00002180@689
578+0000a180@690
579+0000b180@691
580+0000b100@692
581+0000b180@693
582+00007182@694
583+0000f182@695
584+0000b112@696
585+0000b192@697
586+00003192@698
587+0000a112@699
588+0000a182@700
589+00002102@703
590+0000a180@704
591+0000e3a0@705
592+0000e384@706
593+0000e304@707
594+000061a4@708
595+0000e3a4@709
596+0000f3a4@710
597+0000f384@711
598+000073a6@712
599+0000f3a6@713
600+0000f972@714
601+0000b9f2@715
602+000039f2@717
603+0000a972@718
604+0000a182@719
605+00002100@722
606+0000a184@723
607+0000e1a4@724
608+0000e3a4@725
609+000063a4@726
610+0000e1a4@727
611+0000e180@728
612+0000f324@729
613+0000f3a4@730
614+000071a6@731
615+0000f3a6@732
616+0000f166@733
617+0000b1e6@734
618+00003166@736
619+0000a5e6@737
620+0000afc2@738
621+00002fc2@740
622+0000afc0@741
623+0000afe4@742
624+0000efe4@743
625+0000ef64@744
626+00006fc4@745
627+0000efe4@746
628+0000ffe4@747
629+0000ff44@748
630+0000ffe4@749
631+00007fe6@750
632+0000ffe6@751
633+0000b3c6@752
634+000033c6@754
635+0000a346@755
636+0000abe2@756
637+00002b60@759
638+0000abe0@760
639+0000ebe4@761
640+0000eb64@763
641+0000ebe4@764
642+0000fb64@766
643+0000fbe4@767
644+00007be6@768
645+0000fbe6@769
646+0000f932@770
647+0000b9b2@771
648+000039b2@773
649+0000a932@774
650+0000ab82@775
651+0000ab80@778
652+0000aba4@779
653+0000eba4@780
654+0000eb24@781
655+00006ba4@782
656+0000eba4@783
657+0000fb80@784
658+0000fb24@785
659+0000fba4@786
660+00007ba6@787
661+0000fba6@788
662+0000b312@789
663+0000b392@790
664+0000a312@792
665+0000afb2@793
666+0000ada2@794
667+00002d22@796
668+0000ada0@797
669+0000efa4@798
670+0000ef24@800
671+00006fa0@801
672+0000efa4@802
673+0000ffa4@803
674+0000ff24@804
675+0000ffa4@805
676+0000ffa6@806
677+0000fdae@807
678+0000b98a@808
679+0000398a@810
680+0000a90a@811
681+0000abc2@812
682+00002b40@815
683+0000abc0@816
684+0000ebe4@817
685+00006be4@819
686+0000ebe4@820
687+0000fb64@822
688+0000fbe4@823
689+00007be6@824
690+0000fbe6@825
691+0000f90a@826
692+0000f98a@827
693+0000798a@829
694+0000e98a@830
695+0000ebc2@831
696+00006bc2@833
697+0000ebc0@834
698+0000ebe0@835
699+0000abe4@836
700+0000a560@837
701+000025e0@838
702+0000a5e0@839
703+0000b5e0@840
704+0000b560@841
705+0000b5e0@842
706+000075e2@843
707+0000f5e2@844
708+0000b912@845
709+0000b992@846
710+00003992@847
711+0000a912@848
712+0000abd2@849
713+00002b50@852
714+0000abd0@853
715+0000ebf0@854
716+0000ebd4@855
717+0000eb54@856
718+00006bd4@857
719+0000ebf4@858
720+0000fbf4@859
721+00007bf6@861
722+0000fbf6@862
723+0000f912@863
724+0000b992@864
725+00003992@866
726+0000a912@867
727+0000abd2@868
728+00002b50@871
729+0000abd4@872
730+0000ebf4@873
731+0000eb74@874
732+00006bf4@875
733+0000ebf4@876
734+0000ebd0@877
735+0000fb74@878
736+0000fbf4@879
737+00007bf6@880
738+0000fbf6@881
739+0000b16a@882
740+0000b1ea@883
741+000031ea@885
742+0000a5ea@886
743+0000afc2@887
744+00002fc2@889
745+0000afc0@890
746+0000efe4@891
747+0000ef44@893
748+00006fc4@894
749+0000efe4@895
750+0000ffe4@896
751+0000ff40@897
752+0000ffe4@898
753+00007fe6@899
754+0000ffe6@900
755+0000b3c6@901
756+000033c6@903
757+0000a346@904
758+0000abe2@905
759+00002b60@908
760+0000abe0@909
761+0000ebe4@910
762+0000eb64@912
763+0000ebe4@913
764+0000fb64@915
765+0000fbe4@916
766+00007be6@917
767+0000fbe6@918
768+0000f332@919
769+0000b3b2@920
770+000033b2@922
771+0000a332@923
772+0000ada2@924
773+0000ada0@927
774+0000afa4@928
775+0000efa4@929
776+0000ef24@930
777+00006fa4@931
778+0000efa4@932
779+0000ffa0@933
780+0000ff24@934
781+0000ffa4@935
782+00007fa6@936
783+0000ffa6@937
784+0000b512@938
785+0000b592@939
786+0000a512@941
787+0000adb2@942
788+0000ada2@943
789+00002d22@945
790+0000ada0@946
791+0000efa4@947
792+0000eda4@948
793+0000ef24@949
794+00006da4@950
795+0000efa4@951
796+0000ffa4@952
797+0000ff24@953
798+0000ffa4@954
799+0000ffa6@955
800+0000fd2e@956
801+0000b98e@957
802+0000398e@959
803+0000a90e@960
804+0000abc2@961
805+00002b40@964
806+0000abc0@965
807+0000ebe4@966
808+00006be4@968
809+0000ebe4@969
810+0000fb64@971
811+0000fbe4@972
812+00007be6@973
813+0000fbe6@974
814+0000f90e@975
815+0000f98e@976
816+0000798c@978
817+0000f98c@979
818+0000fbc0@980
819+0000ebc0@981
820+00006bc0@982
821+0000ebc0@983
822+0000ebe0@984
823+0000ebe4@985
824+0000eb64@986
825+00006be4@987
826+0000ebe4@988
827+0000fbe4@989
828+0000fb44@990
829+0000fbe4@991
830+00007be6@992
831+0000fbe6@993
832+0000b912@994
833+0000b992@995
834+00003992@996
835+0000a912@997
836+0000abd2@998
837+00002b50@1001
838+0000abd0@1002
839+0000ebf0@1003
840+0000ebd4@1004
841+0000eb54@1005
842+00006bf4@1006
843+0000ebf4@1007
844+0000fbf4@1008
845+00007bf6@1010
846+0000fbf6@1011
847+0000f912@1012
848+0000b992@1013
849+00003992@1015
850+0000a912@1016
851+0000abd2@1017
852+00002b50@1020
853+0000abd4@1021
854+0000ebf4@1022
855+00006bf4@1024
856+0000ebf4@1025
857+0000ebd0@1026
858+0000fb74@1027
859+0000fbf4@1028
860+00007bf6@1029
861+0000fbf6@1030
862+0000b16e@1031
863+0000b1ee@1032
864+000021ee@1034
865+0000a5ee@1035
866+0000afc2@1036
867+00002fc2@1038
868+0000afc0@1039
869+0000efe4@1040
870+0000ef64@1042
871+00006fc4@1043
872+0000efe4@1044
873+0000ffe4@1045
874+0000ff64@1046
875+0000ffe4@1047
876+00007fe6@1048
877+0000ffe6@1049
878+0000b3c6@1050
879+000033c6@1052
880+0000a346@1053
881+0000abe2@1054
882+00002b60@1057
883+0000abe0@1058
884+0000ebe4@1059
885+0000eb64@1061
886+0000ebe4@1062
887+0000fb64@1064
888+0000fbe4@1065
889+00007be6@1066
890+0000fbe6@1067
891+0000f532@1068
892+0000b5b2@1069
893+000035b2@1071
894+0000a532@1072
895+0000ada2@1073
896+0000ada0@1076
897+0000afa4@1077
898+0000efa4@1078
899+0000ef24@1079
900+00006fa4@1080
901+0000efa4@1081
902+0000ffa4@1082
903+0000ff24@1083
904+0000ffa4@1084
905+00007fa6@1085
906+0000ffa6@1086
907+0000b712@1087
908+0000b792@1088
909+0000a712@1090
910+0000adb2@1091
911+0000ada2@1092
912+00002d22@1094
913+0000ada0@1095
914+0000efa4@1096
915+0000ef24@1098
916+00006fa4@1099
917+0000efa4@1100
918+0000ffa4@1101
919+0000ff20@1102
920+00007fa4@1103
921+0000ffa6@1104
922+0000fdb2@1105
923+0000b992@1106
924+00003992@1108
925+0000a912@1109
926+0000abc2@1110
927+00002b40@1113
928+0000abc0@1114
929+0000ebe4@1115
930+00006be4@1117
931+0000ebe4@1118
932+0000fb64@1120
933+0000fbe4@1121
934+00007be6@1122
935+0000fbe6@1123
936+0000f912@1124
937+0000f992@1125
938+00007992@1127
939+0000e992@1128
940+0000ebc2@1129
941+00006bc2@1131
942+0000ebc0@1132
943+0000ebe0@1133
944+0000abe4@1134
945+0000a560@1135
946+000025e0@1136
947+0000a5e0@1137
948+0000b5e0@1138
949+0000b560@1139
950+0000b5e0@1140
951+000075e2@1141
952+0000f5e2@1142
953+0000b912@1143
954+0000b992@1144
955+00003992@1145
956+0000a912@1146
957+0000abd2@1147
958+00002b50@1150
959+0000abd0@1151
960+0000ebf0@1152
961+0000ebd0@1153
962+0000eb54@1154
963+00006bf4@1155
964+0000ebf4@1156
965+0000fbf4@1157
966+00007bf6@1159
967+0000fbf6@1160
968+0000f912@1161
969+0000b992@1162
970+00003992@1164
971+0000a912@1165
972+0000abd2@1166
973+00002b50@1169
974+0000abf4@1170
975+0000ebf4@1171
976+0000eb74@1172
977+00006bf4@1173
978+0000ebf4@1174
979+0000ebd0@1175
980+0000fb74@1176
981+0000fbf4@1177
982+00007bf6@1178
983+0000fbf6@1179
984+0000b172@1180
985+0000b1f2@1181
986+00002172@1183
987+0000a5f2@1184
988+0000afc2@1185
989+00002f42@1187
990+0000afc0@1188
991+0000efe4@1189
992+0000ef64@1191
993+00006fc4@1192
994+0000efe4@1193
995+0000ffe4@1194
996+0000ff44@1195
997+0000ffe4@1196
998+00007fe6@1197
999+0000ffe6@1198
1000+0000b3c6@1199
1001+000033c6@1201
1002+0000a346@1202
1003+0000abe2@1203
1004+00002b60@1206
1005+0000abe0@1207
1006+0000ebe4@1208
1007+0000eb64@1210
1008+0000ebe4@1211
1009+0000fb64@1213
1010+0000fbe4@1214
1011+00007be6@1215
1012+0000fbe6@1216
1013+0000fb12@1217
1014+0000bb92@1218
1015+00003b92@1220
1016+0000ab12@1221
1017+0000ab82@1222
1018+0000ab00@1225
1019+0000aba4@1226
1020+0000eba4@1227
1021+0000eb24@1228
1022+00006ba4@1229
1023+0000eba4@1230
1024+0000fb84@1231
1025+0000fb24@1232
1026+0000fba4@1233
1027+00007ba6@1234
1028+0000fba6@1235
1029+0000fb32@1236
1030+0000bbb2@1237
1031+0000ab32@1239
1032+0000ab82@1240
1033+00002b02@1243
1034+0000ab80@1244
1035+0000eba4@1245
1036+0000eb84@1246
1037+0000eb04@1247
1038+00006b84@1248
1039+0000eba4@1249
1040+0000fba4@1250
1041+0000fb00@1251
1042+00007ba4@1252
1043+0000fba6@1253
1044+0000fb16@1254
1045+0000b996@1255
1046+00003996@1257
1047+0000a916@1258
1048+0000abc2@1259
1049+00002b40@1262
1050+0000abc0@1263
1051+0000ebe4@1264
1052+0000ebc4@1265
1053+00006be4@1266
1054+0000ebe4@1267
1055+0000fb64@1269
1056+0000fbe4@1270
1057+00007be6@1271
1058+0000fbe6@1272
1059+0000f916@1273
1060+0000f996@1274
1061+00007996@1276
1062+0000e996@1277
1063+0000ebc2@1278
1064+00006bc2@1280
1065+0000eb40@1281
1066+0000ebe0@1282
1067+0000abe4@1283
1068+0000a560@1284
1069+000025e0@1285
1070+0000a5e0@1286
1071+0000b5e0@1287
1072+0000b560@1288
1073+0000b5e0@1289
1074+000075e2@1290
1075+0000f5e2@1291
1076+0000b912@1292
1077+0000b992@1293
1078+00003992@1294
1079+0000a912@1295
1080+0000abd2@1296
1081+00002b50@1299
1082+0000abd0@1300
1083+0000ebf0@1301
1084+0000ebd4@1302
1085+0000eb54@1303
1086+00006bf4@1304
1087+0000ebf4@1305
1088+0000fbf4@1306
1089+00007bf6@1308
1090+0000fbf6@1309
1091+0000f912@1310
1092+0000b992@1311
1093+00003992@1313
1094+0000a912@1314
1095+0000abd2@1315
1096+00002b50@1318
1097+0000abf4@1319
1098+0000ebf4@1320
1099+0000eb74@1321
1100+00006bf4@1322
1101+0000ebf4@1323
1102+0000ebd0@1324
1103+0000fb74@1325
1104+0000fbf4@1326
1105+00007bf6@1327
1106+0000fbf6@1328
1107+0000b176@1329
1108+0000b1f6@1330
1109+00003176@1332
1110+0000a7f6@1333
1111+0000afc2@1334
1112+00002fc2@1336
1113+0000afc0@1337
1114+0000efe4@1338
1115+0000ef64@1340
1116+00006fc4@1341
1117+0000efe4@1342
1118+0000ffe4@1343
1119+0000ff44@1344
1120+0000ffe4@1345
1121+00007fe6@1346
1122+0000ffe6@1347
1123+0000b3c6@1348
1124+000033c6@1350
1125+0000a346@1351
1126+0000abe2@1352
1127+00002b60@1355
1128+0000abe0@1356
1129+0000ebe4@1357
1130+0000eb64@1359
1131+0000ebe4@1360
1132+0000fbe4@1362
1133+00007be6@1364
1134+0000fbe6@1365
1135+0000fd12@1366
1136+0000bd92@1367
1137+00003d92@1369
1138+0000ad12@1370
1139+0000ab82@1371
1140+0000ab80@1374
1141+0000aba4@1375
1142+0000eba4@1376
1143+0000eb24@1377
1144+00006ba4@1378
1145+0000eba4@1379
1146+0000fb84@1380
1147+0000fb04@1381
1148+0000fba4@1382
1149+00007ba6@1383
1150+0000fba6@1384
1151+0000fd32@1385
1152+0000bdb2@1386
1153+0000adb2@1388
1154+0000af82@1389
1155+0000ab82@1390
1156+00002b02@1392
1157+0000ab80@1393
1158+0000eba4@1394
1159+0000eb24@1396
1160+00006ba4@1397
1161+0000eba4@1398
1162+0000fba4@1399
1163+0000fb24@1400
1164+00007ba6@1401
1165+0000fba6@1402
1166+0000fb1e@1403
1167+0000b99a@1404
1168+0000399a@1406
1169+0000a91a@1407
1170+0000abc2@1408
1171+00002b40@1411
1172+0000abc0@1412
1173+0000ebe4@1413
1174+00006be4@1415
1175+0000ebe4@1416
1176+0000fb64@1418
1177+0000fbe4@1419
1178+00007be6@1420
1179+0000fbe6@1421
1180+0000f91a@1422
1181+0000f99a@1423
1182+0000799a@1425
1183+0000e99a@1426
1184+0000ebc2@1427
1185+00006bc2@1429
1186+0000ebc0@1430
1187+0000ebe0@1431
1188+0000abe4@1432
1189+0000a560@1433
1190+000025e0@1434
1191+0000a5e0@1435
1192+0000b5e0@1436
1193+0000b560@1437
1194+0000b5e0@1438
1195+000075e2@1439
1196+0000f5e2@1440
1197+0000b912@1441
1198+0000b992@1442
1199+00003992@1443
1200+0000a912@1444
1201+0000abd2@1445
1202+00002b50@1448
1203+0000abd0@1449
1204+0000ebf0@1450
1205+0000ebd4@1451
1206+0000eb54@1452
1207+00006bf4@1453
1208+0000ebf4@1454
1209+0000fbf4@1455
1210+00007bf6@1457
1211+0000fbf6@1458
1212+0000f912@1459
1213+0000b992@1460
1214+00003992@1462
1215+0000a912@1463
1216+0000abd2@1464
1217+00002b50@1467
1218+0000abf4@1468
1219+0000ebf4@1469
1220+0000eb74@1470
1221+00006bf4@1471
1222+0000ebf4@1472
1223+0000ebd0@1473
1224+0000fb74@1474
1225+0000fbf4@1475
1226+00007bf6@1476
1227+0000fbf6@1477
1228+0000b17a@1478
1229+0000b1fa@1479
1230+0000217a@1481
1231+0000a7fa@1482
1232+0000afc2@1483
1233+00002fc2@1485
1234+0000afc0@1486
1235+0000efe4@1487
1236+0000ef64@1489
1237+00006fe4@1490
1238+0000efe4@1491
1239+0000ffe4@1492
1240+0000ff44@1493
1241+0000ffe4@1494
1242+00007fe6@1495
1243+0000ffe6@1496
1244+0000b3c6@1497
1245+000033c6@1499
1246+0000a346@1500
1247+0000abe2@1501
1248+00002b60@1504
1249+0000abe0@1505
1250+0000ebe4@1506
1251+0000eb64@1508
1252+0000ebe4@1509
1253+0000fb64@1511
1254+0000fbe4@1512
1255+00007be6@1513
1256+0000fbe6@1514
1257+0000ff12@1515
1258+0000bf92@1516
1259+00003f92@1518
1260+0000af12@1519
1261+0000ab82@1520
1262+0000ab80@1523
1263+0000aba4@1524
1264+0000eba4@1525
1265+0000eb24@1526
1266+00006ba4@1527
1267+0000eba4@1528
1268+0000fb84@1529
1269+0000fb04@1530
1270+0000fba4@1531
1271+00007ba6@1532
1272+0000fba6@1533
1273+0000ff32@1534
1274+0000bfb2@1535
1275+0000afb2@1537
1276+0000ab82@1538
1277+00002b02@1541
1278+0000ab80@1542
1279+0000eba4@1543
1280+0000eb84@1544
1281+0000eb24@1545
1282+00006ba4@1546
1283+0000eba4@1547
1284+0000fba4@1548
1285+0000fb04@1549
1286+00007ba6@1550
1287+0000fba6@1551
1288+0000fb1e@1552
1289+0000b99e@1553
1290+0000399e@1555
1291+0000a91e@1556
1292+0000abc2@1557
1293+00002b40@1560
1294+0000abc0@1561
1295+0000ebe4@1562
1296+00006be4@1564
1297+0000ebe4@1565
1298+0000fb64@1567
1299+0000fbe4@1568
1300+00007be6@1569
1301+0000fbe6@1570
1302+0000f91e@1571
1303+0000f99e@1572
1304+0000799c@1574
1305+0000f99c@1575
1306+0000fbc0@1576
1307+0000ebc0@1577
1308+00006bc0@1578
1309+0000ebc0@1579
1310+0000ebe0@1580
1311+0000ebe4@1581
1312+0000eb64@1582
1313+00006be4@1583
1314+0000ebe4@1584
1315+0000fbe4@1585
1316+0000fb44@1586
1317+0000fbe4@1587
1318+00007be6@1588
1319+0000fbe6@1589
1320+0000b912@1590
1321+0000b992@1591
1322+00003992@1592
1323+0000a912@1593
1324+0000abd2@1594
1325+00002b50@1597
1326+0000abd0@1598
1327+0000ebf0@1599
1328+0000ebd0@1600
1329+0000eb54@1601
1330+00006bf4@1602
1331+0000ebf4@1603
1332+0000fbf4@1604
1333+00007bf6@1606
1334+0000fbf6@1607
1335+0000fb12@1608
1336+0000bb92@1609
1337+00003b92@1611
1338+0000ab12@1612
1339+0000abe2@1613
1340+00002b60@1616
1341+0000abe4@1617
1342+0000ebe4@1618
1343+0000eb64@1619
1344+00006be4@1620
1345+0000ebe4@1621
1346+0000ebe0@1622
1347+0000fb64@1623
1348+0000fbe4@1624
1349+00007be6@1625
1350+0000fbe6@1626
1351+0000f17e@1627
1352+0000b1fe@1628
1353+000021fe@1630
1354+0000a7fe@1631
1355+0000afc2@1632
1356+00002fc2@1634
1357+0000afc0@1635
1358+0000efe4@1636
1359+0000ef44@1638
1360+00006fc4@1639
1361+0000efe4@1640
1362+0000ffe4@1641
1363+0000ff44@1642
1364+0000ffe4@1643
1365+00007fe6@1644
1366+0000ffe6@1645
1367+0000b3c6@1646
1368+000033c6@1648
1369+0000a346@1649
1370+0000abe2@1650
1371+00002b60@1653
1372+0000abe0@1654
1373+0000ebe4@1655
1374+0000eb64@1657
1375+0000ebe4@1658
1376+0000fb64@1660
1377+0000fbe4@1661
1378+00007be6@1662
1379+0000fbe6@1663
1380+0000f712@1664
1381+0000b792@1665
1382+00003792@1667
1383+0000a712@1668
1384+0000a992@1669
1385+0000a990@1672
1386+0000abb4@1673
1387+0000ebb4@1674
1388+0000eb34@1675
1389+00006bb4@1676
1390+0000ebb4@1677
1391+0000fb94@1678
1392+0000fb14@1679
1393+0000fbb4@1680
1394+00007b96@1681
1395+0000fbb6@1682
1396+0000b732@1683
1397+0000b7b2@1684
1398+0000a7b2@1686
1399+0000a9b2@1687
1400+0000a992@1688
1401+00002912@1690
1402+0000a990@1691
1403+0000ebb4@1692
1404+0000eb94@1693
1405+0000eb14@1694
1406+00006990@1695
1407+0000ebb4@1696
1408+0000fbb4@1697
1409+0000fb10@1698
1410+00007bb4@1699
1411+0000fbb6@1700
1412+0000f9b2@1701
1413+0000b9a2@1702
1414+000039a2@1704
1415+0000a922@1705
1416+0000abc2@1706
1417+00002b40@1709
1418+0000abc0@1710
1419+0000ebe4@1711
1420+00006be4@1713
1421+0000ebe4@1714
1422+0000fb64@1716
1423+0000fbe4@1717
1424+00007be6@1718
1425+0000fbe6@1719
1426+0000f922@1720
1427+0000f9a2@1721
1428+000079a2@1723
1429+0000e9a2@1724
1430+0000ebc2@1725
1431+00006bc2@1727
1432+0000ebc0@1728
1433+0000ebe4@1729
1434+0000abe4@1730
1435+0000a96c@1731
1436+000029ec@1732
1437+0000a9ec@1733
1438+0000b9ec@1734
1439+0000b96c@1735
1440+0000b9ec@1736
1441+000079ee@1737
1442+0000f9ee@1738
1443+0000bbb2@1739
1444+00003bb2@1741
1445+0000ab32@1742
1446+0000abe2@1743
1447+00002b60@1746
1448+0000abe0@1747
1449+0000ebe4@1748
1450+0000eb64@1750
1451+00006be4@1751
1452+0000ebe4@1752
1453+0000fbe4@1753
1454+00007be6@1755
1455+0000fbe6@1756
1456+0000f912@1757
1457+0000b992@1758
1458+00003992@1760
1459+0000a912@1761
1460+0000abd2@1762
1461+00002b50@1765
1462+0000abf4@1766
1463+0000ebf4@1767
1464+0000eb74@1768
1465+00006bf4@1769
1466+0000ebf4@1770
1467+0000ebd0@1771
1468+0000fb74@1772
1469+0000fbf4@1773
1470+00007bf6@1774
1471+0000fbf6@1775
1472+0000b342@1776
1473+0000b3c2@1777
1474+000023c2@1779
1475+0000a7c2@1780
1476+0000afc2@1781
1477+00002f42@1783
1478+0000afc0@1784
1479+0000efe4@1785
1480+0000ef44@1787
1481+00006fc4@1788
1482+0000efe4@1789
1483+0000ffe4@1790
1484+0000ff44@1791
1485+0000ffe4@1792
1486+00007fe6@1793
1487+0000ffe6@1794
1488+0000b3c6@1795
1489+000033c6@1797
1490+0000a346@1798
1491+0000abe2@1799
1492+00002b60@1802
1493+0000abe0@1803
1494+0000ebe4@1804
1495+0000eb64@1806
1496+0000ebe4@1807
1497+0000fb64@1809
1498+0000fbe4@1810
1499+00007be6@1811
1500+0000fbe6@1812
1501+0000ff12@1813
1502+0000bf92@1814
1503+00003f92@1816
1504+0000af12@1817
1505+0000aba2@1818
1506+0000aba0@1821
1507+0000aba4@1822
1508+0000eba4@1823
1509+0000eb24@1824
1510+00006ba4@1825
1511+0000eba4@1826
1512+0000fba4@1827
1513+0000fb24@1828
1514+0000fba4@1829
1515+00007ba6@1830
1516+0000fba6@1831
1517+0000b532@1832
1518+0000b5b2@1833
1519+0000a532@1835
1520+0000a182@1836
1521+00002102@1839
1522+0000a180@1840
1523+0000e3a4@1841
1524+0000e304@1843
1525+00006180@1844
1526+0000e3a4@1845
1527+0000f3a4@1846
1528+0000f304@1847
1529+000073a6@1848
1530+0000f3a6@1849
1531+0000f926@1850
1532+0000b9a6@1851
1533+000039a6@1853
1534+0000a926@1854
1535+0000abc2@1855
1536+00002b40@1858
1537+0000abc0@1859
1538+0000ebe4@1860
1539+00006be4@1862
1540+0000ebe4@1863
1541+0000fb64@1865
1542+0000fbe4@1866
1543+00007be6@1867
1544+0000fbe6@1868
1545+0000f926@1869
1546+0000f9a6@1870
1547+000079a6@1872
1548+0000e9a6@1873
1549+0000ebc2@1874
1550+00006bc2@1876
1551+0000ebc0@1877
1552+0000ebe4@1878
1553+0000abe4@1879
1554+0000a560@1880
1555+000025e0@1881
1556+0000a5e0@1882
1557+0000b5e0@1883
1558+0000b560@1884
1559+0000b5e0@1885
1560+000075e2@1886
1561+0000f5e2@1887
1562+0000b912@1888
1563+0000b992@1889
1564+00003992@1890
1565+0000a912@1891
1566+0000abd2@1892
1567+00002b50@1895
1568+0000abd0@1896
1569+0000ebf0@1897
1570+0000ebd4@1898
1571+0000eb54@1899
1572+00006bf4@1900
1573+0000ebf4@1901
1574+0000fbf4@1902
1575+00007bf6@1904
1576+0000fbf6@1905
1577+0000f912@1906
1578+0000b992@1907
1579+00003992@1909
1580+0000a912@1910
1581+0000abd2@1911
1582+00002b50@1914
1583+0000abf4@1915
1584+0000ebf4@1916
1585+0000eb74@1917
1586+00006bf4@1918
1587+0000ebf4@1919
1588+0000ebd0@1920
1589+0000fb74@1921
1590+0000fbf4@1922
1591+00007bf6@1923
1592+0000fbf6@1924
1593+0000b346@1925
1594+0000b3c6@1926
1595+000023c6@1928
1596+0000afc6@1929
1597+0000afc2@1930
1598+00002f42@1932
1599+0000afc0@1933
1600+0000efe4@1934
1601+0000ef64@1936
1602+00006fc4@1937
1603+0000efe4@1938
1604+0000ffe4@1939
1605+0000ff44@1940
1606+0000ffe4@1941
1607+00007fe6@1942
1608+0000ffe6@1943
1609+0000b3c6@1944
1610+000033c6@1946
1611+0000a346@1947
1612+0000abe2@1948
1613+00002b60@1951
1614+0000abe0@1952
1615+0000ebe4@1953
1616+0000eb64@1955
1617+0000ebe4@1956
1618+0000fb64@1958
1619+0000fbe4@1959
1620+00007be6@1960
1621+0000fbe6@1961
1622+0000f532@1962
1623+0000b5b2@1963
1624+000035b2@1965
1625+0000a532@1966
1626+0000a182@1967
1627+0000a180@1970
1628+0000a3a4@1971
1629+0000e3a4@1972
1630+0000e324@1973
1631+000063a4@1974
1632+0000e3a4@1975
1633+0000f184@1976
1634+0000f304@1977
1635+0000f3a4@1978
1636+000073a6@1979
1637+0000f3a6@1980
1638+0000f532@1981
1639+0000b5b2@1982
1640+0000a5b2@1984
1641+0000a182@1985
1642+00002102@1988
1643+0000a180@1989
1644+0000e3a4@1990
1645+0000e324@1992
1646+00006380@1993
1647+0000e3a4@1994
1648+0000f3a4@1995
1649+0000f304@1996
1650+000073a6@1997
1651+0000f3a6@1998
1652+0000f92a@1999
1653+0000b9aa@2000
1654+000039aa@2002
1655+0000a92a@2003
1656+0000abc2@2004
1657+00002b40@2007
1658+0000abc0@2008
1659+0000ebe4@2009
1660+00006be4@2011
1661+0000ebe4@2012
1662+0000fb64@2014
1663+0000fbe4@2015
1664+00007be6@2016
1665+0000fbe6@2017
1666+0000f92a@2018
1667+0000f9aa@2019
1668+000079aa@2021
1669+0000e9aa@2022
1670+0000ebc2@2023
1671+00006bc2@2025
1672+0000ebc0@2026
1673+0000ebe4@2027
1674+0000abe4@2028
1675+0000a560@2029
1676+000025e0@2030
1677+0000a5e0@2031
1678+0000b5e0@2032
1679+0000b560@2033
1680+0000b5e0@2034
1681+000075e2@2035
1682+0000f5e2@2036
1683+0000b912@2037
1684+0000b992@2038
1685+00003992@2039
1686+0000a912@2040
1687+0000abd2@2041
1688+00002b50@2044
1689+0000abd0@2045
1690+0000ebf4@2046
1691+0000ebd4@2047
1692+0000eb54@2048
1693+00006bf4@2049
1694+0000ebf4@2050
1695+0000fbf4@2051
1696+00007bf6@2053
1697+0000fbf6@2054
1698+0000f912@2055
1699+0000b992@2056
1700+00003992@2058
1701+0000a912@2059
1702+0000abd2@2060
1703+00002b50@2063
1704+0000abf4@2064
1705+0000ebf4@2065
1706+0000eb74@2066
1707+00006bf4@2067
1708+0000ebf4@2068
1709+0000ebd0@2069
1710+0000fb74@2070
1711+0000fbf4@2071
1712+00007bf6@2072
1713+0000fbf6@2073
1714+0000b34a@2074
1715+0000b3ca@2075
1716+000033ca@2077
1717+0000afca@2078
1718+0000afc2@2079
1719+00002f42@2081
1720+0000afc0@2082
1721+0000efe4@2083
1722+0000efc4@2084
1723+0000ef44@2085
1724+00006fc4@2086
1725+0000efe4@2087
1726+0000ffe4@2088
1727+0000ff40@2089
1728+0000ffe4@2090
1729+00007fe6@2091
1730+0000ffe6@2092
1731+0000b3c6@2093
1732+000033c6@2095
1733+0000a346@2096
1734+0000abe2@2097
1735+00002b60@2100
1736+0000abe0@2101
1737+0000ebe4@2102
1738+0000eb64@2104
1739+0000ebe4@2105
1740+0000fb64@2107
1741+0000fbe4@2108
1742+00007be6@2109
1743+0000fbe6@2110
1744+0000f532@2111
1745+0000b5b2@2112
1746+000035b2@2114
1747+0000a532@2115
1748+0000a182@2116
1749+0000a180@2119
1750+0000a3a4@2120
1751+0000e3a4@2121
1752+0000e324@2122
1753+000063a4@2123
1754+0000e3a4@2124
1755+0000f384@2125
1756+0000f304@2126
1757+0000f3a4@2127
1758+000073a6@2128
1759+0000f3a6@2129
1760+0000f532@2130
1761+0000b5b2@2131
1762+0000a532@2133
1763+0000a182@2134
1764+00002102@2137
1765+0000a180@2138
1766+0000e3a4@2139
1767+0000e304@2141
1768+00006184@2142
1769+0000e3a4@2143
1770+0000f3a4@2144
1771+0000f300@2145
1772+000073a6@2146
1773+0000f3a6@2147
1774+0000f92e@2148
1775+0000b9ae@2149
1776+000039ae@2151
1777+0000a92e@2152
1778+0000abc2@2153
1779+00002b40@2156
1780+0000abc0@2157
1781+0000ebe4@2158
1782+00006be4@2160
1783+0000ebe4@2161
1784+0000fb64@2163
1785+0000fbe4@2164
1786+00007be6@2165
1787+0000fbe6@2166
1788+0000f92e@2167
1789+0000f9ae@2168
1790+000079ac@2170
1791+0000f9ac@2171
1792+0000fbc0@2172
1793+0000ebc0@2173
1794+00006bc0@2174
1795+0000ebc0@2175
1796+0000ebe4@2176
1797+0000eb64@2178
1798+00006be4@2179
1799+0000ebe4@2180
1800+0000fbe4@2181
1801+0000fb44@2182
1802+0000fbe4@2183
1803+00007be6@2184
1804+0000fbe6@2185
1805+0000b912@2186
1806+0000b992@2187
1807+00003992@2188
1808+0000a912@2189
1809+0000abd2@2190
1810+00002b50@2193
1811+0000abd0@2194
1812+0000ebf4@2195
1813+0000ebd4@2196
1814+0000eb54@2197
1815+00006bf4@2198
1816+0000ebf4@2199
1817+0000fbf4@2200
1818+00007bf6@2202
1819+0000fbf6@2203
1820+0000f912@2204
1821+0000b992@2205
1822+00003992@2207
1823+0000a912@2208
1824+0000abd2@2209
1825+00002b50@2212
1826+0000abf4@2213
1827+0000ebf4@2214
1828+0000eb74@2215
1829+00006bf4@2216
1830+0000ebf4@2217
1831+0000ebd0@2218
1832+0000fb74@2219
1833+0000fbf4@2220
1834+00007bf6@2221
1835+0000fbf6@2222
1836+0000b34e@2223
1837+0000b3ce@2224
1838+0000234e@2226
1839+0000afce@2227
1840+0000afc2@2228
1841+00002f42@2230
1842+0000afc0@2231
1843+0000efe4@2232
1844+0000ef44@2234
1845+00006fc4@2235
1846+0000efe4@2236
1847+0000ffe4@2237
1848+0000ff44@2238
1849+0000ffe4@2239
1850+0000ffe6@2240
1851+0000b3c6@2242
1852+000033c6@2244
1853+0000a346@2245
1854+0000abe2@2246
1855+00002b60@2249
1856+0000abe0@2250
1857+0000ebe4@2251
1858+0000eb64@2253
1859+0000ebe4@2254
1860+0000fb64@2256
1861+0000fbe4@2257
1862+00007be6@2258
1863+0000fbe6@2259
1864+0000f532@2260
1865+0000b5b2@2261
1866+000035b2@2263
1867+0000a532@2264
1868+0000a182@2265
1869+0000a180@2268
1870+0000a3a4@2269
1871+0000e3a4@2270
1872+0000e324@2271
1873+000063a4@2272
1874+0000e3a4@2273
1875+0000f384@2274
1876+0000f324@2275
1877+0000f3a4@2276
1878+000073a6@2277
1879+0000f3a6@2278
1880+0000f532@2279
1881+0000b5b2@2280
1882+0000a532@2282
1883+0000a182@2283
1884+00002102@2286
1885+0000a180@2287
1886+0000e3a0@2288
1887+0000e3a4@2289
1888+0000e304@2290
1889+00006180@2291
1890+0000e3a4@2292
1891+0000f3a4@2293
1892+0000f104@2294
1893+000073a6@2295
1894+0000f3a6@2296
1895+0000f932@2297
1896+0000b9b2@2298
1897+000039b2@2300
1898+0000a932@2301
1899+0000abc2@2302
1900+00002b40@2305
1901+0000abc0@2306
1902+0000ebe4@2307
1903+00006be4@2309
1904+0000ebe4@2310
1905+0000fb64@2312
1906+0000fbe4@2313
1907+00007be6@2314
1908+0000fbe6@2315
1909+0000f932@2316
1910+0000f9b2@2317
1911+000079b2@2319
1912+0000e9b2@2320
1913+0000ebc2@2321
1914+00006bc2@2323
1915+0000ebc0@2324
1916+0000ebe4@2325
1917+0000abe4@2326
1918+0000a560@2327
1919+000025e0@2328
1920+0000a5e0@2329
1921+0000b5e0@2330
1922+0000b560@2331
1923+0000b5e0@2332
1924+000075e2@2333
1925+0000f5e2@2334
1926+0000b912@2335
1927+0000b992@2336
1928+00003992@2337
1929+0000a912@2338
1930+0000abd2@2339
1931+00002b50@2342
1932+0000abd0@2343
1933+0000ebf4@2344
1934+0000ebd4@2345
1935+0000eb54@2346
1936+00006bf4@2347
1937+0000ebf4@2348
1938+0000fbf4@2349
1939+00007bf6@2351
1940+0000fbf6@2352
1941+0000f912@2353
1942+0000b992@2354
1943+00003992@2356
1944+0000a912@2357
1945+0000abd2@2358
1946+00002b50@2361
1947+0000abf4@2362
1948+0000ebf4@2363
1949+0000eb74@2364
1950+00006bf4@2365
1951+0000ebf4@2366
1952+0000ebd0@2367
1953+0000fb74@2368
1954+0000fbf4@2369
1955+00007bf6@2370
1956+0000fbf6@2371
1957+0000b352@2372
1958+0000b3d2@2373
1959+000023d2@2375
1960+0000afd2@2376
1961+0000afc2@2377
1962+00002f42@2379
1963+0000afc0@2380
1964+0000efe4@2381
1965+0000efc4@2382
1966+0000ef64@2383
1967+00006fc4@2384
1968+0000efe4@2385
1969+0000ffe4@2386
1970+0000ff44@2387
1971+0000ffe4@2388
1972+0000ffe6@2389
1973+0000b3c6@2391
1974+000033c6@2393
1975+0000a346@2394
1976+0000abe2@2395
1977+00002b60@2398
1978+0000abe0@2399
1979+0000ebe4@2400
1980+0000eb64@2402
1981+0000ebe4@2403
1982+0000fb64@2405
1983+0000fbe4@2406
1984+00007be6@2407
1985+0000fbe6@2408
1986+0000f532@2409
1987+0000b5b2@2410
1988+000035b2@2412
1989+0000a532@2413
1990+0000a182@2414
1991+0000a100@2417
1992+0000a3a4@2418
1993+0000e3a4@2419
1994+0000e324@2420
1995+000061a4@2421
1996+0000e3a4@2422
1997+0000f184@2423
1998+0000f304@2424
1999+0000f3a4@2425
2000+000073a6@2426
2001+0000f3a6@2427
2002+0000f532@2428
2003+0000b5b2@2429
2004+000035b2@2430
2005+0000a5b2@2431
2006+0000a182@2432
2007+00002102@2435
2008+0000a180@2436
2009+0000e3a0@2437
2010+0000e384@2438
2011+0000e304@2439
2012+00006180@2440
2013+0000e3a4@2441
2014+0000f3a4@2442
2015+000073a6@2444
2016+0000f3a6@2445
2017+0000f936@2446
2018+0000b9b6@2447
2019+000039b6@2449
2020+0000a936@2450
2021+0000abc2@2451
2022+00002b40@2454
2023+0000abc0@2455
2024+0000ebe4@2456
2025+00006be4@2458
2026+0000ebe4@2459
2027+0000fb64@2461
2028+0000fbe4@2462
2029+00007be6@2463
2030+0000fbe6@2464
2031+0000f936@2465
2032+0000f9b6@2466
2033+000079b6@2468
2034+0000e9b6@2469
2035+0000ebc2@2470
2036+00006bc2@2472
2037+0000eb40@2473
2038+0000ebe4@2474
2039+0000abe4@2475
2040+0000a560@2476
2041+000025e0@2477
2042+0000a5e0@2478
2043+0000b5e0@2479
2044+0000b560@2480
2045+0000b5e0@2481
2046+000075e2@2482
2047+0000f5e2@2483
2048+0000b912@2484
2049+0000b992@2485
2050+00003992@2486
2051+0000a912@2487
2052+0000abd2@2488
2053+00002b50@2491
2054+0000abd0@2492
2055+0000ebf4@2493
2056+0000ebd4@2494
2057+0000eb74@2495
2058+00006bf4@2496
2059+0000ebf4@2497
2060+0000fbf4@2498
2061+00007bf6@2500
2062+0000fbf6@2501
2063+0000f332@2502
2064+0000b3b2@2503
2065+000033b2@2505
2066+0000a332@2506
2067+0000abd2@2507
2068+00002b50@2510
2069+0000abf4@2511
2070+0000ebf4@2512
2071+0000eb74@2513
2072+00006bf4@2514
2073+0000ebf4@2515
2074+0000fbd0@2516
2075+0000fb74@2517
2076+0000fbf4@2518
2077+00007bf6@2519
2078+0000fbf6@2520
2079+0000b356@2521
2080+0000b3d6@2522
2081+00002356@2524
2082+0000afd6@2525
2083+0000afc2@2526
2084+00002f42@2528
2085+0000afc0@2529
2086+0000efe4@2530
2087+0000ef44@2532
2088+00006fc4@2533
2089+0000efe4@2534
2090+0000ffe4@2535
2091+0000ff44@2536
2092+0000ffe4@2537
2093+0000ffe6@2538
2094+0000b3c6@2540
2095+000033c6@2542
2096+0000a346@2543
2097+0000abe2@2544
2098+00002b60@2547
2099+0000abe0@2548
2100+0000ebe4@2549
2101+0000eb64@2551
2102+0000ebe4@2552
2103+0000fb64@2554
2104+0000fbe4@2555
2105+00007be6@2556
2106+0000fbe6@2557
2107+0000f532@2558
2108+0000b5b2@2559
2109+000035b2@2561
2110+0000a532@2562
2111+0000a182@2563
2112+0000a180@2566
2113+0000a3a4@2567
2114+0000e3a4@2568
2115+0000e324@2569
2116+000063a4@2570
2117+0000e3a4@2571
2118+0000f3a4@2572
2119+0000f324@2573
2120+0000f3a4@2574
2121+000073a6@2575
2122+0000f3a6@2576
2123+0000f532@2577
2124+0000b5b2@2578
2125+000035b2@2579
2126+0000a5b2@2580
2127+0000a182@2581
2128+00002102@2584
2129+0000a180@2585
2130+0000e3a0@2586
2131+0000e384@2587
2132+0000e304@2588
2133+00006184@2589
2134+0000e3a4@2590
2135+0000f3a4@2591
2136+0000f304@2592
2137+000073a6@2593
2138+0000f3a6@2594
2139+0000f93a@2595
2140+0000b9ba@2596
2141+000039ba@2598
2142+0000a93a@2599
2143+0000abc2@2600
2144+00002b40@2603
2145+0000abc0@2604
2146+0000ebe4@2605
2147+00006be4@2607
2148+0000ebe4@2608
2149+0000fb64@2610
2150+0000fbe4@2611
2151+00007be6@2612
2152+0000fbe6@2613
2153+0000f93a@2614
2154+0000f9ba@2615
2155+000079ba@2617
2156+0000e9ba@2618
2157+0000ebc2@2619
2158+00006bc2@2621
2159+0000ebc0@2622
2160+0000ebe4@2623
2161+0000abe4@2624
2162+0000a324@2625
2163+000023a4@2626
2164+0000a3a4@2627
2165+0000b3a4@2628
2166+0000b324@2629
2167+0000b3a4@2630
2168+000073a6@2631
2169+0000f3a6@2632
2170+0000b9f2@2633
2171+000039f2@2635
2172+0000a972@2636
2173+0000a182@2637
2174+00002100@2640
2175+0000a180@2641
2176+0000e3a4@2642
2177+0000e104@2644
2178+000063a4@2645
2179+0000e3a4@2646
2180+0000f3a4@2647
2181+000073a6@2649
2182+0000f3a6@2650
2183+0000f112@2651
2184+0000b192@2652
2185+00003192@2654
2186+0000a112@2655
2187+0000a182@2656
2188+00002100@2659
2189+0000a3a4@2660
2190+0000e3a4@2661
2191+0000e324@2662
2192+000063a4@2663
2193+0000e3a4@2664
2194+0000e180@2665
2195+0000f304@2666
2196+0000f3a4@2667
2197+000073a6@2668
2198+0000f3a6@2669
2199+0000f35a@2670
2200+0000b3da@2671
2201+0000335a@2673
2202+0000afda@2674
2203+0000afc2@2675
2204+00002f42@2677
2205+0000afc0@2678
2206+0000efe4@2679
2207+0000ef44@2681
2208+00006fc4@2682
2209+0000efe4@2683
2210+0000ffe4@2684
2211+0000ff40@2685
2212+0000ffe4@2686
2213+0000ffe6@2687
2214+0000b3c6@2689
2215+000033c6@2691
2216+0000a346@2692
2217+0000abe2@2693
2218+00002b60@2696
2219+0000abe0@2697
2220+0000ebe4@2698
2221+0000eb64@2700
2222+0000ebe4@2701
2223+0000fb64@2703
2224+0000fbe4@2704
2225+00007be6@2705
2226+0000fbe6@2706
2227+0000f532@2707
2228+0000b5b2@2708
2229+000035b2@2710
2230+0000a5b2@2711
2231+0000a182@2712
2232+0000a180@2715
2233+0000a3a4@2716
2234+0000e3a4@2717
2235+0000e324@2718
2236+000063a4@2719
2237+0000e3a4@2720
2238+0000f384@2721
2239+0000f324@2722
2240+0000f3a4@2723
2241+000073a6@2724
2242+0000f3a6@2725
2243+0000f532@2726
2244+0000b5b2@2727
2245+000035b2@2728
2246+0000a532@2729
2247+0000a182@2730
2248+00002102@2733
2249+0000a180@2734
2250+0000e3a0@2735
2251+0000e3a4@2736
2252+0000e304@2737
2253+00006180@2738
2254+0000e3a4@2739
2255+0000f3a4@2740
2256+0000f304@2741
2257+000073a6@2742
2258+0000f3a6@2743
2259+0000f93e@2744
2260+0000b9be@2745
2261+000039be@2747
2262+0000a93e@2748
2263+0000abc2@2749
2264+00002b40@2752
2265+0000abc0@2753
2266+0000ebe4@2754
2267+00006be4@2756
2268+0000ebe4@2757
2269+0000ebc0@2758
2270+0000fb64@2759
2271+0000fbe4@2760
2272+00007be6@2761
2273+0000fbe6@2762
2274+0000f93e@2763
2275+0000f9be@2764
2276+000079bc@2766
2277+0000f9bc@2767
2278+0000ebc0@2768
2279+00006bc0@2770
2280+0000ebc0@2771
2281+0000ebe4@2772
2282+0000eb64@2774
2283+00006be4@2775
2284+0000ebe4@2776
2285+0000fbe4@2777
2286+0000fb44@2778
2287+0000fbe4@2779
2288+00007be6@2780
2289+0000fbe6@2781
2290+0000b112@2782
2291+0000b192@2783
2292+00003192@2784
2293+0000a112@2785
2294+0000a182@2786
2295+00002100@2789
2296+0000a180@2790
2297+0000e3a4@2791
2298+0000e384@2792
2299+0000e104@2793
2300+000063a4@2794
2301+0000e3a4@2795
2302+0000f3a4@2796
2303+000073a6@2798
2304+0000f3a6@2799
2305+0000f112@2800
2306+0000b192@2801
2307+00003192@2803
2308+0000a112@2804
2309+0000a182@2805
2310+00002100@2808
2311+0000a3a4@2809
2312+0000e3a4@2810
2313+0000e324@2811
2314+00006384@2812
2315+0000e3a4@2813
2316+0000f180@2814
2317+0000f304@2815
2318+0000f3a4@2816
2319+000073a6@2817
2320+0000f3a6@2818
2321+0000f3de@2819
2322+0000b3de@2820
2323+0000335e@2822
2324+0000afde@2823
2325+0000afc2@2824
2326+00002fc2@2826
2327+0000afc0@2827
2328+0000efe4@2828
2329+0000ef44@2830
2330+00006fc0@2831
2331+0000efe4@2832
2332+0000ffe4@2833
2333+0000ff44@2834
2334+0000ffe4@2835
2335+0000ffe6@2836
2336+0000b3c6@2838
2337+000033c6@2840
2338+0000a346@2841
2339+0000abe2@2842
2340+00002b60@2845
2341+0000abe0@2846
2342+0000ebe4@2847
2343+0000eb64@2849
2344+0000ebe4@2850
2345+0000fb64@2852
2346+0000fbe4@2853
2347+00007be6@2854
2348+0000fbe6@2855
2349+0000f912@2856
2350+0000b992@2857
2351+00003992@2859
2352+0000a992@2860
2353+0000a7a2@2861
2354+0000a7a0@2864
2355+0000a7a4@2865
2356+0000e7a4@2866
2357+0000e724@2867
2358+000067a4@2868
2359+0000e7a4@2869
2360+0000f7a0@2870
2361+0000f724@2871
2362+0000f7a4@2872
2363+000077a6@2873
2364+0000f7a6@2874
2365+0000f932@2875
2366+0000b9b2@2876
2367+000039b2@2877
2368+0000a932@2878
2369+0000a7a2@2879
2370+00002722@2882
2371+0000a7a0@2883
2372+0000e7a0@2884
2373+0000e7a4@2885
2374+0000e724@2886
2375+000067a4@2887
2376+0000e7a4@2888
2377+0000f7a4@2889
2378+0000f724@2890
2379+000077a6@2891
2380+0000f7a6@2892
2381+0000f932@2893
2382+0000f9b2@2894
2383+000079b2@2896
2384+0000e932@2897
2385+0000e7a2@2898
2386+00006720@2901
2387+0000e7a0@2902
2388+0000e7a4@2903
2389+0000a1e4@2904
2390+000021e4@2905
2391+0000a1e4@2906
2392+0000b164@2908
2393+0000b1e4@2909
2394+000071e6@2910
2395+0000f1e6@2911
2396+0000f932@2912
2397+0000f9b2@2913
2398+000079b2@2915
2399+0000e9b2@2916
2400+0000e7a2@2917
2401+000067a2@2919
2402+0000e7a0@2920
2403+0000a7a4@2922
2404+0000a164@2923
2405+000021e4@2924
2406+0000a1e4@2925
2407+0000b1e4@2926
2408+0000b164@2927
2409+0000b1e4@2928
2410+000071e6@2929
2411+0000f1e6@2930
2412+0000b11e@2931
2413+0000b19e@2932
2414+0000319e@2933
2415+0000a11e@2934
2416+0000a9d2@2935
2417+00002950@2938
2418+0000a9d0@2939
2419+0000ebf4@2940
2420+0000ebd4@2941
2421+0000e954@2942
2422+00006bf4@2943
2423+0000ebf4@2944
2424+0000fbf4@2945
2425+00007bf6@2947
2426+0000f9f6@2948
2427+0000f31e@2949
2428+0000b39e@2950
2429+0000339e@2952
2430+0000a31e@2953
2431+0000a9d2@2954
2432+00002950@2957
2433+0000abf4@2958
2434+0000ebf4@2959
2435+0000eb74@2960
2436+00006bf4@2961
2437+0000ebf4@2962
2438+0000f9d0@2963
2439+0000fb54@2964
2440+0000fbf4@2965
2441+00007bf6@2966
2442+0000fbf6@2967
2443+0000b51e@2968
2444+0000b59e@2969
2445+0000359e@2971
2446+0000adde@2972
2447+0000a9d2@2973
2448+00002952@2975
2449+0000a9d0@2976
2450+0000e9f4@2977
2451+0000e9d4@2978
2452+0000eb54@2979
2453+000069d4@2980
2454+0000ebf4@2981
2455+0000fbf4@2982
2456+0000fb54@2983
2457+0000fbf4@2984
2458+0000fbf6@2985
2459+0000ff5e@2986
2460+0000b79e@2987
2461+0000379e@2989
2462+0000a71e@2990
2463+0000a9d2@2991
2464+00002950@2994
2465+0000a9d0@2995
2466+0000ebf4@2996
2467+0000ebd4@2997
2468+0000eb54@2998
2469+0000e9f4@2999
2470+0000ebf4@3000
2471+0000fb74@3001
2472+0000fbf4@3002
2473+00007bf6@3003
2474+0000fbf6@3004
2475+0000f91e@3005
2476+0000b99e@3006
2477+0000399e@3008
2478+0000a99e@3009
2479+0000a5f2@3010
2480+0000a570@3013
2481+0000a7f4@3014
2482+0000e7f4@3015
2483+0000e774@3016
2484+000065f4@3017
2485+0000e7f4@3018
2486+0000f7f4@3019
2487+0000f774@3020
2488+0000f7f4@3021
2489+000077f6@3022
2490+0000f7f6@3023
2491+0000b93e@3024
2492+0000b9be@3025
2493+000039be@3026
2494+0000a9be@3027
2495+0000adf2@3028
2496+0000a5f2@3029
2497+00002572@3031
2498+0000a5f0@3032
2499+0000e7f0@3033
2500+0000e7f4@3034
2501+0000e774@3035
2502+000065f4@3036
2503+0000e7f4@3037
2504+0000f7f4@3038
2505+0000f774@3039
2506+000077f6@3040
2507+0000f7f6@3041
2508+0000ff1e@3042
2509+0000bb9e@3043
2510+00003b9e@3045
2511+0000ab1e@3046
2512+0000a5f2@3047
2513+00002570@3050
2514+0000a5f0@3051
2515+0000e7f4@3052
2516+000067f4@3054
2517+0000e5f4@3055
2518+0000e7f4@3056
2519+0000f774@3057
2520+0000f7f4@3058
2521+000077f6@3059
2522+0000f7f6@3060
2523+0000f91e@3061
2524+0000b99e@3062
2525+0000399e@3064
2526+0000a99e@3065
2527+0000a5f2@3066
2528+000025f2@3068
2529+0000a570@3069
2530+0000a5f0@3070
2531+0000e7f4@3071
2532+0000e774@3072
2533+000065f4@3073
2534+0000e7f4@3074
2535+0000f7f4@3075
2536+0000f574@3076
2537+0000f7f4@3077
2538+000077f6@3078
2539+0000f7f6@3079
2540+0000b93e@3080
2541+0000b9be@3081
2542+000039be@3082
2543+0000a93e@3083
2544+0000adf2@3084
2545+0000a5f2@3085
2546+00002570@3087
2547+0000a5f0@3088
2548+0000e7f4@3089
2549+0000e774@3091
2550+000067f4@3092
2551+0000e7f4@3093
2552+0000f7f4@3094
2553+000077f6@3096
2554+0000f7f6@3097
2555+0000ff1e@3098
2556+0000bb9e@3099
2557+00003b9e@3101
2558+0000ab1e@3102
2559+0000a5f2@3103
2560+00002570@3106
2561+0000a7f4@3107
2562+0000e7f4@3108
2563+0000e774@3109
2564+000067f4@3110
2565+0000e7f4@3111
2566+0000f5f0@3112
2567+0000f774@3113
2568+0000f7f4@3114
2569+000077f6@3115
2570+0000f7f6@3116
2571+0000b91e@3117
2572+0000b99e@3118
2573+0000299e@3120
2574+0000adfa@3121
2575+0000a5f2@3122
2576+00002572@3124
2577+0000a5f0@3125
2578+0000e5f4@3126
2579+0000e774@3128
2580+000067f4@3129
2581+0000e7f4@3130
2582+0000f7f4@3131
2583+0000f770@3132
2584+0000f7f4@3133
2585+0000f7f6@3134
2586+0000fd7e@3135
2587+0000b9be@3136
2588+000039be@3138
2589+0000a93e@3139
2590+0000a5f2@3140
2591+00002570@3143
2592+0000a5f0@3144
2593+0000e7f4@3145
2594+0000e774@3147
2595+0000e7f4@3148
2596+0000f774@3150
2597+0000f7f4@3151
2598+000077f6@3152
2599+0000f7f6@3153
2600+0000fb1e@3154
2601+0000bb9e@3155
2602+00003b9e@3157
2603+0000ab9e@3158
2604+0000a5f2@3159
2605+0000a570@3162
2606+0000a7f4@3163
2607+0000e7f4@3164
2608+0000e774@3165
2609+000065f4@3166
2610+0000e7f4@3167
2611+0000f7f4@3168
2612+0000f774@3169
2613+0000f7f4@3170
2614+000077f6@3171
2615+0000f7f6@3172
2616+0000b91e@3173
2617+0000b99e@3174
2618+0000399e@3175
2619+0000a99e@3176
2620+0000adf2@3177
2621+0000a5f2@3178
2622+00002572@3180
2623+0000a5f0@3181
2624+0000e7f4@3182
2625+0000e774@3184
2626+000065f4@3185
2627+0000e7f4@3186
2628+0000f7f4@3187
2629+0000f774@3188
2630+000077f6@3189
2631+0000f7f6@3190
2632+0000fd1e@3191
2633+0000f99e@3192
2634+0000799e@3194
2635+0000f91e@3195
2636+0000e5f2@3196
2637+00006570@3199
2638+0000e5f0@3200
2639+0000e5f4@3201
2640+0000a100@3202
2641+00002180@3203
2642+0000a180@3204
2643+0000b180@3205
2644+0000b100@3206
2645+0000b180@3207
2646+00007182@3208
2647+0000f182@3209
2648+0000f9be@3210
2649+0000b9be@3211
2650+0000393e@3213
2651+0000a9be@3214
2652+0000a5f2@3215
2653+000025f2@3217
2654+0000a5f0@3218
2655+0000e7f4@3220
2656+0000e774@3221
2657+000065f4@3222
2658+0000e7f4@3223
2659+0000f7f4@3224
2660+0000f574@3225
2661+0000f7f4@3226
2662+000077f6@3227
2663+0000f7f6@3228
2664+0000bb9e@3229
2665+00003b9e@3231
2666+0000ab1e@3232
2667+0000a5f2@3233
2668+00002570@3236
2669+0000a5f0@3237
2670+0000e7f4@3238
2671+0000e774@3240
2672+000067f4@3241
2673+0000e7f4@3242
2674+0000f7f4@3243
2675+000077f6@3245
2676+0000f7f6@3246
2677+0000fd1a@3247
2678+0000b99a@3248
2679+0000399a@3250
2680+0000a91a@3251
2681+0000a5f2@3252
2682+00002570@3255
2683+0000a7f4@3256
2684+0000e7f4@3257
2685+0000e774@3258
2686+000067f4@3259
2687+0000e7f4@3260
2688+0000e5f0@3261
2689+0000f774@3262
2690+0000f7f4@3263
2691+000077f6@3264
2692+0000f7f6@3265
2693+0000b93a@3266
2694+0000b9ba@3267
2695+0000a93a@3269
2696+0000adfa@3270
2697+0000a5f2@3271
2698+00002572@3273
2699+0000a5f0@3274
2700+0000e5f4@3275
2701+0000e774@3277
2702+000065f0@3278
2703+0000e7f4@3279
2704+0000f7f4@3280
2705+0000f770@3281
2706+0000f7f4@3282
2707+0000f7f6@3283
2708+0000fffe@3284
2709+0000bb9a@3285
2710+00003b9a@3287
2711+0000ab1a@3288
2712+0000a5f2@3289
2713+00002570@3292
2714+0000a5f0@3293
2715+0000e7f4@3294
2716+0000e774@3296
2717+0000e7f4@3297
2718+0000f774@3299
2719+0000f7f4@3300
2720+000077f6@3301
2721+0000f7f6@3302
2722+0000f81a@3303
2723+0000b89a@3304
2724+0000389a@3306
2725+0000a89a@3307
2726+0000a4f2@3308
2727+0000a470@3311
2728+0000a674@3312
2729+0000e6f4@3313
2730+00006474@3315
2731+0000e674@3316
2732+0000f6f4@3317
2733+00007676@3320
2734+0000f676@3321
2735+0000f8ba@3322
2736+0000b8ba@3323
2737+000038ba@3324
2738+0000a83a@3325
2739+0000acf2@3326
2740+0000a4f2@3327
2741+00002472@3329
2742+0000a470@3330
2743+0000e6f0@3331
2744+0000e6f4@3332
2745+00006470@3334
2746+0000e674@3335
2747+0000f6f4@3336
2748+000076f6@3338
2749+0000f476@3339
2750+0000fe1e@3340
2751+0000ba9a@3341
2752+00003a1a@3343
2753+0000aa1a@3344
2754+0000a4f2@3345
2755+00002470@3348
2756+0000a470@3349
2757+0000e6f4@3350
2758+000066f4@3352
2759+0000e474@3353
2760+0000f6f4@3355
2761+00007676@3357
2762+0000f676@3358
2763+0000f21a@3359
2764+0000b29a@3360
2765+0000321a@3362
2766+0000a21a@3363
2767+0000a4f2@3364
2768+000024f2@3366
2769+0000a470@3367
2770+0000e470@3368
2771+0000e6f4@3369
2772+00006474@3371
2773+0000e674@3372
2774+0000f6f4@3373
2775+00007676@3376
2776+0000f676@3377
2777+0000b29a@3378
2778+0000329a@3380
2779+0000a29a@3381
2780+0000a4f2@3382
2781+0000a472@3384
2782+000024f0@3385
2783+0000a4f0@3386
2784+0000e6f4@3387
2785+0000e674@3388
2786+000064f4@3390
2787+0000e6f4@3391
2788+0000f6f4@3392
2789+0000f674@3393
2790+00007676@3394
2791+0000f6f6@3395
2792+0000f29a@3396
2793+0000b21a@3397
2794+0000329a@3399
2795+0000a29a@3400
2796+0000a4f2@3401
2797+0000a472@3402
2798+000024f0@3404
2799+0000a6f4@3405
2800+0000e6f4@3406
2801+0000e674@3407
2802+00006674@3408
2803+0000e6f4@3409
2804+0000f4f0@3410
2805+0000f674@3411
2806+000076f6@3413
2807+0000f6f6@3414
2808+0000b22e@3415
2809+0000a2ae@3418
2810+0000a082@3420
2811+0000a002@3421
2812+00002082@3422
2813+0000a080@3423
2814+0000e0a4@3424
2815+0000e024@3425
2816+0000e204@3426
2817+00006084@3427
2818+0000e2a4@3428
2819+0000f2a4@3429
2820+0000f204@3430
2821+0000f2a6@3432
2822+0000f2ae@3433
2823+0000f22e@3435
2824+0000722e@3436
2825+0000e2ae@3437
2826+0000e082@3438
2827+0000e002@3439
2828+00006080@3441
2829+0000e080@3442
2830+0000e2a4@3443
2831+0000a60c@3444
2832+0000260c@3445
2833+0000a68c@3446
2834+0000b68c@3448
2835+0000b60c@3449
2836+0000768e@3450
2837+0000f68e@3451
2838+0000f496@3452
2839+0000b416@3453
2840+00003496@3455
2841+0000a496@3456
2842+0000aaf2@3457
2843+0000aaf0@3460
2844+0000aa74@3461
2845+0000eaf4@3462
2846+00006af4@3464
2847+0000ea74@3465
2848+0000fa74@3466
2849+0000faf4@3467
2850+00007af6@3469
2851+0000fa76@3470
2852+0000b426@3471
2853+0000b4a6@3472
2854+000034a6@3473
2855+0000a4a6@3474
2856+0000a472@3475
2857+0000a4f2@3476
2858+000024f2@3478
2859+0000a470@3479
2860+0000e670@3480
2861+0000e6f4@3481
2862+000064f4@3483
2863+0000e674@3484
2864+0000f674@3485
2865+0000f6f4@3486
2866+000076f6@3487
2867+0000f6f6@3488
2868+0000f606@3489
2869+0000b686@3490
2870+00003686@3492
2871+0000a606@3493
2872+0000a472@3494
2873+0000a4f2@3495
2874+000024f0@3497
2875+0000a470@3498
2876+0000e474@3499
2877+0000e6f4@3500
2878+000066f4@3501
2879+0000e4f4@3502
2880+0000e474@3503
2881+0000f6f4@3504
2882+000074f6@3506
2883+0000f676@3507
2884+0000f626@3508
2885+0000b6a6@3509
2886+000036a6@3511
2887+0000a626@3512
2888+0000a472@3513
2889+0000a4f2@3514
2890+000024f2@3515
2891+0000a470@3516
2892+0000e474@3517
2893+0000e6f4@3518
2894+000064f4@3520
2895+0000e674@3521
2896+0000f674@3522
2897+0000f6f4@3523
2898+000076f6@3525
2899+0000f676@3526
2900+0000b226@3527
2901+0000b2a6@3528
2902+000032a6@3529
2903+0000a226@3530
2904+0000a002@3531
2905+0000a082@3532
2906+00002080@3534
2907+0000a000@3535
2908+0000e2a4@3536
2909+00006004@3539
2910+0000e2a4@3540
2911+0000f2a4@3541
2912+0000f204@3542
2913+00007226@3543
2914+0000f2a6@3544
2915+0000f8be@3545
2916+0000b9be@3546
2917+0000b93e@3547
2918+0000393e@3548
2919+0000a9be@3549
2920+0000abc2@3550
2921+0000ab42@3552
2922+00002b40@3553
2923+0000abe4@3554
2924+0000ebe4@3555
2925+0000eb64@3556
2926+00006b64@3557
2927+0000ebe4@3558
2928+0000fbe4@3559
2929+0000fb64@3561
2930+00007b46@3562
2931+0000fbe6@3563
2932+0000b3a6@3564
2933+0000b326@3566
2934+0000a326@3567
2935+0000a3a6@3568
2936+0000a182@3569
2937+0000a102@3570
2938+00002102@3571
2939+0000a180@3572
2940+0000e3a4@3573
2941+0000e1a4@3574
2942+0000e324@3575
2943+00006104@3576
2944+0000e3a4@3577
2945+0000f3a4@3578
2946+0000f324@3580
2947+0000f326@3581
2948+0000f196@3582
2949+0000b196@3583
2950+0000b116@3584
2951+00003116@3585
2952+0000a196@3586
2953+0000a182@3587
2954+0000a102@3589
2955+00002100@3590
2956+0000a180@3591
2957+0000e3a4@3592
2958+0000e1a4@3593
2959+00006304@3594
2960+0000e104@3595
2961+0000e1a4@3596
2962+0000f3a4@3597
2963+0000f324@3598
2964+00007126@3599
2965+0000f3a6@3600
2966+0000f196@3601
2967+0000b196@3602
2968+0000b116@3603
2969+00003116@3604
2970+0000a196@3605
2971+0000a182@3606
2972+0000a102@3608
2973+0000a100@3609
2974+0000a3a4@3610
2975+0000e3a4@3611
2976+0000e324@3612
2977+000061a4@3613
2978+0000e3a4@3614
2979+0000f3a4@3615
2980+0000f304@3616
2981+0000f3a4@3617
2982+000073a6@3618
2983+0000f3a6@3619
2984+0000f15e@3620
2985+0000b1de@3621
2986+000031de@3622
2987+0000a15e@3623
2988+0000afc2@3624
2989+00002f42@3627
2990+0000afc0@3628
2991+0000efe0@3629
2992+0000efc4@3630
2993+0000ef44@3631
2994+00006fe4@3632
2995+0000efe4@3633
2996+0000ffe4@3634
2997+0000ff44@3635
2998+00007fe6@3636
2999+0000ffe6@3637
3000+0000f356@3638
3001+0000b3d6@3639
3002+000033d6@3641
3003+0000a356@3642
3004+0000a7f2@3643
3005+00002770@3646
3006+0000a7f0@3647
3007+0000e7f4@3648
3008+000067f4@3650
3009+0000e7f4@3651
3010+0000f774@3653
3011+0000f7f4@3654
3012+000077f6@3655
3013+0000f7f6@3656
3014+0000b536@3657
3015+0000b5b6@3658
3016+000035b6@3660
3017+0000a5b6@3661
3018+0000ab82@3662
3019+00002b82@3664
3020+0000ab80@3665
3021+0000aba4@3666
3022+0000eba4@3667
3023+0000eb24@3668
3024+00006ba4@3669
3025+0000eba4@3670
3026+0000fba4@3671
3027+0000fb04@3672
3028+0000fba4@3673
3029+00007ba6@3674
3030+0000fba6@3675
3031+0000f716@3676
3032+0000b796@3677
3033+00003796@3678
3034+0000a716@3679
3035+0000ab82@3680
3036+00002b00@3683
3037+0000ab80@3684
3038+0000eba4@3685
3039+0000eb04@3687
3040+00006ba4@3688
3041+0000eba4@3689
3042+0000fba4@3690
3043+00007ba6@3692
3044+0000fba6@3693
3045+0000f902@3694
3046+0000b982@3695
3047+00003982@3697
3048+0000a902@3698
3049+0000abc2@3699
3050+00002b40@3702
3051+0000abe4@3703
3052+0000ebe4@3704
3053+0000eb64@3705
3054+00006be4@3706
3055+0000ebe4@3707
3056+0000fbc0@3708
3057+0000fb64@3709
3058+0000fbe4@3710
3059+00007be6@3711
3060+0000fbe6@3712
3061+0000f902@3713
3062+0000f982@3714
3063+0000e982@3716
3064+0000ebc2@3717
3065+00006b42@3720
3066+0000ebc0@3721
3067+0000ebe4@3722
3068+0000ebc0@3723
3069+0000a100@3724
3070+00002180@3725
3071+0000a180@3726
3072+0000b180@3727
3073+0000b100@3728
3074+0000b180@3729
3075+0000f182@3730
3076+0000f116@3731
3077+0000b196@3732
3078+00003196@3734
3079+0000a116@3735
3080+0000a182@3736
3081+00002100@3739
3082+0000a180@3740
3083+0000e3a4@3741
3084+0000e184@3742
3085+000063a4@3743
3086+0000e1a4@3744
3087+0000f324@3746
3088+0000f3a4@3747
3089+000073a6@3748
3090+0000f3a6@3749
3091+0000f116@3750
3092+0000b196@3751
3093+00003196@3753
3094+0000a116@3754
3095+0000a182@3755
3096+00002182@3757
3097+0000a180@3758
3098+0000a3a4@3759
3099+0000e3a4@3760
3100+0000e324@3761
3101+000061a4@3762
3102+0000e3a4@3763
3103+0000f184@3764
3104+0000f104@3765
3105+0000f3a4@3766
3106+000073a6@3767
3107+0000f3a6@3768
3108+0000b162@3769
3109+0000b1e2@3770
3110+000031e2@3771
3111+0000a162@3772
3112+0000af42@3773
3113+0000afc2@3774
3114+00002f42@3776
3115+0000afc0@3777
3116+0000efe0@3778
3117+0000efc4@3779
3118+0000ef44@3780
3119+00006fe4@3781
3120+0000efe4@3782
3121+0000ffe4@3783
3122+0000ff64@3784
3123+00007fe6@3785
3124+0000ffe6@3786
3125+0000f346@3787
3126+0000b3c6@3788
3127+000033c6@3790
3128+0000a346@3791
3129+0000abe2@3792
3130+00002b60@3795
3131+0000abe0@3796
3132+0000ebe4@3797
3133+00006be4@3799
3134+0000ebe4@3800
3135+0000ebe0@3801
3136+0000fb64@3802
3137+0000fbe4@3803
3138+00007be6@3804
3139+0000fbe6@3805
3140+0000f736@3806
3141+0000b7b6@3807
3142+000037b6@3809
3143+0000a7b6@3810
3144+0000ab82@3811
3145+00002b82@3813
3146+0000ab80@3814
3147+0000aba4@3815
3148+0000eba4@3816
3149+0000eb24@3817
3150+00006ba4@3818
3151+0000eba4@3819
3152+0000fba4@3820
3153+0000fb24@3821
3154+0000fba4@3822
3155+00007ba6@3823
3156+0000fba6@3824
3157+0000f916@3825
3158+0000b996@3826
3159+00003996@3827
3160+0000a916@3828
3161+0000ab82@3829
3162+00002b00@3832
3163+0000ab80@3833
3164+0000eba4@3834
3165+0000eb84@3835
3166+0000eb04@3836
3167+00006ba4@3837
3168+0000eba4@3838
3169+0000fba4@3839
3170+00007ba6@3841
3171+0000fba6@3842
3172+0000f906@3843
3173+0000b986@3844
3174+00003986@3846
3175+0000a906@3847
3176+0000abc2@3848
3177+00002b40@3851
3178+0000abe4@3852
3179+0000ebe4@3853
3180+0000eb64@3854
3181+00006be4@3855
3182+0000ebe4@3856
3183+0000fbc4@3857
3184+0000fb64@3858
3185+0000fbe4@3859
3186+00007be6@3860
3187+0000fbe6@3861
3188+0000f906@3862
3189+0000f986@3863
3190+0000e986@3865
3191+0000ebc6@3866
3192+0000ebc2@3867
3193+00006b42@3869
3194+0000ebc0@3870
3195+0000ebe4@3871
3196+0000ebc0@3872
3197+0000a100@3873
3198+00002180@3874
3199+0000a180@3875
3200+0000b180@3876
3201+0000b100@3877
3202+0000b180@3878
3203+0000f182@3879
3204+0000f116@3880
3205+0000b196@3881
3206+00003196@3883
3207+0000a116@3884
3208+0000a182@3885
3209+00002100@3888
3210+0000a180@3889
3211+0000e3a4@3890
3212+0000e1a4@3891
3213+00006324@3892
3214+0000e1a4@3893
3215+0000e3a4@3894
3216+0000f324@3895
3217+0000f3a4@3896
3218+000073a6@3897
3219+0000f3a6@3898
3220+0000f976@3899
3221+0000b9f6@3900
3222+000039f6@3902
3223+0000a976@3903
3224+0000a182@3904
3225+00002182@3906
3226+0000a180@3907
3227+0000a3a4@3908
3228+0000e3a4@3909
3229+0000e324@3910
3230+000061a4@3911
3231+0000e3a4@3912
3232+0000f184@3913
3233+0000f104@3914
3234+0000f3a4@3915
3235+000073a6@3916
3236+0000f3a6@3917
3237+0000f166@3918
3238+0000b1e6@3919
3239+000031e6@3920
3240+0000a166@3921
3241+0000af42@3922
3242+0000afc2@3923
3243+00002f42@3925
3244+0000afc0@3926
3245+0000efc0@3927
3246+0000efe4@3928
3247+0000ef64@3929
3248+00006fe4@3930
3249+0000efe4@3931
3250+0000ffe4@3932
3251+00007fe6@3934
3252+0000ffe6@3935
3253+0000f346@3936
3254+0000b3c6@3937
3255+000033c6@3939
3256+0000a346@3940
3257+0000abe2@3941
3258+00002b60@3944
3259+0000abe0@3945
3260+0000ebe4@3946
3261+00006be4@3948
3262+0000ebe4@3949
3263+0000fbe4@3950
3264+0000fb64@3951
3265+0000fbe4@3952
3266+00007be6@3953
3267+0000fbe6@3954
3268+0000f936@3955
3269+0000b9b6@3956
3270+000039b6@3958
3271+0000a9b6@3959
3272+0000ab82@3960
3273+00002b82@3962
3274+0000ab80@3963
3275+0000aba4@3964
3276+0000eba4@3965
3277+0000eb24@3966
3278+00006ba4@3967
3279+0000eba4@3968
3280+0000fba4@3969
3281+0000fb04@3970
3282+0000fba4@3971
3283+00007ba6@3972
3284+0000fba6@3973
3285+0000b316@3974
3286+0000b396@3975
3287+00003396@3976
3288+0000a316@3977
3289+0000afa2@3978
3290+0000ada2@3979
3291+00002d20@3981
3292+0000ada0@3982
3293+0000efa4@3983
3294+0000ef24@3985
3295+00006fa4@3986
3296+0000efa4@3987
3297+0000ff24@3988
3298+0000ffa4@3989
3299+00007fa6@3990
3300+0000ffa6@3991
3301+0000f90a@3992
3302+0000b98a@3993
3303+0000398a@3995
3304+0000a90a@3996
3305+0000abc2@3997
3306+00002b40@4000
3307+0000abe4@4001
3308+0000ebe4@4002
3309+0000eb64@4003
3310+00006be4@4004
3311+0000ebe4@4005
3312+0000fbc4@4006
3313+0000fb64@4007
3314+0000fbe4@4008
3315+00007be6@4009
3316+0000fbe6@4010
3317+0000f90a@4011
3318+0000f98a@4012
3319+0000e98a@4014
3320+0000ebca@4015
3321+0000ebc2@4016
3322+00006b42@4018
3323+0000ebc0@4019
3324+0000ebe4@4020
3325+0000afe0@4021
3326+0000a560@4022
3327+000025e0@4023
3328+0000a5e0@4024
3329+0000b5e0@4025
3330+0000b560@4026
3331+0000b5e0@4027
3332+0000f5e2@4028
3333+0000fd76@4029
3334+0000b996@4030
3335+00003996@4032
3336+0000a916@4033
3337+0000abd2@4034
3338+00002b50@4037
3339+0000abd0@4038
3340+0000ebf4@4039
3341+00006b74@4041
3342+0000ebf4@4042
3343+0000fb74@4044
3344+0000fbf4@4045
3345+00007bf6@4046
3346+0000fbf6@4047
3347+0000f916@4048
3348+0000b996@4049
3349+00003996@4051
3350+0000a996@4052
3351+0000abd2@4053
3352+00002bd2@4055
3353+0000ab50@4056
3354+0000abf4@4057
3355+0000ebf4@4058
3356+0000eb74@4059
3357+00006bf4@4060
3358+0000ebf4@4061
3359+0000fbf4@4062
3360+0000fb54@4063
3361+0000fbf4@4064
3362+00007bf6@4065
3363+0000fbf6@4066
3364+0000b16a@4067
3365+0000b1ea@4068
3366+000031ea@4069
3367+0000a16a@4070
3368+0000afc2@4071
3369+00002f42@4074
3370+0000afc0@4075
3371+0000efc0@4076
3372+0000efc4@4077
3373+0000ef44@4078
3374+00006fe0@4079
3375+0000efe4@4080
3376+0000ffe4@4081
3377+0000ff64@4082
3378+00007fe6@4083
3379+0000ffe6@4084
3380+0000f346@4085
3381+0000b3c6@4086
3382+000033c6@4088
3383+0000a346@4089
3384+0000abe2@4090
3385+00002b60@4093
3386+0000abe0@4094
3387+0000ebe4@4095
3388+00006be4@4097
3389+0000ebe4@4098
3390+0000fb64@4100
3391+0000fbe4@4101
3392+00007be6@4102
3393+0000fbe6@4103
3394+0000f336@4104
3395+0000b3b6@4105
3396+000033b6@4107
3397+0000a3b6@4108
3398+0000ada2@4109
3399+00002da2@4111
3400+0000ada0@4112
3401+0000eda4@4113
3402+0000efa4@4114
3403+0000ef24@4115
3404+00006da4@4116
3405+0000efa4@4117
3406+0000ffa4@4118
3407+0000ff24@4119
3408+0000ffa4@4120
3409+00007fa6@4121
3410+0000ffa6@4122
3411+0000b516@4123
3412+0000b596@4124
3413+00003596@4125
3414+0000a516@4126
3415+0000ada2@4127
3416+00002d20@4130
3417+0000ada0@4131
3418+0000efa4@4132
3419+0000eda4@4133
3420+0000ef24@4134
3421+00006fa4@4135
3422+0000efa4@4136
3423+0000ffa4@4137
3424+00007fa6@4139
3425+0000ffa6@4140
3426+0000f90e@4141
3427+0000b98e@4142
3428+0000398e@4144
3429+0000a90e@4145
3430+0000abc2@4146
3431+00002b40@4149
3432+0000abe4@4150
3433+0000ebe4@4151
3434+0000eb64@4152
3435+00006be4@4153
3436+0000ebe4@4154
3437+0000fbc4@4155
3438+0000fb64@4156
3439+0000fbe4@4157
3440+00007be6@4158
3441+0000fbe6@4159
3442+0000f90e@4160
3443+0000f98e@4161
3444+0000f98c@4163
3445+0000fbc0@4164
3446+0000ebc0@4165
3447+00006b40@4167
3448+0000ebc0@4168
3449+0000ebe4@4169
3450+0000eb44@4171
3451+00006bc4@4172
3452+0000ebe4@4173
3453+0000fbe4@4174
3454+0000fb44@4175
3455+0000fbe4@4176
3456+0000fbe6@4177
3457+0000fb56@4178
3458+0000b996@4179
3459+00003996@4181
3460+0000a916@4182
3461+0000abd2@4183
3462+00002b50@4186
3463+0000abd0@4187
3464+0000ebf4@4188
3465+00006b74@4190
3466+0000ebf4@4191
3467+0000fb74@4193
3468+0000fbf4@4194
3469+00007bf6@4195
3470+0000fbf6@4196
3471+0000f916@4197
3472+0000b996@4198
3473+00003996@4200
3474+0000a996@4201
3475+0000abd2@4202
3476+00002bd2@4204
3477+0000abd0@4205
3478+0000abf4@4206
3479+0000ebf4@4207
3480+0000eb74@4208
3481+00006bf4@4209
3482+0000ebf4@4210
3483+0000fbf4@4211
3484+0000fb54@4212
3485+0000fbf4@4213
3486+00007bf6@4214
3487+0000fbf6@4215
3488+0000b16e@4216
3489+0000b1ee@4217
3490+000031ee@4218
3491+0000a16e@4219
3492+0000afc2@4220
3493+00002f42@4223
3494+0000afc0@4224
3495+0000efe0@4225
3496+0000efc4@4226
3497+0000ef44@4227
3498+00006fe4@4228
3499+0000efe4@4229
3500+0000ffe4@4230
3501+0000ffc4@4231
3502+00007fe6@4232
3503+0000ffe6@4233
3504+0000f346@4234
3505+0000b3c6@4235
3506+000033c6@4237
3507+0000a346@4238
3508+0000abe2@4239
3509+00002b60@4242
3510+0000abe0@4243
3511+0000ebe4@4244
3512+00006be4@4246
3513+0000ebe4@4247
3514+0000fbe4@4248
3515+0000fb64@4249
3516+0000fbe4@4250
3517+00007be6@4251
3518+0000fbe6@4252
3519+0000b536@4253
3520+0000b5b6@4254
3521+000025b6@4256
3522+0000a5b6@4257
3523+0000ada2@4258
3524+00002da2@4260
3525+0000ada0@4261
3526+0000eda4@4262
3527+0000ef24@4264
3528+00006da4@4265
3529+0000efa4@4266
3530+0000ffa4@4267
3531+0000ff24@4268
3532+0000ffa4@4269
3533+00007fa6@4270
3534+0000ffa6@4271
3535+0000b796@4272
3536+00003796@4274
3537+0000a716@4275
3538+0000ada2@4276
3539+00002d20@4279
3540+0000ada0@4280
3541+0000efa4@4281
3542+0000ef24@4283
3543+00006fa4@4284
3544+0000efa4@4285
3545+0000ffa4@4286
3546+00007fa6@4288
3547+0000ffa6@4289
3548+0000f912@4290
3549+0000b992@4291
3550+00003992@4293
3551+0000a912@4294
3552+0000abc2@4295
3553+00002b40@4298
3554+0000abe4@4299
3555+0000ebe4@4300
3556+0000eb64@4301
3557+00006be4@4302
3558+0000ebe4@4303
3559+0000fbc0@4304
3560+0000fb64@4305
3561+0000fbe4@4306
3562+00007be6@4307
3563+0000fbe6@4308
3564+0000f912@4309
3565+0000f992@4310
3566+0000e992@4312
3567+0000ebd2@4313
3568+0000ebc2@4314
3569+00006b42@4316
3570+0000ebc0@4317
3571+0000ebe4@4318
3572+0000afe0@4319
3573+0000a560@4320
3574+000025e0@4321
3575+0000a5e0@4322
3576+0000b5e0@4323
3577+0000b560@4324
3578+0000b5e0@4325
3579+0000f5e2@4326
3580+0000fd36@4327
3581+0000b996@4328
3582+00003996@4330
3583+0000a916@4331
3584+0000abd2@4332
3585+00002b50@4335
3586+0000abd0@4336
3587+0000ebf4@4337
3588+00006b74@4339
3589+0000ebf4@4340
3590+0000fb74@4342
3591+0000fbf4@4343
3592+00007bf6@4344
3593+0000fbf6@4345
3594+0000f916@4346
3595+0000b996@4347
3596+00003996@4349
3597+0000a996@4350
3598+0000abd2@4351
3599+00002bd2@4353
3600+0000ab50@4354
3601+0000abf4@4355
3602+0000ebf4@4356
3603+0000eb74@4357
3604+00006bf4@4358
3605+0000ebf4@4359
3606+0000fbf4@4360
3607+0000fb54@4361
3608+0000fbf4@4362
3609+00007bf6@4363
3610+0000fbf6@4364
3611+0000b172@4365
3612+0000b1f2@4366
3613+000031f2@4367
3614+0000a172@4368
3615+0000af42@4369
3616+0000afc2@4370
3617+00002f42@4372
3618+0000afc0@4373
3619+0000efc0@4374
3620+0000ef44@4376
3621+00006fc0@4377
3622+0000efe4@4378
3623+0000ffe4@4379
3624+00007fe6@4381
3625+0000ffe6@4382
3626+0000f346@4383
3627+0000b3c6@4384
3628+000033c6@4386
3629+0000a346@4387
3630+0000abe2@4388
3631+00002b60@4391
3632+0000abe0@4392
3633+0000ebe4@4393
3634+00006be4@4395
3635+0000ebe4@4396
3636+0000fb64@4398
3637+0000fbe4@4399
3638+00007be6@4400
3639+0000fbe6@4401
3640+0000fb16@4402
3641+0000bb96@4403
3642+00003b96@4405
3643+0000ab96@4406
3644+0000ab82@4407
3645+00002b82@4409
3646+0000ab80@4410
3647+0000aba4@4411
3648+0000eba4@4412
3649+0000eb24@4413
3650+00006ba4@4414
3651+0000eba4@4415
3652+0000fba4@4416
3653+0000fb04@4417
3654+0000fba4@4418
3655+00007ba6@4419
3656+0000fbb6@4420
3657+0000fb36@4421
3658+0000bbb6@4422
3659+00003bb6@4423
3660+0000ab36@4424
3661+0000ab02@4425
3662+0000ab82@4426
3663+00002b00@4428
3664+0000ab80@4429
3665+0000eba4@4430
3666+0000eb24@4432
3667+00006ba4@4433
3668+0000eba4@4434
3669+0000fb24@4435
3670+0000fba4@4436
3671+00007ba6@4437
3672+0000fba6@4438
3673+0000f916@4439
3674+0000b996@4440
3675+00003996@4442
3676+0000a916@4443
3677+0000abc2@4444
3678+00002b40@4447
3679+0000abe4@4448
3680+0000ebe4@4449
3681+0000eb64@4450
3682+00006be4@4451
3683+0000ebe4@4452
3684+0000fbc4@4453
3685+0000fb44@4454
3686+0000fbe4@4455
3687+00007be6@4456
3688+0000fbe6@4457
3689+0000f916@4458
3690+0000f996@4459
3691+0000e996@4461
3692+0000ebd6@4462
3693+0000ebc2@4463
3694+00006b42@4465
3695+0000ebc0@4466
3696+0000ebe4@4467
3697+0000afe0@4468
3698+0000a560@4469
3699+000025e0@4470
3700+0000a5e0@4471
3701+0000b5e0@4472
3702+0000b560@4473
3703+0000b5e0@4474
3704+0000f5e2@4475
3705+0000fd36@4476
3706+0000b996@4477
3707+00003996@4479
3708+0000a916@4480
3709+0000abd2@4481
3710+00002b50@4484
3711+0000abd0@4485
3712+0000ebf4@4486
3713+00006bf4@4488
3714+0000ebf4@4489
3715+0000fb74@4491
3716+0000fbf4@4492
3717+00007bf6@4493
3718+0000fbf6@4494
3719+0000f916@4495
3720+0000b996@4496
3721+00003996@4498
3722+0000a996@4499
3723+0000abd2@4500
3724+00002bd2@4502
3725+0000ab50@4503
3726+0000abf0@4504
3727+0000ebf4@4505
3728+0000eb74@4506
3729+00006bf4@4507
3730+0000ebf4@4508
3731+0000fbf4@4509
3732+0000fb54@4510
3733+0000fbf4@4511
3734+00007bf6@4512
3735+0000fbf6@4513
3736+0000f176@4514
3737+0000b1f6@4515
3738+000031f6@4516
3739+0000a176@4517
3740+0000afc2@4518
3741+00002f42@4521
3742+0000afc0@4522
3743+0000efc0@4523
3744+0000efc4@4524
3745+0000ef64@4525
3746+00006fe4@4526
3747+0000efe4@4527
3748+0000ffe4@4528
3749+00007fe6@4530
3750+0000ffe6@4531
3751+0000f346@4532
3752+0000b3c6@4533
3753+000033c6@4535
3754+0000a346@4536
3755+0000abe2@4537
3756+00002b60@4540
3757+0000abe0@4541
3758+0000ebe4@4542
3759+00006be4@4544
3760+0000ebe4@4545
3761+0000fb64@4547
3762+0000fbe4@4548
3763+00007be6@4549
3764+0000fbe6@4550
3765+0000fd16@4551
3766+0000bd96@4552
3767+00003d96@4554
3768+0000ad96@4555
3769+0000ab82@4556
3770+00002b82@4558
3771+0000ab80@4559
3772+0000aba4@4560
3773+0000eba4@4561
3774+0000eb24@4562
3775+00006ba4@4563
3776+0000eba4@4564
3777+0000fba4@4565
3778+0000fb04@4566
3779+0000fba4@4567
3780+00007ba6@4568
3781+0000ffb6@4569
3782+0000fd36@4570
3783+0000bdb6@4571
3784+00003db6@4572
3785+0000ad36@4573
3786+0000ab02@4574
3787+0000ab82@4575
3788+00002b00@4577
3789+0000ab80@4578
3790+0000eba4@4579
3791+0000eb24@4581
3792+00006ba4@4582
3793+0000eba4@4583
3794+0000fb24@4584
3795+0000fba4@4585
3796+00007ba6@4586
3797+0000fba6@4587
3798+0000f91a@4588
3799+0000b99a@4589
3800+0000399a@4591
3801+0000a91a@4592
3802+0000abc2@4593
3803+00002b40@4596
3804+0000abe4@4597
3805+0000ebe4@4598
3806+0000eb64@4599
3807+00006be4@4600
3808+0000ebe4@4601
3809+0000fbc0@4602
3810+0000fb44@4603
3811+0000fbe4@4604
3812+00007be6@4605
3813+0000fbe6@4606
3814+0000f91a@4607
3815+0000f99a@4608
3816+0000e99a@4610
3817+0000ebc2@4611
3818+00006b42@4614
3819+0000ebc0@4615
3820+0000ebe4@4616
3821+0000afe0@4617
3822+0000a560@4618
3823+000025e0@4619
3824+0000a5e0@4620
3825+0000b5e0@4621
3826+0000b560@4622
3827+0000b5e0@4623
3828+0000f5e2@4624
3829+0000fd36@4625
3830+0000b996@4626
3831+00003996@4628
3832+0000a916@4629
3833+0000abd2@4630
3834+00002b50@4633
3835+0000abd0@4634
3836+0000ebf4@4635
3837+00006bf4@4637
3838+0000ebf4@4638
3839+0000fb74@4640
3840+0000fbf4@4641
3841+00007bf6@4642
3842+0000fbf6@4643
3843+0000f916@4644
3844+0000b996@4645
3845+00003996@4647
3846+0000a996@4648
3847+0000abd2@4649
3848+00002bd2@4651
3849+0000ab50@4652
3850+0000abf0@4653
3851+0000ebf4@4654
3852+0000eb74@4655
3853+00006bf4@4656
3854+0000ebf4@4657
3855+0000fbf4@4658
3856+0000fb54@4659
3857+0000fbf4@4660
3858+00007bf6@4661
3859+0000fbf6@4662
3860+0000f17a@4663
3861+0000b1fa@4664
3862+000031fa@4665
3863+0000a17a@4666
3864+0000afc2@4667
3865+00002f42@4670
3866+0000afc0@4671
3867+0000efe0@4672
3868+0000efc4@4673
3869+0000ef44@4674
3870+00006fe4@4675
3871+0000efe4@4676
3872+0000ffe4@4677
3873+00007fe6@4679
3874+0000ffe6@4680
3875+0000f346@4681
3876+0000b3c6@4682
3877+000033c6@4684
3878+0000a346@4685
3879+0000abe2@4686
3880+00002b60@4689
3881+0000abe4@4690
3882+0000ebe4@4691
3883+0000eb64@4692
3884+00006be4@4693
3885+0000ebe4@4694
3886+0000fb64@4696
3887+0000fbe4@4697
3888+00007be6@4698
3889+0000fbe6@4699
3890+0000ff16@4700
3891+0000bf96@4701
3892+00003f96@4703
3893+0000af96@4704
3894+0000ab82@4705
3895+00002b82@4707
3896+0000ab80@4708
3897+0000aba4@4709
3898+0000eba4@4710
3899+0000eb24@4711
3900+00006b84@4712
3901+0000eba4@4713
3902+0000fba4@4714
3903+0000fb04@4715
3904+0000fba4@4716
3905+00007ba6@4717
3906+0000ffb6@4718
3907+0000ff36@4719
3908+0000bfb6@4720
3909+00003fb6@4721
3910+0000af36@4722
3911+0000ab82@4723
3912+00002b00@4726
3913+0000ab80@4727
3914+0000eba4@4728
3915+0000eb24@4730
3916+00006ba4@4731
3917+0000eba4@4732
3918+0000fb24@4733
3919+0000fba4@4734
3920+00007ba6@4735
3921+0000fba6@4736
3922+0000f91e@4737
3923+0000b99e@4738
3924+0000399e@4740
3925+0000a91e@4741
3926+0000abc2@4742
3927+00002b40@4745
3928+0000abe4@4746
3929+0000ebe4@4747
3930+0000eb64@4748
3931+00006be4@4749
3932+0000ebe4@4750
3933+0000fbc4@4751
3934+0000fb64@4752
3935+0000fbe4@4753
3936+00007be6@4754
3937+0000fbe6@4755
3938+0000f91e@4756
3939+0000f99e@4757
3940+0000f99c@4759
3941+0000fbc0@4760
3942+0000ebc0@4761
3943+00006b40@4763
3944+0000ebc0@4764
3945+0000ebe4@4765
3946+0000eb44@4767
3947+00006bc4@4768
3948+0000ebe4@4769
3949+0000fbe4@4770
3950+0000fb44@4771
3951+0000fbe4@4772
3952+0000fbe6@4773
3953+0000fb56@4774
3954+0000b996@4775
3955+00003996@4777
3956+0000a916@4778
3957+0000abd2@4779
3958+00002b50@4782
3959+0000abd0@4783
3960+0000ebf4@4784
3961+00006bf4@4786
3962+0000ebf4@4787
3963+0000fb74@4789
3964+0000fbf4@4790
3965+00007bf6@4791
3966+0000fbf6@4792
3967+0000fb16@4793
3968+0000bb96@4794
3969+00003b96@4796
3970+0000ab96@4797
3971+0000abe2@4798
3972+00002be2@4800
3973+0000ab60@4801
3974+0000abe0@4802
3975+0000ebe4@4803
3976+0000eb64@4804
3977+00006be4@4805
3978+0000ebe4@4806
3979+0000fbe4@4807
3980+0000fb64@4808
3981+0000fbe4@4809
3982+00007be6@4810
3983+0000fbe6@4811
3984+0000f17e@4812
3985+0000b1fe@4813
3986+000031fe@4814
3987+0000a17e@4815
3988+0000afc2@4816
3989+00002f42@4819
3990+0000afc0@4820
3991+0000efc0@4821
3992+0000efc4@4822
3993+0000ef44@4823
3994+00006fe4@4824
3995+0000efe4@4825
3996+0000ffe4@4826
3997+00007fe6@4828
3998+0000ffe6@4829
3999+0000f346@4830
4000+0000b3c6@4831
4001+000033c6@4833
4002+0000a346@4834
4003+0000abe2@4835
4004+00002b60@4838
4005+0000abe4@4839
4006+0000ebe4@4840
4007+00006be4@4842
4008+0000ebe4@4843
4009+0000fb64@4845
4010+0000fbe4@4846
4011+00007be6@4847
4012+0000fbe6@4848
4013+0000f716@4849
4014+0000b796@4850
4015+00003796@4852
4016+0000a796@4853
4017+0000a992@4854
4018+00002992@4856
4019+0000a990@4857
4020+0000e9b4@4858
4021+0000e994@4859
4022+0000eb34@4860
4023+00006b94@4861
4024+0000ebb4@4862
4025+0000fbb4@4863
4026+0000fb14@4864
4027+0000fbb4@4865
4028+00007bb6@4866
4029+0000ffb6@4867
4030+0000f736@4868
4031+0000b7b6@4869
4032+000037b6@4870
4033+0000a736@4871
4034+0000a992@4872
4035+00002910@4875
4036+0000a990@4876
4037+0000ebb4@4877
4038+0000e9b4@4878
4039+0000eb34@4879
4040+000069b4@4880
4041+0000ebb4@4881
4042+0000fbb4@4882
4043+00007bb6@4884
4044+0000fbb6@4885
4045+0000f922@4886
4046+0000b9a2@4887
4047+000039a2@4889
4048+0000a922@4890
4049+0000abc2@4891
4050+00002b40@4894
4051+0000abe4@4895
4052+0000ebe4@4896
4053+0000eb64@4897
4054+00006be4@4898
4055+0000ebe4@4899
4056+0000fbc4@4900
4057+0000fb64@4901
4058+0000fbe4@4902
4059+00007be6@4903
4060+0000fbe6@4904
4061+0000f922@4905
4062+0000f9a2@4906
4063+0000e9a2@4908
4064+0000ebe2@4909
4065+0000ebc2@4910
4066+00006b42@4912
4067+0000ebc0@4913
4068+0000ebe4@4914
4069+0000ab6c@4915
4070+0000a96c@4916
4071+000029ec@4917
4072+0000a9ec@4918
4073+0000b9ec@4919
4074+0000b96c@4920
4075+0000b9ec@4921
4076+0000f9ee@4922
4077+0000fb3e@4923
4078+0000bbb6@4924
4079+00003bb6@4926
4080+0000ab36@4927
4081+0000abe2@4928
4082+00002b60@4931
4083+0000abe0@4932
4084+0000ebe4@4933
4085+00006be4@4935
4086+0000ebe4@4936
4087+0000fb64@4938
4088+0000fbe4@4939
4089+00007be6@4940
4090+0000fbe6@4941
4091+0000f916@4942
4092+0000b996@4943
4093+00003996@4945
4094+0000a996@4946
4095+0000abd2@4947
4096+00002bd2@4949
4097+0000abd0@4950
4098+0000abf0@4951
4099+0000ebf4@4952
4100+0000eb74@4953
4101+00006bf4@4954
4102+0000ebf4@4955
4103+0000fbf4@4956
4104+0000fb54@4957
4105+0000fbf4@4958
4106+00007bf6@4959
4107+0000fbf6@4960
4108+0000b342@4961
4109+0000b3c2@4962
4110+000033c2@4963
4111+0000a342@4964
4112+0000af42@4965
4113+0000afc2@4966
4114+00002f40@4968
4115+0000afc0@4969
4116+0000efc0@4970
4117+0000efc4@4971
4118+0000ef44@4972
4119+00006fc4@4973
4120+0000efe4@4974
4121+0000ffe4@4975
4122+0000ffc4@4976
4123+00007fe6@4977
4124+0000ffe6@4978
4125+0000f346@4979
4126+0000b3c6@4980
4127+000033c6@4982
4128+0000a346@4983
4129+0000abe2@4984
4130+00002b60@4987
4131+0000abe4@4988
4132+0000ebe4@4989
4133+00006be4@4991
4134+0000ebe4@4992
4135+0000fbe4@4993
4136+0000fb64@4994
4137+0000fbe4@4995
4138+00007be6@4996
4139+0000fbe6@4997
4140+0000ff16@4998
4141+0000bf96@4999
4142+00003f96@5001
4143+0000afb6@5002
4144+0000aba2@5003
4145+00002ba2@5005
4146+0000aba0@5006
4147+0000aba4@5007
4148+0000eba4@5008
4149+0000eb24@5009
4150+00006ba4@5010
4151+0000eba4@5011
4152+0000fba4@5012
4153+0000fb24@5013
4154+0000fba4@5014
4155+00007ba6@5015
4156+0000ffb6@5016
4157+0000b536@5017
4158+0000b5b6@5018
4159+000035b6@5019
4160+0000a536@5020
4161+0000a182@5021
4162+00002100@5024
4163+0000a180@5025
4164+0000e3a4@5026
4165+0000e104@5028
4166+000061a4@5029
4167+0000e3a4@5030
4168+0000f3a4@5031
4169+000073a6@5033
4170+0000f3a6@5034
4171+0000f926@5035
4172+0000b9a6@5036
4173+000039a6@5038
4174+0000a926@5039
4175+0000abc2@5040
4176+00002b40@5043
4177+0000abe4@5044
4178+0000ebe4@5045
4179+0000eb64@5046
4180+00006be4@5047
4181+0000ebe4@5048
4182+0000fbc4@5049
4183+0000fb64@5050
4184+0000fbe4@5051
4185+00007be6@5052
4186+0000fbe6@5053
4187+0000f926@5054
4188+0000f9a6@5055
4189+0000e9a6@5057
4190+0000ebe2@5058
4191+0000ebc2@5059
4192+00006b42@5061
4193+0000ebc0@5062
4194+0000ebe4@5063
4195+0000afe0@5064
4196+0000a560@5065
4197+000025e0@5066
4198+0000a5e0@5067
4199+0000b5e0@5068
4200+0000b560@5069
4201+0000b5e0@5070
4202+0000f5e2@5071
4203+0000fd36@5072
4204+0000b996@5073
4205+00003996@5075
4206+0000a916@5076
4207+0000abd2@5077
4208+00002b50@5080
4209+0000abd0@5081
4210+0000ebf4@5082
4211+00006bf4@5084
4212+0000ebf4@5085
4213+0000fb74@5087
4214+0000fbf4@5088
4215+00007bf6@5089
4216+0000fbf6@5090
4217+0000f916@5091
4218+0000b996@5092
4219+00003996@5094
4220+0000a996@5095
4221+0000abd2@5096
4222+00002bd2@5098
4223+0000ab50@5099
4224+0000abf0@5100
4225+0000ebf4@5101
4226+0000eb74@5102
4227+00006bf4@5103
4228+0000ebf4@5104
4229+0000fbf4@5105
4230+0000fb54@5106
4231+0000fbf4@5107
4232+00007bf6@5108
4233+0000fbf6@5109
4234+0000b346@5110
4235+0000b3c6@5111
4236+000033c6@5112
4237+0000a346@5113
4238+0000afc2@5114
4239+00002f42@5117
4240+0000afc0@5118
4241+0000efc0@5119
4242+0000efc4@5120
4243+0000ef44@5121
4244+00006fe4@5122
4245+0000efe4@5123
4246+0000ffe4@5124
4247+0000ffc4@5125
4248+00007fe6@5126
4249+0000ffe6@5127
4250+0000f346@5128
4251+0000b3c6@5129
4252+000033c6@5131
4253+0000a346@5132
4254+0000abe2@5133
4255+00002b60@5136
4256+0000abe4@5137
4257+0000ebe4@5138
4258+00006be4@5140
4259+0000ebe4@5141
4260+0000fb64@5143
4261+0000fbe4@5144
4262+00007be6@5145
4263+0000fbe6@5146
4264+0000b536@5147
4265+0000b5b6@5148
4266+000035b6@5150
4267+0000a5b6@5151
4268+0000a182@5152
4269+00002182@5154
4270+0000a180@5155
4271+0000e1a4@5156
4272+0000e184@5157
4273+0000e304@5158
4274+00006184@5159
4275+0000e3a4@5160
4276+0000f3a4@5161
4277+0000f104@5162
4278+0000f3a4@5163
4279+000073a6@5164
4280+0000f7b6@5165
4281+0000f536@5166
4282+0000b5b6@5167
4283+000035b6@5168
4284+0000a536@5169
4285+0000a182@5170
4286+00002100@5173
4287+0000a180@5174
4288+0000e3a4@5175
4289+0000e324@5177
4290+0000e1a4@5178
4291+0000f324@5180
4292+0000f3a4@5181
4293+000073a6@5182
4294+0000f3a6@5183
4295+0000f92a@5184
4296+0000b9aa@5185
4297+000039aa@5187
4298+0000a92a@5188
4299+0000abc2@5189
4300+00002b40@5192
4301+0000abe4@5193
4302+0000ebe4@5194
4303+0000eb64@5195
4304+00006be4@5196
4305+0000ebe4@5197
4306+0000fbc4@5198
4307+0000fb64@5199
4308+0000fbe4@5200
4309+00007be6@5201
4310+0000fbe6@5202
4311+0000f92a@5203
4312+0000f9aa@5204
4313+0000e9aa@5206
4314+0000ebe2@5207
4315+0000ebc2@5208
4316+00006b42@5210
4317+0000ebc0@5211
4318+0000ebe4@5212
4319+0000afe0@5213
4320+0000a560@5214
4321+000025e0@5215
4322+0000a5e0@5216
4323+0000b5e0@5217
4324+0000b560@5218
4325+0000b5e0@5219
4326+0000f5e2@5220
4327+0000fd36@5221
4328+0000b996@5222
4329+00003996@5224
4330+0000a916@5225
4331+0000abd2@5226
4332+00002b50@5229
4333+0000abd0@5230
4334+0000ebf4@5231
4335+00006bf4@5233
4336+0000ebf4@5234
4337+0000fb74@5236
4338+0000fbf4@5237
4339+00007bf6@5238
4340+0000fbf6@5239
4341+0000f916@5240
4342+0000b996@5241
4343+00003996@5243
4344+0000a996@5244
4345+0000abd2@5245
4346+00002bd2@5247
4347+0000abd0@5248
4348+0000abf0@5249
4349+0000ebf4@5250
4350+0000eb74@5251
4351+00006bf4@5252
4352+0000ebf4@5253
4353+0000fbf4@5254
4354+0000fb54@5255
4355+0000fbf4@5256
4356+00007bf6@5257
4357+0000fbf6@5258
4358+0000b34a@5259
4359+0000b3ca@5260
4360+000033ca@5261
4361+0000a34a@5262
4362+0000afc2@5263
4363+00002f42@5266
4364+0000afc0@5267
4365+0000efe0@5268
4366+0000efc4@5269
4367+0000ef44@5270
4368+00006fc4@5271
4369+0000efe4@5272
4370+0000ffe4@5273
4371+0000ffc4@5274
4372+00007fe6@5275
4373+0000ffe6@5276
4374+0000f346@5277
4375+0000b3c6@5278
4376+000033c6@5280
4377+0000a346@5281
4378+0000abe2@5282
4379+00002b60@5285
4380+0000abe4@5286
4381+0000ebe4@5287
4382+0000eb64@5288
4383+00006be4@5289
4384+0000ebe4@5290
4385+0000fbe4@5291
4386+0000fb64@5292
4387+0000fbe4@5293
4388+00007be6@5294
4389+0000fbe6@5295
4390+0000b536@5296
4391+0000b5b6@5297
4392+000035b6@5299
4393+0000a5b6@5300
4394+0000a182@5301
4395+00002182@5303
4396+0000a180@5304
4397+0000e1a4@5305
4398+0000e304@5307
4399+00006184@5308
4400+0000e3a4@5309
4401+0000f3a4@5310
4402+0000f304@5311
4403+0000f3a4@5312
4404+000073a6@5313
4405+0000f7b6@5314
4406+0000f536@5315
4407+0000b5b6@5316
4408+000035b6@5317
4409+0000a536@5318
4410+0000a182@5319
4411+00002100@5322
4412+0000a180@5323
4413+0000e3a4@5324
4414+0000e304@5326
4415+0000e3a4@5327
4416+0000f3a4@5329
4417+000073a6@5331
4418+0000f3a6@5332
4419+0000f92e@5333
4420+0000b9ae@5334
4421+000039ae@5336
4422+0000a92e@5337
4423+0000abc2@5338
4424+00002b40@5341
4425+0000abe4@5342
4426+0000ebe4@5343
4427+0000eb64@5344
4428+00006be4@5345
4429+0000ebe4@5346
4430+0000fbc4@5347
4431+0000fb64@5348
4432+0000fbe4@5349
4433+00007be6@5350
4434+0000fbe6@5351
4435+0000f92e@5352
4436+0000f9ae@5353
4437+0000f9ac@5355
4438+0000fbe0@5356
4439+0000ebc0@5357
4440+00006b40@5359
4441+0000ebc0@5360
4442+0000ebe4@5361
4443+0000eb44@5363
4444+00006bc0@5364
4445+0000ebe4@5365
4446+0000fbe4@5366
4447+0000fb44@5367
4448+0000fbe4@5368
4449+0000fbe6@5369
4450+0000fb56@5370
4451+0000b996@5371
4452+00003996@5373
4453+0000a916@5374
4454+0000abd2@5375
4455+00002b50@5378
4456+0000abd0@5379
4457+0000ebf4@5380
4458+00006bf4@5382
4459+0000ebf4@5383
4460+0000fb74@5385
4461+0000fbf4@5386
4462+00007bf6@5387
4463+0000fbf6@5388
4464+0000f916@5389
4465+0000b996@5390
4466+00003996@5392
4467+0000a996@5393
4468+0000abd2@5394
4469+00002bd2@5396
4470+0000ab50@5397
4471+0000abf0@5398
4472+0000ebf4@5399
4473+0000eb74@5400
4474+00006bf4@5401
4475+0000ebf4@5402
4476+0000fbf4@5403
4477+0000fb54@5404
4478+0000fbf4@5405
4479+00007bf6@5406
4480+0000fbf6@5407
4481+0000b34e@5408
4482+0000b3ce@5409
4483+000033ce@5410
4484+0000a34e@5411
4485+0000afc2@5412
4486+00002f40@5415
4487+0000afc0@5416
4488+0000efc0@5417
4489+0000efc4@5418
4490+0000ef44@5419
4491+00006fc4@5420
4492+0000efe4@5421
4493+0000ffe4@5422
4494+00007fe6@5424
4495+0000ffe6@5425
4496+0000f346@5426
4497+0000b3c6@5427
4498+000033c6@5429
4499+0000a346@5430
4500+0000abe2@5431
4501+00002b60@5434
4502+0000abe4@5435
4503+0000ebe4@5436
4504+00006be4@5438
4505+0000ebe4@5439
4506+0000fb64@5441
4507+0000fbe4@5442
4508+00007be6@5443
4509+0000fbe6@5444
4510+0000b536@5445
4511+0000b5b6@5446
4512+000035b6@5448
4513+0000a5b6@5449
4514+0000a182@5450
4515+00002102@5452
4516+0000a180@5453
4517+0000e1a4@5454
4518+0000e324@5456
4519+00006184@5457
4520+0000e3a4@5458
4521+0000f3a4@5459
4522+0000f104@5460
4523+0000f3a4@5461
4524+000073a6@5462
4525+0000f7b6@5463
4526+0000f536@5464
4527+0000b5b6@5465
4528+000035b6@5466
4529+0000a536@5467
4530+0000a182@5468
4531+00002100@5471
4532+0000a180@5472
4533+0000e3a4@5473
4534+0000e304@5475
4535+0000e1a4@5476
4536+0000e3a4@5477
4537+0000f324@5478
4538+0000f3a4@5479
4539+000073a6@5480
4540+0000f3a6@5481
4541+0000f932@5482
4542+0000b9b2@5483
4543+000039b2@5485
4544+0000a932@5486
4545+0000abc2@5487
4546+00002b40@5490
4547+0000abe4@5491
4548+0000ebe4@5492
4549+0000eb64@5493
4550+00006be4@5494
4551+0000ebe4@5495
4552+0000fbc4@5496
4553+0000fb64@5497
4554+0000fbe4@5498
4555+00007be6@5499
4556+0000fbe6@5500
4557+0000f932@5501
4558+0000f9b2@5502
4559+0000e9b2@5504
4560+0000ebc2@5505
4561+00006b42@5508
4562+0000ebc0@5509
4563+0000ebe4@5510
4564+0000afe0@5511
4565+0000a560@5512
4566+000025e0@5513
4567+0000a5e0@5514
4568+0000b5e0@5515
4569+0000b560@5516
4570+0000b5e0@5517
4571+0000f5e2@5518
4572+0000fd36@5519
4573+0000b996@5520
4574+00003996@5522
4575+0000a916@5523
4576+0000abd2@5524
4577+00002b50@5527
4578+0000abd0@5528
4579+0000ebf4@5529
4580+00006bf4@5531
4581+0000ebf4@5532
4582+0000fb74@5534
4583+0000fbf4@5535
4584+00007bf6@5536
4585+0000fbf6@5537
4586+0000f916@5538
4587+0000b996@5539
4588+00003996@5541
4589+0000a996@5542
4590+0000abd2@5543
4591+00002bd2@5545
4592+0000abd0@5546
4593+0000abf0@5547
4594+0000ebf4@5548
4595+0000eb74@5549
4596+00006bf4@5550
4597+0000ebf4@5551
4598+0000fbf4@5552
4599+0000fb54@5553
4600+0000fbf4@5554
4601+00007bf6@5555
4602+0000fbf6@5556
4603+0000b352@5557
4604+0000b3d2@5558
4605+000033d2@5559
4606+0000a352@5560
4607+0000af42@5561
4608+0000afc2@5562
4609+00002f40@5564
4610+0000afc0@5565
4611+0000efe0@5566
4612+0000efc4@5567
4613+0000ef44@5568
4614+00006fe4@5569
4615+0000efe4@5570
4616+0000ffe4@5571
4617+00007fe6@5573
4618+0000ffe6@5574
4619+0000f346@5575
4620+0000b3c6@5576
4621+000033c6@5578
4622+0000a346@5579
4623+0000abe2@5580
4624+00002b60@5583
4625+0000abe4@5584
4626+0000ebe4@5585
4627+0000eb64@5586
4628+00006be4@5587
4629+0000ebe4@5588
4630+0000fb64@5590
4631+0000fbe4@5591
4632+00007be6@5592
4633+0000fbe6@5593
4634+0000b536@5594
4635+0000b5b6@5595
4636+000025b6@5597
4637+0000a5b6@5598
4638+0000a182@5599
4639+00002182@5601
4640+0000a180@5602
4641+0000e1a4@5603
4642+0000e304@5605
4643+00006184@5606
4644+0000e3a4@5607
4645+0000f3a4@5608
4646+0000f124@5609
4647+0000f3a4@5610
4648+000073a6@5611
4649+0000f7b6@5612
4650+0000f536@5613
4651+0000b5b6@5614
4652+000035b6@5615
4653+0000a536@5616
4654+0000a182@5617
4655+00002100@5620
4656+0000a180@5621
4657+0000e3a4@5622
4658+0000e324@5624
4659+0000e1a4@5625
4660+0000f324@5627
4661+0000f3a4@5628
4662+000073a6@5629
4663+0000f3a6@5630
4664+0000f936@5631
4665+0000b9b6@5632
4666+000039b6@5634
4667+0000a936@5635
4668+0000abc2@5636
4669+0000ab40@5639
4670+0000abe4@5640
4671+0000ebe4@5641
4672+0000eb64@5642
4673+00006be4@5643
4674+0000ebe4@5644
4675+0000fbe4@5645
4676+0000fb64@5646
4677+0000fbe4@5647
4678+00007be6@5648
4679+0000fbe6@5649
4680+0000f936@5650
4681+0000f9b6@5651
4682+0000e9b6@5653
4683+0000ebc2@5654
4684+00006b42@5657
4685+0000ebc0@5658
4686+0000ebe4@5659
4687+0000afe0@5660
4688+0000a560@5661
4689+000025e0@5662
4690+0000a5e0@5663
4691+0000b5e0@5664
4692+0000b560@5665
4693+0000b5e0@5666
4694+0000f5e2@5667
4695+0000fd36@5668
4696+0000b996@5669
4697+00003996@5671
4698+0000a916@5672
4699+0000abd2@5673
4700+00002b50@5676
4701+0000abd0@5677
4702+0000ebf4@5678
4703+00006bf4@5680
4704+0000ebf4@5681
4705+0000fb74@5683
4706+0000fbf4@5684
4707+00007bf6@5685
4708+0000fbf6@5686
4709+0000f336@5687
4710+0000b3b6@5688
4711+000033b6@5690
4712+0000a3b6@5691
4713+0000abd2@5692
4714+00002bd2@5694
4715+0000abd0@5695
4716+0000abf0@5696
4717+0000ebf4@5697
4718+0000eb74@5698
4719+00006bf4@5699
4720+0000ebf4@5700
4721+0000fbf4@5701
4722+0000fb54@5702
4723+0000fbf4@5703
4724+00007bf6@5704
4725+0000fbf6@5705
4726+0000b356@5706
4727+0000b3d6@5707
4728+000033d6@5708
4729+0000a356@5709
4730+0000afc2@5710
4731+00002f40@5713
4732+0000afc0@5714
4733+0000efe0@5715
4734+0000efc4@5716
4735+0000ef44@5717
4736+00006fe4@5718
4737+0000efe4@5719
4738+0000ffe4@5720
4739+00007fe6@5722
4740+0000ffe6@5723
4741+0000f346@5724
4742+0000b3c6@5725
4743+000033c6@5727
4744+0000a346@5728
4745+0000abe2@5729
4746+00002b60@5732
4747+0000abe4@5733
4748+0000ebe4@5734
4749+0000eb64@5735
4750+00006be4@5736
4751+0000ebe4@5737
4752+0000fb64@5739
4753+0000fbe4@5740
4754+00007be6@5741
4755+0000fbe6@5742
4756+0000b536@5743
4757+0000b5b6@5744
4758+000025b6@5746
4759+0000a5b6@5747
4760+0000a182@5748
4761+00002182@5750
4762+0000a180@5751
4763+0000e1a4@5752
4764+0000e324@5754
4765+00006184@5755
4766+0000e3a4@5756
4767+0000f3a4@5757
4768+0000f304@5758
4769+0000f3a4@5759
4770+000073a6@5760
4771+0000f7b6@5761
4772+0000f536@5762
4773+0000b5b6@5763
4774+000035b6@5764
4775+0000a536@5765
4776+0000a182@5766
4777+00002100@5769
4778+0000a180@5770
4779+0000e3a4@5771
4780+0000e384@5772
4781+0000e304@5773
4782+0000e3a4@5774
4783+0000f324@5776
4784+0000f3a4@5777
4785+000073a6@5778
4786+0000f3a6@5779
4787+0000f93a@5780
4788+0000b9ba@5781
4789+000039ba@5783
4790+0000a93a@5784
4791+0000abc2@5785
4792+0000ab40@5788
4793+0000abe4@5789
4794+0000ebe4@5790
4795+0000eb64@5791
4796+00006be4@5792
4797+0000ebe4@5793
4798+0000fbc4@5794
4799+0000fb64@5795
4800+0000fbe4@5796
4801+00007be6@5797
4802+0000fbe6@5798
4803+0000f93a@5799
4804+0000f9ba@5800
4805+0000e9ba@5802
4806+0000ebc2@5803
4807+00006b42@5806
4808+0000ebc0@5807
4809+0000ebe4@5808
4810+0000ab24@5809
4811+0000a324@5810
4812+000023a4@5811
4813+0000a3a4@5812
4814+0000b3a4@5813
4815+0000b324@5814
4816+0000b3a6@5815
4817+0000f3a6@5816
4818+0000fb76@5817
4819+0000b9f6@5818
4820+000039f6@5820
4821+0000a976@5821
4822+0000a102@5822
4823+0000a182@5823
4824+00002100@5825
4825+0000a180@5826
4826+0000e3a4@5827
4827+000063a4@5829
4828+0000e1a4@5830
4829+0000f324@5832
4830+0000f3a4@5833
4831+000073a6@5834
4832+0000f3a6@5835
4833+0000f116@5836
4834+0000b196@5837
4835+00003196@5839
4836+0000a196@5840
4837+0000a182@5841
4838+00002182@5843
4839+0000a180@5844
4840+0000a1a0@5845
4841+0000e3a4@5846
4842+0000e324@5847
4843+000061a4@5848
4844+0000e3a4@5849
4845+0000f3a4@5850
4846+0000f304@5851
4847+0000f3a4@5852
4848+000073a6@5853
4849+0000f3a6@5854
4850+0000f35a@5855
4851+0000b3da@5856
4852+000033da@5857
4853+0000a35a@5858
4854+0000af42@5859
4855+0000afc2@5860
4856+00002f40@5862
4857+0000afc0@5863
4858+0000efe0@5864
4859+0000efc4@5865
4860+0000ef44@5866
4861+00006fe4@5867
4862+0000efe4@5868
4863+0000ffe4@5869
4864+00007fe6@5871
4865+0000ffe6@5872
4866+0000f346@5873
4867+0000b3c6@5874
4868+000033c6@5876
4869+0000a346@5877
4870+0000abe2@5878
4871+00002b60@5881
4872+0000abe4@5882
4873+0000ebe4@5883
4874+00006be4@5885
4875+0000ebe4@5886
4876+0000fb64@5888
4877+0000fbe4@5889
4878+00007be6@5890
4879+0000fbe6@5891
4880+0000b536@5892
4881+0000b5b6@5893
4882+000025b6@5895
4883+0000a5b6@5896
4884+0000a182@5897
4885+00002182@5899
4886+0000a180@5900
4887+0000e1a4@5901
4888+0000e304@5903
4889+00006184@5904
4890+0000e3a4@5905
4891+0000f3a4@5906
4892+0000f304@5907
4893+0000f3a4@5908
4894+000073a6@5909
4895+0000f7b6@5910
4896+0000f5b6@5911
4897+0000b5b6@5912
4898+000035b6@5913
4899+0000a536@5914
4900+0000a182@5915
4901+00002100@5918
4902+0000a180@5919
4903+0000e3a4@5920
4904+0000e324@5922
4905+0000e1a4@5923
4906+0000e3a4@5924
4907+0000f324@5925
4908+0000f3a4@5926
4909+000073a6@5927
4910+0000f3a6@5928
4911+0000f93e@5929
4912+0000b9be@5930
4913+000039be@5932
4914+0000a93e@5933
4915+0000abc2@5934
4916+0000ab40@5937
4917+0000abe4@5938
4918+0000ebe4@5939
4919+0000eb64@5940
4920+00006be4@5941
4921+0000ebe4@5942
4922+0000fbc4@5943
4923+0000fb44@5944
4924+0000fbe4@5945
4925+00007be6@5946
4926+0000fbe6@5947
4927+0000f93e@5948
4928+0000f9be@5949
4929+0000f9bc@5951
4930+0000fbc0@5952
4931+0000ebc0@5953
4932+00006b40@5955
4933+0000ebc0@5956
4934+0000ebe4@5957
4935+0000eb64@5959
4936+00006bc4@5960
4937+0000ebe4@5961
4938+0000fbe4@5962
4939+0000fb44@5963
4940+00007be4@5964
4941+0000fbe6@5965
4942+0000fb16@5966
4943+0000b196@5967
4944+00003196@5969
4945+0000a116@5970
4946+0000a182@5971
4947+00002100@5974
4948+0000a180@5975
4949+0000e3a4@5976
4950+000063a4@5978
4951+0000e1a4@5979
4952+0000f324@5981
4953+0000f3a4@5982
4954+000071a6@5983
4955+0000f3a6@5984
4956+0000f116@5985
4957+0000b196@5986
4958+00003196@5988
4959+0000a196@5989
4960+0000a182@5990
4961+00002182@5992
4962+0000a180@5993
4963+0000e3a4@5995
4964+0000e324@5996
4965+000061a4@5997
4966+0000e3a4@5998
4967+0000f3a4@5999
4968+0000f104@6000
4969+0000f3a4@6001
4970+000073a6@6002
4971+0000f3a6@6003
4972+0000f35e@6004
4973+0000b3de@6005
4974+000033de@6006
4975+0000a35e@6007
4976+0000af42@6008
4977+0000afc2@6009
4978+00002f40@6011
4979+0000afc0@6012
4980+0000efe0@6013
4981+0000efc4@6014
4982+0000ef44@6015
4983+00006fe4@6016
4984+0000efe4@6017
4985+0000ffe4@6018
4986+00007fe6@6020
4987+0000ffe6@6021
4988+0000f346@6022
4989+0000b3c6@6023
4990+000033c6@6025
4991+0000a346@6026
4992+0000abe2@6027
4993+00002b60@6030
4994+0000abe4@6031
4995+0000ebe4@6032
4996+0000eb64@6033
4997+00006be4@6034
4998+0000ebe4@6035
4999+0000fbe4@6036
5000+0000fb64@6037
5001+0000fbe4@6038
5002+00007be6@6039
5003+0000fbe6@6040
5004+0000b916@6041
5005+0000b996@6042
5006+00003996@6044
5007+0000afb6@6045
5008+0000a7a2@6046
5009+00002722@6048
5010+0000a7a0@6049
5011+0000e7a4@6050
5012+0000e724@6052
5013+000067a4@6053
5014+0000e7a4@6054
5015+0000f7a4@6055
5016+0000f724@6056
5017+0000f7a4@6057
5018+000077a6@6058
5019+0000ffb6@6059
5020+0000b9b6@6060
5021+000039b6@6062
5022+0000a936@6063
5023+0000a722@6064
5024+0000a7a2@6065
5025+00002720@6067
5026+0000a7a0@6068
5027+0000e7a4@6069
5028+0000e724@6071
5029+0000e7a4@6072
5030+0000f724@6074
5031+0000f7a4@6075
5032+000077a6@6076
5033+0000f7a6@6077
5034+0000f936@6078
5035+0000f9b6@6079
5036+000079b6@6081
5037+0000e936@6082
5038+0000e7a2@6083
5039+0000e7a0@6086
5040+0000e7a4@6087
5041+0000ab18@6089
5042+00002b98@6090
5043+0000ab98@6091
5044+0000bb98@6092
5045+0000bb18@6093
5046+0000bb98@6094
5047+00007b9a@6095
5048+0000fb9a@6096
5049+0000f936@6097
5050+0000f9b6@6098
5051+0000e936@6100
5052+0000efa2@6101
5053+0000e7a2@6102
5054+00006722@6104
5055+0000e7a0@6105
5056+0000e7a4@6106
5057+0000ab98@6107
5058+0000ab18@6108
5059+00002b98@6109
5060+0000ab98@6110
5061+0000bb98@6111
5062+0000bb18@6112
5063+00003b9a@6113
5064+0000fb9a@6114
5065+0000fb1e@6115
5066+0000b19e@6116
5067+0000319e@6118
5068+0000a11e@6119
5069+0000a9d2@6120
5070+00002950@6123
5071+0000a9d0@6124
5072+0000ebf4@6125
5073+0000ebd4@6126
5074+00006bf4@6127
5075+0000e9f4@6128
5076+0000e9d0@6129
5077+0000fb54@6130
5078+0000fbf4@6131
5079+000079f6@6132
5080+0000fbf6@6133
5081+0000f31e@6134
5082+0000b39e@6135
5083+0000339e@6137
5084+0000a39e@6138
5085+0000a9d2@6139
5086+000029d2@6141
5087+0000a9d0@6142
5088+0000ebf4@6144
5089+0000eb74@6145
5090+000069f4@6146
5091+0000ebf4@6147
5092+0000fbf4@6148
5093+0000fb54@6149
5094+0000fbf4@6150
5095+00007bf6@6151
5096+0000fbf6@6152
5097+0000b51e@6153
5098+0000b59e@6154
5099+0000359e@6155
5100+0000a59e@6156
5101+0000a9d2@6157
5102+00002950@6160
5103+0000a9d0@6161
5104+0000ebf4@6162
5105+0000e9d4@6163
5106+0000e954@6164
5107+00006bf4@6165
5108+0000ebf4@6166
5109+0000fbf4@6167
5110+0000fbd4@6168
5111+00007bf6@6169
5112+0000fbf6@6170
5113+0000ff1e@6171
5114+0000b79e@6172
5115+0000379e@6174
5116+0000a71e@6175
5117+0000a9d2@6176
5118+00002950@6179
5119+0000a9f4@6180
5120+0000ebf4@6181
5121+00006bf4@6183
5122+0000ebf4@6184
5123+0000e9d0@6185
5124+0000fb54@6186
5125+0000fbf4@6187
5126+000079f6@6188
5127+0000fbf6@6189
5128+0000f91e@6190
5129+0000b99e@6191
5130+0000299e@6193
5131+0000adfe@6194
5132+0000a5f2@6195
5133+00002572@6197
5134+0000a5f0@6198
5135+0000e5f4@6199
5136+0000e774@6201
5137+000065f4@6202
5138+0000e7f4@6203
5139+0000f7f4@6204
5140+0000f574@6205
5141+0000f7f4@6206
5142+000077f6@6207
5143+0000fffe@6208
5144+0000b9be@6209
5145+000039be@6211
5146+0000a93e@6212
5147+0000a5f2@6213
5148+00002570@6216
5149+0000a5f0@6217
5150+0000e7f4@6218
5151+0000e5f4@6219
5152+0000e774@6220
5153+0000e7f4@6221
5154+0000f7f4@6223
5155+000077f6@6225
5156+0000f7f6@6226
5157+0000fb1e@6227
5158+0000bb9e@6228
5159+00003b9e@6230
5160+0000ab1e@6231
5161+0000a5f2@6232
5162+0000a570@6235
5163+0000a7f4@6236
5164+0000e7f4@6237
5165+0000e774@6238
5166+000067f4@6239
5167+0000e7f4@6240
5168+0000f5f4@6241
5169+0000f774@6242
5170+0000f7f4@6243
5171+000077f6@6244
5172+0000f7f6@6245
5173+0000b91e@6246
5174+0000b99e@6247
5175+0000a99e@6249
5176+0000adf2@6250
5177+0000a5f2@6251
5178+00002572@6253
5179+0000a5f0@6254
5180+0000e7f4@6255
5181+0000e5f4@6256
5182+0000e774@6257
5183+000067f0@6258
5184+0000e7f4@6259
5185+0000f7f4@6260
5186+0000f770@6261
5187+000077f6@6262
5188+0000f7f6@6263
5189+0000fd3e@6264
5190+0000b9be@6265
5191+000039be@6267
5192+0000a93e@6268
5193+0000a5f2@6269
5194+00002570@6272
5195+0000a5f0@6273
5196+0000e7f4@6274
5197+000067f4@6276
5198+0000e7f4@6277
5199+0000f774@6279
5200+0000f7f4@6280
5201+000077f6@6281
5202+0000f7f6@6282
5203+0000fb1e@6283
5204+0000bb9e@6284
5205+00003b9e@6286
5206+0000ab9e@6287
5207+0000a5f2@6288
5208+000025f2@6290
5209+0000a5f0@6291
5210+0000e7f4@6293
5211+0000e774@6294
5212+000065f4@6295
5213+0000e7f4@6296
5214+0000f7f4@6297
5215+0000f774@6298
5216+0000f7f4@6299
5217+000077f6@6300
5218+0000f7f6@6301
5219+0000b91e@6302
5220+0000b99e@6303
5221+0000399e@6304
5222+0000a91e@6305
5223+0000a5f2@6306
5224+00002570@6309
5225+0000a5f0@6310
5226+0000e7f4@6311
5227+0000e774@6313
5228+000067f4@6314
5229+0000e7f4@6315
5230+0000f7f4@6316
5231+000077f6@6318
5232+0000f7f6@6319
5233+0000f93e@6320
5234+0000b9be@6321
5235+000039be@6323
5236+0000a93e@6324
5237+0000a5f2@6325
5238+00002570@6328
5239+0000a5f4@6329
5240+0000e7f4@6330
5241+0000e774@6331
5242+000067f4@6332
5243+0000e7f4@6333
5244+0000e5f0@6334
5245+0000f774@6335
5246+0000f7f4@6336
5247+000075f6@6337
5248+0000f7f6@6338
5249+0000fb1e@6339
5250+0000bb9e@6340
5251+00002b9e@6342
5252+0000affe@6343
5253+0000a5f2@6344
5254+00002572@6346
5255+0000a5f0@6347
5256+0000e5f4@6348
5257+0000e774@6350
5258+000065f4@6351
5259+0000e7f4@6352
5260+0000f7f4@6353
5261+0000f774@6354
5262+0000f7f4@6355
5263+000077f6@6356
5264+0000fffe@6357
5265+0000b99e@6358
5266+0000399e@6360
5267+0000a91e@6361
5268+0000a5f2@6362
5269+00002570@6365
5270+0000a5f0@6366
5271+0000e7f4@6367
5272+0000e5f4@6368
5273+0000e774@6369
5274+0000e7f4@6370
5275+0000f774@6372
5276+0000f7f4@6373
5277+000077f6@6374
5278+0000f7f6@6375
5279+0000f91e@6376
5280+0000f99e@6377
5281+0000799e@6379
5282+0000e91e@6380
5283+0000e5f2@6381
5284+0000e570@6384
5285+0000e7f4@6385
5286+0000a7f4@6386
5287+0000a100@6387
5288+00002180@6388
5289+0000a180@6389
5290+0000b180@6390
5291+0000b100@6391
5292+0000b180@6392
5293+00007182@6393
5294+0000f182@6394
5295+0000f93e@6395
5296+0000b9be@6396
5297+0000a9be@6398
5298+0000adf2@6399
5299+0000a5f2@6400
5300+00002572@6402
5301+0000a5f0@6403
5302+0000e7f4@6404
5303+0000e5f4@6405
5304+0000e774@6406
5305+000065f4@6407
5306+0000e7f4@6408
5307+0000f7f4@6409
5308+0000f774@6410
5309+000077f6@6411
5310+0000f7f6@6412
5311+0000ff3e@6413
5312+0000bb9e@6414
5313+00003b9e@6416
5314+0000ab1e@6417
5315+0000a5f2@6418
5316+00002570@6421
5317+0000a5f0@6422
5318+0000e7f4@6423
5319+000067f4@6425
5320+0000e7f4@6426
5321+0000f774@6428
5322+0000f7f4@6429
5323+000077f6@6430
5324+0000f7f6@6431
5325+0000f91a@6432
5326+0000b99a@6433
5327+0000399a@6435
5328+0000a99a@6436
5329+0000a5f2@6437
5330+000025f2@6439
5331+0000a570@6440
5332+0000a5f0@6441
5333+0000e7f4@6442
5334+0000e774@6443
5335+000065f4@6444
5336+0000e7f4@6445
5337+0000f7f4@6446
5338+0000f774@6447
5339+0000f7f4@6448
5340+000077f6@6449
5341+0000f7f6@6450
5342+0000b93a@6451
5343+0000b9ba@6452
5344+000039ba@6453
5345+0000a93a@6454
5346+0000a5f2@6455
5347+00002570@6458
5348+0000a5f0@6459
5349+0000e7f4@6460
5350+0000e774@6462
5351+000065f4@6463
5352+0000e7f4@6464
5353+0000f7f4@6465
5354+000077f6@6467
5355+0000f7f6@6468
5356+0000ff1a@6469
5357+0000bb9a@6470
5358+00003b9a@6472
5359+0000ab1a@6473
5360+0000a5f2@6474
5361+00002570@6477
5362+0000a7f4@6478
5363+0000e7f4@6479
5364+0000e774@6480
5365+000067f4@6481
5366+0000e7f4@6482
5367+0000e7f0@6483
5368+0000f774@6484
5369+0000f7f4@6485
5370+000077f6@6486
5371+0000f7f6@6487
5372+0000f81a@6488
5373+0000b89a@6489
5374+0000389a@6491
5375+0000acfa@6492
5376+0000a4f2@6493
5377+00002472@6495
5378+0000a470@6496
5379+0000e474@6497
5380+0000e6f4@6498
5381+00006470@6500
5382+0000e674@6501
5383+0000f6f4@6502
5384+00007676@6505
5385+0000fe7e@6506
5386+0000b8ba@6507
5387+000038ba@6509
5388+0000a83a@6510
5389+0000a4f2@6511
5390+00002470@6514
5391+0000a470@6515
5392+0000e6f4@6516
5393+0000e474@6519
5394+0000f6f4@6521
5395+00007676@6523
5396+0000f676@6524
5397+0000fa1a@6525
5398+0000ba9a@6526
5399+00003a1a@6528
5400+0000aa1a@6529
5401+0000a4f2@6530
5402+0000a470@6533
5403+0000a674@6534
5404+0000e6f4@6535
5405+00006674@6537
5406+0000e674@6538
5407+0000f6f4@6539
5408+00007676@6542
5409+0000f676@6543
5410+0000b29a@6544
5411+0000a21a@6547
5412+0000a6f2@6548
5413+0000a4f2@6549
5414+00002472@6551
5415+0000a470@6552
5416+0000e6f4@6553
5417+00006470@6556
5418+0000e674@6557
5419+0000f6f4@6558
5420+000076f6@6560
5421+0000f676@6561
5422+0000f63e@6562
5423+0000b29a@6563
5424+0000321a@6565
5425+0000a29a@6566
5426+0000a4f2@6567
5427+0000a472@6569
5428+000024f0@6570
5429+0000a4f0@6571
5430+0000e6f4@6572
5431+0000e674@6573
5432+00006674@6574
5433+0000e4f4@6575
5434+0000e6f4@6576
5435+0000f674@6577
5436+000076f6@6579
5437+0000f6f6@6580
5438+0000f29a@6581
5439+0000b21a@6582
5440+0000329a@6584
5441+0000a29a@6585
5442+0000a4f2@6586
5443+0000a472@6587
5444+00002472@6588
5445+0000a4f0@6589
5446+0000e674@6591
5447+000064f4@6593
5448+0000e6f4@6594
5449+0000f6f4@6595
5450+0000f674@6596
5451+000076f6@6598
5452+0000f6f6@6599
5453+0000b2ae@6600
5454+0000b22e@6601
5455+000032ae@6602
5456+0000a2ae@6603
5457+0000a082@6604
5458+0000a002@6605
5459+00002080@6607
5460+0000a080@6608
5461+0000e284@6609
5462+0000e204@6610
5463+000060a4@6612
5464+0000e2a4@6613
5465+0000f2a4@6614
5466+0000f204@6615
5467+00007226@6616
5468+0000f2a6@6617
5469+0000f2ae@6618
5470+0000f22e@6619
5471+000072ae@6621
5472+0000e2ae@6622
5473+0000e082@6623
5474+0000e002@6624
5475+00006080@6626
5476+0000e2a4@6627
5477+0000e0a4@6628
5478+0000a60c@6629
5479+0000260c@6630
5480+0000a68c@6631
5481+0000b68c@6632
5482+0000b60c@6633
5483+0000768e@6635
5484+0000f68e@6636
5485+0000b49a@6637
5486+0000b41a@6638
5487+0000349a@6640
5488+0000a4fa@6641
5489+0000aaf2@6642
5490+00002af2@6644
5491+0000aaf0@6645
5492+0000ea74@6646
5493+0000eaf4@6647
5494+00006af4@6649
5495+0000ea74@6650
5496+0000fa74@6651
5497+0000faf4@6652
5498+00007af6@6654
5499+0000fe76@6655
5500+0000b426@6656
5501+0000b4a6@6657
5502+000034a6@6658
5503+0000a426@6659
5504+0000a472@6660
5505+0000a4f2@6661
5506+000024f0@6663
5507+0000a470@6664
5508+0000e674@6665
5509+0000e6f4@6666
5510+0000e4f4@6668
5511+0000e474@6669
5512+0000f6f4@6670
5513+000076f6@6672
5514+0000f676@6673
5515+0000f606@6674
5516+0000b686@6675
5517+00003686@6677
5518+0000a606@6678
5519+0000a472@6679
5520+0000a4f2@6680
5521+0000a4f0@6682
5522+0000a674@6683
5523+0000e674@6684
5524+0000e6f4@6685
5525+000066f4@6686
5526+0000e674@6687
5527+0000f674@6688
5528+0000f6f4@6689
5529+000076f6@6691
5530+0000f676@6692
5531+0000b626@6693
5532+0000b6a6@6694
5533+0000a6a6@6696
5534+0000a472@6697
5535+0000a4f2@6698
5536+000024f2@6700
5537+0000a470@6701
5538+0000e674@6702
5539+0000e6f4@6703
5540+000064f4@6705
5541+0000e674@6706
5542+0000f674@6707
5543+0000f6f4@6708
5544+000076f6@6709
5545+0000f6f6@6710
5546+0000f636@6711
5547+0000b2a6@6712
5548+000032a6@6714
5549+0000a226@6715
5550+0000a002@6716
5551+0000a082@6717
5552+00002080@6719
5553+0000a080@6720
5554+0000e2a4@6721
5555+000062a4@6723
5556+0000e0a4@6724
5557+0000f2a4@6726
5558+0000f224@6727
5559+00007026@6728
5560+0000f2a6@6729
5561+0000f9be@6730
5562+0000b9be@6731
5563+0000b93e@6732
5564+0000393e@6733
5565+0000a9be@6734
5566+0000abc2@6735
5567+0000ab42@6736
5568+00002b42@6737
5569+0000ab40@6738
5570+0000abe4@6739
5571+0000ebe4@6740
5572+0000eb64@6741
5573+00006b44@6742
5574+0000ebe4@6743
5575+0000fbe4@6744
5576+0000fb64@6746
5577+00007b66@6747
5578+0000fbe6@6748
5579+0000f3a6@6749
5580+0000b3a6@6750
5581+00003326@6751
5582+0000a3a6@6752
5583+0000a182@6753
5584+0000a102@6755
5585+00002100@6756
5586+0000a180@6757
5587+0000e3a4@6758
5588+0000e384@6759
5589+0000e304@6760
5590+00006304@6761
5591+0000e3a4@6762
5592+0000f3a4@6763
5593+00007326@6765
5594+0000f3a6@6766
5595+0000f19a@6767
5596+0000b19a@6768
5597+0000b11a@6769
5598+0000311a@6770
5599+0000a19a@6771
5600+0000a182@6772
5601+0000a102@6774
5602+00002100@6775
5603+0000a3a4@6776
5604+0000e3a4@6777
5605+00006304@6779
5606+0000e1a4@6780
5607+0000e180@6781
5608+0000f3a4@6782
5609+0000f324@6783
5610+00007106@6784
5611+0000f3a6@6785
5612+0000f19a@6786
5613+0000b19a@6787
5614+0000b11a@6788
5615+0000211a@6789
5616+0000a19a@6790
5617+0000a182@6791
5618+0000a102@6792
5619+00002102@6793
5620+0000a180@6794
5621+0000e1a4@6795
5622+0000e304@6797
5623+00006184@6798
5624+0000e3a4@6799
5625+0000f3a4@6800
5626+0000f304@6801
5627+0000f3a4@6802
5628+000073a6@6803
5629+0000f3de@6804
5630+0000b1de@6805
5631+000031de@6807
5632+0000a15e@6808
5633+0000bf42@6809
5634+0000afc2@6810
5635+00002f40@6812
5636+0000afc0@6813
5637+0000efe4@6814
5638+0000efc4@6815
5639+0000ef44@6816
5640+0000efe4@6817
5641+0000ff64@6819
5642+0000ffe4@6820
5643+00007fe6@6821
5644+0000ffe6@6822
5645+0000f356@6823
5646+0000b3d6@6824
5647+000033d6@6826
5648+0000a356@6827
5649+0000a7f2@6828
5650+0000a7f0@6831
5651+0000a7f4@6832
5652+0000e7f4@6833
5653+0000e774@6834
5654+000067f4@6835
5655+0000e7f4@6836
5656+0000f7f4@6837
5657+0000f774@6838
5658+0000f7f4@6839
5659+000077f6@6840
5660+0000f7f6@6841
5661+0000b53a@6842
5662+0000b5ba@6843
5663+0000a5ba@6845
5664+0000af82@6846
5665+0000ab82@6847
5666+00002b02@6849
5667+0000ab80@6850
5668+0000eba0@6851
5669+0000eba4@6852
5670+0000eb24@6853
5671+00006ba4@6854
5672+0000eba4@6855
5673+0000fba4@6856
5674+0000fb04@6857
5675+00007ba6@6858
5676+0000fba6@6859
5677+0000ff1a@6860
5678+0000b79a@6861
5679+0000379a@6863
5680+0000a71a@6864
5681+0000ab82@6865
5682+00002b00@6868
5683+0000ab80@6869
5684+0000eba4@6870
5685+00006ba4@6872
5686+0000eba4@6873
5687+0000eb80@6874
5688+0000fb24@6875
5689+0000fba4@6876
5690+00007ba6@6877
5691+0000fba6@6878
5692+0000f902@6879
5693+0000b982@6880
5694+00003982@6882
5695+0000a982@6883
5696+0000abc2@6884
5697+00002bc2@6886
5698+0000abc0@6887
5699+0000abe4@6888
5700+0000ebe4@6889
5701+0000eb64@6890
5702+00006be4@6891
5703+0000ebe4@6892
5704+0000fbe4@6893
5705+0000fb44@6894
5706+0000fbe4@6895
5707+00007be6@6896
5708+0000fbe6@6897
5709+0000f902@6898
5710+0000f982@6899
5711+00007982@6900
5712+0000e902@6901
5713+0000ebc2@6902
5714+00006b40@6905
5715+0000ebc0@6906
5716+0000ebe0@6907
5717+0000e180@6908
5718+0000a100@6909
5719+00002180@6910
5720+0000a180@6911
5721+0000b180@6912
5722+00003182@6914
5723+0000f182@6915
5724+0000f11a@6916
5725+0000b19a@6917
5726+0000319a@6919
5727+0000a11a@6920
5728+0000a182@6921
5729+00002100@6924
5730+0000a3a4@6925
5731+0000e3a4@6926
5732+0000e324@6927
5733+000063a4@6928
5734+0000e3a4@6929
5735+0000f180@6930
5736+0000f304@6931
5737+0000f3a4@6932
5738+000073a6@6933
5739+0000f3a6@6934
5740+0000f11a@6935
5741+0000b19a@6936
5742+0000219a@6938
5743+0000a19a@6939
5744+0000a182@6940
5745+00002102@6942
5746+0000a180@6943
5747+0000e1a4@6944
5748+0000e184@6945
5749+0000e304@6946
5750+00006180@6947
5751+0000e3a4@6948
5752+0000f3a4@6949
5753+0000f304@6950
5754+0000f3a4@6951
5755+000073a6@6952
5756+0000f3e2@6953
5757+0000b1e2@6954
5758+000031e2@6956
5759+0000a162@6957
5760+0000bfc2@6958
5761+0000afc2@6959
5762+00002f40@6961
5763+0000afc0@6962
5764+0000efe4@6963
5765+0000ef64@6965
5766+0000efe4@6966
5767+0000ff64@6968
5768+0000ffe4@6969
5769+00007fe6@6970
5770+0000ffe6@6971
5771+0000f346@6972
5772+0000b3c6@6973
5773+000033c6@6975
5774+0000a346@6976
5775+0000abe2@6977
5776+0000abe0@6980
5777+0000abe4@6981
5778+0000ebe4@6982
5779+0000eb64@6983
5780+00006be4@6984
5781+0000ebe4@6985
5782+0000fbe4@6986
5783+0000fb64@6987
5784+0000fbe4@6988
5785+00007be6@6989
5786+0000fbe6@6990
5787+0000b73a@6991
5788+0000b7ba@6992
5789+0000a7ba@6994
5790+0000af82@6995
5791+0000ab82@6996
5792+00002b02@6998
5793+0000ab80@6999
5794+0000eba0@7000
5795+0000eba4@7001
5796+0000eb24@7002
5797+00006ba4@7003
5798+0000eba4@7004
5799+0000fba4@7005
5800+00007ba6@7007
5801+0000fba6@7008
5802+0000fb1e@7009
5803+0000b99a@7010
5804+0000399a@7012
5805+0000a91a@7013
5806+0000ab82@7014
5807+00002b00@7017
5808+0000ab80@7018
5809+0000eba4@7019
5810+00006ba4@7021
5811+0000eba4@7022
5812+0000fb24@7024
5813+0000fba4@7025
5814+00007ba6@7026
5815+0000fba6@7027
5816+0000f906@7028
5817+0000b986@7029
5818+00003986@7031
5819+0000a986@7032
5820+0000abc2@7033
5821+00002bc2@7035
5822+0000abc0@7036
5823+0000abe4@7037
5824+0000ebe4@7038
5825+0000eb64@7039
5826+00006be4@7040
5827+0000ebe4@7041
5828+0000fbe4@7042
5829+0000fb44@7043
5830+0000fbe4@7044
5831+00007be6@7045
5832+0000fbe6@7046
5833+0000f906@7047
5834+0000f986@7048
5835+00007986@7049
5836+0000e906@7050
5837+0000ebc2@7051
5838+00006b40@7054
5839+0000ebc0@7055
5840+0000ebe4@7056
5841+0000e180@7057
5842+0000a100@7058
5843+00002180@7059
5844+0000a180@7060
5845+0000b180@7061
5846+00003182@7063
5847+0000f182@7064
5848+0000f11a@7065
5849+0000b19a@7066
5850+0000319a@7068
5851+0000a11a@7069
5852+0000a182@7070
5853+00002100@7073
5854+0000a3a4@7074
5855+0000e3a4@7075
5856+0000e324@7076
5857+000063a4@7077
5858+0000e3a4@7078
5859+0000f180@7079
5860+0000f304@7080
5861+0000f3a4@7081
5862+000073a6@7082
5863+0000f3a6@7083
5864+0000f9fa@7084
5865+0000b9fa@7085
5866+0000397a@7087
5867+0000a9fa@7088
5868+0000a182@7089
5869+00002182@7091
5870+0000a180@7092
5871+0000e1a4@7093
5872+0000e304@7095
5873+00006184@7096
5874+0000e3a4@7097
5875+0000f3a4@7098
5876+0000f300@7099
5877+0000f3a4@7100
5878+0000f3a6@7101
5879+0000f3e6@7102
5880+0000b1e6@7103
5881+000031e6@7105
5882+0000a166@7106
5883+0000bf42@7107
5884+0000afc2@7108
5885+00002f40@7110
5886+0000afc0@7111
5887+0000efe4@7112
5888+0000ef64@7114
5889+0000efe4@7115
5890+0000ff64@7117
5891+0000ffe4@7118
5892+00007fe6@7119
5893+0000ffe6@7120
5894+0000f346@7121
5895+0000b3c6@7122
5896+000033c6@7124
5897+0000a346@7125
5898+0000abe2@7126
5899+0000abe0@7129
5900+0000abe4@7130
5901+0000ebe4@7131
5902+0000eb64@7132
5903+00006be4@7133
5904+0000ebe4@7134
5905+0000fbe4@7135
5906+0000fb64@7136
5907+0000fbe4@7137
5908+00007be6@7138
5909+0000fbe6@7139
5910+0000b93a@7140
5911+0000b9ba@7141
5912+0000a9ba@7143
5913+0000ab82@7144
5914+00002b02@7147
5915+0000ab80@7148
5916+0000eba0@7149
5917+0000eba4@7150
5918+0000eb24@7151
5919+00006ba4@7152
5920+0000eba4@7153
5921+0000fba4@7154
5922+0000fb24@7155
5923+00007ba6@7156
5924+0000fba6@7157
5925+0000fb1a@7158
5926+0000b39a@7159
5927+0000339a@7161
5928+0000a31a@7162
5929+0000ada2@7163
5930+00002d20@7166
5931+0000ada0@7167
5932+0000efa4@7168
5933+00006fa4@7170
5934+0000efa4@7171
5935+0000efa0@7172
5936+0000ff24@7173
5937+0000ffa4@7174
5938+00007fa6@7175
5939+0000ffa6@7176
5940+0000b90a@7177
5941+0000b98a@7178
5942+0000390a@7180
5943+0000a98a@7181
5944+0000abc2@7182
5945+00002bc2@7184
5946+0000abc0@7185
5947+0000abe4@7186
5948+0000ebe4@7187
5949+0000eb64@7188
5950+00006bc4@7189
5951+0000ebe4@7190
5952+0000fbe4@7191
5953+0000fb44@7192
5954+0000fbe4@7193
5955+00007be6@7194
5956+0000fbe6@7195
5957+0000f90a@7196
5958+0000f98a@7197
5959+0000798a@7198
5960+0000e90a@7199
5961+0000ebc2@7200
5962+00006b40@7203
5963+0000ebc0@7204
5964+0000ebe4@7205
5965+0000a5e0@7206
5966+000025e0@7208
5967+0000a5e0@7209
5968+0000b5e0@7210
5969+0000b560@7211
5970+000035e2@7212
5971+0000f5e2@7213
5972+0000f91a@7214
5973+0000b99a@7215
5974+0000399a@7217
5975+0000a91a@7218
5976+0000abd2@7219
5977+00002b50@7222
5978+0000abf4@7223
5979+0000ebf4@7224
5980+0000eb74@7225
5981+00006bf4@7226
5982+0000ebf4@7227
5983+0000ebd0@7228
5984+0000fb74@7229
5985+0000fbf4@7230
5986+00007bf6@7231
5987+0000fbf6@7232
5988+0000b91a@7233
5989+0000b99a@7234
5990+0000299a@7236
5991+0000abda@7237
5992+0000abd2@7238
5993+00002b52@7240
5994+0000abd0@7241
5995+0000ebf4@7242
5996+0000ebd4@7243
5997+0000eb54@7244
5998+00006bd4@7245
5999+0000ebf4@7246
6000+0000fbf4@7247
6001+0000fb50@7248
6002+0000fbf4@7249
6003+0000fbf6@7250
6004+0000fbfe@7251
6005+0000b1ea@7252
6006+000031ea@7254
6007+0000a16a@7255
6008+0000bfc2@7256
6009+0000afc2@7257
6010+00002f40@7259
6011+0000afc0@7260
6012+0000efe4@7261
6013+0000efc4@7262
6014+0000ef64@7263
6015+0000efe4@7264
6016+0000ff64@7266
6017+0000ffe4@7267
6018+00007fe6@7268
6019+0000ffe6@7269
6020+0000f346@7270
6021+0000b3c6@7271
6022+000033c6@7273
6023+0000a346@7274
6024+0000abe2@7275
6025+0000abe0@7278
6026+0000abe4@7279
6027+0000ebe4@7280
6028+0000eb64@7281
6029+00006be4@7282
6030+0000ebe4@7283
6031+0000fbe4@7284
6032+0000fb64@7285
6033+0000fbe4@7286
6034+00007be6@7287
6035+0000fbe6@7288
6036+0000b33a@7289
6037+0000b3ba@7290
6038+0000a3ba@7292
6039+0000afa2@7293
6040+0000ada2@7294
6041+00002d22@7296
6042+0000ada0@7297
6043+0000efa4@7298
6044+0000ef20@7300
6045+00006fa0@7301
6046+0000efa4@7302
6047+0000ffa4@7303
6048+0000ff20@7304
6049+00007fa6@7305
6050+0000ffa6@7306
6051+0000fd3e@7307
6052+0000b59a@7308
6053+0000359a@7310
6054+0000a51a@7311
6055+0000ada2@7312
6056+00002d20@7315
6057+0000ada0@7316
6058+0000efa4@7317
6059+00006fa4@7319
6060+0000eda4@7320
6061+0000eda0@7321
6062+0000ff24@7322
6063+0000ffa4@7323
6064+00007da6@7324
6065+0000ffa6@7325
6066+0000f90e@7326
6067+0000b98e@7327
6068+0000390e@7329
6069+0000a98e@7330
6070+0000abc2@7331
6071+00002bc2@7333
6072+0000abc0@7334
6073+0000abe4@7335
6074+0000ebe4@7336
6075+0000eb64@7337
6076+00006be4@7338
6077+0000ebe4@7339
6078+0000fbe4@7340
6079+0000fb44@7341
6080+0000fbe4@7342
6081+00007be6@7343
6082+0000fbe6@7344
6083+0000f90e@7345
6084+0000f98e@7346
6085+0000798e@7347
6086+0000f90c@7348
6087+0000fbc0@7349
6088+0000ebc0@7350
6089+00006b40@7352
6090+0000ebc0@7353
6091+0000ebe4@7354
6092+0000ebc4@7355
6093+0000eb44@7356
6094+00006be4@7357
6095+0000ebe4@7358
6096+0000fbe4@7359
6097+00007be6@7361
6098+0000fbe6@7362
6099+0000f91a@7363
6100+0000b99a@7364
6101+0000399a@7366
6102+0000a91a@7367
6103+0000abd2@7368
6104+00002b50@7371
6105+0000abf4@7372
6106+0000ebf4@7373
6107+0000eb74@7374
6108+00006bf4@7375
6109+0000ebf4@7376
6110+0000ebd0@7377
6111+0000fb54@7378
6112+0000fbf4@7379
6113+00007bf6@7380
6114+0000fbf6@7381
6115+0000b91a@7382
6116+0000b99a@7383
6117+0000299a@7385
6118+0000abda@7386
6119+0000abd2@7387
6120+00002b52@7389
6121+0000abd0@7390
6122+0000ebf4@7391
6123+0000eb54@7393
6124+00006bd0@7394
6125+0000ebf4@7395
6126+0000fbf4@7396
6127+0000fb54@7397
6128+0000fbf4@7398
6129+0000fbf6@7399
6130+0000fbfe@7400
6131+0000b1ee@7401
6132+000031ee@7403
6133+0000a16e@7404
6134+0000bf42@7405
6135+0000afc2@7406
6136+00002f40@7408
6137+0000afc0@7409
6138+0000efe4@7410
6139+0000ef64@7412
6140+0000efe4@7413
6141+0000ff64@7415
6142+0000ffe4@7416
6143+00007fe6@7417
6144+0000ffe6@7418
6145+0000f346@7419
6146+0000b3c6@7420
6147+000033c6@7422
6148+0000a346@7423
6149+0000abe2@7424
6150+0000ab60@7427
6151+0000abe4@7428
6152+0000ebe4@7429
6153+0000eb64@7430
6154+00006be4@7431
6155+0000ebe4@7432
6156+0000fbe4@7433
6157+0000fb64@7434
6158+0000fbe4@7435
6159+00007be6@7436
6160+0000fbe6@7437
6161+0000b53a@7438
6162+0000b5ba@7439
6163+0000a5ba@7441
6164+0000ada2@7442
6165+00002d22@7445
6166+0000ada0@7446
6167+0000efa0@7447
6168+0000efa4@7448
6169+0000ef24@7449
6170+00006da0@7450
6171+0000efa4@7451
6172+0000ffa4@7452
6173+0000ff24@7453
6174+00007fa6@7454
6175+0000ffa6@7455
6176+0000ff3e@7456
6177+0000b79a@7457
6178+0000379a@7459
6179+0000a71a@7460
6180+0000ada2@7461
6181+00002d20@7464
6182+0000ada0@7465
6183+0000efa4@7466
6184+00006fa4@7468
6185+0000efa4@7469
6186+0000ff24@7471
6187+0000ffa4@7472
6188+00007fa6@7473
6189+0000ffa6@7474
6190+0000b912@7475
6191+0000b992@7476
6192+00003992@7478
6193+0000a992@7479
6194+0000abc2@7480
6195+00002bc2@7482
6196+0000abc0@7483
6197+0000abe4@7484
6198+0000ebe4@7485
6199+0000eb64@7486
6200+00006be4@7487
6201+0000ebe4@7488
6202+0000fbe4@7489
6203+0000fb44@7490
6204+0000fbe4@7491
6205+00007be6@7492
6206+0000fbe6@7493
6207+0000f912@7494
6208+0000f992@7495
6209+00007992@7496
6210+0000e912@7497
6211+0000ebc2@7498
6212+00006b40@7501
6213+0000ebc0@7502
6214+0000ebe4@7503
6215+0000a5e0@7504
6216+000025e0@7506
6217+0000a5e0@7507
6218+0000b5e0@7508
6219+000035e2@7510
6220+0000f5e2@7511
6221+0000f91a@7512
6222+0000b99a@7513
6223+0000399a@7515
6224+0000a91a@7516
6225+0000abd2@7517
6226+00002b50@7520
6227+0000abf4@7521
6228+0000ebf4@7522
6229+0000eb74@7523
6230+00006bf4@7524
6231+0000ebf4@7525
6232+0000fbd0@7526
6233+0000fb74@7527
6234+0000fbf4@7528
6235+00007bf6@7529
6236+0000fbf6@7530
6237+0000b91a@7531
6238+0000b99a@7532
6239+0000399a@7534
6240+0000abda@7535
6241+0000abd2@7536
6242+00002b52@7538
6243+0000abd0@7539
6244+0000ebf4@7540
6245+0000ebd4@7541
6246+0000eb54@7542
6247+00006bd4@7543
6248+0000ebf4@7544
6249+0000fbf4@7545
6250+0000fb54@7546
6251+0000fbf4@7547
6252+0000fbf6@7548
6253+0000b1f2@7550
6254+000031f2@7552
6255+0000a172@7553
6256+0000bf42@7554
6257+0000afc2@7555
6258+00002f40@7557
6259+0000afc0@7558
6260+0000efe4@7559
6261+0000ef64@7561
6262+0000efe4@7562
6263+0000ff64@7564
6264+0000ffe4@7565
6265+00007fe6@7566
6266+0000ffe6@7567
6267+0000f346@7568
6268+0000b3c6@7569
6269+000033c6@7571
6270+0000a346@7572
6271+0000abe2@7573
6272+0000abe0@7576
6273+0000abe4@7577
6274+0000ebe4@7578
6275+0000eb64@7579
6276+00006be4@7580
6277+0000ebe4@7581
6278+0000fbe4@7582
6279+0000fb64@7583
6280+0000fbe4@7584
6281+00007be6@7585
6282+0000fbe6@7586
6283+0000bb1a@7587
6284+0000bb9a@7588
6285+00003b9a@7589
6286+0000ab9a@7590
6287+0000ab82@7591
6288+00002b02@7594
6289+0000ab80@7595
6290+0000eba0@7596
6291+0000eba4@7597
6292+0000eb24@7598
6293+00006ba4@7599
6294+0000eba4@7600
6295+0000fba4@7601
6296+0000fb04@7602
6297+00007ba6@7603
6298+0000fba6@7604
6299+0000fb3a@7605
6300+0000bbba@7606
6301+00003bba@7608
6302+0000ab3a@7609
6303+0000ab82@7610
6304+00002b00@7613
6305+0000ab80@7614
6306+0000eba4@7615
6307+00006ba4@7617
6308+0000eba4@7618
6309+0000fb24@7620
6310+0000fba4@7621
6311+00007ba6@7622
6312+0000fba6@7623
6313+0000f916@7624
6314+0000b996@7625
6315+00003916@7627
6316+0000a996@7628
6317+0000abc2@7629
6318+00002bc2@7631
6319+0000abc0@7632
6320+0000abe4@7633
6321+0000ebe4@7634
6322+0000eb64@7635
6323+00006bc4@7636
6324+0000ebe4@7637
6325+0000fbe4@7638
6326+0000fb44@7639
6327+0000fbe4@7640
6328+00007be6@7641
6329+0000fbe6@7642
6330+0000f916@7643
6331+0000f996@7644
6332+00007996@7645
6333+0000e916@7646
6334+0000ebc2@7647
6335+00006b40@7650
6336+0000ebc0@7651
6337+0000ebe4@7652
6338+0000a5e0@7653
6339+000025e0@7655
6340+0000a5e0@7656
6341+0000b5e0@7657
6342+000035e2@7659
6343+0000f5e2@7660
6344+0000f91a@7661
6345+0000b99a@7662
6346+0000399a@7664
6347+0000a91a@7665
6348+0000abd2@7666
6349+00002b50@7669
6350+0000abf4@7670
6351+0000ebf4@7671
6352+0000eb74@7672
6353+00006bf4@7673
6354+0000ebf4@7674
6355+0000ebd0@7675
6356+0000fb74@7676
6357+0000fbf4@7677
6358+00007bf6@7678
6359+0000fbf6@7679
6360+0000b91a@7680
6361+0000b99a@7681
6362+0000a99a@7683
6363+0000abda@7684
6364+0000abd2@7685
6365+00002b52@7687
6366+0000abd0@7688
6367+0000ebf4@7689
6368+0000eb54@7691
6369+00006bd4@7692
6370+0000ebf4@7693
6371+0000fbf4@7694
6372+0000fb54@7695
6373+0000fbf4@7696
6374+0000fbf6@7697
6375+0000b1f6@7699
6376+000031f6@7701
6377+0000a176@7702
6378+0000bf42@7703
6379+0000afc2@7704
6380+00002f40@7706
6381+0000afc0@7707
6382+0000efe4@7708
6383+0000ef64@7710
6384+0000efe4@7711
6385+0000ff64@7713
6386+0000ffe4@7714
6387+00007fe6@7715
6388+0000ffe6@7716
6389+0000f346@7717
6390+0000b3c6@7718
6391+000033c6@7720
6392+0000a346@7721
6393+0000abe2@7722
6394+0000abe0@7725
6395+0000abe4@7726
6396+0000ebe4@7727
6397+0000eb64@7728
6398+00006be4@7729
6399+0000ebe4@7730
6400+0000fbe4@7731
6401+0000fb64@7732
6402+0000fbe4@7733
6403+00007be6@7734
6404+0000fbe6@7735
6405+0000bd1a@7736
6406+0000bd9a@7737
6407+00003d9a@7738
6408+0000ad9a@7739
6409+0000af82@7740
6410+0000ab82@7741
6411+00002b02@7743
6412+0000ab80@7744
6413+0000eba0@7745
6414+0000eb84@7746
6415+0000eb04@7747
6416+00006ba4@7748
6417+0000eba4@7749
6418+0000fba4@7750
6419+0000fb04@7751
6420+00007ba6@7752
6421+0000fba6@7753
6422+0000ff3a@7754
6423+0000bdba@7755
6424+00003dba@7757
6425+0000ad3a@7758
6426+0000ab82@7759
6427+00002b00@7762
6428+0000ab80@7763
6429+0000eba4@7764
6430+00006ba4@7766
6431+0000eba4@7767
6432+0000eba0@7768
6433+0000fb24@7769
6434+0000fba4@7770
6435+00007ba6@7771
6436+0000fba6@7772
6437+0000f91a@7773
6438+0000b99a@7774
6439+0000399a@7776
6440+0000a99a@7777
6441+0000abc2@7778
6442+00002bc2@7780
6443+0000abc0@7781
6444+0000abe4@7782
6445+0000ebe4@7783
6446+0000eb64@7784
6447+00006be4@7785
6448+0000ebe4@7786
6449+0000fbe4@7787
6450+0000fb44@7788
6451+0000fbe4@7789
6452+00007be6@7790
6453+0000fbe6@7791
6454+0000f91a@7792
6455+0000f99a@7793
6456+0000799a@7794
6457+0000e91a@7795
6458+0000ebc2@7796
6459+00006b40@7799
6460+0000ebc0@7800
6461+0000ebe4@7801
6462+0000a5e0@7802
6463+000025e0@7804
6464+0000a5e0@7805
6465+0000b5e0@7806
6466+000035e2@7808
6467+0000f5e2@7809
6468+0000f91a@7810
6469+0000b99a@7811
6470+0000399a@7813
6471+0000a91a@7814
6472+0000abd2@7815
6473+00002b50@7818
6474+0000abf4@7819
6475+0000ebf4@7820
6476+0000eb74@7821
6477+00006bf4@7822
6478+0000ebf4@7823
6479+0000ebd0@7824
6480+0000fb74@7825
6481+0000fbf4@7826
6482+00007bf6@7827
6483+0000fbf6@7828
6484+0000b91a@7829
6485+0000b99a@7830
6486+0000a99a@7832
6487+0000abda@7833
6488+0000abd2@7834
6489+00002b52@7836
6490+0000abd0@7837
6491+0000ebf4@7838
6492+0000eb54@7840
6493+00006bd4@7841
6494+0000ebf4@7842
6495+0000fbf4@7843
6496+0000fb54@7844
6497+0000fbf4@7845
6498+0000fbf6@7846
6499+0000fbfe@7847
6500+0000b1fa@7848
6501+000031fa@7850
6502+0000a17a@7851
6503+0000bf42@7852
6504+0000afc2@7853
6505+00002f40@7855
6506+0000afc0@7856
6507+0000efe4@7857
6508+0000ef44@7859
6509+0000efe4@7860
6510+0000ff64@7862
6511+0000ffe4@7863
6512+00007fe6@7864
6513+0000ffe6@7865
6514+0000f346@7866
6515+0000b3c6@7867
6516+000033c6@7869
6517+0000a346@7870
6518+0000abe2@7871
6519+0000abe0@7874
6520+0000abe4@7875
6521+0000ebe4@7876
6522+0000eb64@7877
6523+00006be4@7878
6524+0000ebe4@7879
6525+0000fbe4@7880
6526+0000fb64@7881
6527+0000fbe4@7882
6528+00007be6@7883
6529+0000fbe6@7884
6530+0000bf1a@7885
6531+0000bf9a@7886
6532+00003f9a@7887
6533+0000af9a@7888
6534+0000ab82@7889
6535+00002b02@7892
6536+0000ab80@7893
6537+0000eba0@7894
6538+0000eb84@7895
6539+0000eb04@7896
6540+00006b84@7897
6541+0000eba4@7898
6542+0000fba4@7899
6543+0000fb04@7900
6544+00007ba6@7901
6545+0000fba6@7902
6546+0000ff3a@7903
6547+0000bfba@7904
6548+00003fba@7906
6549+0000af3a@7907
6550+0000ab82@7908
6551+00002b00@7911
6552+0000ab80@7912
6553+0000eba4@7913
6554+00006ba4@7915
6555+0000eba4@7916
6556+0000fb24@7918
6557+0000fba4@7919
6558+00007ba6@7920
6559+0000fba6@7921
6560+0000f91e@7922
6561+0000b99e@7923
6562+0000391e@7925
6563+0000a99e@7926
6564+0000abc2@7927
6565+00002bc2@7929
6566+0000abc0@7930
6567+0000abe4@7931
6568+0000ebe4@7932
6569+0000eb64@7933
6570+00006be4@7934
6571+0000ebe4@7935
6572+0000fbe4@7936
6573+0000fb44@7937
6574+0000fbe4@7938
6575+00007be6@7939
6576+0000fbe6@7940
6577+0000f91e@7941
6578+0000f99e@7942
6579+0000799e@7943
6580+0000f91c@7944
6581+0000fbc0@7945
6582+0000ebc0@7947
6583+00006b40@7948
6584+0000ebc0@7949
6585+0000ebe4@7950
6586+0000eb44@7952
6587+00006be4@7953
6588+0000ebe4@7954
6589+0000fbe4@7955
6590+00007be6@7957
6591+0000fbe6@7958
6592+0000f91a@7959
6593+0000b99a@7960
6594+0000399a@7962
6595+0000a91a@7963
6596+0000abd2@7964
6597+00002b50@7967
6598+0000abf4@7968
6599+0000ebf4@7969
6600+0000eb74@7970
6601+00006bf4@7971
6602+0000ebf4@7972
6603+0000fbd0@7973
6604+0000fb74@7974
6605+0000fbf4@7975
6606+00007bf6@7976
6607+0000fbf6@7977
6608+0000bb1a@7978
6609+0000bb9a@7979
6610+0000ab9a@7981
6611+0000abfa@7982
6612+0000abe2@7983
6613+00002b62@7985
6614+0000abe0@7986
6615+0000ebe4@7987
6616+0000eb64@7989
6617+00006be4@7990
6618+0000ebe4@7991
6619+0000fbe4@7992
6620+0000fb64@7993
6621+0000fbe4@7994
6622+0000fbe6@7995
6623+0000fb7e@7996
6624+0000b1fe@7997
6625+000031fe@7999
6626+0000a17e@8000
6627+0000bf42@8001
6628+0000afc2@8002
6629+00002f40@8004
6630+0000afc0@8005
6631+0000efe4@8006
6632+0000ef64@8008
6633+0000efe4@8009
6634+0000ff64@8011
6635+0000ffe4@8012
6636+00007fe6@8013
6637+0000ffe6@8014
6638+0000f346@8015
6639+0000b3c6@8016
6640+000033c6@8018
6641+0000a346@8019
6642+0000abe2@8020
6643+0000abe0@8023
6644+0000abe4@8024
6645+0000ebe4@8025
6646+0000eb64@8026
6647+00006be4@8027
6648+0000ebe4@8028
6649+0000fbe4@8029
6650+0000fb64@8030
6651+0000fbe4@8031
6652+00007be6@8032
6653+0000fbe6@8033
6654+0000b71a@8034
6655+0000b79a@8035
6656+0000379a@8036
6657+0000a79a@8037
6658+0000a992@8038
6659+00002912@8041
6660+0000a990@8042
6661+0000eb90@8043
6662+0000eb94@8044
6663+0000eb14@8045
6664+00006b94@8046
6665+0000ebb4@8047
6666+0000fbb4@8048
6667+0000fb14@8049
6668+00007bb6@8050
6669+0000fbb6@8051
6670+0000ff3a@8052
6671+0000b7ba@8053
6672+000037ba@8055
6673+0000a73a@8056
6674+0000a992@8057
6675+00002910@8060
6676+0000a990@8061
6677+0000ebb4@8062
6678+00006bb4@8064
6679+0000e9b4@8065
6680+0000eb90@8066
6681+0000fb34@8067
6682+0000fbb4@8068
6683+000079b6@8069
6684+0000fbb6@8070
6685+0000f922@8071
6686+0000b9a2@8072
6687+000039a2@8074
6688+0000a9a2@8075
6689+0000abc2@8076
6690+00002bc2@8078
6691+0000abc0@8079
6692+0000abe4@8080
6693+0000ebe4@8081
6694+0000eb64@8082
6695+00006be4@8083
6696+0000ebe4@8084
6697+0000fbe4@8085
6698+0000fb44@8086
6699+0000fbe4@8087
6700+00007be6@8088
6701+0000fbe6@8089
6702+0000f922@8090
6703+0000f9a2@8091
6704+000079a2@8092
6705+0000e922@8093
6706+0000ebc2@8094
6707+00006b40@8097
6708+0000ebc0@8098
6709+0000ebe4@8099
6710+0000a9ec@8100
6711+000029ec@8102
6712+0000a9ec@8103
6713+0000b9ec@8104
6714+000039ee@8106
6715+0000f9ee@8107
6716+0000fb3a@8108
6717+0000bbba@8109
6718+00003bba@8111
6719+0000ab3a@8112
6720+0000abe2@8113
6721+00002b60@8116
6722+0000abe4@8117
6723+0000ebe4@8118
6724+0000eb64@8119
6725+00006be4@8120
6726+0000ebe4@8121
6727+0000fbe4@8122
6728+0000fb64@8123
6729+0000fbe4@8124
6730+00007be6@8125
6731+0000fbe6@8126
6732+0000b91a@8127
6733+0000b99a@8128
6734+0000a99a@8130
6735+0000abda@8131
6736+0000abd2@8132
6737+00002b52@8134
6738+0000abd0@8135
6739+0000ebf4@8136
6740+0000ebd4@8137
6741+0000eb54@8138
6742+00006bd4@8139
6743+0000ebf4@8140
6744+0000fbf4@8141
6745+0000fb50@8142
6746+0000fbf4@8143
6747+0000fbf6@8144
6748+0000fbd6@8145
6749+0000b3c2@8146
6750+000033c2@8148
6751+0000a342@8149
6752+0000afc2@8150
6753+00002f40@8153
6754+0000afc0@8154
6755+0000efe4@8155
6756+0000efc4@8156
6757+0000ef44@8157
6758+0000efe4@8158
6759+0000ff64@8160
6760+0000ffe4@8161
6761+00007fe6@8162
6762+0000ffe6@8163
6763+0000f346@8164
6764+0000b3c6@8165
6765+000033c6@8167
6766+0000a346@8168
6767+0000abe2@8169
6768+00002be2@8171
6769+0000abe0@8172
6770+0000abe4@8173
6771+0000ebe4@8174
6772+0000eb64@8175
6773+00006be4@8176
6774+0000ebe4@8177
6775+0000fbe4@8178
6776+0000fb64@8179
6777+0000fbe4@8180
6778+00007be6@8181
6779+0000fbe6@8182
6780+0000bf1a@8183
6781+0000bf9a@8184
6782+00003f9a@8185
6783+0000af9a@8186
6784+0000aba2@8187
6785+00002b22@8190
6786+0000aba0@8191
6787+0000eba0@8192
6788+0000eba4@8193
6789+0000eb24@8194
6790+00006ba4@8195
6791+0000eba4@8196
6792+0000fba4@8197
6793+0000fb24@8198
6794+00007ba6@8199
6795+0000fba6@8200
6796+0000ff3a@8201
6797+0000b5ba@8202
6798+000035ba@8204
6799+0000a53a@8205
6800+0000a182@8206
6801+00002100@8209
6802+0000a180@8210
6803+0000e3a4@8211
6804+000063a4@8213
6805+0000e1a4@8214
6806+0000e180@8215
6807+0000f324@8216
6808+0000f3a4@8217
6809+000071a6@8218
6810+0000f3a6@8219
6811+0000f926@8220
6812+0000b9a6@8221
6813+000039a6@8223
6814+0000a9a6@8224
6815+0000abc2@8225
6816+00002bc2@8227
6817+0000abc0@8228
6818+0000abe4@8229
6819+0000ebe4@8230
6820+0000eb64@8231
6821+00006be4@8232
6822+0000ebe4@8233
6823+0000fbe4@8234
6824+0000fb44@8235
6825+0000fbe4@8236
6826+00007be6@8237
6827+0000fbe6@8238
6828+0000f926@8239
6829+0000f9a6@8240
6830+000079a6@8241
6831+0000e926@8242
6832+0000ebc2@8243
6833+00006b40@8246
6834+0000ebc0@8247
6835+0000ebe4@8248
6836+0000a5e0@8249
6837+000025e0@8251
6838+0000a5e0@8252
6839+0000b5e0@8253
6840+000035e2@8255
6841+0000f5e2@8256
6842+0000f91a@8257
6843+0000b99a@8258
6844+0000399a@8260
6845+0000a91a@8261
6846+0000abd2@8262
6847+00002b50@8265
6848+0000abf4@8266
6849+0000ebf4@8267
6850+0000eb74@8268
6851+00006bf4@8269
6852+0000ebf4@8270
6853+0000fbd0@8271
6854+0000fb74@8272
6855+0000fbf4@8273
6856+00007bf6@8274
6857+0000fbf6@8275
6858+0000b91a@8276
6859+0000b99a@8277
6860+0000a99a@8279
6861+0000abda@8280
6862+0000abd2@8281
6863+00002b52@8283
6864+0000abd0@8284
6865+0000ebf4@8285
6866+0000ebd4@8286
6867+0000eb54@8287
6868+00006bd4@8288
6869+0000ebf4@8289
6870+0000fbf4@8290
6871+0000fb50@8291
6872+0000fbf4@8292
6873+0000fbf6@8293
6874+0000fbd6@8294
6875+0000b3c6@8295
6876+000033c6@8297
6877+0000a346@8298
6878+0000afc2@8299
6879+00002f40@8302
6880+0000afc0@8303
6881+0000efe4@8304
6882+00006f64@8306
6883+0000efe4@8307
6884+0000ff64@8309
6885+0000ffe4@8310
6886+00007fe6@8311
6887+0000ffe6@8312
6888+0000f346@8313
6889+0000b3c6@8314
6890+000033c6@8316
6891+0000a346@8317
6892+0000abe2@8318
6893+00002be2@8320
6894+0000abe0@8321
6895+0000abe4@8322
6896+0000ebe4@8323
6897+0000eb64@8324
6898+00006be4@8325
6899+0000ebe4@8326
6900+0000fbe4@8327
6901+0000fb64@8328
6902+0000fbe4@8329
6903+00007be6@8330
6904+0000fbe6@8331
6905+0000b53a@8332
6906+0000b5ba@8333
6907+000035ba@8334
6908+0000a5ba@8335
6909+0000a182@8336
6910+00002102@8339
6911+0000a180@8340
6912+0000e3a0@8341
6913+0000e384@8342
6914+0000e304@8343
6915+00006184@8344
6916+0000e3a4@8345
6917+0000f3a4@8346
6918+0000f304@8347
6919+000073a6@8348
6920+0000f3a6@8349
6921+0000f53a@8350
6922+0000b5ba@8351
6923+000035ba@8353
6924+0000b53a@8354
6925+0000a182@8355
6926+00002100@8358
6927+0000a180@8359
6928+0000e3a4@8360
6929+000063a4@8362
6930+0000e1a4@8363
6931+0000e180@8364
6932+0000f324@8365
6933+0000f3a4@8366
6934+000071a6@8367
6935+0000f3a6@8368
6936+0000f92a@8369
6937+0000b9aa@8370
6938+000039aa@8372
6939+0000a9aa@8373
6940+0000abc2@8374
6941+00002bc2@8376
6942+0000abc0@8377
6943+0000abe4@8378
6944+0000ebe4@8379
6945+0000eb64@8380
6946+00006be4@8381
6947+0000ebe4@8382
6948+0000fbe4@8383
6949+0000fb44@8384
6950+0000fbe4@8385
6951+00007be6@8386
6952+0000fbe6@8387
6953+0000f92a@8388
6954+0000f9aa@8389
6955+000079aa@8390
6956+0000e92a@8391
6957+0000ebc2@8392
6958+00006b40@8395
6959+0000ebc0@8396
6960+0000ebe4@8397
6961+0000a5e0@8398
6962+000025e0@8400
6963+0000a5e0@8401
6964+0000b5e0@8402
6965+000035e2@8404
6966+0000f5e2@8405
6967+0000f91a@8406
6968+0000b99a@8407
6969+0000399a@8409
6970+0000a91a@8410
6971+0000abd2@8411
6972+00002b50@8414
6973+0000abf4@8415
6974+0000ebf4@8416
6975+0000eb74@8417
6976+00006bf4@8418
6977+0000ebf4@8419
6978+0000fbd0@8420
6979+0000fb54@8421
6980+0000fbf4@8422
6981+00007bf6@8423
6982+0000fbf6@8424
6983+0000b91a@8425
6984+0000b99a@8426
6985+0000a99a@8428
6986+0000abda@8429
6987+0000abd2@8430
6988+00002b52@8432
6989+0000abd0@8433
6990+0000ebf4@8434
6991+0000ebd4@8435
6992+0000eb54@8436
6993+00006bd4@8437
6994+0000ebf4@8438
6995+0000fbf4@8439
6996+0000fb50@8440
6997+0000fbf4@8441
6998+0000fbf6@8442
6999+0000fbde@8443
7000+0000b3ca@8444
7001+000033ca@8446
7002+0000a34a@8447
7003+0000afc2@8448
7004+00002f40@8451
7005+0000afc0@8452
7006+0000efe4@8453
7007+00006f64@8455
7008+0000efe4@8456
7009+0000ff64@8458
7010+0000ffe4@8459
7011+00007fe6@8460
7012+0000ffe6@8461
7013+0000f346@8462
7014+0000b3c6@8463
7015+000033c6@8465
7016+0000a346@8466
7017+0000abe2@8467
7018+00002be2@8469
7019+0000abe0@8470
7020+0000abe4@8471
7021+0000ebe4@8472
7022+0000eb64@8473
7023+00006be4@8474
7024+0000ebe4@8475
7025+0000fbe4@8476
7026+0000fb64@8477
7027+0000fbe4@8478
7028+00007be6@8479
7029+0000fbe6@8480
7030+0000b53a@8481
7031+0000b5ba@8482
7032+000035ba@8483
7033+0000a5ba@8484
7034+0000a182@8485
7035+00002102@8488
7036+0000a180@8489
7037+0000e3a0@8490
7038+0000e3a4@8491
7039+0000e304@8492
7040+000061a4@8493
7041+0000e3a4@8494
7042+0000f3a4@8495
7043+0000f324@8496
7044+000073a6@8497
7045+0000f3a6@8498
7046+0000f53a@8499
7047+0000b5ba@8500
7048+000035ba@8502
7049+0000a53a@8503
7050+0000a182@8504
7051+00002100@8507
7052+0000a180@8508
7053+0000e3a4@8509
7054+000063a4@8511
7055+0000e1a4@8512
7056+0000e184@8513
7057+0000f324@8514
7058+0000f3a4@8515
7059+000071a6@8516
7060+0000f3a6@8517
7061+0000f92e@8518
7062+0000b9ae@8519
7063+000039ae@8521
7064+0000a9ae@8522
7065+0000abc2@8523
7066+00002bc2@8525
7067+0000abc0@8526
7068+0000abe4@8527
7069+0000ebe4@8528
7070+0000eb64@8529
7071+00006be4@8530
7072+0000ebe4@8531
7073+0000fbe4@8532
7074+0000fb44@8533
7075+0000fbe4@8534
7076+00007be6@8535
7077+0000fbee@8536
7078+0000f92e@8537
7079+0000f9ae@8538
7080+000079ae@8539
7081+0000f92c@8540
7082+0000fbc0@8541
7083+0000ebc0@8542
7084+00006b40@8544
7085+0000ebc0@8545
7086+0000ebe4@8546
7087+0000eb64@8548
7088+00006be4@8549
7089+0000ebe4@8550
7090+0000fbe4@8551
7091+00007be6@8553
7092+0000fbe6@8554
7093+0000f91a@8555
7094+0000b99a@8556
7095+0000399a@8558
7096+0000a91a@8559
7097+0000abd2@8560
7098+00002b50@8563
7099+0000abf4@8564
7100+0000ebf4@8565
7101+0000eb74@8566
7102+00006bf4@8567
7103+0000ebf4@8568
7104+0000fbd0@8569
7105+0000fb74@8570
7106+0000fbf4@8571
7107+00007bf6@8572
7108+0000fbf6@8573
7109+0000b91a@8574
7110+0000b99a@8575
7111+0000a99a@8577
7112+0000abda@8578
7113+0000abd2@8579
7114+00002b52@8581
7115+0000abd0@8582
7116+0000ebf4@8583
7117+0000ebd4@8584
7118+0000eb54@8585
7119+00006bd4@8586
7120+0000ebf4@8587
7121+0000fbf4@8588
7122+0000fb50@8589
7123+0000fbf4@8590
7124+0000fbf6@8591
7125+0000fbde@8592
7126+0000b3ce@8593
7127+000033ce@8595
7128+0000a34e@8596
7129+0000afc2@8597
7130+00002f40@8600
7131+0000afc0@8601
7132+0000efe4@8602
7133+00006fc4@8604
7134+0000efe4@8605
7135+0000ff64@8607
7136+0000ffe4@8608
7137+00007fe6@8609
7138+0000ffe6@8610
7139+0000f346@8611
7140+0000b3c6@8612
7141+000033c6@8614
7142+0000a346@8615
7143+0000abe2@8616
7144+00002be2@8618
7145+0000abe0@8619
7146+0000abe4@8620
7147+0000ebe4@8621
7148+0000eb64@8622
7149+00006be4@8623
7150+0000ebe4@8624
7151+0000fbe4@8625
7152+0000fb64@8626
7153+0000fbe4@8627
7154+00007be6@8628
7155+0000fbe6@8629
7156+0000b53a@8630
7157+0000b5ba@8631
7158+000035ba@8632
7159+0000a5ba@8633
7160+0000a182@8634
7161+00002102@8637
7162+0000a180@8638
7163+0000e3a0@8639
7164+0000e384@8640
7165+0000e304@8641
7166+000063a4@8642
7167+0000e3a4@8643
7168+0000f3a4@8644
7169+000073a6@8646
7170+0000f3a6@8647
7171+0000f53a@8648
7172+0000b5ba@8649
7173+000035ba@8651
7174+0000a53a@8652
7175+0000a182@8653
7176+00002100@8656
7177+0000a180@8657
7178+0000e3a4@8658
7179+000063a4@8660
7180+0000e1a4@8661
7181+0000e180@8662
7182+0000f324@8663
7183+0000f3a4@8664
7184+000071a6@8665
7185+0000f3a6@8666
7186+0000f932@8667
7187+0000b9b2@8668
7188+000039b2@8670
7189+0000a9f2@8671
7190+0000abc2@8672
7191+00002bc2@8674
7192+0000abc0@8675
7193+0000abe4@8676
7194+0000ebe4@8677
7195+0000eb64@8678
7196+00006bc4@8679
7197+0000ebe4@8680
7198+0000fbe4@8681
7199+0000fb40@8682
7200+0000fbe4@8683
7201+00007be6@8684
7202+0000fbf6@8685
7203+0000f932@8686
7204+0000f9b2@8687
7205+000079b2@8688
7206+0000e932@8689
7207+0000ebc2@8690
7208+00006b40@8693
7209+0000ebc0@8694
7210+0000ebe4@8695
7211+0000a5e0@8696
7212+000025e0@8698
7213+0000a5e0@8699
7214+0000b5e0@8700
7215+000035e2@8702
7216+0000f5e2@8703
7217+0000f91a@8704
7218+0000b99a@8705
7219+0000399a@8707
7220+0000a91a@8708
7221+0000abd2@8709
7222+00002b50@8712
7223+0000abf4@8713
7224+0000ebf4@8714
7225+0000eb74@8715
7226+00006bf4@8716
7227+0000ebf4@8717
7228+0000fbd0@8718
7229+0000fb54@8719
7230+0000fbf4@8720
7231+00007bf6@8721
7232+0000fbf6@8722
7233+0000b91a@8723
7234+0000b99a@8724
7235+0000a99a@8726
7236+0000abda@8727
7237+0000abd2@8728
7238+00002b52@8730
7239+0000abd0@8731
7240+0000ebf4@8732
7241+0000eb74@8734
7242+00006bd4@8735
7243+0000ebf4@8736
7244+0000fbf4@8737
7245+0000fb54@8738
7246+0000fbf4@8739
7247+0000fbf6@8740
7248+0000fbd2@8741
7249+0000b3d2@8742
7250+000033d2@8744
7251+0000a352@8745
7252+0000afc2@8746
7253+00002f40@8749
7254+0000afc0@8750
7255+0000efe4@8751
7256+00006f64@8753
7257+0000efe4@8754
7258+0000efc4@8755
7259+0000ff64@8756
7260+0000ffe4@8757
7261+00007fe6@8758
7262+0000ffe6@8759
7263+0000f346@8760
7264+0000b3c6@8761
7265+000033c6@8763
7266+0000a346@8764
7267+0000abe2@8765
7268+00002be2@8767
7269+0000abe0@8768
7270+0000abe4@8769
7271+0000ebe4@8770
7272+0000eb64@8771
7273+00006be4@8772
7274+0000ebe4@8773
7275+0000fbe4@8774
7276+0000fb64@8775
7277+0000fbe4@8776
7278+00007be6@8777
7279+0000fbe6@8778
7280+0000b53a@8779
7281+0000b5ba@8780
7282+000035ba@8781
7283+0000a5ba@8782
7284+0000a182@8783
7285+00002102@8786
7286+0000a180@8787
7287+0000e3a0@8788
7288+0000e3a4@8789
7289+0000e104@8790
7290+000061a4@8791
7291+0000e3a4@8792
7292+0000f3a4@8793
7293+0000f304@8794
7294+000073a6@8795
7295+0000f3a6@8796
7296+0000f53a@8797
7297+0000b5ba@8798
7298+000035ba@8800
7299+0000a53a@8801
7300+0000a182@8802
7301+00002100@8805
7302+0000a180@8806
7303+0000e3a4@8807
7304+000063a4@8809
7305+0000e1a4@8810
7306+0000e180@8811
7307+0000f324@8812
7308+0000f3a4@8813
7309+000071a6@8814
7310+0000f3a6@8815
7311+0000f936@8816
7312+0000b9b6@8817
7313+00003936@8819
7314+0000a9f6@8820
7315+0000abc2@8821
7316+00002bc2@8823
7317+0000ab40@8824
7318+0000ebe4@8825
7319+0000eb64@8827
7320+00006be4@8828
7321+0000ebe4@8829
7322+0000fbe4@8830
7323+0000fb44@8831
7324+0000fbe4@8832
7325+00007be6@8833
7326+0000fbf6@8834
7327+0000f936@8835
7328+0000f9b6@8836
7329+000079b6@8837
7330+0000e936@8838
7331+0000ebc2@8839
7332+00006b40@8842
7333+0000ebc0@8843
7334+0000ebe4@8844
7335+0000a5e0@8845
7336+000025e0@8847
7337+0000a5e0@8848
7338+0000b5e0@8849
7339+000035e2@8851
7340+0000f5e2@8852
7341+0000f91a@8853
7342+0000b99a@8854
7343+0000399a@8856
7344+0000a91a@8857
7345+0000abd2@8858
7346+00002b50@8861
7347+0000abf4@8862
7348+0000ebf4@8863
7349+0000eb74@8864
7350+00006bf4@8865
7351+0000ebf4@8866
7352+0000fbd0@8867
7353+0000fb74@8868
7354+0000fbf4@8869
7355+00007bf6@8870
7356+0000fbf6@8871
7357+0000b33a@8872
7358+0000b3ba@8873
7359+0000a3ba@8875
7360+0000abfa@8876
7361+0000abd2@8877
7362+00002b52@8879
7363+0000abd0@8880
7364+0000ebf4@8881
7365+0000eb74@8883
7366+00006bd4@8884
7367+0000ebf4@8885
7368+0000fbf4@8886
7369+0000fb54@8887
7370+0000fbf4@8888
7371+0000fbf6@8889
7372+0000fbd6@8890
7373+0000b3d6@8891
7374+000033d6@8893
7375+0000a356@8894
7376+0000afc2@8895
7377+00002f40@8898
7378+0000afc0@8899
7379+0000efe4@8900
7380+0000efc4@8901
7381+00006f64@8902
7382+0000efe4@8903
7383+0000ff64@8905
7384+0000ffe4@8906
7385+00007fe6@8907
7386+0000ffe6@8908
7387+0000f346@8909
7388+0000b3c6@8910
7389+000033c6@8912
7390+0000a3c6@8913
7391+0000abe2@8914
7392+00002be2@8916
7393+0000abe0@8917
7394+0000abe4@8918
7395+0000ebe4@8919
7396+0000eb64@8920
7397+00006be4@8921
7398+0000ebe4@8922
7399+0000fbe4@8923
7400+0000fb64@8924
7401+0000fbe4@8925
7402+00007be6@8926
7403+0000fbe6@8927
7404+0000b53a@8928
7405+0000b5ba@8929
7406+000035ba@8930
7407+0000a53a@8931
7408+0000a182@8932
7409+00002102@8935
7410+0000a180@8936
7411+0000e380@8937
7412+0000e3a4@8938
7413+0000e304@8939
7414+000061a4@8940
7415+0000e3a4@8941
7416+0000f3a4@8942
7417+0000f384@8943
7418+000073a6@8944
7419+0000f3a6@8945
7420+0000f53a@8946
7421+0000b5ba@8947
7422+000035ba@8949
7423+0000a53a@8950
7424+0000a182@8951
7425+00002100@8954
7426+0000a180@8955
7427+0000e3a4@8956
7428+000063a4@8958
7429+0000e1a4@8959
7430+0000e180@8960
7431+0000f324@8961
7432+0000f3a4@8962
7433+000071a6@8963
7434+0000f3a6@8964
7435+0000f93a@8965
7436+0000b9ba@8966
7437+000039ba@8968
7438+0000a9fa@8969
7439+0000abc2@8970
7440+00002bc2@8972
7441+0000abc0@8973
7442+0000abe4@8974
7443+0000ebe4@8975
7444+0000eb64@8976
7445+00006be4@8977
7446+0000ebe4@8978
7447+0000fbe4@8979
7448+0000fb40@8980
7449+0000fbe4@8981
7450+00007be6@8982
7451+0000fbfe@8983
7452+0000f93a@8984
7453+0000f9ba@8985
7454+000079ba@8986
7455+0000e93a@8987
7456+0000eb42@8988
7457+0000ebc2@8989
7458+00006b40@8991
7459+0000ebc0@8992
7460+0000ebe4@8993
7461+0000a3a4@8994
7462+0000a324@8995
7463+000023a4@8996
7464+0000a3a4@8997
7465+0000b3a4@8998
7466+000033a6@9000
7467+0000f3a6@9001
7468+0000f97e@9002
7469+0000b9fa@9003
7470+000039fa@9005
7471+0000a97a@9006
7472+0000a182@9007
7473+00002180@9010
7474+0000a3a4@9011
7475+0000e3a4@9012
7476+0000e324@9013
7477+000063a4@9014
7478+0000e3a4@9015
7479+0000f180@9016
7480+0000f304@9017
7481+0000f3a4@9018
7482+000073a6@9019
7483+0000f3a6@9020
7484+0000f11a@9021
7485+0000b19a@9022
7486+0000a19a@9024
7487+0000a192@9025
7488+0000a182@9026
7489+00002102@9028
7490+0000a180@9029
7491+0000e3a4@9030
7492+0000e184@9031
7493+0000e304@9032
7494+00006180@9033
7495+0000e3a4@9034
7496+0000f3a4@9035
7497+0000f300@9036
7498+0000f3a4@9037
7499+0000f3a6@9038
7500+0000f35a@9039
7501+0000b3da@9040
7502+000033da@9042
7503+0000a35a@9043
7504+0000afc2@9044
7505+00002f40@9047
7506+0000afc0@9048
7507+0000efe4@9049
7508+00006fe4@9051
7509+0000efe4@9052
7510+0000ff64@9054
7511+0000ffe4@9055
7512+00007fe6@9056
7513+0000ffe6@9057
7514+0000f346@9058
7515+0000b3c6@9059
7516+00003346@9061
7517+0000a3c6@9062
7518+0000abe2@9063
7519+00002be2@9065
7520+0000abe0@9066
7521+0000ebe4@9068
7522+0000eb64@9069
7523+00006be4@9070
7524+0000ebe4@9071
7525+0000fbe4@9072
7526+0000fb64@9073
7527+0000fbe4@9074
7528+00007be6@9075
7529+0000fbe6@9076
7530+0000b53a@9077
7531+0000b5ba@9078
7532+000035ba@9079
7533+0000a5ba@9080
7534+0000a182@9081
7535+00002102@9084
7536+0000a180@9085
7537+0000e380@9086
7538+0000e384@9087
7539+0000e300@9088
7540+000061a4@9089
7541+0000e3a4@9090
7542+0000f3a4@9091
7543+000073a6@9093
7544+0000f3a6@9094
7545+0000f53a@9095
7546+0000b5ba@9096
7547+000035ba@9098
7548+0000a53a@9099
7549+0000a182@9100
7550+00002100@9103
7551+0000a180@9104
7552+0000e1a4@9105
7553+0000e3a4@9106
7554+000063a4@9107
7555+0000e1a4@9108
7556+0000e180@9109
7557+0000f324@9110
7558+0000f3a4@9111
7559+000071a6@9112
7560+0000f3a6@9113
7561+0000f93e@9114
7562+0000b9be@9115
7563+000039be@9117
7564+0000a9fe@9118
7565+0000abc2@9119
7566+00002bc2@9121
7567+0000ab40@9122
7568+0000abe4@9123
7569+0000ebe4@9124
7570+0000eb64@9125
7571+00006be4@9126
7572+0000ebe4@9127
7573+0000fbe4@9128
7574+0000fb64@9129
7575+0000fbe4@9130
7576+00007be6@9131
7577+0000fbfe@9132
7578+0000f93e@9133
7579+0000f9be@9134
7580+000079be@9135
7581+0000f93c@9136
7582+0000fb40@9137
7583+0000fbc0@9138
7584+0000ebc0@9139
7585+00006b40@9140
7586+0000ebc0@9141
7587+0000ebe4@9142
7588+0000eb64@9144
7589+00006be4@9145
7590+0000ebe4@9146
7591+0000fbe4@9147
7592+00007be6@9149
7593+0000fbe6@9150
7594+0000f11a@9151
7595+0000b19a@9152
7596+0000319a@9154
7597+0000a11a@9155
7598+0000a182@9156
7599+00002100@9159
7600+0000a3a4@9160
7601+0000e3a4@9161
7602+0000e324@9162
7603+000063a4@9163
7604+0000e3a4@9164
7605+0000f180@9165
7606+0000f304@9166
7607+0000f3a4@9167
7608+000073a6@9168
7609+0000f3a6@9169
7610+0000f11a@9170
7611+0000b19a@9171
7612+0000a19a@9173
7613+0000a182@9174
7614+00002102@9177
7615+0000a180@9178
7616+0000e3a4@9179
7617+0000e384@9180
7618+0000e304@9181
7619+00006180@9182
7620+0000e3a4@9183
7621+0000f3a4@9184
7622+0000f304@9185
7623+0000f3a4@9186
7624+0000f3a6@9187
7625+0000f35e@9188
7626+0000b3de@9189
7627+000033de@9191
7628+0000a35e@9192
7629+0000af42@9193
7630+0000afc2@9194
7631+00002f40@9196
7632+0000afc0@9197
7633+0000efe4@9198
7634+00006fe4@9200
7635+0000efe4@9201
7636+0000ff64@9203
7637+0000ffe4@9204
7638+00007fe6@9205
7639+0000ffe6@9206
7640+0000f346@9207
7641+0000b3c6@9208
7642+000033c6@9210
7643+0000a3c6@9211
7644+0000abe2@9212
7645+00002be2@9214
7646+0000abe0@9215
7647+0000ebe4@9217
7648+0000eb64@9218
7649+00006be4@9219
7650+0000ebe4@9220
7651+0000fbe4@9221
7652+0000fb64@9222
7653+0000fbe4@9223
7654+00007be6@9224
7655+0000fbe6@9225
7656+0000b91a@9226
7657+0000b99a@9227
7658+0000399a@9228
7659+0000a99a@9229
7660+0000afa2@9230
7661+0000a7a2@9231
7662+00002722@9233
7663+0000a7a0@9234
7664+0000e7a0@9235
7665+0000e7a4@9236
7666+0000e724@9237
7667+000067a4@9238
7668+0000e7a4@9239
7669+0000f7a4@9240
7670+000077a6@9242
7671+0000f7a6@9243
7672+0000f93a@9244
7673+0000b9ba@9245
7674+000039ba@9247
7675+0000a93a@9248
7676+0000a7a2@9249
7677+00002720@9252
7678+0000a7a4@9253
7679+0000e7a4@9254
7680+000067a4@9256
7681+0000e7a4@9257
7682+0000f724@9259
7683+0000f7a4@9260
7684+000077a6@9261
7685+0000f7a6@9262
7686+0000f93a@9263
7687+0000f9ba@9264
7688+000079ba@9266
7689+0000e9ba@9267
7690+0000e7a2@9268
7691+000067a2@9270
7692+0000e7a0@9271
7693+0000e7a4@9272
7694+0000a7a4@9273
7695+0000a568@9274
7696+000025e8@9275
7697+0000a5e8@9276
7698+0000b5e8@9277
7699+0000b568@9278
7700+0000b5e8@9279
7701+000075ea@9280
7702+0000f5fa@9281
7703+0000f9ba@9282
7704+000079ba@9284
7705+0000e93a@9285
7706+0000ef22@9286
7707+0000e7a2@9287
7708+00006720@9289
7709+0000e7a0@9290
7710+0000e7a4@9291
7711+0000a5e8@9292
7712+000025e8@9294
7713+0000a5e8@9295
7714+0000b568@9296
7715+0000b5e8@9297
7716+000035ea@9298
7717+0000f5ea@9299
7718+0000f11e@9300
7719+0000b19e@9301
7720+0000319e@9303
7721+0000a11e@9304
7722+0000a9d2@9305
7723+00002950@9308
7724+0000abf4@9309
7725+0000ebf4@9310
7726+0000eb74@9311
7727+00006bf4@9312
7728+0000ebf4@9313
7729+0000f9d0@9314
7730+0000fb54@9315
7731+0000fbf4@9316
7732+00007bf6@9317
7733+0000fbf6@9318
7734+0000b31e@9319
7735+0000b39e@9320
7736+0000a39e@9322
7737+0000abd2@9323
7738+0000a9d2@9324
7739+00002952@9326
7740+0000a9d0@9327
7741+0000ebf4@9328
7742+0000e9d4@9329
7743+0000eb54@9330
7744+000069d4@9331
7745+0000ebf4@9332
7746+0000fbf4@9333
7747+0000fb50@9334
7748+0000fbf4@9335
7749+0000fbf6@9336
7750+0000ff1e@9337
7751+0000b59e@9338
7752+0000359e@9340
7753+0000a51e@9341
7754+0000a9d2@9342
7755+00002950@9345
7756+0000a9d0@9346
7757+0000ebf4@9347
7758+0000e9d4@9348
7759+00006bf4@9349
7760+0000e9f4@9350
7761+0000fb74@9352
7762+0000fbf4@9353
7763+000079f6@9354
7764+0000fbf6@9355
7765+0000f71e@9356
7766+0000b79e@9357
7767+0000379e@9359
7768+0000a79e@9360
7769+0000a9d2@9361
7770+000029d2@9363
7771+0000a950@9364
7772+0000abf0@9365
7773+0000ebf4@9366
7774+0000eb74@9367
7775+000069f4@9368
7776+0000ebf4@9369
7777+0000fbf4@9370
7778+0000fb54@9371
7779+0000fbf4@9372
7780+00007bf6@9373
7781+0000fbf6@9374
7782+0000b91e@9375
7783+0000b99e@9376
7784+0000399e@9377
7785+0000a91e@9378
7786+0000a5f2@9379
7787+00002572@9382
7788+0000a5f0@9383
7789+0000e7f0@9384
7790+0000e7f4@9385
7791+0000e774@9386
7792+000065f4@9387
7793+0000e7f4@9388
7794+0000f7f4@9389
7795+000077f6@9391
7796+0000f7f6@9392
7797+0000f93e@9393
7798+0000b9be@9394
7799+000039be@9396
7800+0000a93e@9397
7801+0000a5f2@9398
7802+00002570@9401
7803+0000a5f4@9402
7804+0000e7f4@9403
7805+000067f4@9405
7806+0000e7f4@9406
7807+0000e5f0@9407
7808+0000f774@9408
7809+0000f7f4@9409
7810+000075f6@9410
7811+0000f7f6@9411
7812+0000fb1e@9412
7813+0000bb9e@9413
7814+00003b9e@9415
7815+0000abfe@9416
7816+0000a5f2@9417
7817+00002572@9419
7818+0000a5f0@9420
7819+0000e5f4@9421
7820+0000e774@9423
7821+000065f4@9424
7822+0000e7f4@9425
7823+0000f7f4@9426
7824+0000f774@9427
7825+0000f7f4@9428
7826+000077f6@9429
7827+0000fffe@9430
7828+0000b99e@9431
7829+0000399e@9433
7830+0000a91e@9434
7831+0000a5f2@9435
7832+00002570@9438
7833+0000a5f0@9439
7834+0000e7f4@9440
7835+0000e774@9442
7836+000067f4@9443
7837+0000e7f4@9444
7838+0000f774@9445
7839+0000f7f4@9446
7840+000077f6@9447
7841+0000f7f6@9448
7842+0000f93e@9449
7843+0000b9be@9450
7844+000039be@9452
7845+0000a93e@9453
7846+0000a5f2@9454
7847+0000a570@9457
7848+0000a7f4@9458
7849+0000e7f4@9459
7850+0000e774@9460
7851+000067f4@9461
7852+0000e7f4@9462
7853+0000f5f0@9463
7854+0000f774@9464
7855+0000f7f4@9465
7856+000077f6@9466
7857+0000f7f6@9467
7858+0000bb1e@9468
7859+0000bb9e@9469
7860+0000ab9e@9471
7861+0000aff2@9472
7862+0000a5f2@9473
7863+00002572@9475
7864+0000a5f0@9476
7865+0000e7f4@9477
7866+0000e774@9479
7867+000065f4@9480
7868+0000e7f4@9481
7869+0000f7f4@9482
7870+0000f774@9483
7871+0000f7f4@9484
7872+0000f7f6@9485
7873+0000fd3e@9486
7874+0000b99e@9487
7875+0000399e@9489
7876+0000a91e@9490
7877+0000a5f2@9491
7878+00002570@9494
7879+0000a5f0@9495
7880+0000e7f4@9496
7881+000067f4@9498
7882+0000e7f4@9499
7883+0000f774@9501
7884+0000f7f4@9502
7885+000075f6@9503
7886+0000f7f6@9504
7887+0000f93e@9505
7888+0000b9be@9506
7889+000039be@9508
7890+0000a9be@9509
7891+0000a5f2@9510
7892+000025f2@9512
7893+0000a5f0@9513
7894+0000a7f0@9514
7895+0000e7f4@9515
7896+0000e774@9516
7897+000065f4@9517
7898+0000e7f4@9518
7899+0000f7f4@9519
7900+0000f774@9520
7901+0000f7f4@9521
7902+000077f6@9522
7903+0000f7f6@9523
7904+0000bb1e@9524
7905+0000bb9e@9525
7906+00003b9e@9526
7907+0000ab1e@9527
7908+0000a5f2@9528
7909+00002572@9531
7910+0000a5f0@9532
7911+0000e7f0@9533
7912+0000e7f4@9534
7913+0000e774@9535
7914+000067f4@9536
7915+0000e7f4@9537
7916+0000f7f4@9538
7917+000077f6@9540
7918+0000f7f6@9541
7919+0000fd1e@9542
7920+0000b99e@9543
7921+0000399e@9545
7922+0000a91e@9546
7923+0000a5f2@9547
7924+00002570@9550
7925+0000a5f4@9551
7926+0000e7f4@9552
7927+0000e774@9553
7928+000067f4@9554
7929+0000e5f4@9555
7930+0000f774@9557
7931+0000f7f4@9558
7932+000075f6@9559
7933+0000f7f6@9560
7934+0000f91e@9561
7935+0000f99e@9562
7936+0000799e@9564
7937+0000e9fe@9565
7938+0000e5f2@9566
7939+000065f2@9568
7940+0000e5f0@9569
7941+0000e5f4@9570
7942+0000a5f4@9571
7943+0000a100@9572
7944+00002180@9573
7945+0000a180@9574
7946+0000b180@9575
7947+0000b100@9576
7948+0000b180@9577
7949+00007182@9578
7950+0000f10e@9579
7951+0000f93e@9580
7952+0000b9be@9581
7953+000039be@9582
7954+0000a93e@9583
7955+0000a5f2@9584
7956+00002570@9587
7957+0000a5f0@9588
7958+0000e7f4@9589
7959+0000e5f4@9590
7960+0000e774@9591
7961+000065f4@9592
7962+0000e7f4@9593
7963+0000f774@9594
7964+0000f7f4@9595
7965+000077f6@9596
7966+0000f7f6@9597
7967+0000fb1e@9598
7968+0000bb9e@9599
7969+00003b9e@9601
7970+0000ab1e@9602
7971+0000a5f2@9603
7972+00002570@9606
7973+0000a7f4@9607
7974+0000e7f4@9608
7975+0000e774@9609
7976+000067f4@9610
7977+0000e7f4@9611
7978+0000f7f4@9612
7979+0000f774@9613
7980+0000f7f4@9614
7981+000077f6@9615
7982+0000f7f6@9616
7983+0000b91a@9617
7984+0000b99a@9618
7985+0000a99a@9620
7986+0000adf2@9621
7987+0000a5f2@9622
7988+00002572@9624
7989+0000a5f0@9625
7990+0000e7f4@9626
7991+0000e5f4@9627
7992+0000e774@9628
7993+000065f0@9629
7994+0000e7f4@9630
7995+0000f7f4@9631
7996+0000f770@9632
7997+0000f7f4@9633
7998+0000f7f6@9634
7999+0000fd7e@9635
8000+0000b9ba@9636
8001+000039ba@9638
8002+0000a93a@9639
8003+0000a5f2@9640
8004+00002570@9643
8005+0000a5f0@9644
8006+0000e7f4@9645
8007+000067f4@9647
8008+0000e5f4@9648
8009+0000f774@9650
8010+0000f7f4@9651
8011+000075f6@9652
8012+0000f7f6@9653
8013+0000fb1a@9654
8014+0000bb9a@9655
8015+00003b9a@9657
8016+0000ab9a@9658
8017+0000a5f2@9659
8018+000025f2@9661
8019+0000a570@9662
8020+0000a7f0@9663
8021+0000e7f4@9664
8022+0000e774@9665
8023+000067f4@9666
8024+0000e7f4@9667
8025+0000f7f4@9668
8026+0000f774@9669
8027+0000f7f4@9670
8028+000077f6@9671
8029+0000f7f6@9672
8030+0000b81a@9673
8031+0000b89a@9674
8032+0000389a@9675
8033+0000a89a@9676
8034+0000a4f2@9677
8035+00002470@9680
8036+0000a470@9681
8037+0000e6f0@9682
8038+0000e6f4@9683
8039+00006470@9685
8040+0000e674@9686
8041+0000f6f4@9687
8042+000076f6@9689
8043+0000f676@9690
8044+0000f83a@9691
8045+0000b8ba@9692
8046+0000383a@9694
8047+0000a83a@9695
8048+0000a4f2@9696
8049+00002470@9699
8050+0000a474@9700
8051+0000e6f4@9701
8052+000066f4@9703
8053+0000e474@9704
8054+0000f6f4@9706
8055+00007476@9708
8056+0000f676@9709
8057+0000fa9a@9710
8058+0000ba9a@9711
8059+00003a1a@9713
8060+0000aa7a@9714
8061+0000a4f2@9715
8062+000024f2@9717
8063+0000a470@9718
8064+0000e474@9719
8065+0000e6f4@9720
8066+00006474@9722
8067+0000e674@9723
8068+0000f6f4@9724
8069+00007676@9727
8070+0000f67e@9728
8071+0000b29a@9729
8072+0000329a@9731
8073+0000a21a@9732
8074+0000a4f2@9733
8075+00002470@9736
8076+0000a470@9737
8077+0000e6f4@9738
8078+0000e474@9741
8079+0000e674@9742
8080+0000f6f4@9743
8081+00007676@9745
8082+0000f676@9746
8083+0000f21a@9747
8084+0000b29a@9748
8085+0000321a@9750
8086+0000a29a@9751
8087+0000a4f2@9752
8088+0000a472@9754
8089+0000a4f0@9755
8090+0000a6f4@9756
8091+0000e6f4@9757
8092+0000e674@9758
8093+00006674@9759
8094+0000e6f4@9760
8095+0000f6f4@9761
8096+0000f674@9762
8097+000076f6@9764
8098+0000f6f6@9765
8099+0000b21a@9766
8100+0000a29a@9769
8101+0000a6f2@9770
8102+0000a4f2@9771
8103+0000a472@9772
8104+00002472@9773
8105+0000a4f0@9774
8106+0000e6f4@9775
8107+0000e674@9776
8108+000064f0@9778
8109+0000e6f4@9779
8110+0000f6f4@9780
8111+0000f674@9781
8112+00007674@9782
8113+0000f6f6@9783
8114+0000f6be@9784
8115+0000b22e@9785
8116+000032ae@9787
8117+0000a2ae@9788
8118+0000a082@9789
8119+0000a002@9790
8120+00002080@9792
8121+0000a080@9793
8122+0000e2a4@9794
8123+0000e204@9795
8124+00006224@9796
8125+0000e0a4@9797
8126+0000e2a4@9798
8127+0000f224@9799
8128+0000f204@9800
8129+000072a6@9801
8130+0000f2a6@9802
8131+0000f2ae@9803
8132+0000f22e@9804
8133+000072ae@9806
8134+0000e2ae@9807
8135+0000e082@9808
8136+0000e002@9809
8137+00006002@9810
8138+0000e080@9811
8139+0000e2a0@9812
8140+0000a2a4@9813
8141+0000a60c@9814
8142+0000268c@9815
8143+0000a68c@9816
8144+0000b68c@9817
8145+0000b60c@9818
8146+0000768e@9820
8147+0000f68e@9821
8148+0000b49e@9822
8149+0000b41e@9823
8150+0000341e@9824
8151+0000a49e@9825
8152+0000aef2@9826
8153+0000aa72@9827
8154+0000aaf2@9828
8155+00002af0@9829
8156+0000aaf0@9830
8157+0000ea70@9831
8158+0000eaf4@9832
8159+00006af4@9834
8160+0000ea74@9835
8161+0000fa74@9836
8162+0000faf4@9837
8163+00007af6@9838
8164+0000faf6@9839
8165+0000fe26@9840
8166+0000b4a6@9841
8167+000034a6@9843
8168+0000a426@9844
8169+0000a472@9845
8170+0000a4f2@9846
8171+000024f0@9848
8172+0000a474@9849
8173+0000e474@9850
8174+0000e6f4@9851
8175+000066f4@9852
8176+0000e6f4@9853
8177+0000e474@9854
8178+0000f6f4@9855
8179+000074f6@9857
8180+0000f676@9858
8181+0000f606@9859
8182+0000b686@9860
8183+00003686@9862
8184+0000a676@9863
8185+0000a472@9864
8186+0000a4f2@9865
8187+000024f2@9866
8188+0000a470@9867
8189+0000e474@9868
8190+0000e6f4@9869
8191+000064f4@9871
8192+0000e674@9872
8193+0000f674@9873
8194+0000f6f4@9874
8195+000076f6@9876
8196+0000f676@9877
8197+0000b626@9878
8198+0000b6a6@9879
8199+000036a6@9880
8200+0000a626@9881
8201+0000a472@9882
8202+0000a4f2@9883
8203+000024f0@9885
8204+0000a470@9886
8205+0000e674@9887
8206+0000e6f4@9888
8207+000066f4@9890
8208+0000e674@9891
8209+0000f674@9892
8210+0000f6f4@9893
8211+000076f6@9894
8212+0000f676@9895
8213+0000f226@9896
8214+0000b2a6@9897
8215+000032a6@9899
8216+0000a226@9900
8217+0000a002@9901
8218+0000a082@9902
8219+00002080@9904
8220+0000a2a4@9905
8221+0000e2a4@9906
8222+00006224@9908
8223+0000e2a4@9909
8224+0000f280@9910
8225+0000f2a4@9911
8226+0000f224@9912
8227+00007206@9913
8228+0000f2a6@9914
8229+0000f9be@9915
8230+0000b9be@9916
8231+0000b93e@9917
8232+0000a93e@9918
8233+0000abe2@9919
8234+0000abc2@9920
8235+0000ab42@9921
8236+00002b42@9922
8237+0000abc0@9923
8238+0000ebe4@9924
8239+0000eb64@9926
8240+00006b44@9927
8241+0000ebe4@9928
8242+0000fbe4@9929
8243+00007b44@9931
8244+0000fb66@9932
8245+0000fbe6@9933
8246+0000b3a6@9934
8247+0000b326@9935
8248+00003326@9936
8249+0000a3a6@9937
8250+0000a182@9938
8251+0000a102@9940
8252+00002100@9941
8253+0000a180@9942
8254+0000e3a4@9943
8255+00006324@9945
8256+0000e124@9946
8257+0000e3a4@9947
8258+0000f3a4@9948
8259+0000f324@9949
8260+00007326@9950
8261+0000f3a6@9951
8262+0000f19e@9952
8263+0000b19e@9953
8264+0000b11e@9954
8265+0000311e@9955
8266+0000a19e@9956
8267+0000a182@9957
8268+00002102@9959
8269+0000a100@9960
8270+0000a3a0@9961
8271+0000e3a4@9962
8272+0000e324@9963
8273+00006104@9964
8274+0000e3a4@9965
8275+0000f3a4@9966
8276+0000f324@9968
8277+00007306@9969
8278+0000f3a6@9970
8279+0000f19e@9971
8280+0000b19e@9972
8281+0000311e@9973
8282+0000a11e@9974
8283+0000a182@9975
8284+0000a102@9977
8285+00002102@9978
8286+0000a180@9979
8287+0000e380@9980
8288+0000e384@9981
8289+0000e304@9982
8290+000063a4@9983
8291+0000e3a4@9984
8292+0000f3a4@9985
8293+000073a6@9987
8294+0000f3a6@9988
8295+0000f17e@9989
8296+0000b1de@9990
8297+000031de@9992
8298+0000a15e@9993
8299+0000afc2@9994
8300+00002f40@9997
8301+0000afc4@9998
8302+0000efe4@9999
8303+00006fe4@10001
8304+0000efe4@10002
8305+0000efc4@10003
8306+0000ff64@10004
8307+0000ffe4@10005
8308+00007fe6@10006
8309+0000ffe6@10007
8310+0000b356@10008
8311+0000b3d6@10009
8312+00003356@10011
8313+0000a7f6@10012
8314+0000a7f2@10013
8315+000027f2@10015
8316+0000a7f0@10016
8317+0000e7f4@10017
8318+0000e774@10019
8319+000067f4@10020
8320+0000e7f4@10021
8321+0000f7f4@10022
8322+0000f774@10023
8323+0000f7f4@10024
8324+000077f6@10025
8325+0000f7fe@10026
8326+0000b53e@10027
8327+0000b5be@10028
8328+000035be@10029
8329+0000a53e@10030
8330+0000af02@10031
8331+0000ab82@10032
8332+00002b00@10034
8333+0000ab80@10035
8334+0000eba4@10036
8335+0000eb24@10038
8336+0000eba4@10039
8337+0000fb24@10041
8338+0000fba4@10042
8339+00007ba6@10043
8340+0000fba6@10044
8341+0000f71e@10045
8342+0000b79e@10046
8343+0000379e@10048
8344+0000a71e@10049
8345+0000ab82@10050
8346+0000ab80@10053
8347+0000aba4@10054
8348+0000eba4@10055
8349+0000eb24@10056
8350+00006ba4@10057
8351+0000eba4@10058
8352+0000fb84@10059
8353+0000fb04@10060
8354+0000fba4@10061
8355+00007ba6@10062
8356+0000fba6@10063
8357+0000b902@10064
8358+0000b982@10065
8359+0000a902@10067
8360+0000abc2@10068
8361+00002b42@10071
8362+0000abc0@10072
8363+0000ebe4@10073
8364+0000ebc4@10074
8365+0000eb44@10075
8366+00006bc4@10076
8367+0000ebe4@10077
8368+0000fbe4@10078
8369+0000fb40@10079
8370+00007be4@10080
8371+0000fbe6@10081
8372+0000fb46@10082
8373+0000f982@10083
8374+00007982@10085
8375+0000e902@10086
8376+0000ebc2@10087
8377+00006b40@10090
8378+0000ebc0@10091
8379+0000ebe4@10092
8380+0000a180@10093
8381+00002100@10094
8382+0000a180@10095
8383+0000b100@10097
8384+0000b180@10098
8385+00007182@10099
8386+0000f182@10100
8387+0000f11e@10101
8388+0000b19e@10102
8389+0000319e@10104
8390+0000a19e@10105
8391+0000a182@10106
8392+00002182@10108
8393+0000a180@10109
8394+0000a3a0@10110
8395+0000e3a4@10111
8396+0000e324@10112
8397+000061a4@10113
8398+0000e3a4@10114
8399+0000f384@10115
8400+0000f104@10116
8401+0000f3a4@10117
8402+000073a6@10118
8403+0000f3a6@10119
8404+0000f11e@10120
8405+0000b19e@10121
8406+0000319e@10122
8407+0000a11e@10123
8408+0000a182@10124
8409+00002100@10127
8410+0000a180@10128
8411+0000e380@10129
8412+0000e384@10130
8413+0000e304@10131
8414+00006184@10132
8415+0000e3a4@10133
8416+0000f3a4@10134
8417+0000f384@10135
8418+000073a6@10136
8419+0000f3a6@10137
8420+0000f162@10138
8421+0000b1e2@10139
8422+000031e2@10141
8423+0000a162@10142
8424+0000afc2@10143
8425+00002f40@10146
8426+0000afe4@10147
8427+0000efe4@10148
8428+0000ef64@10149
8429+00006fe4@10150
8430+0000efe4@10151
8431+0000efc0@10152
8432+0000ff64@10153
8433+0000ffe4@10154
8434+00007fe6@10155
8435+0000ffe6@10156
8436+0000b346@10157
8437+0000b3c6@10158
8438+000033c6@10160
8439+0000a3e6@10161
8440+0000abe2@10162
8441+00002b62@10164
8442+0000abe0@10165
8443+0000ebe4@10166
8444+0000eb64@10168
8445+00006be4@10169
8446+0000ebe4@10170
8447+0000fbe4@10171
8448+0000fb64@10172
8449+0000fbe4@10173
8450+00007be6@10174
8451+0000fffe@10175
8452+0000b7be@10176
8453+000037be@10178
8454+0000a73e@10179
8455+0000ab02@10180
8456+0000ab82@10181
8457+00002b00@10183
8458+0000ab80@10184
8459+0000eba4@10185
8460+0000eb24@10187
8461+0000eba4@10188
8462+0000fb24@10190
8463+0000fba4@10191
8464+00007ba6@10192
8465+0000fba6@10193
8466+0000f91e@10194
8467+0000b99e@10195
8468+0000399e@10197
8469+0000a91e@10198
8470+0000ab82@10199
8471+0000ab00@10202
8472+0000aba4@10203
8473+0000eba4@10204
8474+0000eb24@10205
8475+00006ba4@10206
8476+0000eba4@10207
8477+0000fb84@10208
8478+0000fb24@10209
8479+0000fba4@10210
8480+00007ba6@10211
8481+0000fba6@10212
8482+0000b906@10213
8483+0000b986@10214
8484+0000a906@10216
8485+0000abc2@10217
8486+00002b42@10220
8487+0000abc0@10221
8488+0000ebe4@10222
8489+0000ebc4@10223
8490+0000eb44@10224
8491+00006bc4@10225
8492+0000ebe4@10226
8493+0000fbe4@10227
8494+0000fb44@10228
8495+0000fbe4@10229
8496+0000fbe6@10230
8497+0000fb06@10231
8498+0000f986@10232
8499+00007986@10234
8500+0000e906@10235
8501+0000ebc2@10236
8502+00006b40@10239
8503+0000ebc0@10240
8504+0000ebe4@10241
8505+0000a100@10242
8506+00002100@10243
8507+0000a180@10244
8508+0000b100@10246
8509+0000b180@10247
8510+00007182@10248
8511+0000f182@10249
8512+0000f11e@10250
8513+0000b19e@10251
8514+0000319e@10253
8515+0000a19e@10254
8516+0000a182@10255
8517+00002182@10257
8518+0000a180@10258
8519+0000a3a0@10259
8520+0000e3a4@10260
8521+0000e324@10261
8522+000061a4@10262
8523+0000e3a4@10263
8524+0000f3a4@10264
8525+0000f304@10265
8526+0000f3a4@10266
8527+000073a6@10267
8528+0000f3a6@10268
8529+0000f97e@10269
8530+0000b9fe@10270
8531+000039fe@10271
8532+0000a97e@10272
8533+0000a982@10273
8534+0000a182@10274
8535+00002102@10276
8536+0000a180@10277
8537+0000e3a0@10278
8538+0000e384@10279
8539+0000e104@10280
8540+000061a4@10281
8541+0000e3a4@10282
8542+0000f3a4@10283
8543+0000f384@10284
8544+000073a6@10285
8545+0000f3a6@10286
8546+0000f166@10287
8547+0000b1e6@10288
8548+000031e6@10290
8549+0000a166@10291
8550+0000afc2@10292
8551+00002f40@10295
8552+0000afc4@10296
8553+0000efe4@10297
8554+00006fe4@10299
8555+0000efe4@10300
8556+0000efc0@10301
8557+0000ff64@10302
8558+0000ffe4@10303
8559+00007fe6@10304
8560+0000ffe6@10305
8561+0000b346@10306
8562+0000b3c6@10307
8563+00003346@10309
8564+0000a3e6@10310
8565+0000abe2@10311
8566+00002b62@10313
8567+0000abe0@10314
8568+0000ebe4@10315
8569+0000eb64@10317
8570+00006be4@10318
8571+0000ebe4@10319
8572+0000fbe4@10320
8573+0000fb64@10321
8574+0000fbe4@10322
8575+00007be6@10323
8576+0000fbfe@10324
8577+0000b9be@10325
8578+000039be@10327
8579+0000a93e@10328
8580+0000ab02@10329
8581+0000ab82@10330
8582+00002b00@10332
8583+0000ab80@10333
8584+0000eba4@10334
8585+0000eb84@10335
8586+0000eb24@10336
8587+0000eba4@10337
8588+0000fb24@10339
8589+0000fba4@10340
8590+00007ba6@10341
8591+0000fba6@10342
8592+0000f31e@10343
8593+0000b39e@10344
8594+0000339e@10346
8595+0000a31e@10347
8596+0000ada2@10348
8597+0000ada0@10351
8598+0000afa4@10352
8599+0000efa4@10353
8600+0000ef24@10354
8601+00006fa4@10355
8602+0000efa4@10356
8603+0000ffa4@10357
8604+0000ff24@10358
8605+0000ffa4@10359
8606+00007fa6@10360
8607+0000ffa6@10361
8608+0000b90a@10362
8609+0000b98a@10363
8610+0000a90a@10365
8611+0000abc2@10366
8612+00002b42@10369
8613+0000abc0@10370
8614+0000ebe4@10371
8615+0000ebc4@10372
8616+0000eb44@10373
8617+00006bc0@10374
8618+0000ebe4@10375
8619+0000fbe4@10376
8620+0000fb40@10377
8621+00007be4@10378
8622+0000fbe6@10379
8623+0000fb0e@10380
8624+0000f98a@10381
8625+0000798a@10383
8626+0000e90a@10384
8627+0000ebc2@10385
8628+00006b40@10388
8629+0000ebc0@10389
8630+0000ebe4@10390
8631+0000a5e0@10391
8632+000025e0@10392
8633+0000a5e0@10393
8634+0000b560@10395
8635+0000b5e0@10396
8636+000075e2@10397
8637+0000f5e2@10398
8638+0000f91e@10399
8639+0000b99e@10400
8640+0000399e@10402
8641+0000a99e@10403
8642+0000abd2@10404
8643+00002bd2@10406
8644+0000ab50@10407
8645+0000abf0@10408
8646+0000ebf4@10409
8647+0000eb74@10410
8648+00006bf4@10411
8649+0000ebf4@10412
8650+0000fbf4@10413
8651+0000fb54@10414
8652+0000fbf4@10415
8653+00007bf6@10416
8654+0000fbf6@10417
8655+0000b91e@10418
8656+0000b99e@10419
8657+0000399e@10420
8658+0000a91e@10421
8659+0000abd2@10422
8660+00002b50@10425
8661+0000abd0@10426
8662+0000ebf4@10427
8663+0000eb74@10429
8664+00006bf4@10430
8665+0000ebf4@10431
8666+0000fbf4@10432
8667+00007bf6@10434
8668+0000fbf6@10435
8669+0000f97a@10436
8670+0000b1ea@10437
8671+000031ea@10439
8672+0000b16a@10440
8673+0000afc2@10441
8674+00002f40@10444
8675+0000afe4@10445
8676+0000efe4@10446
8677+0000ef64@10447
8678+00006fe4@10448
8679+0000efe4@10449
8680+0000efc0@10450
8681+0000ff64@10451
8682+0000ffe4@10452
8683+00007fe6@10453
8684+0000ffe6@10454
8685+0000b346@10455
8686+0000b3c6@10456
8687+00003346@10458
8688+0000a3e6@10459
8689+0000abe2@10460
8690+00002be2@10462
8691+0000abe0@10463
8692+0000ebe4@10464
8693+0000eb64@10466
8694+00006be4@10467
8695+0000ebe4@10468
8696+0000fbe4@10469
8697+0000fb64@10470
8698+0000fbe4@10471
8699+00007be6@10472
8700+0000fb7e@10473
8701+0000b3be@10474
8702+000033be@10476
8703+0000a33e@10477
8704+0000ad22@10478
8705+0000ada2@10479
8706+00002d20@10481
8707+0000ada0@10482
8708+0000efa4@10483
8709+0000ef24@10485
8710+0000efa4@10486
8711+0000ff24@10488
8712+0000ffa4@10489
8713+00007fa6@10490
8714+0000ffa6@10491
8715+0000f51e@10492
8716+0000b59e@10493
8717+0000359e@10495
8718+0000a51e@10496
8719+0000ada2@10497
8720+0000ada0@10500
8721+0000afa4@10501
8722+0000efa4@10502
8723+0000ef24@10503
8724+00006fa4@10504
8725+0000efa4@10505
8726+0000ffa4@10506
8727+0000ff24@10507
8728+0000ffa4@10508
8729+00007fa6@10509
8730+0000ffa6@10510
8731+0000b90e@10511
8732+0000b98e@10512
8733+0000a90e@10514
8734+0000abc2@10515
8735+00002b42@10518
8736+0000abc0@10519
8737+0000ebe4@10520
8738+0000ebc4@10521
8739+0000eb44@10522
8740+00006bc4@10523
8741+0000ebe4@10524
8742+0000fbe4@10525
8743+0000fb44@10526
8744+00007be4@10527
8745+0000fbe6@10528
8746+0000fb0e@10529
8747+0000f98e@10530
8748+0000798e@10532
8749+0000f90c@10533
8750+0000fbc0@10534
8751+0000ebc0@10535
8752+00006b40@10537
8753+0000ebc0@10538
8754+0000ebe4@10539
8755+00006be4@10541
8756+0000ebe4@10542
8757+0000fb64@10544
8758+0000fbe4@10545
8759+00007be6@10546
8760+0000fbe6@10547
8761+0000f91e@10548
8762+0000b99e@10549
8763+0000399e@10551
8764+0000a99e@10552
8765+0000abd2@10553
8766+00002bd2@10555
8767+0000ab50@10556
8768+0000abf0@10557
8769+0000ebf4@10558
8770+0000eb74@10559
8771+00006bf4@10560
8772+0000ebf4@10561
8773+0000fbf4@10562
8774+0000fb54@10563
8775+0000fbf4@10564
8776+00007bf6@10565
8777+0000fbf6@10566
8778+0000b91e@10567
8779+0000b99e@10568
8780+0000399e@10569
8781+0000a91e@10570
8782+0000abd2@10571
8783+00002b50@10574
8784+0000abd0@10575
8785+0000ebf0@10576
8786+0000ebd4@10577
8787+0000eb54@10578
8788+00006bf4@10579
8789+0000ebf4@10580
8790+0000fbf4@10581
8791+00007bf6@10583
8792+0000fbf6@10584
8793+0000f17e@10585
8794+0000b1ee@10586
8795+000031ee@10588
8796+0000a16e@10589
8797+0000afc2@10590
8798+00002f40@10593
8799+0000afe4@10594
8800+0000efe4@10595
8801+0000ef64@10596
8802+00006fe4@10597
8803+0000efe4@10598
8804+0000efc4@10599
8805+0000ff64@10600
8806+0000ffe4@10601
8807+00007fe6@10602
8808+0000ffe6@10603
8809+0000b346@10604
8810+0000b3c6@10605
8811+00002346@10607
8812+0000a3e6@10608
8813+0000abe2@10609
8814+00002b62@10611
8815+0000abe0@10612
8816+0000ebe4@10613
8817+0000eb64@10615
8818+00006be4@10616
8819+0000ebe4@10617
8820+0000fbe4@10618
8821+0000fb64@10619
8822+0000fbe4@10620
8823+00007be6@10621
8824+0000fffe@10622
8825+0000b5be@10623
8826+000035be@10625
8827+0000a53e@10626
8828+0000ad22@10627
8829+0000ada2@10628
8830+00002d20@10630
8831+0000ada0@10631
8832+0000efa4@10632
8833+0000eda4@10633
8834+0000ef24@10634
8835+0000efa4@10635
8836+0000ff24@10637
8837+0000ffa4@10638
8838+00007fa6@10639
8839+0000ffa6@10640
8840+0000f71e@10641
8841+0000b79e@10642
8842+0000379e@10644
8843+0000a71e@10645
8844+0000ada2@10646
8845+0000ada0@10649
8846+0000afa4@10650
8847+0000efa4@10651
8848+0000ef24@10652
8849+00006fa4@10653
8850+0000efa4@10654
8851+0000ffa4@10655
8852+0000ff24@10656
8853+0000ffa4@10657
8854+00007fa6@10658
8855+0000ffa6@10659
8856+0000b912@10660
8857+0000b992@10661
8858+0000a992@10663
8859+0000abc2@10664
8860+00002b42@10667
8861+0000abc0@10668
8862+0000ebe4@10669
8863+0000ebc4@10670
8864+0000eb44@10671
8865+00006bc4@10672
8866+0000ebe4@10673
8867+0000fbe4@10674
8868+0000fb44@10675
8869+00007be6@10676
8870+0000fbe6@10677
8871+0000fb52@10678
8872+0000f992@10679
8873+00007992@10681
8874+0000e912@10682
8875+0000ebc2@10683
8876+00006b40@10686
8877+0000ebc0@10687
8878+0000ebe4@10688
8879+0000a5e0@10689
8880+000025e0@10690
8881+0000a5e0@10691
8882+0000b560@10693
8883+0000b5e0@10694
8884+000075e2@10695
8885+0000f5e2@10696
8886+0000f91e@10697
8887+0000b99e@10698
8888+0000399e@10700
8889+0000a99e@10701
8890+0000abd2@10702
8891+00002bd2@10704
8892+0000ab50@10705
8893+0000abf0@10706
8894+0000ebf4@10707
8895+0000eb74@10708
8896+00006bf4@10709
8897+0000ebf4@10710
8898+0000fbf4@10711
8899+0000fb54@10712
8900+0000fbf4@10713
8901+00007bf6@10714
8902+0000fbf6@10715
8903+0000b91e@10716
8904+0000b99e@10717
8905+0000399e@10718
8906+0000a91e@10719
8907+0000abd2@10720
8908+00002b50@10723
8909+0000abd0@10724
8910+0000ebf0@10725
8911+0000ebd4@10726
8912+0000eb54@10727
8913+00006bf4@10728
8914+0000ebf4@10729
8915+0000fbf4@10730
8916+00007bf6@10732
8917+0000fbf6@10733
8918+0000f172@10734
8919+0000b1f2@10735
8920+000031f2@10737
8921+0000a172@10738
8922+0000afc2@10739
8923+00002f40@10742
8924+0000afe4@10743
8925+0000efe4@10744
8926+0000ef64@10745
8927+00006fe4@10746
8928+0000efe4@10747
8929+0000efc0@10748
8930+0000ff64@10749
8931+0000ffe4@10750
8932+00007fe6@10751
8933+0000ffe6@10752
8934+0000b346@10753
8935+0000b3c6@10754
8936+00002346@10756
8937+0000a3e6@10757
8938+0000abe2@10758
8939+00002b62@10760
8940+0000abe0@10761
8941+0000ebe4@10762
8942+0000eb64@10764
8943+00006be4@10765
8944+0000ebe4@10766
8945+0000fbe4@10767
8946+0000fb64@10768
8947+0000fbe4@10769
8948+00007be6@10770
8949+0000fb7e@10771
8950+0000bb9e@10772
8951+00003b9e@10774
8952+0000ab1e@10775
8953+0000ab02@10776
8954+0000ab82@10777
8955+00002b00@10779
8956+0000ab80@10780
8957+0000eba4@10781
8958+0000eb84@10782
8959+0000eb24@10783
8960+0000eba4@10784
8961+0000fb24@10786
8962+0000fba4@10787
8963+00007ba6@10788
8964+0000fba6@10789
8965+0000fb3e@10790
8966+0000bbbe@10791
8967+00003bbe@10793
8968+0000ab3e@10794
8969+0000ab82@10795
8970+0000ab80@10798
8971+0000aba4@10799
8972+0000eba4@10800
8973+0000eb24@10801
8974+00006ba4@10802
8975+0000eba4@10803
8976+0000fb84@10804
8977+0000fb24@10805
8978+0000fba4@10806
8979+00007ba6@10807
8980+0000fba6@10808
8981+0000f916@10809
8982+0000b996@10810
8983+0000a916@10812
8984+0000abc2@10813
8985+00002b42@10816
8986+0000abc0@10817
8987+0000ebe4@10818
8988+0000ebc4@10819
8989+0000eb44@10820
8990+00006bc4@10821
8991+0000ebe4@10822
8992+0000fbe4@10823
8993+0000fb44@10824
8994+00007be4@10825
8995+0000fbe6@10826
8996+0000fb16@10827
8997+0000f996@10828
8998+00007996@10830
8999+0000e916@10831
9000+0000ebc2@10832
9001+00006b40@10835
9002+0000ebc0@10836
9003+0000ebe4@10837
9004+0000a5e0@10838
9005+000025e0@10839
9006+0000a5e0@10840
9007+0000b560@10842
9008+0000b5e0@10843
9009+000075e2@10844
9010+0000f5e2@10845
9011+0000f91e@10846
9012+0000b99e@10847
9013+0000399e@10849
9014+0000a99e@10850
9015+0000abd2@10851
9016+00002bd2@10853
9017+0000abd0@10854
9018+0000abf0@10855
9019+0000ebf4@10856
9020+0000eb74@10857
9021+00006bd4@10858
9022+0000ebf4@10859
9023+0000fbf4@10860
9024+0000fb54@10861
9025+0000fbf4@10862
9026+00007bf6@10863
9027+0000fbf6@10864
9028+0000b91e@10865
9029+0000b99e@10866
9030+0000399e@10867
9031+0000a91e@10868
9032+0000abd2@10869
9033+00002b50@10872
9034+0000abd0@10873
9035+0000ebf0@10874
9036+0000ebd4@10875
9037+0000eb54@10876
9038+00006bf4@10877
9039+0000ebf4@10878
9040+0000fbf4@10879
9041+00007bf6@10881
9042+0000fbf6@10882
9043+0000f176@10883
9044+0000b1f6@10884
9045+000031f6@10886
9046+0000a176@10887
9047+0000afc2@10888
9048+00002f40@10891
9049+0000afe4@10892
9050+0000efe4@10893
9051+0000ef64@10894
9052+00006fe4@10895
9053+0000efe4@10896
9054+0000efc0@10897
9055+0000ff64@10898
9056+0000ffe4@10899
9057+00007fe6@10900
9058+0000ffe6@10901
9059+0000b346@10902
9060+0000b3c6@10903
9061+00002346@10905
9062+0000a3e6@10906
9063+0000abe2@10907
9064+00002b62@10909
9065+0000abe0@10910
9066+0000ebe4@10911
9067+0000eb64@10913
9068+00006be4@10914
9069+0000ebe4@10915
9070+0000fbe4@10916
9071+0000fb64@10917
9072+0000fbe4@10918
9073+00007be6@10919
9074+0000ff7e@10920
9075+0000bd9e@10921
9076+00003d9e@10923
9077+0000ad1e@10924
9078+0000ab02@10925
9079+0000ab82@10926
9080+00002b00@10928
9081+0000ab80@10929
9082+0000eba4@10930
9083+0000eb24@10932
9084+0000eba4@10933
9085+0000fb24@10935
9086+0000fba4@10936
9087+00007ba6@10937
9088+0000fba6@10938
9089+0000fd3e@10939
9090+0000bdbe@10940
9091+00003dbe@10942
9092+0000ad3e@10943
9093+0000ab82@10944
9094+0000ab80@10947
9095+0000aba4@10948
9096+0000eba4@10949
9097+0000eb24@10950
9098+00006ba4@10951
9099+0000eba4@10952
9100+0000fb84@10953
9101+0000fb24@10954
9102+0000fba4@10955
9103+00007ba6@10956
9104+0000fba6@10957
9105+0000f91a@10958
9106+0000b99a@10959
9107+0000a91a@10961
9108+0000abc2@10962
9109+00002b42@10965
9110+0000abc0@10966
9111+0000ebe4@10967
9112+0000eb44@10969
9113+00006bc4@10970
9114+0000ebe4@10971
9115+0000fbe4@10972
9116+0000fb44@10973
9117+00007be6@10974
9118+0000fbe6@10975
9119+0000fb1e@10976
9120+0000f99a@10977
9121+0000799a@10979
9122+0000e91a@10980
9123+0000ebc2@10981
9124+00006b40@10984
9125+0000ebc0@10985
9126+0000ebe4@10986
9127+0000a5e0@10987
9128+000025e0@10988
9129+0000a5e0@10989
9130+0000b560@10991
9131+0000b5e0@10992
9132+000075e2@10993
9133+0000f5e2@10994
9134+0000f91e@10995
9135+0000b99e@10996
9136+0000399e@10998
9137+0000a99e@10999
9138+0000abd2@11000
9139+00002bd2@11002
9140+0000ab50@11003
9141+0000abf0@11004
9142+0000ebf4@11005
9143+0000eb74@11006
9144+00006bf4@11007
9145+0000ebf4@11008
9146+0000fbf4@11009
9147+0000fb54@11010
9148+0000fbf4@11011
9149+00007bf6@11012
9150+0000fbf6@11013
9151+0000b91e@11014
9152+0000b99e@11015
9153+0000399e@11016
9154+0000a91e@11017
9155+0000abd2@11018
9156+00002b50@11021
9157+0000abd0@11022
9158+0000ebf0@11023
9159+0000ebd4@11024
9160+0000eb54@11025
9161+00006bf4@11026
9162+0000ebf4@11027
9163+0000fbf4@11028
9164+00007bf6@11030
9165+0000fbf6@11031
9166+0000f17a@11032
9167+0000b1fa@11033
9168+000031fa@11035
9169+0000a17a@11036
9170+0000afc2@11037
9171+00002f40@11040
9172+0000afe4@11041
9173+0000efe4@11042
9174+0000ef64@11043
9175+00006fe4@11044
9176+0000efe4@11045
9177+0000ffe4@11046
9178+0000ff64@11047
9179+0000ffe4@11048
9180+00007fe6@11049
9181+0000ffe6@11050
9182+0000b346@11051
9183+0000b3c6@11052
9184+00003346@11054
9185+0000a3e6@11055
9186+0000abe2@11056
9187+00002b62@11058
9188+0000abe0@11059
9189+0000ebe4@11060
9190+0000eb64@11062
9191+00006be4@11063
9192+0000ebe4@11064
9193+0000fbe4@11065
9194+0000fb64@11066
9195+0000fbe4@11067
9196+00007be6@11068
9197+0000ff7e@11069
9198+0000bf9e@11070
9199+00003f9e@11072
9200+0000af1e@11073
9201+0000ab02@11074
9202+0000ab82@11075
9203+00002b00@11077
9204+0000ab80@11078
9205+0000eba4@11079
9206+0000eb24@11081
9207+0000eba4@11082
9208+0000fb24@11084
9209+0000fba4@11085
9210+00007ba6@11086
9211+0000fba6@11087
9212+0000ff3e@11088
9213+0000bfbe@11089
9214+00003fbe@11091
9215+0000af3e@11092
9216+0000ab82@11093
9217+0000ab80@11096
9218+0000aba4@11097
9219+0000eba4@11098
9220+0000eb24@11099
9221+00006ba4@11100
9222+0000eba4@11101
9223+0000fba4@11102
9224+0000fb24@11103
9225+0000fba4@11104
9226+00007ba6@11105
9227+0000fba6@11106
9228+0000f91e@11107
9229+0000b99e@11108
9230+0000a91e@11110
9231+0000abc2@11111
9232+00002b42@11114
9233+0000abc0@11115
9234+0000ebe0@11116
9235+0000ebc4@11117
9236+0000eb44@11118
9237+00006bc4@11119
9238+0000ebe4@11120
9239+0000fbe4@11121
9240+0000fb44@11122
9241+00007be6@11123
9242+0000fbe6@11124
9243+0000fb1e@11125
9244+0000f99e@11126
9245+0000799e@11128
9246+0000f91c@11129
9247+0000fbc0@11130
9248+0000ebc0@11131
9249+00006b40@11133
9250+0000ebc0@11134
9251+0000ebe4@11135
9252+00006be4@11137
9253+0000ebe4@11138
9254+0000fb64@11140
9255+0000fbe4@11141
9256+00007be6@11142
9257+0000fbe6@11143
9258+0000f91e@11144
9259+0000b99e@11145
9260+0000399e@11147
9261+0000a99e@11148
9262+0000abd2@11149
9263+00002bd2@11151
9264+0000abd0@11152
9265+0000abf0@11153
9266+0000ebf4@11154
9267+0000eb74@11155
9268+00006bf4@11156
9269+0000ebf4@11157
9270+0000fbf4@11158
9271+0000fb54@11159
9272+0000fbf4@11160
9273+00007bf6@11161
9274+0000fbf6@11162
9275+0000bb1e@11163
9276+0000bb9e@11164
9277+00003b9e@11165
9278+0000ab9e@11166
9279+0000abe2@11167
9280+00002b60@11170
9281+0000abe0@11171
9282+0000ebe4@11172
9283+0000eb64@11174
9284+00006be4@11175
9285+0000ebe4@11176
9286+0000fbe4@11177
9287+00007be6@11179
9288+0000fbe6@11180
9289+0000f17e@11181
9290+0000b1fe@11182
9291+000031fe@11184
9292+0000a17e@11185
9293+0000afc2@11186
9294+00002f40@11189
9295+0000afe4@11190
9296+0000efe4@11191
9297+00006fe4@11193
9298+0000efe4@11194
9299+0000ff64@11196
9300+0000ffe4@11197
9301+00007fe6@11198
9302+0000ffe6@11199
9303+0000b346@11200
9304+0000b3c6@11201
9305+00002346@11203
9306+0000abe6@11204
9307+0000abe2@11205
9308+00002b62@11207
9309+0000abe0@11208
9310+0000ebe4@11209
9311+0000eb64@11211
9312+00006be4@11212
9313+0000ebe4@11213
9314+0000fbe4@11214
9315+0000fb64@11215
9316+0000fbe4@11216
9317+00007be6@11217
9318+0000ff7e@11218
9319+0000b79e@11219
9320+0000379e@11221
9321+0000a71e@11222
9322+0000a992@11223
9323+00002910@11226
9324+0000a990@11227
9325+0000ebb4@11228
9326+0000eb94@11229
9327+0000eb34@11230
9328+0000e9b4@11231
9329+0000fb34@11233
9330+0000fbb4@11234
9331+00007bb6@11235
9332+0000fbb6@11236
9333+0000f73e@11237
9334+0000b7be@11238
9335+000037be@11240
9336+0000a73e@11241
9337+0000a992@11242
9338+0000a990@11245
9339+0000abb4@11246
9340+0000ebb4@11247
9341+0000eb34@11248
9342+00006bb4@11249
9343+0000ebb4@11250
9344+0000fb94@11251
9345+0000fb34@11252
9346+0000fbb4@11253
9347+00007bb6@11254
9348+0000fbb6@11255
9349+0000b922@11256
9350+0000b9a2@11257
9351+0000a9a2@11259
9352+0000abc2@11260
9353+00002b42@11263
9354+0000abc0@11264
9355+0000ebe0@11265
9356+0000ebe4@11266
9357+0000eb64@11267
9358+00006be4@11268
9359+0000ebe4@11269
9360+0000fbe4@11270
9361+0000fb44@11271
9362+00007be6@11272
9363+0000fbe6@11273
9364+0000fb62@11274
9365+0000f9a2@11275
9366+000079a2@11277
9367+0000e922@11278
9368+0000ebc2@11279
9369+00006b40@11282
9370+0000ebc0@11283
9371+0000ebe4@11284
9372+0000a9ec@11285
9373+000029ec@11286
9374+0000a9ec@11287
9375+0000b96c@11289
9376+0000b9ec@11290
9377+000079ee@11291
9378+0000f9ee@11292
9379+0000fb3e@11293
9380+0000bbbe@11294
9381+00003bbe@11296
9382+0000abbe@11297
9383+0000abe2@11298
9384+00002be2@11300
9385+0000abe0@11301
9386+0000ebe4@11303
9387+0000eb64@11304
9388+00006be4@11305
9389+0000ebe4@11306
9390+0000fbe4@11307
9391+0000fb64@11308
9392+0000fbe4@11309
9393+00007be6@11310
9394+0000fbe6@11311
9395+0000b91e@11312
9396+0000b99e@11313
9397+0000399e@11314
9398+0000a91e@11315
9399+0000abd2@11316
9400+00002b50@11319
9401+0000abd0@11320
9402+0000ebf4@11321
9403+0000ebd4@11322
9404+0000eb54@11323
9405+00006bf4@11324
9406+0000ebf4@11325
9407+0000fbf4@11326
9408+00007bf6@11328
9409+0000fbf6@11329
9410+0000fb42@11330
9411+0000b3c2@11331
9412+000033c2@11333
9413+0000a342@11334
9414+0000afc2@11335
9415+00002f40@11338
9416+0000afe4@11339
9417+0000efe4@11340
9418+0000ef64@11341
9419+00006fe4@11342
9420+0000efe4@11343
9421+0000efc0@11344
9422+0000ff64@11345
9423+0000ffe4@11346
9424+00007fe6@11347
9425+0000ffe6@11348
9426+0000b346@11349
9427+0000b3c6@11350
9428+00002346@11352
9429+0000abe6@11353
9430+0000abe2@11354
9431+00002b62@11356
9432+0000abe0@11357
9433+0000ebe4@11358
9434+0000eb64@11360
9435+00006be4@11361
9436+0000ebe4@11362
9437+0000fbe4@11363
9438+0000fb64@11364
9439+0000fbe4@11365
9440+00007be6@11366
9441+0000ff7e@11367
9442+0000bf9e@11368
9443+00003f9e@11370
9444+0000af1e@11371
9445+0000aba2@11372
9446+00002b20@11375
9447+0000aba0@11376
9448+0000eba4@11377
9449+0000eb24@11379
9450+0000eba4@11380
9451+0000fb24@11382
9452+0000fba4@11383
9453+00007ba6@11384
9454+0000fba6@11385
9455+0000f53e@11386
9456+0000b5be@11387
9457+000035be@11389
9458+0000a53e@11390
9459+0000a182@11391
9460+0000a100@11394
9461+0000a3a4@11395
9462+0000e3a4@11396
9463+0000e324@11397
9464+000063a4@11398
9465+0000e3a4@11399
9466+0000f184@11400
9467+0000f324@11401
9468+0000f3a4@11402
9469+000073a6@11403
9470+0000f3a6@11404
9471+0000f926@11405
9472+0000b9a6@11406
9473+0000a926@11408
9474+0000abe2@11409
9475+0000abc2@11410
9476+00002b42@11412
9477+0000abc0@11413
9478+0000ebe0@11414
9479+0000ebc4@11415
9480+0000eb44@11416
9481+00006be4@11417
9482+0000ebe4@11418
9483+0000fbe4@11419
9484+0000fb44@11420
9485+00007be6@11421
9486+0000fbe6@11422
9487+0000fb66@11423
9488+0000f9a6@11424
9489+000079a6@11426
9490+0000f926@11427
9491+0000ebc2@11428
9492+00006b40@11431
9493+0000ebc0@11432
9494+0000ebe4@11433
9495+0000a5e0@11434
9496+000025e0@11435
9497+0000a5e0@11436
9498+0000b560@11438
9499+0000b5e0@11439
9500+000075e2@11440
9501+0000f5e2@11441
9502+0000f91e@11442
9503+0000b99e@11443
9504+0000399e@11445
9505+0000a99e@11446
9506+0000abd2@11447
9507+00002bd2@11449
9508+0000abd0@11450
9509+0000abf4@11451
9510+0000ebf4@11452
9511+0000eb74@11453
9512+00006bf4@11454
9513+0000ebf4@11455
9514+0000fbf4@11456
9515+0000fb54@11457
9516+0000fbf4@11458
9517+00007bf6@11459
9518+0000fbf6@11460
9519+0000b91e@11461
9520+0000b99e@11462
9521+0000399e@11463
9522+0000a91e@11464
9523+0000abd2@11465
9524+00002b50@11468
9525+0000abd0@11469
9526+0000ebf4@11470
9527+0000eb74@11472
9528+00006bf4@11473
9529+0000ebf4@11474
9530+0000fbf4@11475
9531+00007bf6@11477
9532+0000fbf6@11478
9533+0000fb46@11479
9534+0000b3c6@11480
9535+000033c6@11482
9536+0000b346@11483
9537+0000afc2@11484
9538+00002f40@11487
9539+0000afe4@11488
9540+0000efe4@11489
9541+0000ef64@11490
9542+00006fe4@11491
9543+0000efe4@11492
9544+0000efc0@11493
9545+0000ff44@11494
9546+0000ffe4@11495
9547+00007fe6@11496
9548+0000ffe6@11497
9549+0000b346@11498
9550+0000b3c6@11499
9551+00002346@11501
9552+0000abe6@11502
9553+0000abe2@11503
9554+00002b62@11505
9555+0000abe0@11506
9556+0000ebe4@11507
9557+0000eb64@11509
9558+00006be4@11510
9559+0000ebe4@11511
9560+0000fbe4@11512
9561+0000fb64@11513
9562+0000fbe4@11514
9563+00007be6@11515
9564+0000ff7e@11516
9565+0000b5be@11517
9566+000035be@11519
9567+0000a53e@11520
9568+0000a102@11521
9569+0000a182@11522
9570+00002100@11524
9571+0000a180@11525
9572+0000e3a4@11526
9573+0000e324@11528
9574+0000e3a4@11529
9575+0000f324@11531
9576+0000f3a4@11532
9577+000073a6@11533
9578+0000f3a6@11534
9579+0000f53e@11535
9580+0000b5be@11536
9581+000035be@11538
9582+0000a53e@11539
9583+0000a182@11540
9584+0000a100@11543
9585+0000a3a4@11544
9586+0000e3a4@11545
9587+0000e324@11546
9588+000063a4@11547
9589+0000e3a4@11548
9590+0000f184@11549
9591+0000f104@11550
9592+0000f3a4@11551
9593+000073a6@11552
9594+0000f3a6@11553
9595+0000f92a@11554
9596+0000b9aa@11555
9597+0000a92a@11557
9598+0000abc2@11558
9599+00002b42@11561
9600+0000abc0@11562
9601+0000ebe0@11563
9602+0000ebe4@11564
9603+0000eb64@11565
9604+00006be4@11566
9605+0000ebe4@11567
9606+0000fbe4@11568
9607+0000fb64@11569
9608+00007be6@11570
9609+0000fbe6@11571
9610+0000fb6e@11572
9611+0000f9aa@11573
9612+000079aa@11575
9613+0000e92a@11576
9614+0000ebc2@11577
9615+00006b40@11580
9616+0000ebc0@11581
9617+0000ebe4@11582
9618+0000a5e0@11583
9619+000025e0@11584
9620+0000a5e0@11585
9621+0000b560@11587
9622+0000b5e0@11588
9623+000075e2@11589
9624+0000f5e2@11590
9625+0000f91e@11591
9626+0000b99e@11592
9627+0000399e@11594
9628+0000a99e@11595
9629+0000abd2@11596
9630+00002bd2@11598
9631+0000abd0@11599
9632+0000abf4@11600
9633+0000ebf4@11601
9634+0000eb74@11602
9635+00006bf4@11603
9636+0000ebf4@11604
9637+0000fbf4@11605
9638+0000fb54@11606
9639+0000fbf4@11607
9640+00007bf6@11608
9641+0000fbf6@11609
9642+0000b91e@11610
9643+0000b99e@11611
9644+0000399e@11612
9645+0000a91e@11613
9646+0000abd2@11614
9647+00002b50@11617
9648+0000abd0@11618
9649+0000ebf4@11619
9650+0000ebd4@11620
9651+0000eb54@11621
9652+00006bf4@11622
9653+0000ebf4@11623
9654+0000fbf4@11624
9655+00007bf6@11626
9656+0000fbf6@11627
9657+0000fb5a@11628
9658+0000b3ca@11629
9659+000033ca@11631
9660+0000a34a@11632
9661+0000afc2@11633
9662+00002f40@11636
9663+0000afe4@11637
9664+0000efe4@11638
9665+0000ef64@11639
9666+00006fe4@11640
9667+0000efe4@11641
9668+0000ffc0@11642
9669+0000ff64@11643
9670+0000ffe4@11644
9671+00007fe6@11645
9672+0000ffe6@11646
9673+0000b346@11647
9674+0000b3c6@11648
9675+00002346@11650
9676+0000abe6@11651
9677+0000abe2@11652
9678+00002b62@11654
9679+0000abe0@11655
9680+0000ebe4@11656
9681+0000eb64@11658
9682+00006be4@11659
9683+0000ebe4@11660
9684+0000fbe4@11661
9685+0000fb64@11662
9686+0000fbe4@11663
9687+00007be6@11664
9688+0000ff7e@11665
9689+0000b5be@11666
9690+000035be@11668
9691+0000a53e@11669
9692+0000a102@11670
9693+0000a182@11671
9694+00002100@11673
9695+0000a180@11674
9696+0000e3a4@11675
9697+0000e184@11676
9698+0000e324@11677
9699+0000e1a4@11678
9700+0000e3a4@11679
9701+0000f324@11680
9702+0000f3a4@11681
9703+000073a6@11682
9704+0000f3a6@11683
9705+0000f53e@11684
9706+0000b5be@11685
9707+000035be@11687
9708+0000a53e@11688
9709+0000a182@11689
9710+0000a180@11692
9711+0000a3a4@11693
9712+0000e3a4@11694
9713+0000e324@11695
9714+000061a4@11696
9715+0000e3a4@11697
9716+0000f384@11698
9717+0000f324@11699
9718+0000f3a4@11700
9719+000073a6@11701
9720+0000f3a6@11702
9721+0000f92e@11703
9722+0000b9ae@11704
9723+000039ae@11705
9724+0000a92e@11706
9725+0000abc2@11707
9726+00002b42@11710
9727+0000abc0@11711
9728+0000ebe0@11712
9729+0000ebe4@11713
9730+0000eb64@11714
9731+00006be4@11715
9732+0000ebe4@11716
9733+0000fbe4@11717
9734+0000fb44@11718
9735+00007be6@11719
9736+0000fbe6@11720
9737+0000fb2e@11721
9738+0000f9ae@11722
9739+000079ae@11724
9740+0000f92c@11725
9741+0000fbc0@11726
9742+0000ebc0@11727
9743+00006b40@11729
9744+0000ebc0@11730
9745+0000ebe4@11731
9746+00006be4@11733
9747+0000ebe4@11734
9748+0000fb64@11736
9749+0000fbe4@11737
9750+00007be6@11738
9751+0000fbe6@11739
9752+0000f91e@11740
9753+0000b99e@11741
9754+0000399e@11743
9755+0000a99e@11744
9756+0000abd2@11745
9757+00002bd2@11747
9758+0000abd0@11748
9759+0000abf4@11749
9760+0000ebf4@11750
9761+0000eb74@11751
9762+00006bf4@11752
9763+0000ebf4@11753
9764+0000fbf4@11754
9765+0000fb54@11755
9766+0000fbf4@11756
9767+00007bf6@11757
9768+0000fbf6@11758
9769+0000b91e@11759
9770+0000b99e@11760
9771+0000399e@11761
9772+0000a91e@11762
9773+0000abd2@11763
9774+00002b50@11766
9775+0000abd0@11767
9776+0000ebf4@11768
9777+0000ebd4@11769
9778+0000eb74@11770
9779+00006bf4@11771
9780+0000ebf4@11772
9781+0000fbf4@11773
9782+00007bf6@11775
9783+0000fbf6@11776
9784+0000f35e@11777
9785+0000b3ce@11778
9786+000033ce@11780
9787+0000a34e@11781
9788+0000afc2@11782
9789+00002f40@11785
9790+0000afe4@11786
9791+0000efe4@11787
9792+0000ef64@11788
9793+00006fe4@11789
9794+0000efe4@11790
9795+0000efc4@11791
9796+0000ff64@11792
9797+0000ffe4@11793
9798+00007fe6@11794
9799+0000ffe6@11795
9800+0000b346@11796
9801+0000b3c6@11797
9802+00002346@11799
9803+0000abe6@11800
9804+0000abe2@11801
9805+00002b62@11803
9806+0000abe0@11804
9807+0000ebe4@11805
9808+0000eb64@11807
9809+00006be4@11808
9810+0000ebe4@11809
9811+0000fbe4@11810
9812+0000fb64@11811
9813+0000fbe4@11812
9814+0000fbe6@11813
9815+0000ff7e@11814
9816+0000b5be@11815
9817+000035be@11817
9818+0000a53e@11818
9819+0000a102@11819
9820+0000a182@11820
9821+00002100@11822
9822+0000a180@11823
9823+0000e3a4@11824
9824+0000e1a4@11825
9825+0000e324@11826
9826+0000e3a4@11827
9827+0000f324@11829
9828+0000f3a4@11830
9829+000073a6@11831
9830+0000f3a6@11832
9831+0000f53e@11833
9832+0000b5be@11834
9833+000035be@11836
9834+0000a53e@11837
9835+0000a182@11838
9836+0000a180@11841
9837+0000a3a4@11842
9838+0000e3a4@11843
9839+0000e324@11844
9840+000061a4@11845
9841+0000e3a4@11846
9842+0000f384@11847
9843+0000f304@11848
9844+0000f3a4@11849
9845+000073a6@11850
9846+0000f3a6@11851
9847+0000f932@11852
9848+0000b9b2@11853
9849+000039b2@11854
9850+0000a9b2@11855
9851+0000abc2@11856
9852+00002b42@11859
9853+0000abc0@11860
9854+0000ebe0@11861
9855+0000ebc4@11862
9856+0000eb44@11863
9857+00006bc4@11864
9858+0000ebe4@11865
9859+0000fbe4@11866
9860+0000fbc4@11867
9861+00007be6@11868
9862+0000fbe6@11869
9863+0000fb72@11870
9864+0000f9b2@11871
9865+000079b2@11873
9866+0000e932@11874
9867+0000ebc2@11875
9868+00006b40@11878
9869+0000ebc0@11879
9870+0000ebe4@11880
9871+0000a5e0@11881
9872+000025e0@11882
9873+0000a5e0@11883
9874+0000b560@11885
9875+0000b5e0@11886
9876+000075e2@11887
9877+0000f5e2@11888
9878+0000f91e@11889
9879+0000b99e@11890
9880+0000399e@11892
9881+0000a99e@11893
9882+0000abd2@11894
9883+00002bd2@11896
9884+0000ab50@11897
9885+0000abf4@11898
9886+0000ebf4@11899
9887+0000eb74@11900
9888+00006bf4@11901
9889+0000ebf4@11902
9890+0000fbf4@11903
9891+0000fb54@11904
9892+0000fbf4@11905
9893+00007bf6@11906
9894+0000fbf6@11907
9895+0000b91e@11908
9896+0000b99e@11909
9897+0000399e@11910
9898+0000a91e@11911
9899+0000abd2@11912
9900+00002b50@11915
9901+0000abd0@11916
9902+0000ebf4@11917
9903+0000ebd4@11918
9904+0000eb54@11919
9905+00006bf4@11920
9906+0000ebf4@11921
9907+0000fbf4@11922
9908+00007bf6@11924
9909+0000fbf6@11925
9910+0000f352@11926
9911+0000b3d2@11927
9912+000033d2@11929
9913+0000a352@11930
9914+0000afc2@11931
9915+00002f40@11934
9916+0000afe4@11935
9917+0000efe4@11936
9918+0000ef64@11937
9919+00006fe4@11938
9920+0000efe4@11939
9921+0000efc0@11940
9922+0000ff44@11941
9923+0000ffe4@11942
9924+00007fe6@11943
9925+0000ffe6@11944
9926+0000b346@11945
9927+0000b3c6@11946
9928+00002346@11948
9929+0000abe6@11949
9930+0000abe2@11950
9931+00002b62@11952
9932+0000abe0@11953
9933+0000ebe4@11954
9934+0000eb64@11956
9935+00006be4@11957
9936+0000ebe4@11958
9937+0000fbe4@11959
9938+0000fb64@11960
9939+0000fbe4@11961
9940+0000fbe6@11962
9941+0000ff7e@11963
9942+0000b5be@11964
9943+000035be@11966
9944+0000a53e@11967
9945+0000a102@11968
9946+0000a182@11969
9947+00002100@11971
9948+0000a180@11972
9949+0000e3a4@11973
9950+0000e1a4@11974
9951+0000e304@11975
9952+0000e1a4@11976
9953+0000e3a4@11977
9954+0000f324@11978
9955+0000f3a4@11979
9956+000073a6@11980
9957+0000f3a6@11981
9958+0000f53e@11982
9959+0000b5be@11983
9960+000035be@11985
9961+0000a53e@11986
9962+0000a182@11987
9963+0000a180@11990
9964+0000a3a4@11991
9965+0000e3a4@11992
9966+0000e324@11993
9967+000063a4@11994
9968+0000e3a4@11995
9969+0000f184@11996
9970+0000f304@11997
9971+0000f3a4@11998
9972+000073a6@11999
9973+0000f3a6@12000
9974+0000f936@12001
9975+0000b9b6@12002
9976+000039b6@12003
9977+0000a936@12004
9978+0000abc2@12005
9979+00002b42@12008
9980+0000abc0@12009
9981+0000ebe0@12010
9982+0000ebc4@12011
9983+0000eb44@12012
9984+00006be4@12013
9985+0000ebe4@12014
9986+0000fbe4@12015
9987+0000fb64@12016
9988+00007be6@12017
9989+0000fbe6@12018
9990+0000fb76@12019
9991+0000f9b6@12020
9992+000079b6@12022
9993+0000e936@12023
9994+0000ebc2@12024
9995+00006b40@12027
9996+0000ebc0@12028
9997+0000ebe4@12029
9998+0000a5e0@12030
9999+000025e0@12031
10000+0000a5e0@12032
10001+0000b560@12034
10002+0000b5e0@12035
10003+000075e2@12036
10004+0000f5e2@12037
10005+0000f91e@12038
10006+0000b99e@12039
10007+0000399e@12041
10008+0000a99e@12042
10009+0000abd2@12043
10010+00002bd2@12045
10011+0000abd0@12046
10012+0000abf4@12047
10013+0000ebf4@12048
10014+0000eb74@12049
10015+00006bf4@12050
10016+0000ebf4@12051
10017+0000fbf4@12052
10018+0000fb54@12053
10019+0000fbf4@12054
10020+00007bf6@12055
10021+0000fbf6@12056
10022+0000b33e@12057
10023+0000b3be@12058
10024+000033be@12059
10025+0000a33e@12060
10026+0000abd2@12061
10027+00002b50@12064
10028+0000abd0@12065
10029+0000ebf4@12066
10030+0000eb54@12068
10031+00006bf4@12069
10032+0000ebf4@12070
10033+0000fbf4@12071
10034+00007bf6@12073
10035+0000fbf6@12074
10036+0000f356@12075
10037+0000b3d6@12076
10038+000033d6@12078
10039+0000a356@12079
10040+0000afc2@12080
10041+00002f40@12083
10042+0000afe4@12084
10043+0000efe4@12085
10044+0000ef64@12086
10045+00006fe4@12087
10046+0000efe4@12088
10047+0000ffc4@12089
10048+0000ff44@12090
10049+0000ffe4@12091
10050+00007fe6@12092
10051+0000ffe6@12093
10052+0000b346@12094
10053+0000b3c6@12095
10054+000033c6@12097
10055+0000abe6@12098
10056+0000abe2@12099
10057+00002b62@12101
10058+0000abe0@12102
10059+0000ebe4@12103
10060+0000eb64@12105
10061+00006be4@12106
10062+0000ebe4@12107
10063+0000fbe4@12108
10064+0000fb64@12109
10065+0000fbe4@12110
10066+0000fbe6@12111
10067+0000ff7e@12112
10068+0000b5be@12113
10069+000035be@12115
10070+0000a53e@12116
10071+0000a102@12117
10072+0000a182@12118
10073+00002100@12120
10074+0000a180@12121
10075+0000e3a4@12122
10076+0000e1a4@12125
10077+0000f324@12127
10078+0000f3a4@12128
10079+000073a6@12129
10080+0000f3a6@12130
10081+0000f53e@12131
10082+0000b5be@12132
10083+000035be@12134
10084+0000a53e@12135
10085+0000a182@12136
10086+0000a180@12139
10087+0000a3a4@12140
10088+0000e3a4@12141
10089+0000e324@12142
10090+000063a4@12143
10091+0000e3a4@12144
10092+0000f384@12145
10093+0000f304@12146
10094+0000f3a4@12147
10095+000073a6@12148
10096+0000f3a6@12149
10097+0000f93a@12150
10098+0000b9ba@12151
10099+000039ba@12152
10100+0000a93a@12153
10101+0000abc2@12154
10102+00002b42@12157
10103+0000abc0@12158
10104+0000ebe0@12159
10105+0000ebe4@12160
10106+0000eb64@12161
10107+00006be4@12162
10108+0000ebe4@12163
10109+0000fbe4@12164
10110+0000fb64@12165
10111+00007be6@12166
10112+0000fbe6@12167
10113+0000fb7a@12168
10114+0000f9ba@12169
10115+000079ba@12171
10116+0000e93a@12172
10117+0000ebc2@12173
10118+00006b40@12176
10119+0000ebc0@12177
10120+0000ebe4@12178
10121+0000a3a4@12179
10122+000023a4@12180
10123+0000a3a4@12181
10124+0000b324@12183
10125+0000b3a4@12184
10126+000073a6@12185
10127+0000f3a6@12186
10128+0000f9fe@12187
10129+0000b9fe@12188
10130+0000397e@12190
10131+0000a9fe@12191
10132+0000a182@12192
10133+00002182@12194
10134+0000a180@12195
10135+0000a184@12196
10136+0000e380@12197
10137+0000e324@12198
10138+00006184@12199
10139+0000e3a4@12200
10140+0000f3a4@12201
10141+0000f104@12202
10142+0000f3a4@12203
10143+000073a6@12204
10144+0000f3a6@12205
10145+0000f11e@12206
10146+0000b19e@12207
10147+0000319e@12208
10148+0000a11e@12209
10149+0000a182@12210
10150+00002100@12213
10151+0000a180@12214
10152+0000e3a4@12215
10153+0000e384@12216
10154+0000e304@12217
10155+000061a4@12218
10156+0000e3a4@12219
10157+0000f3a4@12220
10158+000073a6@12222
10159+0000f3a6@12223
10160+0000f37a@12224
10161+0000b3da@12225
10162+000033da@12227
10163+0000a35a@12228
10164+0000afc2@12229
10165+00002f40@12232
10166+0000afe4@12233
10167+0000efe4@12234
10168+0000ef64@12235
10169+00006fe4@12236
10170+0000efe4@12237
10171+0000efc0@12238
10172+0000ff64@12239
10173+0000ffe4@12240
10174+00007fe6@12241
10175+0000ffe6@12242
10176+0000b346@12243
10177+0000b3c6@12244
10178+0000a346@12246
10179+0000abe6@12247
10180+0000abe2@12248
10181+00002b62@12250
10182+0000abe0@12251
10183+0000ebe4@12252
10184+0000eb64@12254
10185+00006be4@12255
10186+0000ebe4@12256
10187+0000fbe4@12257
10188+0000fb64@12258
10189+0000fbe4@12259
10190+0000fbe6@12260
10191+0000ff7e@12261
10192+0000b5be@12262
10193+000035be@12264
10194+0000a53e@12265
10195+0000a102@12266
10196+0000a182@12267
10197+00002100@12269
10198+0000a180@12270
10199+0000e3a4@12271
10200+0000e384@12272
10201+0000e324@12273
10202+0000e3a4@12274
10203+0000f324@12276
10204+0000f3a4@12277
10205+000073a6@12278
10206+0000f3a6@12279
10207+0000f53e@12280
10208+0000b5be@12281
10209+000035be@12283
10210+0000a53e@12284
10211+0000a182@12285
10212+0000a182@12288
+9716,
-0
1@@ -0,0 +1,9716 @@
2+;Size: 9708
3+;Rate: 50000000
4+;Channels: 16
5+;EnabledChannels: 65535
6+;TriggerPosition: 119
7+;Compressed: true
8+;AbsoluteLength: 12287
9+;CursorEnabled: true
10+0000e08a@0
11+0000e00a@1
12+0000600a@2
13+0000e088@3
14+0000a080@5
15+0000a000@6
16+00002000@7
17+0000a080@8
18+0000b080@9
19+00003002@11
20+0000f002@12
21+0000f082@13
22+0000f002@15
23+00007002@16
24+0000e082@17
25+0000e08a@18
26+0000e00a@20
27+00006008@21
28+0000e088@22
29+0000a080@24
30+00002000@25
31+0000a000@26
32+0000a080@27
33+0000b080@28
34+0000b000@29
35+00007002@30
36+0000f082@31
37+0000f002@34
38+00007002@35
39+0000e082@36
40+0000e08a@37
41+0000600a@39
42+0000e008@40
43+0000e088@41
44+0000a088@42
45+0000a000@43
46+00002000@44
47+0000a080@45
48+0000b080@46
49+0000b000@48
50+00007002@49
51+0000f082@50
52+00007002@53
53+0000e002@54
54+0000e08a@55
55+0000e00a@57
56+00006008@58
57+0000e088@59
58+0000a080@61
59+0000a000@62
60+00002000@63
61+0000a080@64
62+0000b080@65
63+00003002@67
64+0000f002@68
65+0000f082@69
66+0000f002@71
67+00007082@72
68+0000e082@73
69+0000e08a@74
70+0000e00a@75
71+0000e08a@76
72+00006088@77
73+0000e088@78
74+0000e008@79
75+0000a000@80
76+00002080@81
77+0000a080@82
78+0000b000@83
79+0000b080@85
80+00007082@86
81+0000f082@87
82+0000f002@88
83+0000f082@90
84+00007082@91
85+0000e08a@92
86+0000e00a@93
87+0000608a@95
88+0000e088@96
89+0000e008@97
90+0000a008@98
91+0000a080@99
92+00002080@100
93+0000a080@101
94+0000b000@102
95+0000b080@104
96+00007082@105
97+0000f282@106
98+0000f202@107
99+00007282@109
100+0000e282@110
101+0000ea72@111
102+0000eaf2@113
103+00006af0@114
104+0000eaf0@115
105+0000e040@116
106+0000e0c0@118
107+0000c0c0@119
108+0000d040@121
109+000070c2@123
110+0000f0c2@124
111+0000f202@125
112+0000f282@127
113+00007282@128
114+0000e282@129
115+0000ea76@130
116+0000eaf6@132
117+0000eaf4@133
118+0000ee7c@134
119+00004efc@137
120+0000cefc@138
121+0000de7c@139
122+0000defc@141
123+00007efe@142
124+0000fefe@143
125+0000f202@144
126+0000f282@146
127+0000e282@147
128+0000ea7a@148
129+0000eafa@149
130+00006afa@151
131+0000ea78@152
132+0000e0c0@153
133+00004040@156
134+0000c040@157
135+0000d0c0@158
136+000070c2@160
137+0000f042@161
138+0000f202@162
139+0000f282@163
140+00007202@165
141+0000e202@166
142+0000eafe@167
143+00006a7c@170
144+0000ea7c@171
145+0000eefc@172
146+00006efc@174
147+0000ce7c@175
148+0000defc@177
149+00007e7e@179
150+0000fe7e@180
151+0000f206@181
152+0000f286@182
153+00007206@184
154+0000e206@185
155+0000eaf2@186
156+00006af2@188
157+0000ea70@189
158+0000eac0@190
159+0000e0c0@191
160+00004040@193
161+0000c040@194
162+0000d0c0@195
163+00007042@198
164+0000f042@199
165+0000f286@200
166+00007286@202
167+0000e206@203
168+0000ea76@204
169+0000eaf6@205
170+00006a74@207
171+0000ea74@208
172+0000eefc@209
173+00004e7c@212
174+0000ce7c@213
175+0000defc@214
176+00007efe@216
177+0000fe7e@217
178+0000f286@218
179+00007206@221
180+0000e206@222
181+0000eafa@223
182+00006a78@226
183+0000eaf8@227
184+0000e0c0@228
185+0000e040@229
186+000040c0@230
187+0000c0c0@231
188+0000d040@233
189+000070c2@235
190+0000f0c2@236
191+0000f386@237
192+0000f306@238
193+0000f386@240
194+0000ebfe@241
195+0000eb7e@243
196+00006b7e@244
197+0000ebfc@245
198+0000effc@246
199+0000ef7c@247
200+00004ffc@249
201+0000cffc@250
202+0000dffc@251
203+0000df7c@252
204+0000fffe@254
205+0000f386@256
206+0000f306@257
207+00007386@258
208+0000f384@259
209+0000fbfc@260
210+0000eb7c@261
211+00006bfc@263
212+0000ebfc@264
213+0000eb7c@266
214+0000ebfc@268
215+0000fbfc@270
216+0000fb7c@271
217+00007bfe@272
218+0000fbfe@273
219+0000f38a@274
220+0000f30a@275
221+0000738a@277
222+0000e38a@278
223+0000ebf2@279
224+0000eb72@280
225+0000ebf0@282
226+0000e1c0@284
227+0000e140@285
228+000041c0@286
229+0000c1c0@287
230+0000d1c0@288
231+0000d140@289
232+000071c2@291
233+0000f1c2@292
234+0000f38a@293
235+0000f30a@294
236+0000730a@295
237+0000e38a@296
238+0000ebf6@297
239+0000eb76@299
240+00006b76@300
241+0000ebf4@301
242+0000effc@302
243+0000ef7c@303
244+0000effc@304
245+00004ffc@305
246+0000cffc@306
247+0000df7c@307
248+0000dffc@308
249+00007ffe@309
250+0000ff7e@310
251+0000fffe@311
252+0000f38a@312
253+0000730a@314
254+0000e38a@315
255+0000ebfa@316
256+0000eb7a@318
257+00006bf8@319
258+0000ebf8@320
259+0000e140@321
260+0000e1c0@322
261+000061c0@323
262+0000c1c0@324
263+0000c140@325
264+0000d1c0@326
265+000071c2@328
266+0000f142@329
267+0000f38a@330
268+0000730a@333
269+0000e38a@334
270+0000ebfe@335
271+00006bfe@337
272+0000ebfc@338
273+0000effc@339
274+0000ef7c@340
275+0000effc@341
276+00004ffc@342
277+0000cffc@343
278+0000df7c@344
279+0000dffc@345
280+00007ffe@347
281+0000fffe@348
282+0000f38e@349
283+0000738e@351
284+0000e38e@352
285+0000ebf2@353
286+0000eb72@355
287+00006bf0@356
288+0000ebf0@357
289+0000e140@358
290+0000e1c0@360
291+000041c0@361
292+0000c1c0@362
293+0000d1c0@363
294+000071c2@365
295+0000f142@366
296+0000f38e@367
297+0000730e@370
298+0000e38e@371
299+0000ebf6@372
300+0000eb76@374
301+00006bf4@375
302+0000effc@376
303+00004ffc@379
304+0000cffc@380
305+0000cf7c@381
306+0000dffc@382
307+00007ffe@384
308+0000ff7e@385
309+0000f30e@386
310+0000f38e@387
311+0000e30e@389
312+0000ebfe@390
313+0000ebfa@391
314+00006bfa@393
315+0000ebf8@394
316+0000e1c0@395
317+0000e140@396
318+0000e1c0@397
319+000041c0@398
320+0000c1c0@399
321+0000d140@400
322+0000d1c0@401
323+0000f1c2@403
324+0000f3ce@404
325+0000f38e@405
326+0000730e@407
327+0000e38e@408
328+0000ebfe@409
329+0000eb7e@411
330+00006bfc@412
331+0000ebfc@413
332+0000effc@414
333+0000ef7c@415
334+0000effc@416
335+0000cffc@417
336+0000cf7c@418
337+0000dffc@419
338+00007ffe@421
339+0000ff7e@422
340+0000f312@423
341+0000f392@424
342+00007312@426
343+0000e392@427
344+0000ebf2@428
345+0000ebf0@431
346+0000e140@433
347+0000e1c0@434
348+000041c0@435
349+0000c1c0@436
350+0000d140@437
351+0000d1c0@438
352+000071c2@440
353+0000f142@441
354+0000f392@442
355+00007392@444
356+0000e392@445
357+0000ebf6@446
358+0000eb76@448
359+00006bf6@449
360+0000ebf4@450
361+0000effc@451
362+0000ef7c@452
363+0000effc@453
364+00004ffc@454
365+0000cffc@455
366+0000df7c@456
367+0000dffc@457
368+00007ffe@458
369+0000ff7e@459
370+0000fffe@460
371+0000f392@461
372+00007312@463
373+0000e392@464
374+0000ebfa@465
375+0000eb7a@467
376+00006bf8@468
377+0000ebf8@469
378+0000e140@470
379+0000e1c0@471
380+000061c0@472
381+0000c1c0@473
382+0000c140@474
383+0000d1c0@475
384+000071c2@477
385+0000f142@478
386+0000f392@479
387+00007312@482
388+0000e392@483
389+0000ebfe@484
390+00006bfe@486
391+0000ebfc@487
392+0000effc@488
393+0000ef7c@489
394+0000effc@490
395+00004ffc@491
396+0000cffc@492
397+0000df7c@493
398+0000dffc@494
399+00007ffe@496
400+0000fffe@497
401+0000f396@498
402+00007396@500
403+0000e396@501
404+0000ebf2@502
405+0000eb72@504
406+00006bf0@505
407+0000ebf0@506
408+0000e140@507
409+0000e1c0@509
410+000041c0@510
411+0000c1c0@511
412+0000d1c0@512
413+000071c2@514
414+0000f142@515
415+0000f396@516
416+00007316@519
417+0000e396@520
418+0000ebf6@521
419+0000eb76@523
420+00006bf4@524
421+0000effc@525
422+00004ffc@528
423+0000cffc@529
424+0000df7c@530
425+0000dffc@531
426+00007ffe@533
427+0000ff7e@534
428+0000f316@535
429+0000f396@536
430+0000e316@538
431+0000ebfe@539
432+0000ebfa@540
433+00006bfa@542
434+0000ebf8@543
435+0000e1c0@544
436+0000e140@545
437+0000e1c0@546
438+000041c0@547
439+0000c1c0@548
440+0000d140@549
441+0000d1c0@550
442+0000f1c2@552
443+0000f3d6@553
444+0000f396@554
445+00007316@556
446+0000e396@557
447+0000ebfe@558
448+0000eb7e@560
449+00006bfc@561
450+0000ebfc@562
451+0000effc@563
452+0000ef7c@564
453+0000effc@565
454+0000cffc@566
455+0000cf7c@567
456+0000dffc@568
457+00007ffe@570
458+0000ff7e@571
459+0000f39a@572
460+0000731a@575
461+0000e39a@576
462+0000ebf2@577
463+0000ebf0@580
464+0000e140@582
465+0000e1c0@583
466+000041c0@584
467+0000c1c0@585
468+0000d140@586
469+0000d1c0@587
470+000071c2@589
471+0000f142@590
472+0000f39a@591
473+0000739a@593
474+0000e39a@594
475+0000ebf6@595
476+0000eb76@597
477+00006bf6@598
478+0000ebf4@599
479+0000effc@600
480+0000ef7c@601
481+0000effc@602
482+00004ffc@603
483+0000cffc@604
484+0000df7c@605
485+0000dffc@606
486+00007ffe@607
487+0000ff7e@608
488+0000fbfe@609
489+0000f39a@610
490+0000731a@612
491+0000e39a@613
492+0000ebfa@614
493+0000eb7a@616
494+00006bf8@617
495+0000ebf8@618
496+0000e140@619
497+0000e1c0@620
498+000061c0@621
499+0000c1c0@622
500+0000c140@623
501+0000d1c0@624
502+000071c2@626
503+0000f142@627
504+0000f39a@628
505+0000731a@631
506+0000e39a@632
507+0000ebfe@633
508+00006bfe@635
509+0000ebfc@636
510+0000effc@637
511+0000ef7c@638
512+0000effc@639
513+00004ffc@640
514+0000cffc@641
515+0000df7c@642
516+0000dffc@643
517+00007ffe@645
518+0000fffe@646
519+0000f39e@647
520+0000739e@649
521+0000e39e@650
522+0000ebf2@651
523+0000eb72@653
524+00006bf0@654
525+0000ebf0@655
526+0000e140@656
527+0000e1c0@658
528+000041c0@659
529+0000c1c0@660
530+0000d1c0@661
531+000071c2@663
532+0000f142@664
533+0000f39e@665
534+0000731e@668
535+0000e39e@669
536+0000ebf6@670
537+0000eb76@672
538+00006bf4@673
539+0000effc@674
540+00004ffc@677
541+0000cffc@678
542+0000cf7c@679
543+0000dffc@680
544+00007ffe@682
545+0000ff7e@683
546+0000f39e@684
547+0000e39e@687
548+0000ebfe@688
549+0000ebfa@689
550+0000eb7a@690
551+00006bfa@691
552+0000ebf8@692
553+0000e1c0@693
554+0000e140@694
555+0000e1c0@695
556+000041c0@696
557+0000c1c0@697
558+0000d140@698
559+0000d1c0@699
560+0000f1c2@701
561+0000f35e@702
562+0000f39e@703
563+0000731e@705
564+0000e39e@706
565+0000ebfe@707
566+0000eb7e@709
567+00006bfc@710
568+0000ebfc@711
569+0000effc@712
570+0000ef7c@713
571+0000effc@714
572+0000cffc@715
573+0000cf7c@716
574+0000dffc@717
575+00007ffe@719
576+0000ff7e@720
577+0000f322@721
578+0000f3a2@722
579+00007322@724
580+0000e3a2@725
581+0000ebf2@726
582+0000ebf0@729
583+0000e140@731
584+0000e1c0@732
585+000041c0@733
586+0000c1c0@734
587+0000d140@735
588+0000d1c0@736
589+000071c2@738
590+0000f142@739
591+0000f3a2@740
592+000073a2@742
593+0000e3a2@743
594+0000ebf6@744
595+0000eb76@746
596+00006bf6@747
597+0000ebf4@748
598+0000effc@749
599+0000ef7c@750
600+0000effc@751
601+00004ffc@752
602+0000cffc@753
603+0000dffc@754
604+00007ffe@756
605+0000ff7e@757
606+0000fff6@758
607+0000f3a2@759
608+00007322@761
609+0000e3a2@762
610+0000ebfa@763
611+0000eb7a@765
612+00006bf8@766
613+0000ebf8@767
614+0000e140@768
615+0000e1c0@769
616+000061c0@770
617+0000c1c0@771
618+0000c140@772
619+0000d1c0@773
620+000071c2@775
621+0000f142@776
622+0000f3a2@777
623+00007322@780
624+0000e3a2@781
625+0000ebfe@782
626+00006bfe@784
627+0000ebfc@785
628+0000effc@786
629+0000ef7c@787
630+0000effc@788
631+00004ffc@789
632+0000cffc@790
633+0000df7c@791
634+0000dffc@792
635+00007ffe@794
636+0000fffe@795
637+0000f3a6@796
638+000073a6@798
639+0000e3a6@799
640+0000ebf2@800
641+0000eb72@802
642+00006bf0@803
643+0000ebf0@804
644+0000e140@805
645+0000e1c0@807
646+000041c0@808
647+0000c1c0@809
648+0000d1c0@810
649+000071c2@812
650+0000f142@813
651+0000f3a6@814
652+00007326@817
653+0000e3a6@818
654+0000ebf6@819
655+0000eb76@821
656+00006bf4@822
657+0000effc@823
658+0000ef7c@824
659+0000effc@825
660+00004ffc@826
661+0000cffc@827
662+0000df7c@828
663+0000dffc@829
664+00007ffe@831
665+0000ff7e@832
666+0000f326@833
667+0000f3a6@834
668+0000e3a6@836
669+0000ebfe@837
670+0000ebfa@838
671+00006bfa@840
672+0000ebf8@841
673+0000e1c0@842
674+0000e140@843
675+0000e1c0@844
676+000041c0@845
677+0000c1c0@846
678+0000d140@847
679+0000d1c0@848
680+0000f1c2@850
681+0000f3e6@851
682+0000f3a6@852
683+00007326@854
684+0000f3a4@855
685+0000fbf8@856
686+0000ebf8@857
687+0000eb78@858
688+00006bf8@859
689+0000ebf8@860
690+0000effc@861
691+0000eb7c@862
692+0000effc@863
693+0000ebfc@864
694+0000eb7c@865
695+0000fffc@866
696+00007bfe@868
697+0000ff7e@869
698+0000f3a6@870
699+00007326@873
700+0000e3a6@874
701+0000ebfe@875
702+0000ebfc@878
703+0000effc@879
704+0000ef7c@880
705+0000effc@881
706+00004ffc@882
707+0000cffc@883
708+0000df7c@884
709+0000dffc@885
710+00007ffe@887
711+0000ff7e@888
712+0000f3aa@889
713+0000e3aa@892
714+0000ebf2@893
715+0000eb72@895
716+00006bf2@896
717+0000ebf0@897
718+0000e1c0@898
719+0000e140@899
720+0000e1c0@900
721+000041c0@901
722+0000c1c0@902
723+0000d140@903
724+0000d1c0@904
725+000071c2@905
726+0000f142@906
727+0000f36a@907
728+0000f3aa@908
729+0000732a@910
730+0000e3aa@911
731+0000ebf6@912
732+0000eb76@914
733+00006bf4@915
734+0000ebf4@916
735+0000effc@917
736+00006ffc@919
737+0000cffc@920
738+0000cf7c@921
739+0000dffc@922
740+00007ffe@924
741+0000ff7e@925
742+0000f32a@926
743+0000f3aa@927
744+0000732a@929
745+0000e3aa@930
746+0000ebfa@931
747+00006bfa@933
748+0000ebf8@934
749+0000e9c0@935
750+0000e140@936
751+0000e1c0@937
752+000041c0@938
753+0000c1c0@939
754+0000d140@940
755+0000d1c0@941
756+000071c2@943
757+0000f1c2@944
758+0000f3aa@945
759+000073aa@947
760+0000e3aa@948
761+0000ebfe@949
762+0000eb7e@951
763+00006bfc@952
764+0000ebfc@953
765+0000effc@954
766+0000ef7c@955
767+0000effc@956
768+00004ffc@957
769+0000cffc@958
770+0000dffc@959
771+00007ffe@961
772+0000ff7e@962
773+0000f3ae@963
774+0000732e@966
775+0000e3ae@967
776+0000ebf2@968
777+0000eb72@970
778+00006bf0@971
779+0000ebf0@972
780+0000e1c0@973
781+000041c0@975
782+0000c1c0@976
783+0000d140@977
784+0000d1c0@978
785+000071c2@980
786+0000f142@981
787+0000f3ae@982
788+0000e3ae@985
789+0000ebfe@986
790+0000ebf6@987
791+0000eb76@988
792+00006bf6@989
793+0000ebf4@990
794+0000effc@991
795+0000ef7c@992
796+0000effc@993
797+00004ffc@994
798+0000cffc@995
799+0000df7c@996
800+0000dffc@997
801+0000fffe@999
802+0000f3ae@1001
803+000073ae@1003
804+0000e3ae@1004
805+0000ebfa@1005
806+0000eb7a@1007
807+00006bf8@1008
808+0000ebf8@1009
809+0000e140@1010
810+0000e1c0@1011
811+0000c1c0@1013
812+0000c140@1014
813+0000d1c0@1015
814+000071c2@1017
815+0000f142@1018
816+0000f3ae@1019
817+0000732e@1022
818+0000e3ae@1023
819+0000ebfe@1024
820+0000ebfc@1027
821+0000effc@1028
822+0000ef7c@1029
823+0000effc@1030
824+00004ffc@1031
825+0000cffc@1032
826+0000df7c@1033
827+0000dffc@1034
828+00007ffe@1036
829+0000ff7e@1037
830+0000f3b2@1038
831+000073b2@1040
832+0000e3b2@1041
833+0000ebf2@1042
834+0000eb72@1044
835+00006bf2@1045
836+0000ebf0@1046
837+0000e1c0@1047
838+0000e140@1048
839+0000e1c0@1049
840+000041c0@1050
841+0000c1c0@1051
842+0000d140@1052
843+0000d1c0@1053
844+000071c2@1054
845+0000f142@1055
846+0000f372@1056
847+0000f3b2@1057
848+00007332@1059
849+0000e3b2@1060
850+0000ebf6@1061
851+0000eb76@1063
852+00006bf4@1064
853+0000ebf4@1065
854+0000effc@1066
855+00006ffc@1068
856+0000cffc@1069
857+0000cf7c@1070
858+0000dffc@1071
859+00007ffe@1073
860+0000ff7e@1074
861+0000f332@1075
862+0000f3b2@1076
863+00007332@1078
864+0000e3b2@1079
865+0000ebfa@1080
866+00006bfa@1082
867+0000ebf8@1083
868+0000e9c0@1084
869+0000e140@1085
870+0000e1c0@1086
871+000041c0@1087
872+0000c1c0@1088
873+0000d140@1089
874+0000d1c0@1090
875+000071c2@1092
876+0000f1c2@1093
877+0000f3b2@1094
878+000073b2@1096
879+0000e3b2@1097
880+0000ebfe@1098
881+0000eb7e@1100
882+00006bfc@1101
883+0000ebfc@1102
884+0000effc@1103
885+0000ef7c@1104
886+0000effc@1105
887+00004ffc@1106
888+0000cffc@1107
889+0000dffc@1108
890+00007ffe@1110
891+0000ff7e@1111
892+0000f3b6@1112
893+00007336@1115
894+0000e3b6@1116
895+0000ebf2@1117
896+0000eb72@1119
897+00006bf0@1120
898+0000ebf0@1121
899+0000e1c0@1122
900+000041c0@1124
901+0000c1c0@1125
902+0000d140@1126
903+0000d1c0@1127
904+000071c2@1129
905+0000f142@1130
906+0000f3b6@1131
907+0000e3b6@1134
908+0000ebf6@1135
909+0000eb76@1137
910+00006bf6@1138
911+0000ebf4@1139
912+0000effc@1140
913+0000ef7c@1141
914+0000effc@1142
915+00004ffc@1143
916+0000cffc@1144
917+0000df7c@1145
918+0000dffc@1146
919+0000fffe@1148
920+0000f3b6@1150
921+000073b6@1152
922+0000e3b6@1153
923+0000ebfa@1154
924+0000eb7a@1156
925+00006bf8@1157
926+0000ebf8@1158
927+0000e140@1159
928+0000e1c0@1160
929+0000c1c0@1162
930+0000c140@1163
931+0000d1c0@1164
932+000071c2@1166
933+0000f142@1167
934+0000f3b6@1168
935+00007336@1171
936+0000e3b6@1172
937+0000ebfe@1173
938+0000ebfc@1176
939+0000effc@1177
940+0000ef7c@1178
941+0000effc@1179
942+00004ffc@1180
943+0000cffc@1181
944+0000df7c@1182
945+0000dffc@1183
946+00007ffe@1185
947+0000ff7e@1186
948+0000f3ba@1187
949+000073ba@1189
950+0000e3ba@1190
951+0000ebf2@1191
952+0000eb72@1193
953+00006bf2@1194
954+0000ebf0@1195
955+0000e1c0@1196
956+0000e140@1197
957+0000e1c0@1198
958+000041c0@1199
959+0000c1c0@1200
960+0000d1c0@1201
961+000071c2@1203
962+0000f142@1204
963+0000f37a@1205
964+0000f3ba@1206
965+0000733a@1208
966+0000e3ba@1209
967+0000ebf6@1210
968+0000eb76@1212
969+00006bf4@1213
970+0000ebf4@1214
971+0000effc@1215
972+00006ffc@1217
973+0000cffc@1218
974+0000cf7c@1219
975+0000dffc@1220
976+00007ffe@1222
977+0000ff7e@1223
978+0000f3ba@1224
979+0000733a@1227
980+0000e3ba@1228
981+0000ebfa@1229
982+00006bfa@1231
983+0000ebf8@1232
984+0000e9c0@1233
985+0000e140@1234
986+0000e1c0@1235
987+000041c0@1236
988+0000c1c0@1237
989+0000d140@1238
990+0000d1c0@1239
991+000071c2@1241
992+0000f1c2@1242
993+0000f3ba@1243
994+000073ba@1245
995+0000e3ba@1246
996+0000ebfe@1247
997+0000eb7e@1249
998+00006bfc@1250
999+0000ebfc@1251
1000+0000effc@1252
1001+0000ef7c@1253
1002+0000effc@1254
1003+00004ffc@1255
1004+0000cffc@1256
1005+0000dffc@1257
1006+00007ffe@1259
1007+0000ff7e@1260
1008+0000f3be@1261
1009+0000733e@1264
1010+0000e3be@1265
1011+0000ebf2@1266
1012+0000eb72@1268
1013+00006bf0@1269
1014+0000ebf0@1270
1015+0000e1c0@1271
1016+000041c0@1273
1017+0000c1c0@1274
1018+0000d140@1275
1019+0000d1c0@1276
1020+000071c2@1278
1021+0000f142@1279
1022+0000f3be@1280
1023+0000e3be@1283
1024+0000ebfe@1284
1025+0000ebf6@1285
1026+0000eb76@1286
1027+00006bf6@1287
1028+0000ebf4@1288
1029+0000effc@1289
1030+0000ef7c@1290
1031+0000effc@1291
1032+00004ffc@1292
1033+0000cffc@1293
1034+0000df7c@1294
1035+0000dffc@1295
1036+0000fffe@1297
1037+0000f3be@1299
1038+0000733e@1301
1039+0000e3be@1302
1040+0000ebfa@1303
1041+0000eb7a@1305
1042+00006bf8@1306
1043+0000ebf8@1307
1044+0000e140@1308
1045+0000e1c0@1309
1046+0000c1c0@1311
1047+0000c140@1312
1048+0000d1c0@1313
1049+000071c2@1315
1050+0000f142@1316
1051+0000f3be@1317
1052+0000733e@1320
1053+0000e3be@1321
1054+0000ebfe@1322
1055+0000ebfc@1325
1056+0000effc@1326
1057+0000ef7c@1327
1058+0000effc@1328
1059+00004ffc@1329
1060+0000cffc@1330
1061+0000df7c@1331
1062+0000dffc@1332
1063+00007ffe@1334
1064+0000ff7e@1335
1065+0000f582@1336
1066+00007582@1338
1067+0000e582@1339
1068+0000ebf2@1340
1069+0000eb72@1342
1070+00006bf2@1343
1071+0000ebf0@1344
1072+0000e1c0@1345
1073+0000e140@1346
1074+0000e1c0@1347
1075+000041c0@1348
1076+0000c1c0@1349
1077+0000d1c0@1350
1078+000071c2@1352
1079+0000f142@1353
1080+0000f502@1354
1081+0000f582@1355
1082+00007502@1357
1083+0000e582@1358
1084+0000ebf6@1359
1085+0000eb76@1361
1086+00006bf4@1362
1087+0000ebf4@1363
1088+0000effc@1364
1089+00006ffc@1366
1090+0000cffc@1367
1091+0000cf7c@1368
1092+0000dffc@1369
1093+00007ffe@1371
1094+0000ff7e@1372
1095+0000f502@1373
1096+0000f582@1374
1097+00007502@1376
1098+0000e582@1377
1099+0000ebfa@1378
1100+00006bfa@1380
1101+0000ebf8@1381
1102+0000e9c0@1382
1103+0000e140@1383
1104+0000e1c0@1384
1105+000041c0@1385
1106+0000c1c0@1386
1107+0000d140@1387
1108+0000d1c0@1388
1109+000071c2@1390
1110+0000f1c2@1391
1111+0000f582@1392
1112+00007582@1394
1113+0000e582@1395
1114+0000ebfe@1396
1115+0000eb7e@1398
1116+00006bfc@1399
1117+0000ebfc@1400
1118+0000effc@1401
1119+0000ef7c@1402
1120+0000effc@1403
1121+00004ffc@1404
1122+0000cffc@1405
1123+0000dffc@1406
1124+00007ffe@1408
1125+0000ff7e@1409
1126+0000fd86@1410
1127+0000f586@1411
1128+00007506@1413
1129+0000e586@1414
1130+0000ebf2@1415
1131+0000eb72@1417
1132+00006bf0@1418
1133+0000ebf0@1419
1134+0000e1c0@1420
1135+000041c0@1422
1136+0000c1c0@1423
1137+0000d140@1424
1138+0000d1c0@1425
1139+000071c2@1427
1140+0000f142@1428
1141+0000f586@1429
1142+0000e586@1432
1143+0000e7f6@1433
1144+0000ebf6@1434
1145+00006bf6@1436
1146+0000ebf4@1437
1147+0000effc@1438
1148+0000ef7c@1439
1149+0000effc@1440
1150+00004ffc@1441
1151+0000cffc@1442
1152+0000df7c@1443
1153+0000dffc@1444
1154+0000fffe@1446
1155+0000f586@1448
1156+00007586@1450
1157+0000f584@1451
1158+0000fbf4@1452
1159+0000ebf4@1453
1160+0000eb74@1454
1161+00006bf4@1455
1162+0000ebf4@1456
1163+0000eb74@1458
1164+0000ebf4@1459
1165+0000eb74@1461
1166+0000fbf4@1462
1167+00007bf6@1464
1168+0000fb76@1465
1169+0000f506@1466
1170+0000f586@1467
1171+00007506@1469
1172+0000e586@1470
1173+0000ebfa@1471
1174+0000ebf8@1474
1175+0000e140@1476
1176+0000e1c0@1477
1177+000041c0@1478
1178+0000c1c0@1479
1179+0000d140@1480
1180+0000d1c0@1481
1181+000071c2@1483
1182+0000f142@1484
1183+0000f586@1485
1184+00007586@1487
1185+0000e586@1488
1186+0000ebfe@1489
1187+0000eb7e@1491
1188+00006bfe@1492
1189+0000ebfc@1493
1190+0000effc@1494
1191+0000ef7c@1495
1192+0000effc@1496
1193+00004ffc@1497
1194+0000cffc@1498
1195+0000dffc@1499
1196+00007ffe@1501
1197+0000ff7e@1502
1198+0000ff9e@1503
1199+0000f58a@1504
1200+0000750a@1506
1201+0000e58a@1507
1202+0000ebf2@1508
1203+0000eb72@1510
1204+00006bf0@1511
1205+0000ebf0@1512
1206+0000e140@1513
1207+0000e1c0@1514
1208+000061c0@1515
1209+0000c1c0@1516
1210+0000c140@1517
1211+0000d1c0@1518
1212+000071c2@1520
1213+0000f142@1521
1214+0000f58a@1522
1215+0000750a@1525
1216+0000e58a@1526
1217+0000ebf6@1527
1218+00006bf6@1529
1219+0000ebf4@1530
1220+0000effc@1531
1221+0000ef7c@1532
1222+0000effc@1533
1223+00004ffc@1534
1224+0000cffc@1535
1225+0000df7c@1536
1226+0000dffc@1537
1227+00007ffe@1539
1228+0000fffe@1540
1229+0000f58a@1541
1230+0000758a@1543
1231+0000e58a@1544
1232+0000ebfa@1545
1233+0000eb7a@1547
1234+00006bf8@1548
1235+0000ebf8@1549
1236+0000e140@1550
1237+0000e1c0@1552
1238+000041c0@1553
1239+0000c1c0@1554
1240+0000d1c0@1555
1241+000071c2@1557
1242+0000f142@1558
1243+0000f58a@1559
1244+0000750a@1562
1245+0000e58a@1563
1246+0000ebfe@1564
1247+0000eb7e@1566
1248+00006bfc@1567
1249+0000effc@1568
1250+0000ef7c@1569
1251+0000effc@1570
1252+00004ffc@1571
1253+0000cffc@1572
1254+0000df7c@1573
1255+0000dffc@1574
1256+00007ffe@1576
1257+0000ff7e@1577
1258+0000f58e@1578
1259+0000e58e@1581
1260+0000effa@1582
1261+0000ebf2@1583
1262+0000eb72@1584
1263+00006bf2@1585
1264+0000ebf0@1586
1265+0000e1c0@1587
1266+0000e140@1588
1267+0000e1c0@1589
1268+000041c0@1590
1269+0000c1c0@1591
1270+0000d140@1592
1271+0000d1c0@1593
1272+0000f1c2@1595
1273+0000f54e@1596
1274+0000f58e@1597
1275+0000750e@1599
1276+0000e58e@1600
1277+0000ebf6@1601
1278+0000eb76@1603
1279+00006bf4@1604
1280+0000ebf4@1605
1281+0000effc@1606
1282+0000ef7c@1607
1283+0000effc@1608
1284+0000cffc@1609
1285+0000cf7c@1610
1286+0000dffc@1611
1287+00007ffe@1613
1288+0000ff7e@1614
1289+0000f58e@1615
1290+0000750e@1618
1291+0000e58e@1619
1292+0000ebfa@1620
1293+0000ebf8@1623
1294+0000e140@1625
1295+0000e1c0@1626
1296+000041c0@1627
1297+0000c1c0@1628
1298+0000d140@1629
1299+0000d1c0@1630
1300+000071c2@1632
1301+0000f142@1633
1302+0000f58e@1634
1303+0000758e@1636
1304+0000e58e@1637
1305+0000ebfe@1638
1306+0000eb7e@1640
1307+00006bfe@1641
1308+0000ebfc@1642
1309+0000effc@1643
1310+0000ef7c@1644
1311+0000effc@1645
1312+00004ffc@1646
1313+0000cffc@1647
1314+0000dffc@1648
1315+00007ffe@1650
1316+0000ff7e@1651
1317+0000ffbe@1652
1318+0000f592@1653
1319+00007512@1655
1320+0000e592@1656
1321+0000ebf2@1657
1322+0000eb72@1659
1323+00006bf0@1660
1324+0000ebf0@1661
1325+0000e140@1662
1326+0000e1c0@1663
1327+000061c0@1664
1328+0000c1c0@1665
1329+0000c140@1666
1330+0000d1c0@1667
1331+000071c2@1669
1332+0000f142@1670
1333+0000f592@1671
1334+00007512@1674
1335+0000e592@1675
1336+0000ebf6@1676
1337+00006bf6@1678
1338+0000ebf4@1679
1339+0000effc@1680
1340+0000ef7c@1681
1341+0000effc@1682
1342+00004ffc@1683
1343+0000cffc@1684
1344+0000df7c@1685
1345+0000dffc@1686
1346+00007ffe@1688
1347+0000fffe@1689
1348+0000f592@1690
1349+00007592@1692
1350+0000e592@1693
1351+0000ebfa@1694
1352+0000eb7a@1696
1353+00006bf8@1697
1354+0000ebf8@1698
1355+0000e140@1699
1356+0000e1c0@1701
1357+000041c0@1702
1358+0000c1c0@1703
1359+0000d1c0@1704
1360+000071c2@1706
1361+0000f142@1707
1362+0000f592@1708
1363+00007512@1711
1364+0000e592@1712
1365+0000ebfe@1713
1366+0000eb7e@1715
1367+00006bfc@1716
1368+0000effc@1717
1369+0000ef7c@1718
1370+0000effc@1719
1371+00004ffc@1720
1372+0000cffc@1721
1373+0000df7c@1722
1374+0000dffc@1723
1375+00007ffe@1725
1376+0000ff7e@1726
1377+0000f596@1727
1378+0000e596@1730
1379+0000eff6@1731
1380+0000ebf2@1732
1381+0000eb72@1733
1382+00006bf2@1734
1383+0000ebf0@1735
1384+0000e1c0@1736
1385+0000e140@1737
1386+0000e1c0@1738
1387+000041c0@1739
1388+0000c1c0@1740
1389+0000d140@1741
1390+0000d1c0@1742
1391+0000f1c0@1743
1392+0000f1c2@1744
1393+0000f556@1745
1394+0000f596@1746
1395+00007516@1748
1396+0000e596@1749
1397+0000ebf6@1750
1398+0000eb76@1752
1399+00006bf4@1753
1400+0000ebf4@1754
1401+0000effc@1755
1402+0000ef7c@1756
1403+0000effc@1757
1404+0000cffc@1758
1405+0000cf7c@1759
1406+0000dffc@1760
1407+00007ffe@1762
1408+0000ff7e@1763
1409+0000f516@1764
1410+0000f596@1765
1411+00007516@1767
1412+0000e596@1768
1413+0000ebfa@1769
1414+00006bfa@1771
1415+0000ebf8@1772
1416+0000e140@1774
1417+0000e1c0@1775
1418+000041c0@1776
1419+0000c1c0@1777
1420+0000d140@1778
1421+0000d1c0@1779
1422+000071c2@1781
1423+0000f142@1782
1424+0000f596@1783
1425+00007596@1785
1426+0000e596@1786
1427+0000ebfe@1787
1428+0000eb7e@1789
1429+00006bfe@1790
1430+0000ebfc@1791
1431+0000effc@1792
1432+0000ef7c@1793
1433+0000effc@1794
1434+00004ffc@1795
1435+0000cffc@1796
1436+0000dffc@1797
1437+00007ffe@1799
1438+0000ff7e@1800
1439+0000ffbe@1801
1440+0000f59a@1802
1441+0000751a@1804
1442+0000e59a@1805
1443+0000ebf2@1806
1444+0000eb72@1808
1445+00006bf0@1809
1446+0000ebf0@1810
1447+0000e140@1811
1448+0000e1c0@1812
1449+000061c0@1813
1450+0000c1c0@1814
1451+0000c140@1815
1452+0000d1c0@1816
1453+000071c2@1818
1454+0000f142@1819
1455+0000f59a@1820
1456+0000751a@1823
1457+0000e59a@1824
1458+0000ebf6@1825
1459+00006bf6@1827
1460+0000ebf4@1828
1461+0000effc@1829
1462+0000ef7c@1830
1463+0000effc@1831
1464+00004ffc@1832
1465+0000cffc@1833
1466+0000df7c@1834
1467+0000dffc@1835
1468+00007ffe@1837
1469+0000fffe@1838
1470+0000f59a@1839
1471+0000759a@1841
1472+0000e59a@1842
1473+0000ebfa@1843
1474+0000eb7a@1845
1475+00006bf8@1846
1476+0000ebf8@1847
1477+0000e140@1848
1478+0000e1c0@1850
1479+000041c0@1851
1480+0000c1c0@1852
1481+0000d1c0@1853
1482+000071c2@1855
1483+0000f142@1856
1484+0000f59a@1857
1485+0000751a@1860
1486+0000e59a@1861
1487+0000ebfe@1862
1488+0000eb7e@1864
1489+00006bfc@1865
1490+0000effc@1866
1491+0000ef7c@1867
1492+0000effc@1868
1493+00004ffc@1869
1494+0000cffc@1870
1495+0000df7c@1871
1496+0000dffc@1872
1497+00007ffe@1874
1498+0000ff7e@1875
1499+0000f59e@1876
1500+0000e59e@1879
1501+0000eff2@1880
1502+0000ebf2@1881
1503+0000eb72@1882
1504+00006bf2@1883
1505+0000ebf0@1884
1506+0000e1c0@1885
1507+0000e140@1886
1508+0000e1c0@1887
1509+000041c0@1888
1510+0000c1c0@1889
1511+0000d140@1890
1512+0000d1c0@1891
1513+0000f1c0@1892
1514+0000f1c2@1893
1515+0000f55e@1894
1516+0000f59e@1895
1517+0000751e@1897
1518+0000e59e@1898
1519+0000ebf6@1899
1520+0000eb76@1901
1521+00006bf4@1902
1522+0000ebf4@1903
1523+0000effc@1904
1524+0000ef7c@1905
1525+0000effc@1906
1526+0000cffc@1907
1527+0000cf7c@1908
1528+0000dffc@1909
1529+00007ffe@1911
1530+0000ff7e@1912
1531+0000f59e@1913
1532+0000751e@1916
1533+0000e59e@1917
1534+0000ebfa@1918
1535+00006bfa@1920
1536+0000ebf8@1921
1537+0000e140@1923
1538+0000e1c0@1924
1539+000041c0@1925
1540+0000c1c0@1926
1541+0000d140@1927
1542+0000d1c0@1928
1543+000071c2@1930
1544+0000f142@1931
1545+0000f59e@1932
1546+0000759e@1934
1547+0000e59e@1935
1548+0000ebfe@1936
1549+0000eb7e@1938
1550+00006bfe@1939
1551+0000ebfc@1940
1552+0000effc@1941
1553+0000ef7c@1942
1554+0000effc@1943
1555+00004ffc@1944
1556+0000cffc@1945
1557+0000dffc@1946
1558+00007ffe@1948
1559+0000ff7e@1949
1560+0000ffe6@1950
1561+0000f5a2@1951
1562+00007522@1953
1563+0000e5a2@1954
1564+0000ebf2@1955
1565+0000eb72@1957
1566+00006bf0@1958
1567+0000ebf0@1959
1568+0000e1c0@1960
1569+000061c0@1962
1570+0000c1c0@1963
1571+0000c140@1964
1572+0000d1c0@1965
1573+000071c2@1967
1574+0000f142@1968
1575+0000f5a2@1969
1576+00007522@1972
1577+0000e5a2@1973
1578+0000ebf6@1974
1579+00006bf6@1976
1580+0000ebf4@1977
1581+0000effc@1978
1582+0000ef7c@1979
1583+0000effc@1980
1584+00004ffc@1981
1585+0000cffc@1982
1586+0000df7c@1983
1587+0000dffc@1984
1588+00007ffe@1986
1589+0000fffe@1987
1590+0000f5a2@1988
1591+000075a2@1990
1592+0000e5a2@1991
1593+0000ebfa@1992
1594+0000eb7a@1994
1595+00006bf8@1995
1596+0000ebf8@1996
1597+0000e140@1997
1598+0000e1c0@1999
1599+000041c0@2000
1600+0000c1c0@2001
1601+0000d1c0@2002
1602+000071c2@2004
1603+0000f142@2005
1604+0000f5a2@2006
1605+00007522@2009
1606+0000e5a2@2010
1607+0000ebfe@2011
1608+0000eb7e@2013
1609+00006bfc@2014
1610+0000effc@2015
1611+0000ef7c@2016
1612+0000effc@2017
1613+00004ffc@2018
1614+0000cffc@2019
1615+0000df7c@2020
1616+0000dffc@2021
1617+00007ffe@2023
1618+0000ff7e@2024
1619+0000f5a6@2025
1620+0000e5a6@2028
1621+0000eff2@2029
1622+0000ebf2@2030
1623+0000eb72@2031
1624+00006bf2@2032
1625+0000ebf0@2033
1626+0000e1c0@2034
1627+0000e140@2035
1628+0000e1c0@2036
1629+000041c0@2037
1630+0000c1c0@2038
1631+0000d140@2039
1632+0000d1c0@2040
1633+0000f1c0@2041
1634+0000f1c2@2042
1635+0000f566@2043
1636+0000f5a6@2044
1637+00007526@2046
1638+0000f5a4@2047
1639+0000fbf0@2048
1640+0000ebf0@2049
1641+0000eb70@2050
1642+00006bf0@2051
1643+0000ebf0@2052
1644+0000ef7c@2053
1645+0000ebfc@2054
1646+0000effc@2055
1647+0000ebfc@2056
1648+0000eb7c@2057
1649+0000fffc@2058
1650+00007bfe@2060
1651+0000ff7e@2061
1652+0000f5a6@2062
1653+00007526@2065
1654+0000e5a6@2066
1655+0000ebf6@2067
1656+00006bf6@2069
1657+0000ebf4@2070
1658+0000effc@2071
1659+0000ef7c@2072
1660+0000effc@2073
1661+00004ffc@2074
1662+0000cffc@2075
1663+0000df7c@2076
1664+0000dffc@2077
1665+00007ffe@2079
1666+0000ff7e@2080
1667+0000f5a6@2081
1668+000075a6@2083
1669+0000e5a6@2084
1670+0000ebfa@2085
1671+0000eb7a@2087
1672+00006bfa@2088
1673+0000ebf8@2089
1674+0000e140@2090
1675+0000e1c0@2092
1676+000041c0@2093
1677+0000c1c0@2094
1678+0000d1c0@2095
1679+000071c2@2097
1680+0000f142@2098
1681+0000f526@2099
1682+0000f5a6@2100
1683+00007526@2102
1684+0000e5a6@2103
1685+0000ebfe@2104
1686+0000eb7e@2106
1687+00006bfc@2107
1688+0000ebfc@2108
1689+0000effc@2109
1690+00006ffc@2111
1691+0000cffc@2112
1692+0000cf7c@2113
1693+0000dffc@2114
1694+00007ffe@2116
1695+0000ff7e@2117
1696+0000f52a@2118
1697+0000f5aa@2119
1698+0000752a@2121
1699+0000e5aa@2122
1700+0000ebf2@2123
1701+00006bf2@2125
1702+0000ebf0@2126
1703+0000e1c0@2127
1704+0000e140@2128
1705+0000e1c0@2129
1706+000041c0@2130
1707+0000c1c0@2131
1708+0000d140@2132
1709+0000d1c0@2133
1710+000071c2@2135
1711+0000f1c2@2136
1712+0000f5aa@2137
1713+000075aa@2139
1714+0000e5aa@2140
1715+0000ebf6@2141
1716+0000eb76@2143
1717+00006bf4@2144
1718+0000ebf4@2145
1719+0000effc@2146
1720+0000ef7c@2147
1721+0000effc@2148
1722+00004ffc@2149
1723+0000cffc@2150
1724+0000dffc@2151
1725+00007ffe@2153
1726+0000ff7e@2154
1727+0000f5aa@2155
1728+0000752a@2158
1729+0000e5aa@2159
1730+0000ebfa@2160
1731+0000eb7a@2162
1732+00006bf8@2163
1733+0000ebf8@2164
1734+0000e1c0@2165
1735+000041c0@2167
1736+0000c1c0@2168
1737+0000d140@2169
1738+0000d1c0@2170
1739+000071c2@2172
1740+0000f142@2173
1741+0000f5aa@2174
1742+0000e5aa@2177
1743+0000effe@2178
1744+0000ebfe@2179
1745+0000eb7e@2180
1746+00006bfe@2181
1747+0000ebfc@2182
1748+0000effc@2183
1749+0000ef7c@2184
1750+0000effc@2185
1751+00004ffc@2186
1752+0000cffc@2187
1753+0000df7c@2188
1754+0000dffc@2189
1755+0000fffc@2190
1756+0000fffe@2191
1757+0000f5ae@2193
1758+0000752e@2195
1759+0000e5ae@2196
1760+0000ebf2@2197
1761+0000eb72@2199
1762+00006bf0@2200
1763+0000ebf0@2201
1764+0000e140@2202
1765+0000e1c0@2203
1766+0000c1c0@2205
1767+0000c140@2206
1768+0000d1c0@2207
1769+000071c2@2209
1770+0000f142@2210
1771+0000f5ae@2211
1772+0000752e@2214
1773+0000e5ae@2215
1774+0000ebf6@2216
1775+00006bf6@2218
1776+0000ebf4@2219
1777+0000effc@2220
1778+0000ef7c@2221
1779+0000effc@2222
1780+00004ffc@2223
1781+0000cffc@2224
1782+0000df7c@2225
1783+0000dffc@2226
1784+00007ffe@2228
1785+0000ff7e@2229
1786+0000f5ae@2230
1787+000075ae@2232
1788+0000e5ae@2233
1789+0000effa@2234
1790+0000ebfa@2235
1791+0000eb7a@2236
1792+00006bfa@2237
1793+0000ebf8@2238
1794+0000e140@2239
1795+0000e1c0@2241
1796+000041c0@2242
1797+0000c1c0@2243
1798+0000d1c0@2244
1799+000071c2@2246
1800+0000f142@2247
1801+0000f52e@2248
1802+0000f5ae@2249
1803+0000752e@2251
1804+0000e5ae@2252
1805+0000ebfe@2253
1806+0000eb7e@2255
1807+00006bfc@2256
1808+0000ebfc@2257
1809+0000effc@2258
1810+00006ffc@2260
1811+0000cffc@2261
1812+0000cf7c@2262
1813+0000dffc@2263
1814+00007ffe@2265
1815+0000ff7e@2266
1816+0000f532@2267
1817+0000f5b2@2268
1818+00007532@2270
1819+0000e5f2@2271
1820+0000ebf2@2272
1821+00006bf2@2274
1822+0000ebf0@2275
1823+0000e1c0@2276
1824+0000e140@2277
1825+0000e1c0@2278
1826+000041c0@2279
1827+0000c1c0@2280
1828+0000d140@2281
1829+0000d1c0@2282
1830+000071c2@2284
1831+0000f5f2@2285
1832+0000f5b2@2286
1833+000075b2@2288
1834+0000e5b2@2289
1835+0000ebf6@2290
1836+0000eb76@2292
1837+00006bf4@2293
1838+0000ebf4@2294
1839+0000effc@2295
1840+0000ef7c@2296
1841+0000effc@2297
1842+00004ffc@2298
1843+0000cffc@2299
1844+0000dffc@2300
1845+00007ffe@2302
1846+0000ff7e@2303
1847+0000f5b2@2304
1848+00007532@2307
1849+0000e5b2@2308
1850+0000ebfa@2309
1851+0000eb7a@2311
1852+00006bf8@2312
1853+0000ebf8@2313
1854+0000e1c0@2314
1855+000041c0@2316
1856+0000c1c0@2317
1857+0000d140@2318
1858+0000d1c0@2319
1859+000071c2@2321
1860+0000f142@2322
1861+0000f5b2@2323
1862+0000e5b2@2326
1863+0000effe@2327
1864+0000ebfe@2328
1865+0000eb7e@2329
1866+00006bfe@2330
1867+0000ebfc@2331
1868+0000effc@2332
1869+0000ef7c@2333
1870+0000effc@2334
1871+00004ffc@2335
1872+0000cffc@2336
1873+0000df7c@2337
1874+0000dffc@2338
1875+0000fffc@2339
1876+0000fffe@2340
1877+0000f5b6@2342
1878+00007536@2344
1879+0000e5b6@2345
1880+0000ebf2@2346
1881+0000eb72@2348
1882+00006bf0@2349
1883+0000ebf0@2350
1884+0000e140@2351
1885+0000e1c0@2352
1886+0000c1c0@2354
1887+0000c140@2355
1888+0000d1c0@2356
1889+000071c2@2358
1890+0000f142@2359
1891+0000f5b6@2360
1892+00007536@2363
1893+0000e5b6@2364
1894+0000ebf6@2365
1895+00006bf6@2367
1896+0000ebf4@2368
1897+0000effc@2369
1898+0000ef7c@2370
1899+0000effc@2371
1900+00004ffc@2372
1901+0000cffc@2373
1902+0000df7c@2374
1903+0000dffc@2375
1904+00007ffe@2377
1905+0000fffe@2378
1906+0000f5b6@2379
1907+000075b6@2381
1908+0000e5b6@2382
1909+0000effa@2383
1910+0000ebfa@2384
1911+0000eb7a@2385
1912+00006bfa@2386
1913+0000ebf8@2387
1914+0000e140@2388
1915+0000e1c0@2390
1916+000041c0@2391
1917+0000c1c0@2392
1918+0000d1c0@2393
1919+000071c2@2395
1920+0000f142@2396
1921+0000f576@2397
1922+0000f5b6@2398
1923+00007536@2400
1924+0000e5b6@2401
1925+0000ebfe@2402
1926+0000eb7e@2404
1927+00006bfc@2405
1928+0000ebfc@2406
1929+0000effc@2407
1930+00006ffc@2409
1931+0000cffc@2410
1932+0000cf7c@2411
1933+0000dffc@2412
1934+00007ffe@2414
1935+0000ff7e@2415
1936+0000f5ba@2416
1937+0000753a@2419
1938+0000e5fa@2420
1939+0000ebf2@2421
1940+0000eb72@2422
1941+00006bf2@2423
1942+0000ebf0@2424
1943+0000e1c0@2425
1944+0000e140@2426
1945+0000e1c0@2427
1946+000041c0@2428
1947+0000c1c0@2429
1948+0000d140@2430
1949+0000d1c0@2431
1950+000071c2@2433
1951+0000f1d2@2434
1952+0000f5ba@2435
1953+000075ba@2437
1954+0000e5ba@2438
1955+0000ebf6@2439
1956+0000eb76@2441
1957+00006bf4@2442
1958+0000ebf4@2443
1959+0000effc@2444
1960+0000ef7c@2445
1961+0000effc@2446
1962+00004ffc@2447
1963+0000cffc@2448
1964+0000dffc@2449
1965+00007ffe@2451
1966+0000ff7e@2452
1967+0000f5ba@2453
1968+0000753a@2456
1969+0000e5ba@2457
1970+0000ebfa@2458
1971+0000eb7a@2460
1972+0000ebf8@2461
1973+0000e1c0@2463
1974+000041c0@2465
1975+0000c1c0@2466
1976+0000d140@2467
1977+0000d1c0@2468
1978+000071c2@2470
1979+0000f142@2471
1980+0000f5ba@2472
1981+0000e5ba@2475
1982+0000effe@2476
1983+0000ebfe@2477
1984+0000eb7e@2478
1985+00006bfe@2479
1986+0000ebfc@2480
1987+0000effc@2481
1988+0000ef7c@2482
1989+0000effc@2483
1990+00004ffc@2484
1991+0000cffc@2485
1992+0000df7c@2486
1993+0000dffc@2487
1994+0000fffc@2488
1995+0000fffe@2489
1996+0000f5be@2491
1997+0000753e@2493
1998+0000e5be@2494
1999+0000ebf2@2495
2000+0000eb72@2497
2001+00006bf0@2498
2002+0000ebf0@2499
2003+0000e140@2500
2004+0000e1c0@2501
2005+0000c1c0@2503
2006+0000c140@2504
2007+0000d1c0@2505
2008+000071c2@2507
2009+0000f142@2508
2010+0000f5be@2509
2011+0000753e@2512
2012+0000e5be@2513
2013+0000ebf6@2514
2014+00006bf6@2516
2015+0000ebf4@2517
2016+0000effc@2518
2017+0000ef7c@2519
2018+0000effc@2520
2019+00004ffc@2521
2020+0000cffc@2522
2021+0000df7c@2523
2022+0000dffc@2524
2023+00007ffe@2526
2024+0000fffe@2527
2025+0000f5be@2528
2026+000075be@2530
2027+0000e5be@2531
2028+0000effa@2532
2029+0000ebfa@2533
2030+0000eb7a@2534
2031+00006bfa@2535
2032+0000ebf8@2536
2033+0000e140@2537
2034+0000e1c0@2539
2035+000041c0@2540
2036+0000c1c0@2541
2037+0000d1c0@2542
2038+000071c2@2544
2039+0000f142@2545
2040+0000f57e@2546
2041+0000f5be@2547
2042+0000753e@2549
2043+0000e5be@2550
2044+0000ebfe@2551
2045+0000eb7e@2553
2046+00006bfc@2554
2047+0000ebfc@2555
2048+0000effc@2556
2049+00006ffc@2558
2050+0000cffc@2559
2051+0000cf7c@2560
2052+0000dffc@2561
2053+00007ffe@2563
2054+0000ff7e@2564
2055+0000f702@2565
2056+0000f782@2566
2057+00007702@2568
2058+0000e782@2569
2059+0000ebf2@2570
2060+00006bf2@2572
2061+0000ebf0@2573
2062+0000e1c0@2574
2063+0000e140@2575
2064+0000e1c0@2576
2065+000041c0@2577
2066+0000c1c0@2578
2067+0000d140@2579
2068+0000d1c0@2580
2069+000071c2@2582
2070+0000f5c2@2583
2071+0000f782@2584
2072+00007782@2586
2073+0000e782@2587
2074+0000ebf6@2588
2075+0000eb76@2590
2076+00006bf4@2591
2077+0000ebf4@2592
2078+0000effc@2593
2079+0000ef7c@2594
2080+0000effc@2595
2081+00004ffc@2596
2082+0000cffc@2597
2083+0000dffc@2598
2084+00007ffe@2600
2085+0000ff7e@2601
2086+0000ff82@2602
2087+0000f782@2603
2088+00007702@2605
2089+0000e782@2606
2090+0000ebfa@2607
2091+0000eb7a@2609
2092+0000ebf8@2610
2093+0000e140@2612
2094+0000e1c0@2613
2095+000041c0@2614
2096+0000c1c0@2615
2097+0000d140@2616
2098+0000d1c0@2617
2099+000071c2@2619
2100+0000f142@2620
2101+0000f782@2621
2102+0000e782@2624
2103+0000ebfe@2625
2104+0000eb7e@2627
2105+00006bfe@2628
2106+0000ebfc@2629
2107+0000effc@2630
2108+0000ef7c@2631
2109+0000effc@2632
2110+00004ffc@2633
2111+0000cffc@2634
2112+0000df7c@2635
2113+0000dffc@2636
2114+0000fffc@2637
2115+0000fffe@2638
2116+0000f782@2640
2117+00007702@2642
2118+0000f780@2643
2119+0000fbfe@2644
2120+0000ebfc@2645
2121+0000eb7c@2646
2122+00006bfc@2647
2123+0000ebfc@2648
2124+0000eb7c@2650
2125+0000ebfc@2651
2126+0000eb7c@2653
2127+0000fbfc@2654
2128+00007bfe@2656
2129+0000fb7e@2657
2130+0000f706@2658
2131+0000f786@2659
2132+00007706@2661
2133+0000e786@2662
2134+0000ebf2@2663
2135+00006bf2@2665
2136+0000ebf0@2666
2137+0000ebc0@2667
2138+0000e140@2668
2139+0000e1c0@2669
2140+000041c0@2670
2141+0000c1c0@2671
2142+0000d140@2672
2143+0000d1c0@2673
2144+000071c2@2675
2145+0000f1c2@2676
2146+0000f786@2677
2147+00007786@2679
2148+0000e786@2680
2149+0000ebf6@2681
2150+0000eb76@2683
2151+00006bf6@2684
2152+0000ebf4@2685
2153+0000effc@2686
2154+0000ef7c@2687
2155+0000effc@2688
2156+00004ffc@2689
2157+0000cffc@2690
2158+0000dffc@2691
2159+00007ffe@2693
2160+0000ff7e@2694
2161+0000ff86@2695
2162+0000f786@2696
2163+00007706@2698
2164+0000e786@2699
2165+0000ebfa@2700
2166+0000eb7a@2702
2167+00006bf8@2703
2168+0000ebf8@2704
2169+0000e1c0@2705
2170+000061c0@2707
2171+0000c1c0@2708
2172+0000c140@2709
2173+0000d1c0@2710
2174+000071c2@2712
2175+0000f142@2713
2176+0000f786@2714
2177+00007706@2717
2178+0000e786@2718
2179+0000ebfe@2719
2180+00006bfe@2721
2181+0000ebfc@2722
2182+0000effc@2723
2183+0000ef7c@2724
2184+0000effc@2725
2185+00004ffc@2726
2186+0000cffc@2727
2187+0000df7c@2728
2188+0000dffc@2729
2189+00007ffe@2731
2190+0000fffe@2732
2191+0000f78a@2733
2192+0000778a@2735
2193+0000e78a@2736
2194+0000ebf2@2737
2195+0000eb72@2739
2196+00006bf0@2740
2197+0000ebf0@2741
2198+0000e140@2742
2199+0000e1c0@2744
2200+000041c0@2745
2201+0000c1c0@2746
2202+0000d1c0@2747
2203+000071c2@2749
2204+0000f142@2750
2205+0000f78a@2751
2206+0000770a@2754
2207+0000e78a@2755
2208+0000ebf6@2756
2209+0000eb76@2758
2210+0000ebf4@2759
2211+0000effc@2760
2212+0000ef7c@2761
2213+0000effc@2762
2214+00004ffc@2763
2215+0000cffc@2764
2216+0000df7c@2765
2217+0000dffc@2766
2218+00007ffe@2768
2219+0000ff7e@2769
2220+0000f78a@2770
2221+0000e78a@2773
2222+0000ebfa@2774
2223+0000eb7a@2776
2224+00006bfa@2777
2225+0000ebf8@2778
2226+0000e1c0@2779
2227+0000e140@2780
2228+0000e1c0@2781
2229+000041c0@2782
2230+0000c1c0@2783
2231+0000d140@2784
2232+0000d1c0@2785
2233+0000f1c0@2786
2234+0000f1c2@2787
2235+0000f74a@2788
2236+0000f78a@2789
2237+0000770a@2791
2238+0000e78a@2792
2239+0000ebfe@2793
2240+0000eb7e@2795
2241+00006bfc@2796
2242+0000ebfc@2797
2243+0000effc@2798
2244+0000ef7c@2799
2245+0000effc@2800
2246+0000cffc@2801
2247+0000cf7c@2802
2248+0000dffc@2803
2249+00007ffe@2805
2250+0000ff7e@2806
2251+0000f70e@2807
2252+0000f78e@2808
2253+0000770e@2810
2254+0000e78e@2811
2255+0000ebf2@2812
2256+00006bf2@2814
2257+0000ebf0@2815
2258+0000ebc0@2816
2259+0000e140@2817
2260+0000e1c0@2818
2261+000041c0@2819
2262+0000c1c0@2820
2263+0000d140@2821
2264+0000d1c0@2822
2265+000071c2@2824
2266+0000f1c2@2825
2267+0000f78e@2826
2268+0000778e@2828
2269+0000e78e@2829
2270+0000ebf6@2830
2271+0000eb76@2832
2272+00006bf4@2833
2273+0000ebf4@2834
2274+0000effc@2835
2275+0000ef7c@2836
2276+0000effc@2837
2277+00004ffc@2838
2278+0000cffc@2839
2279+0000dffc@2840
2280+00007ffe@2842
2281+0000ff7e@2843
2282+0000ff8e@2844
2283+0000f78e@2845
2284+0000770e@2847
2285+0000e78e@2848
2286+0000ebfa@2849
2287+0000eb7a@2851
2288+00006bf8@2852
2289+0000ebf8@2853
2290+0000e1c0@2854
2291+000061c0@2856
2292+0000c1c0@2857
2293+0000c140@2858
2294+0000d1c0@2859
2295+000071c2@2861
2296+0000f142@2862
2297+0000f78e@2863
2298+0000770e@2866
2299+0000e7ae@2867
2300+0000ebfe@2868
2301+00006bfe@2870
2302+0000ebfc@2871
2303+0000effc@2872
2304+0000ef7c@2873
2305+0000effc@2874
2306+00004ffc@2875
2307+0000cffc@2876
2308+0000df7c@2877
2309+0000dffc@2878
2310+00007ffe@2880
2311+0000fffe@2881
2312+0000f792@2882
2313+00007792@2884
2314+0000e792@2885
2315+0000ebf2@2886
2316+0000eb72@2888
2317+00006bf0@2889
2318+0000ebf0@2890
2319+0000e140@2891
2320+0000e1c0@2893
2321+000041c0@2894
2322+0000c1c0@2895
2323+0000d1c0@2896
2324+000071c2@2898
2325+0000f142@2899
2326+0000f792@2900
2327+00007712@2903
2328+0000e792@2904
2329+0000ebf6@2905
2330+0000eb76@2907
2331+0000ebf4@2908
2332+0000effc@2909
2333+0000ef7c@2910
2334+0000effc@2911
2335+00004ffc@2912
2336+0000cffc@2913
2337+0000df7c@2914
2338+0000dffc@2915
2339+00007ffe@2917
2340+0000ff7e@2918
2341+0000f792@2919
2342+0000e792@2922
2343+0000ebfa@2923
2344+0000eb7a@2925
2345+00006bfa@2926
2346+0000ebf8@2927
2347+0000e1c0@2928
2348+0000e140@2929
2349+0000e1c0@2930
2350+000041c0@2931
2351+0000c1c0@2932
2352+0000d140@2933
2353+0000d1c0@2934
2354+0000f1c0@2935
2355+0000f142@2936
2356+0000f752@2937
2357+0000f792@2938
2358+00007712@2940
2359+0000e792@2941
2360+0000ebfe@2942
2361+0000eb7e@2944
2362+00006bfc@2945
2363+0000ebfc@2946
2364+0000effc@2947
2365+0000ef7c@2948
2366+0000effc@2949
2367+0000cffc@2950
2368+0000cf7c@2951
2369+0000dffc@2952
2370+00007ffe@2954
2371+0000ff7e@2955
2372+0000f716@2956
2373+0000f796@2957
2374+00007716@2959
2375+0000e796@2960
2376+0000ebf2@2961
2377+00006bf2@2963
2378+0000ebf0@2964
2379+0000ebc0@2965
2380+0000e140@2966
2381+0000e1c0@2967
2382+000041c0@2968
2383+0000c1c0@2969
2384+0000d140@2970
2385+0000d1c0@2971
2386+000071c2@2973
2387+0000f1c2@2974
2388+0000f796@2975
2389+00007796@2977
2390+0000e796@2978
2391+0000ebf6@2979
2392+0000eb76@2981
2393+00006bf4@2982
2394+0000ebf4@2983
2395+0000effc@2984
2396+0000ef7c@2985
2397+0000effc@2986
2398+00004ffc@2987
2399+0000cffc@2988
2400+0000dffc@2989
2401+00007ffe@2991
2402+0000ff7e@2992
2403+0000ff96@2993
2404+0000f796@2994
2405+00007716@2996
2406+0000e796@2997
2407+0000ebfa@2998
2408+0000eb7a@3000
2409+00006bf8@3001
2410+0000ebf8@3002
2411+0000e1c0@3003
2412+000041c0@3005
2413+0000c1c0@3006
2414+0000c140@3007
2415+0000d1c0@3008
2416+000071c2@3010
2417+0000f142@3011
2418+0000f796@3012
2419+00007716@3015
2420+0000e796@3016
2421+0000ebfe@3017
2422+00006bfe@3019
2423+0000ebfc@3020
2424+0000effc@3021
2425+0000ef7c@3022
2426+0000effc@3023
2427+00004ffc@3024
2428+0000cffc@3025
2429+0000df7c@3026
2430+0000dffc@3027
2431+00007ffe@3029
2432+0000fffe@3030
2433+0000f79a@3031
2434+0000779a@3033
2435+0000e79a@3034
2436+0000ebf2@3035
2437+0000eb72@3037
2438+00006bf0@3038
2439+0000ebf0@3039
2440+0000e140@3040
2441+0000e1c0@3042
2442+000041c0@3043
2443+0000c1c0@3044
2444+0000d1c0@3045
2445+000071c2@3047
2446+0000f142@3048
2447+0000f79a@3049
2448+0000771a@3052
2449+0000e79a@3053
2450+0000ebf6@3054
2451+0000eb76@3056
2452+0000ebf4@3057
2453+0000effc@3058
2454+0000ef7c@3059
2455+0000effc@3060
2456+00004ffc@3061
2457+0000cffc@3062
2458+0000df7c@3063
2459+0000dffc@3064
2460+00007ffe@3066
2461+0000ff7e@3067
2462+0000f79a@3068
2463+0000e79a@3071
2464+0000ebfa@3072
2465+0000eb7a@3074
2466+00006bfa@3075
2467+0000ebf8@3076
2468+0000e1c0@3077
2469+0000e140@3078
2470+0000e1c0@3079
2471+000041c0@3080
2472+0000c1c0@3081
2473+0000d140@3082
2474+0000d1c0@3083
2475+0000f1c0@3084
2476+0000f1c2@3085
2477+0000f75a@3086
2478+0000f79a@3087
2479+0000771a@3089
2480+0000e79a@3090
2481+0000ebfe@3091
2482+0000eb7e@3093
2483+00006bfc@3094
2484+0000ebfc@3095
2485+0000effc@3096
2486+0000ef7c@3097
2487+0000effc@3098
2488+0000cffc@3099
2489+0000cf7c@3100
2490+0000dffc@3101
2491+00007ffe@3103
2492+0000ff7e@3104
2493+0000f79e@3105
2494+0000771e@3108
2495+0000e79e@3109
2496+0000ebf2@3110
2497+00006bf2@3112
2498+0000ebf0@3113
2499+0000ebc0@3114
2500+0000e140@3115
2501+0000e1c0@3116
2502+000041c0@3117
2503+0000c1c0@3118
2504+0000d140@3119
2505+0000d1c0@3120
2506+000071c2@3122
2507+0000f1c2@3123
2508+0000f79e@3124
2509+0000779e@3126
2510+0000e79e@3127
2511+0000ebf6@3128
2512+0000eb76@3130
2513+00006bf4@3131
2514+0000ebf4@3132
2515+0000effc@3133
2516+0000ef7c@3134
2517+0000effc@3135
2518+00004ffc@3136
2519+0000cffc@3137
2520+0000dffc@3138
2521+00007ffe@3140
2522+0000ff7e@3141
2523+0000ff9e@3142
2524+0000f79e@3143
2525+0000771e@3145
2526+0000e79e@3146
2527+0000ebfa@3147
2528+0000eb7a@3149
2529+00006bf8@3150
2530+0000ebf8@3151
2531+0000e1c0@3152
2532+000041c0@3154
2533+0000c1c0@3155
2534+0000c140@3156
2535+0000d1c0@3157
2536+000071c2@3159
2537+0000f142@3160
2538+0000f79e@3161
2539+0000771e@3164
2540+0000e7fe@3165
2541+0000ebfe@3166
2542+00006bfe@3168
2543+0000ebfc@3169
2544+0000effc@3170
2545+0000ef7c@3171
2546+0000effc@3172
2547+00004ffc@3173
2548+0000cffc@3174
2549+0000df7c@3175
2550+0000dffc@3176
2551+00007ffe@3178
2552+0000fffe@3179
2553+0000f6a2@3180
2554+000076a2@3182
2555+0000e6a2@3183
2556+0000eaf2@3184
2557+0000ea72@3186
2558+00006a70@3187
2559+0000eaf0@3188
2560+0000e0c0@3189
2561+0000e040@3191
2562+0000c040@3192
2563+0000c0c0@3193
2564+0000d0c0@3194
2565+00007042@3196
2566+0000f0c2@3197
2567+0000f6a2@3198
2568+0000f622@3200
2569+00007622@3201
2570+0000e6a2@3202
2571+0000eaf6@3203
2572+0000ea76@3205
2573+0000ea74@3206
2574+0000eefc@3207
2575+00004e7c@3210
2576+0000cefc@3211
2577+0000defc@3212
2578+0000de7c@3214
2579+00007e7e@3215
2580+0000fefe@3216
2581+0000f6a2@3217
2582+0000f622@3219
2583+0000e622@3220
2584+0000eafa@3221
2585+00006a7a@3224
2586+0000eaf8@3225
2587+0000e0c0@3226
2588+0000e040@3228
2589+00004040@3229
2590+0000c0c0@3230
2591+0000d0c0@3231
2592+00007040@3233
2593+0000f042@3234
2594+0000f6e2@3235
2595+0000f6a2@3236
2596+0000f622@3237
2597+00007622@3238
2598+0000e6a2@3239
2599+0000eafe@3240
2600+0000ea7e@3242
2601+00006a7c@3243
2602+0000eafc@3244
2603+0000eefc@3245
2604+00006e7c@3247
2605+0000ce7c@3248
2606+0000cefc@3249
2607+0000defc@3250
2608+0000de7c@3251
2609+00007e7e@3252
2610+0000fefe@3253
2611+0000f6a6@3254
2612+0000f626@3256
2613+000076a6@3257
2614+0000e6a6@3258
2615+0000eaf2@3259
2616+0000ea72@3260
2617+00006af2@3261
2618+0000eaf0@3262
2619+0000eac0@3263
2620+0000e040@3264
2621+000040c0@3266
2622+0000c0c0@3267
2623+0000d040@3268
2624+0000d0c0@3270
2625+000070c2@3271
2626+0000f0c2@3272
2627+0000f626@3273
2628+000076a6@3275
2629+0000e6a6@3276
2630+0000ea76@3277
2631+0000eaf6@3279
2632+00006af4@3280
2633+0000eaf4@3281
2634+0000ee7c@3282
2635+0000eefc@3284
2636+00004efc@3285
2637+0000cefc@3286
2638+0000de7c@3287
2639+00007efe@3289
2640+0000fefe@3290
2641+0000fea6@3291
2642+0000f626@3292
2643+0000f6a6@3293
2644+000076a6@3294
2645+0000e6a6@3295
2646+0000ea7a@3296
2647+0000eafa@3298
2648+00006af8@3299
2649+0000eaf8@3300
2650+0000e040@3301
2651+000040c0@3303
2652+0000c0c0@3304
2653+0000c040@3305
2654+0000d040@3306
2655+0000d0c0@3307
2656+000070c2@3308
2657+0000f0c2@3309
2658+0000f626@3310
2659+0000f6a6@3312
2660+000076a6@3313
2661+0000e6ae@3314
2662+0000ea7e@3315
2663+00006afe@3317
2664+0000eafc@3318
2665+0000ee7c@3319
2666+0000eefc@3321
2667+00004efc@3322
2668+0000cefc@3323
2669+0000de7c@3324
2670+0000defc@3326
2671+00007efe@3327
2672+0000fefe@3328
2673+0000f62a@3329
2674+000076aa@3331
2675+0000e6aa@3332
2676+0000ea72@3333
2677+0000eaf2@3334
2678+00006af0@3336
2679+0000ea70@3337
2680+0000e0c0@3338
2681+0000c040@3341
2682+0000d0c0@3343
2683+00007042@3345
2684+0000f042@3346
2685+0000f6aa@3347
2686+0000762a@3350
2687+0000e62a@3351
2688+0000eaf6@3352
2689+0000ea74@3355
2690+0000ee7c@3356
2691+0000eefc@3357
2692+00004efc@3359
2693+0000ce7c@3360
2694+0000defc@3361
2695+00007e7e@3364
2696+0000fe7e@3365
2697+0000f6aa@3366
2698+0000e62a@3369
2699+0000ea7a@3370
2700+0000eafa@3371
2701+00006a7a@3373
2702+0000ea78@3374
2703+0000e040@3375
2704+0000e0c0@3376
2705+00004040@3378
2706+0000c040@3379
2707+0000d0c0@3380
2708+0000f0c0@3382
2709+0000f042@3383
2710+0000f66a@3384
2711+0000f6aa@3385
2712+0000762a@3387
2713+0000e62a@3388
2714+0000eafe@3389
2715+00006a7c@3392
2716+0000ea7c@3393
2717+0000eefc@3394
2718+00006efc@3396
2719+0000ce7c@3397
2720+0000defc@3399
2721+00007e7e@3401
2722+0000fe7e@3402
2723+0000f62e@3403
2724+0000f6ae@3404
2725+0000762e@3406
2726+0000e62e@3407
2727+0000eaf2@3408
2728+00006af2@3410
2729+0000eaf0@3411
2730+0000eac0@3412
2731+0000e0c0@3413
2732+0000e040@3414
2733+000040c0@3415
2734+0000c0c0@3416
2735+0000d0c0@3417
2736+0000d040@3418
2737+000070c2@3420
2738+0000f0c2@3421
2739+0000f7ae@3422
2740+0000f72e@3423
2741+0000772e@3424
2742+0000e7ae@3425
2743+0000ebf6@3426
2744+0000eb76@3428
2745+00006b74@3429
2746+0000ebf4@3430
2747+0000effc@3431
2748+0000ef7c@3432
2749+00004ffc@3434
2750+0000cffc@3435
2751+0000dffc@3436
2752+0000df7c@3437
2753+00007f7e@3438
2754+0000fffe@3439
2755+0000ffae@3440
2756+0000f72e@3441
2757+000077ac@3443
2758+0000f7ac@3444
2759+0000fbf4@3445
2760+0000eb74@3446
2761+00006bf4@3448
2762+0000ebf4@3449
2763+0000eb74@3451
2764+00006b74@3452
2765+0000ebf4@3453
2766+0000fb74@3455
2767+00007bf6@3457
2768+0000fbf6@3458
2769+0000f7ae@3459
2770+0000f72e@3460
2771+000077ae@3462
2772+0000e7fe@3463
2773+0000ebfa@3464
2774+0000eb7a@3465
2775+00006b7a@3466
2776+0000ebf8@3467
2777+0000e1c0@3468
2778+0000e140@3469
2779+000041c0@3471
2780+0000c1c0@3472
2781+0000d1c0@3473
2782+0000d140@3474
2783+000071c2@3476
2784+0000f7ee@3477
2785+0000f7ae@3478
2786+0000f72e@3479
2787+000077ae@3480
2788+0000e7ae@3481
2789+0000ebfe@3482
2790+0000eb7e@3483
2791+00006bfc@3485
2792+0000ebfc@3486
2793+0000effc@3487
2794+0000ef7c@3488
2795+0000effc@3489
2796+0000cffc@3490
2797+0000dffc@3492
2798+00007ffe@3494
2799+0000ff7e@3495
2800+0000f7b2@3496
2801+00007732@3499
2802+0000e7b2@3500
2803+0000ebf2@3501
2804+0000eb72@3503
2805+0000ebf0@3504
2806+0000e1c0@3506
2807+000041c0@3508
2808+0000c1c0@3509
2809+0000d140@3510
2810+0000d1c0@3511
2811+000071c2@3513
2812+0000f142@3514
2813+0000f7b2@3515
2814+0000e7b2@3518
2815+0000ebf6@3519
2816+0000eb76@3521
2817+00006bf6@3522
2818+0000ebf4@3523
2819+0000effc@3524
2820+0000ef7c@3525
2821+0000effc@3526
2822+00004ffc@3527
2823+0000cffc@3528
2824+0000df7c@3529
2825+0000dffc@3530
2826+0000fffc@3531
2827+0000ff7e@3532
2828+0000fffe@3533
2829+0000f7b2@3534
2830+00007732@3536
2831+0000e7b2@3537
2832+0000ebfa@3538
2833+0000eb7a@3540
2834+00006bf8@3541
2835+0000ebf8@3542
2836+0000e140@3543
2837+0000e1c0@3544
2838+0000c1c0@3546
2839+0000c140@3547
2840+0000d1c0@3548
2841+000071c2@3550
2842+0000f142@3551
2843+0000f7b2@3552
2844+00007732@3555
2845+0000e7b2@3556
2846+0000ebfe@3557
2847+00006bfe@3559
2848+0000ebfc@3560
2849+0000effc@3561
2850+0000ef7c@3562
2851+0000effc@3563
2852+00004ffc@3564
2853+0000cffc@3565
2854+0000df7c@3566
2855+0000dffc@3567
2856+00007ffe@3569
2857+0000fffe@3570
2858+0000f7b6@3571
2859+000077b6@3573
2860+0000e7b6@3574
2861+0000ebf2@3575
2862+0000eb72@3577
2863+00006bf0@3578
2864+0000ebf0@3579
2865+0000e140@3580
2866+0000e1c0@3582
2867+000041c0@3583
2868+0000c1c0@3584
2869+0000d1c0@3585
2870+000071c2@3587
2871+0000f142@3588
2872+0000f736@3589
2873+0000f7b6@3590
2874+00007736@3592
2875+0000e7b6@3593
2876+0000ebf6@3594
2877+0000eb76@3596
2878+00006bf4@3597
2879+0000effc@3598
2880+00004ffc@3601
2881+0000cffc@3602
2882+0000cf7c@3603
2883+0000dffc@3604
2884+00007ffe@3606
2885+0000ff7e@3607
2886+0000f7b6@3608
2887+00006736@3611
2888+0000e7f6@3612
2889+0000ebfa@3613
2890+0000eb7a@3614
2891+00006bfa@3615
2892+0000ebf8@3616
2893+0000e1c0@3617
2894+0000e140@3618
2895+0000e1c0@3619
2896+000041c0@3620
2897+0000c1c0@3621
2898+0000d140@3622
2899+0000d1c0@3623
2900+000071c2@3625
2901+0000f5f6@3626
2902+0000f7b6@3627
2903+00007736@3629
2904+0000e7b6@3630
2905+0000ebfe@3631
2906+0000eb7e@3633
2907+00006bfc@3634
2908+0000ebfc@3635
2909+0000effc@3636
2910+0000ef7c@3637
2911+0000effc@3638
2912+0000cffc@3639
2913+0000dffc@3641
2914+00007ffe@3643
2915+0000ff7e@3644
2916+0000f7ba@3645
2917+0000773a@3648
2918+0000e7ba@3649
2919+0000ebf2@3650
2920+0000ebf0@3653
2921+0000e1c0@3655
2922+000041c0@3657
2923+0000c1c0@3658
2924+0000d140@3659
2925+0000d1c0@3660
2926+000071c2@3662
2927+0000f142@3663
2928+0000f7ba@3664
2929+0000e7ba@3667
2930+0000effe@3668
2931+0000ebf6@3669
2932+0000eb76@3670
2933+00006bf6@3671
2934+0000ebf4@3672
2935+0000effc@3673
2936+0000ef7c@3674
2937+0000effc@3675
2938+00004ffc@3676
2939+0000cffc@3677
2940+0000df7c@3678
2941+0000dffc@3679
2942+0000fffc@3680
2943+0000fffe@3681
2944+0000f7ba@3683
2945+0000773a@3685
2946+0000e7ba@3686
2947+0000ebfa@3687
2948+0000eb7a@3689
2949+00006bf8@3690
2950+0000ebf8@3691
2951+0000e140@3692
2952+0000e1c0@3693
2953+0000c1c0@3695
2954+0000c140@3696
2955+0000d1c0@3697
2956+000071c2@3699
2957+0000f142@3700
2958+0000f7ba@3701
2959+0000773a@3704
2960+0000e7ba@3705
2961+0000ebfe@3706
2962+00006bfe@3708
2963+0000ebfc@3709
2964+0000effc@3710
2965+0000ef7c@3711
2966+0000effc@3712
2967+00004ffc@3713
2968+0000cffc@3714
2969+0000df7c@3715
2970+0000dffc@3716
2971+00007ffe@3718
2972+0000fffe@3719
2973+0000f7be@3720
2974+000077be@3722
2975+0000e7be@3723
2976+0000ebf2@3724
2977+0000eb72@3726
2978+00006bf0@3727
2979+0000ebf0@3728
2980+0000e140@3729
2981+0000e1c0@3731
2982+000041c0@3732
2983+0000c1c0@3733
2984+0000d1c0@3734
2985+000071c2@3736
2986+0000f142@3737
2987+0000f73e@3738
2988+0000f7be@3739
2989+0000773e@3741
2990+0000e7be@3742
2991+0000ebf6@3743
2992+0000eb76@3745
2993+00006bf4@3746
2994+0000effc@3747
2995+00004ffc@3750
2996+0000cffc@3751
2997+0000cf7c@3752
2998+0000dffc@3753
2999+00007ffe@3755
3000+0000ff7e@3756
3001+0000f7be@3757
3002+0000673e@3760
3003+0000e7fe@3761
3004+0000ebfa@3762
3005+0000eb7a@3763
3006+00006bfa@3764
3007+0000ebf8@3765
3008+0000e1c0@3766
3009+0000e140@3767
3010+0000e1c0@3768
3011+000041c0@3769
3012+0000c1c0@3770
3013+0000d140@3771
3014+0000d1c0@3772
3015+000071c2@3774
3016+0000f57e@3775
3017+0000f7be@3776
3018+0000773e@3778
3019+0000e7be@3779
3020+0000ebfe@3780
3021+0000eb7e@3782
3022+00006bfc@3783
3023+0000ebfc@3784
3024+0000effc@3785
3025+0000ef7c@3786
3026+0000effc@3787
3027+0000cffc@3788
3028+0000dffc@3790
3029+00007ffe@3792
3030+0000ff7e@3793
3031+0000f982@3794
3032+00007902@3797
3033+0000e982@3798
3034+0000ebf2@3799
3035+0000eb72@3801
3036+0000ebf0@3802
3037+0000e1c0@3804
3038+000041c0@3806
3039+0000c1c0@3807
3040+0000d140@3808
3041+0000d1c0@3809
3042+000071c2@3811
3043+0000f142@3812
3044+0000f982@3813
3045+0000e982@3816
3046+0000ebf6@3817
3047+0000eb76@3819
3048+00006bf6@3820
3049+0000ebf4@3821
3050+0000effc@3822
3051+0000ef7c@3823
3052+0000effc@3824
3053+00004ffc@3825
3054+0000cffc@3826
3055+0000df7c@3827
3056+0000dffc@3828
3057+00007ffc@3829
3058+0000ff7e@3830
3059+0000fffe@3831
3060+0000f982@3832
3061+00007902@3834
3062+0000e982@3835
3063+0000ebfa@3836
3064+0000eb7a@3838
3065+00006bf8@3839
3066+0000ebf8@3840
3067+0000e140@3841
3068+0000e1c0@3842
3069+000061c0@3843
3070+0000c1c0@3844
3071+0000c140@3845
3072+0000d1c0@3846
3073+000071c2@3848
3074+0000f142@3849
3075+0000f982@3850
3076+00007902@3853
3077+0000e982@3854
3078+0000fbfe@3855
3079+0000ebfe@3856
3080+00006bfe@3857
3081+0000ebfc@3858
3082+0000effc@3859
3083+0000ef7c@3860
3084+0000effc@3861
3085+00004ffc@3862
3086+0000cffc@3863
3087+0000df7c@3864
3088+0000dffc@3865
3089+00007ffe@3867
3090+0000fffe@3868
3091+0000f986@3869
3092+00007986@3871
3093+0000e986@3872
3094+0000ebf2@3873
3095+0000eb72@3875
3096+00006bf0@3876
3097+0000ebf0@3877
3098+0000e140@3878
3099+0000e1c0@3880
3100+000041c0@3881
3101+0000c1c0@3882
3102+0000d1c0@3883
3103+000071c2@3885
3104+0000f142@3886
3105+0000f906@3887
3106+0000f986@3888
3107+00007906@3890
3108+0000e986@3891
3109+0000ebf6@3892
3110+0000eb76@3894
3111+00006bf4@3895
3112+0000effc@3896
3113+00004ffc@3899
3114+0000cffc@3900
3115+0000cf7c@3901
3116+0000dffc@3902
3117+00007ffe@3904
3118+0000ff7e@3905
3119+0000f906@3906
3120+0000f986@3907
3121+00006906@3909
3122+0000e9f6@3910
3123+0000ebfa@3911
3124+00006bfa@3913
3125+0000ebf8@3914
3126+0000e1c0@3915
3127+0000e140@3916
3128+0000e1c0@3917
3129+000041c0@3918
3130+0000c1c0@3919
3131+0000d140@3920
3132+0000d1c0@3921
3133+000071c2@3923
3134+0000f9c6@3924
3135+0000f986@3925
3136+00007906@3927
3137+0000e986@3928
3138+0000ebfe@3929
3139+0000eb7e@3931
3140+00006bfc@3932
3141+0000ebfc@3933
3142+0000effc@3934
3143+0000ef7c@3935
3144+0000effc@3936
3145+0000cffc@3937
3146+0000dffc@3939
3147+00007ffe@3941
3148+0000ff7e@3942
3149+0000f98a@3943
3150+0000790a@3946
3151+0000e98a@3947
3152+0000ebf2@3948
3153+0000eb72@3950
3154+0000ebf0@3951
3155+0000e1c0@3953
3156+000041c0@3955
3157+0000c1c0@3956
3158+0000d140@3957
3159+0000d1c0@3958
3160+000071c2@3960
3161+0000f142@3961
3162+0000f98a@3962
3163+0000e98a@3965
3164+0000ebf6@3966
3165+0000eb76@3968
3166+00006bf6@3969
3167+0000ebf4@3970
3168+0000effc@3971
3169+0000ef7c@3972
3170+0000effc@3973
3171+00004ffc@3974
3172+0000cffc@3975
3173+0000df7c@3976
3174+0000dffc@3977
3175+00007ffc@3978
3176+0000ff7e@3979
3177+0000fffe@3980
3178+0000f98a@3981
3179+0000790a@3983
3180+0000e98a@3984
3181+0000ebfa@3985
3182+0000eb7a@3987
3183+00006bf8@3988
3184+0000ebf8@3989
3185+0000e140@3990
3186+0000e1c0@3991
3187+000061c0@3992
3188+0000c1c0@3993
3189+0000c140@3994
3190+0000d1c0@3995
3191+000071c2@3997
3192+0000f142@3998
3193+0000f98a@3999
3194+0000790a@4002
3195+0000e98a@4003
3196+0000ebfe@4004
3197+00006bfe@4006
3198+0000ebfc@4007
3199+0000effc@4008
3200+0000ef7c@4009
3201+0000effc@4010
3202+00004ffc@4011
3203+0000cffc@4012
3204+0000df7c@4013
3205+0000dffc@4014
3206+00007ffe@4016
3207+0000fffe@4017
3208+0000f98e@4018
3209+0000798e@4020
3210+0000e98e@4021
3211+0000ebf2@4022
3212+0000eb72@4024
3213+00006bf0@4025
3214+0000ebf0@4026
3215+0000e140@4027
3216+0000e1c0@4029
3217+000041c0@4030
3218+0000c1c0@4031
3219+0000d1c0@4032
3220+000071c2@4034
3221+0000f142@4035
3222+0000f90e@4036
3223+0000f98e@4037
3224+0000790c@4039
3225+0000f98c@4040
3226+0000fbf0@4041
3227+0000ebf0@4042
3228+0000eb70@4043
3229+00006bf0@4044
3230+0000effc@4045
3231+0000ebfc@4046
3232+00006ffc@4048
3233+0000ebfc@4049
3234+0000fb7c@4050
3235+0000fffc@4051
3236+00007bfe@4053
3237+0000ff7e@4054
3238+0000f98e@4055
3239+0000690e@4058
3240+0000ebfe@4059
3241+0000ebf6@4060
3242+00006bf6@4062
3243+0000ebf4@4063
3244+0000effc@4064
3245+0000ef7c@4065
3246+0000effc@4066
3247+00004ffc@4067
3248+0000cffc@4068
3249+0000df7c@4069
3250+0000dffc@4070
3251+00007ffe@4072
3252+0000fffe@4073
3253+0000f98e@4074
3254+0000798e@4076
3255+0000e98e@4077
3256+0000ebfa@4078
3257+0000eb7a@4080
3258+00006bf8@4081
3259+0000ebf8@4082
3260+0000e140@4083
3261+0000e1c0@4084
3262+0000c1c0@4086
3263+0000d1c0@4088
3264+000071c2@4090
3265+0000f142@4091
3266+0000f98e@4092
3267+0000790e@4095
3268+0000e98e@4096
3269+0000ebfe@4097
3270+0000eb7e@4099
3271+0000ebfc@4100
3272+0000effc@4101
3273+0000ef7c@4102
3274+0000effc@4103
3275+00004ffc@4104
3276+0000cffc@4105
3277+0000df7c@4106
3278+0000dffc@4107
3279+00007ffe@4109
3280+0000ff7e@4110
3281+0000f992@4111
3282+0000e992@4114
3283+0000ebf2@4115
3284+0000eb72@4117
3285+00006bf2@4118
3286+0000ebf0@4119
3287+0000e1c0@4120
3288+0000e140@4121
3289+0000e1c0@4122
3290+000041c0@4123
3291+0000c1c0@4124
3292+0000d140@4125
3293+0000d1c0@4126
3294+000071c0@4127
3295+0000f142@4128
3296+0000f952@4129
3297+0000f992@4130
3298+00007912@4132
3299+0000e992@4133
3300+0000ebf6@4134
3301+0000eb76@4136
3302+00006bf4@4137
3303+0000ebf4@4138
3304+0000effc@4139
3305+00006ffc@4141
3306+0000cffc@4142
3307+0000cf7c@4143
3308+0000dffc@4144
3309+00007ffe@4146
3310+0000ff7e@4147
3311+0000f912@4148
3312+0000f992@4149
3313+00007912@4151
3314+0000e992@4152
3315+0000ebfa@4153
3316+00006bfa@4155
3317+0000ebf8@4156
3318+0000ebc0@4157
3319+0000e140@4158
3320+0000e1c0@4159
3321+000041c0@4160
3322+0000c1c0@4161
3323+0000d140@4162
3324+0000d1c0@4163
3325+000071c2@4165
3326+0000f1c2@4166
3327+0000f992@4167
3328+00007992@4169
3329+0000e992@4170
3330+0000ebfe@4171
3331+0000eb7e@4173
3332+00006bfc@4174
3333+0000ebfc@4175
3334+0000effc@4176
3335+0000ef7c@4177
3336+0000effc@4178
3337+00004ffc@4179
3338+0000cffc@4180
3339+0000dffc@4181
3340+00007ffe@4183
3341+0000ff7e@4184
3342+0000f996@4185
3343+00007916@4188
3344+0000e996@4189
3345+0000ebf2@4190
3346+0000eb72@4192
3347+00006bf0@4193
3348+0000ebf0@4194
3349+0000e1c0@4195
3350+000041c0@4197
3351+0000c1c0@4198
3352+0000c140@4199
3353+0000d1c0@4200
3354+000071c2@4202
3355+0000f142@4203
3356+0000f996@4204
3357+00006916@4207
3358+0000ebf6@4208
3359+00006bf6@4211
3360+0000ebf4@4212
3361+0000effc@4213
3362+0000ef7c@4214
3363+0000effc@4215
3364+00004ffc@4216
3365+0000cffc@4217
3366+0000df7c@4218
3367+0000dffc@4219
3368+00007ffe@4221
3369+0000fffe@4222
3370+0000f996@4223
3371+00007996@4225
3372+0000e996@4226
3373+0000ebfa@4227
3374+0000eb7a@4229
3375+00006bf8@4230
3376+0000ebf8@4231
3377+0000e140@4232
3378+0000e1c0@4233
3379+0000c1c0@4235
3380+0000d1c0@4237
3381+000071c2@4239
3382+0000f142@4240
3383+0000f996@4241
3384+00007916@4244
3385+0000e996@4245
3386+0000ebfe@4246
3387+0000eb7e@4248
3388+0000ebfc@4249
3389+0000effc@4250
3390+0000ef7c@4251
3391+0000effc@4252
3392+00004ffc@4253
3393+0000cffc@4254
3394+0000df7c@4255
3395+0000dffc@4256
3396+00007ffe@4258
3397+0000ff7e@4259
3398+0000f99a@4260
3399+0000e99a@4263
3400+0000ebf2@4264
3401+0000eb72@4266
3402+00006bf2@4267
3403+0000ebf0@4268
3404+0000e1c0@4269
3405+0000e140@4270
3406+0000e1c0@4271
3407+000041c0@4272
3408+0000c1c0@4273
3409+0000d140@4274
3410+0000d1c0@4275
3411+000071c0@4276
3412+0000f142@4277
3413+0000f95a@4278
3414+0000f99a@4279
3415+0000791a@4281
3416+0000e99a@4282
3417+0000ebf6@4283
3418+0000eb76@4285
3419+00006bf4@4286
3420+0000ebf4@4287
3421+0000effc@4288
3422+00006ffc@4290
3423+0000cffc@4291
3424+0000cf7c@4292
3425+0000dffc@4293
3426+00007ffe@4295
3427+0000ff7e@4296
3428+0000f91a@4297
3429+0000f99a@4298
3430+0000791a@4300
3431+0000e99a@4301
3432+0000ebfa@4302
3433+00006bfa@4304
3434+0000ebf8@4305
3435+0000ebc0@4306
3436+0000e140@4307
3437+0000e1c0@4308
3438+000041c0@4309
3439+0000c1c0@4310
3440+0000d140@4311
3441+0000d1c0@4312
3442+000071c2@4314
3443+0000f1c2@4315
3444+0000f99a@4316
3445+0000799a@4318
3446+0000e99a@4319
3447+0000ebfe@4320
3448+0000eb7e@4322
3449+00006bfc@4323
3450+0000ebfc@4324
3451+0000effc@4325
3452+0000ef7c@4326
3453+0000effc@4327
3454+00004ffc@4328
3455+0000cffc@4329
3456+0000dffc@4330
3457+00007ffe@4332
3458+0000ff7e@4333
3459+0000f99e@4334
3460+0000791e@4337
3461+0000e99e@4338
3462+0000ebf2@4339
3463+0000eb72@4341
3464+00006bf0@4342
3465+0000ebf0@4343
3466+0000e1c0@4344
3467+000041c0@4346
3468+0000c1c0@4347
3469+0000c140@4348
3470+0000d1c0@4349
3471+000071c2@4351
3472+0000f142@4352
3473+0000f99e@4353
3474+0000691e@4356
3475+0000ebfe@4357
3476+0000ebf6@4358
3477+00006bf6@4360
3478+0000ebf4@4361
3479+0000effc@4362
3480+0000ef7c@4363
3481+0000effc@4364
3482+00004ffc@4365
3483+0000cffc@4366
3484+0000df7c@4367
3485+0000dffc@4368
3486+00007ffe@4370
3487+0000fffe@4371
3488+0000f99e@4372
3489+0000799e@4374
3490+0000e99e@4375
3491+0000ebfa@4376
3492+0000eb7a@4378
3493+00006bf8@4379
3494+0000ebf8@4380
3495+0000e140@4381
3496+0000e1c0@4382
3497+0000c1c0@4384
3498+0000d1c0@4386
3499+000071c2@4388
3500+0000f142@4389
3501+0000f99e@4390
3502+0000791e@4393
3503+0000e99e@4394
3504+0000ebfe@4395
3505+0000eb7e@4397
3506+0000ebfc@4398
3507+0000effc@4399
3508+0000ef7c@4400
3509+0000effc@4401
3510+00004ffc@4402
3511+0000cffc@4403
3512+0000df7c@4404
3513+0000dffc@4405
3514+00007ffe@4407
3515+0000ff7e@4408
3516+0000f9a2@4409
3517+0000e9a2@4412
3518+0000ebf2@4413
3519+0000eb72@4415
3520+00006bf2@4416
3521+0000ebf0@4417
3522+0000e1c0@4418
3523+0000e140@4419
3524+0000e1c0@4420
3525+000041c0@4421
3526+0000c1c0@4422
3527+0000d140@4423
3528+0000d1c0@4424
3529+000071c0@4425
3530+0000f142@4426
3531+0000f962@4427
3532+0000f9a2@4428
3533+00007922@4430
3534+0000e9a2@4431
3535+0000ebf6@4432
3536+0000eb76@4434
3537+00006bf4@4435
3538+0000ebf4@4436
3539+0000effc@4437
3540+00006ffc@4439
3541+0000cffc@4440
3542+0000cf7c@4441
3543+0000dffc@4442
3544+00007ffe@4444
3545+0000ff7e@4445
3546+0000f922@4446
3547+0000f9a2@4447
3548+00007922@4449
3549+0000e9a2@4450
3550+0000ebfa@4451
3551+00006bfa@4453
3552+0000ebf8@4454
3553+0000ebc0@4455
3554+0000e140@4456
3555+0000e1c0@4457
3556+000041c0@4458
3557+0000c1c0@4459
3558+0000d140@4460
3559+0000d1c0@4461
3560+000071c2@4463
3561+0000f1c2@4464
3562+0000f9a2@4465
3563+000079a2@4467
3564+0000e9a2@4468
3565+0000ebfe@4469
3566+0000eb7e@4471
3567+00006bfc@4472
3568+0000ebfc@4473
3569+0000effc@4474
3570+0000ef7c@4475
3571+0000effc@4476
3572+00004ffc@4477
3573+0000cffc@4478
3574+0000dffc@4479
3575+00007ffe@4481
3576+0000ff7e@4482
3577+0000f9a6@4483
3578+00007926@4486
3579+0000e9a6@4487
3580+0000ebf2@4488
3581+0000eb72@4490
3582+00006bf0@4491
3583+0000ebf0@4492
3584+0000e1c0@4493
3585+000041c0@4495
3586+0000c1c0@4496
3587+0000c140@4497
3588+0000d1c0@4498
3589+000071c2@4500
3590+0000f142@4501
3591+0000f9a6@4502
3592+00007926@4505
3593+0000ebf6@4506
3594+00006bf6@4509
3595+0000ebf4@4510
3596+0000effc@4511
3597+0000ef7c@4512
3598+0000effc@4513
3599+00004ffc@4514
3600+0000cffc@4515
3601+0000df7c@4516
3602+0000dffc@4517
3603+00007ffe@4519
3604+0000fffe@4520
3605+0000f9a6@4521
3606+000079a6@4523
3607+0000e9a6@4524
3608+0000ebfa@4525
3609+0000eb7a@4527
3610+00006bf8@4528
3611+0000ebf8@4529
3612+0000e140@4530
3613+0000e1c0@4531
3614+0000c1c0@4533
3615+0000d1c0@4535
3616+000071c2@4537
3617+0000f142@4538
3618+0000f9a6@4539
3619+00007926@4542
3620+0000e9a6@4543
3621+0000ebfe@4544
3622+0000eb7e@4546
3623+0000ebfc@4547
3624+0000effc@4548
3625+0000ef7c@4549
3626+0000effc@4550
3627+00004ffc@4551
3628+0000cffc@4552
3629+0000df7c@4553
3630+0000dffc@4554
3631+00007ffe@4556
3632+0000ff7e@4557
3633+0000f9aa@4558
3634+0000e9aa@4561
3635+0000ebf2@4562
3636+0000eb72@4564
3637+00006bf2@4565
3638+0000ebf0@4566
3639+0000e1c0@4567
3640+0000e140@4568
3641+0000e1c0@4569
3642+000041c0@4570
3643+0000c1c0@4571
3644+0000d140@4572
3645+0000d1c0@4573
3646+000071c2@4574
3647+0000f142@4575
3648+0000f96a@4576
3649+0000f9aa@4577
3650+0000792a@4579
3651+0000e9aa@4580
3652+0000ebf6@4581
3653+0000eb76@4583
3654+00006bf4@4584
3655+0000ebf4@4585
3656+0000effc@4586
3657+00006ffc@4588
3658+0000cffc@4589
3659+0000cf7c@4590
3660+0000dffc@4591
3661+00007ffe@4593
3662+0000ff7e@4594
3663+0000f92a@4595
3664+0000f9aa@4596
3665+0000792a@4598
3666+0000e9aa@4599
3667+0000ebfa@4600
3668+00006bfa@4602
3669+0000ebf8@4603
3670+0000ebc0@4604
3671+0000e140@4605
3672+0000e1c0@4606
3673+000041c0@4607
3674+0000c1c0@4608
3675+0000d140@4609
3676+0000d1c0@4610
3677+000071c2@4612
3678+0000f1c2@4613
3679+0000f9aa@4614
3680+000079aa@4616
3681+0000e9aa@4617
3682+0000ebfe@4618
3683+0000eb7e@4620
3684+00006bfc@4621
3685+0000ebfc@4622
3686+0000effc@4623
3687+0000ef7c@4624
3688+0000effc@4625
3689+00004ffc@4626
3690+0000cffc@4627
3691+0000dffc@4628
3692+00007ffe@4630
3693+0000ff7e@4631
3694+0000f9aa@4632
3695+00007928@4635
3696+0000f9a8@4636
3697+0000fbfc@4637
3698+0000ebfc@4638
3699+0000eb7c@4639
3700+00006bfc@4640
3701+0000ebfc@4641
3702+00006bfc@4644
3703+0000ebfc@4645
3704+0000fb7c@4646
3705+0000fbfc@4647
3706+00007bfe@4649
3707+0000fb7e@4650
3708+0000f9ae@4651
3709+0000692e@4654
3710+0000ebfe@4655
3711+0000ebf2@4656
3712+0000eb72@4657
3713+00006bf2@4658
3714+0000ebf0@4659
3715+0000e1c0@4660
3716+0000e140@4661
3717+0000e1c0@4662
3718+000041c0@4663
3719+0000c1c0@4664
3720+0000d140@4665
3721+0000d1c0@4666
3722+000071c2@4668
3723+0000f96e@4669
3724+0000f9ae@4670
3725+0000792e@4672
3726+0000e9ae@4673
3727+0000ebf6@4674
3728+0000eb76@4676
3729+00006bf4@4677
3730+0000ebf4@4678
3731+0000effc@4679
3732+0000ef7c@4680
3733+0000effc@4681
3734+0000cffc@4682
3735+0000cf7c@4683
3736+0000dffc@4684
3737+00007ffe@4686
3738+0000ff7e@4687
3739+0000f9ae@4688
3740+0000792e@4691
3741+0000e9ae@4692
3742+0000ebfa@4693
3743+0000ebf8@4696
3744+0000e140@4698
3745+0000e1c0@4699
3746+000041c0@4700
3747+0000c1c0@4701
3748+0000d140@4702
3749+0000d1c0@4703
3750+000071c2@4705
3751+0000f142@4706
3752+0000f9ae@4707
3753+000079ae@4709
3754+0000e9ae@4710
3755+0000ebfe@4711
3756+0000eb7e@4713
3757+00006bfe@4714
3758+0000ebfc@4715
3759+0000effc@4716
3760+0000ef7c@4717
3761+0000effc@4718
3762+00004ffc@4719
3763+0000cffc@4720
3764+0000dffc@4721
3765+00007ffe@4723
3766+0000ff7e@4724
3767+0000fffe@4725
3768+0000f9b2@4726
3769+00007932@4728
3770+0000e9b2@4729
3771+0000ebf2@4730
3772+0000eb72@4732
3773+00006bf0@4733
3774+0000ebf0@4734
3775+0000e140@4735
3776+0000e1c0@4736
3777+000061c0@4737
3778+0000c1c0@4738
3779+0000c140@4739
3780+0000d1c0@4740
3781+000071c2@4742
3782+0000f142@4743
3783+0000f9b2@4744
3784+00007932@4747
3785+0000e9b2@4748
3786+0000ebf6@4749
3787+00006bf6@4751
3788+0000ebf4@4752
3789+0000effc@4753
3790+0000ef7c@4754
3791+0000effc@4755
3792+00004ffc@4756
3793+0000cffc@4757
3794+0000df7c@4758
3795+0000dffc@4759
3796+00007ffe@4761
3797+0000fffe@4762
3798+0000f9b2@4763
3799+000079b2@4765
3800+0000e9b2@4766
3801+0000ebfa@4767
3802+0000eb7a@4769
3803+00006bf8@4770
3804+0000ebf8@4771
3805+0000e140@4772
3806+0000e1c0@4774
3807+000041c0@4775
3808+0000c1c0@4776
3809+0000d1c0@4777
3810+000071c2@4779
3811+0000f142@4780
3812+0000f9b2@4781
3813+00007932@4784
3814+0000e9b2@4785
3815+0000ebfe@4786
3816+0000eb7e@4788
3817+00006bfc@4789
3818+0000effc@4790
3819+00004ffc@4793
3820+0000cffc@4794
3821+0000cf7c@4795
3822+0000dffc@4796
3823+00007ffe@4798
3824+0000ff7e@4799
3825+0000f936@4800
3826+0000f9b6@4801
3827+0000e936@4803
3828+0000ebf6@4804
3829+0000ebf2@4805
3830+0000eb72@4806
3831+00006bf2@4807
3832+0000ebf0@4808
3833+0000e1c0@4809
3834+0000e140@4810
3835+0000e1c0@4811
3836+000041c0@4812
3837+0000c1c0@4813
3838+0000d140@4814
3839+0000d1c0@4815
3840+0000f1c2@4817
3841+0000f976@4818
3842+0000f9b6@4819
3843+00007936@4821
3844+0000e9b6@4822
3845+0000ebf6@4823
3846+0000eb76@4825
3847+00006bf4@4826
3848+0000ebf4@4827
3849+0000effc@4828
3850+0000ef7c@4829
3851+0000effc@4830
3852+0000cffc@4831
3853+0000cf7c@4832
3854+0000dffc@4833
3855+00007ffe@4835
3856+0000ff7e@4836
3857+0000f9b6@4837
3858+00007936@4840
3859+0000e9b6@4841
3860+0000ebfa@4842
3861+0000ebf8@4845
3862+0000e140@4847
3863+0000e1c0@4848
3864+000041c0@4849
3865+0000c1c0@4850
3866+0000d140@4851
3867+0000d1c0@4852
3868+000071c2@4854
3869+0000f142@4855
3870+0000f9b6@4856
3871+000079b6@4858
3872+0000e9b6@4859
3873+0000ebfe@4860
3874+0000eb7e@4862
3875+00006bfe@4863
3876+0000ebfc@4864
3877+0000effc@4865
3878+0000ef7c@4866
3879+0000effc@4867
3880+00004ffc@4868
3881+0000cffc@4869
3882+0000dffc@4870
3883+00007ffe@4872
3884+0000ff7e@4873
3885+0000fbfe@4874
3886+0000f9ba@4875
3887+0000793a@4877
3888+0000e9ba@4878
3889+0000ebf2@4879
3890+0000eb72@4881
3891+00006bf0@4882
3892+0000ebf0@4883
3893+0000e140@4884
3894+0000e1c0@4885
3895+000061c0@4886
3896+0000c1c0@4887
3897+0000c140@4888
3898+0000d1c0@4889
3899+000071c2@4891
3900+0000f142@4892
3901+0000f9ba@4893
3902+0000793a@4896
3903+0000e9ba@4897
3904+0000ebf6@4898
3905+00006bf6@4900
3906+0000ebf4@4901
3907+0000effc@4902
3908+0000ef7c@4903
3909+0000effc@4904
3910+00004ffc@4905
3911+0000cffc@4906
3912+0000df7c@4907
3913+0000dffc@4908
3914+00007ffe@4910
3915+0000fffe@4911
3916+0000f9ba@4912
3917+000079ba@4914
3918+0000e9ba@4915
3919+0000ebfa@4916
3920+0000eb7a@4918
3921+00006bf8@4919
3922+0000ebf8@4920
3923+0000e140@4921
3924+0000e1c0@4923
3925+000041c0@4924
3926+0000c1c0@4925
3927+0000d1c0@4926
3928+000071c2@4928
3929+0000f142@4929
3930+0000f9fa@4930
3931+0000f9ba@4931
3932+0000793a@4933
3933+0000e9ba@4934
3934+0000ebfe@4935
3935+0000eb7e@4937
3936+00006bfc@4938
3937+0000effc@4939
3938+00004ffc@4942
3939+0000cffc@4943
3940+0000cf7c@4944
3941+0000dffc@4945
3942+00007ffe@4947
3943+0000ff7e@4948
3944+0000f9be@4949
3945+0000e93e@4952
3946+0000ebfe@4953
3947+0000ebf2@4954
3948+0000eb72@4955
3949+00006bf2@4956
3950+0000ebf0@4957
3951+0000e1c0@4958
3952+0000e140@4959
3953+0000e1c0@4960
3954+000041c0@4961
3955+0000c1c0@4962
3956+0000d140@4963
3957+0000d1c0@4964
3958+0000f1c2@4966
3959+0000f97e@4967
3960+0000f9be@4968
3961+0000793e@4970
3962+0000e9be@4971
3963+0000ebf6@4972
3964+0000eb76@4974
3965+00006bf4@4975
3966+0000ebf4@4976
3967+0000effc@4977
3968+0000ef7c@4978
3969+0000effc@4979
3970+0000cffc@4980
3971+0000cf7c@4981
3972+0000dffc@4982
3973+00007ffe@4984
3974+0000ff7e@4985
3975+0000f9be@4986
3976+0000793e@4989
3977+0000e9be@4990
3978+0000ebfa@4991
3979+0000ebf8@4994
3980+0000e140@4996
3981+0000e1c0@4997
3982+000041c0@4998
3983+0000c1c0@4999
3984+0000d140@5000
3985+0000d1c0@5001
3986+000071c2@5003
3987+0000f142@5004
3988+0000f9be@5005
3989+000079be@5007
3990+0000e9be@5008
3991+0000ebfe@5009
3992+0000eb7e@5011
3993+00006bfe@5012
3994+0000ebfc@5013
3995+0000effc@5014
3996+0000ef7c@5015
3997+0000effc@5016
3998+00004ffc@5017
3999+0000cffc@5018
4000+0000dffc@5019
4001+00007ffe@5021
4002+0000ff7e@5022
4003+0000fffe@5023
4004+0000fb82@5024
4005+00007b02@5026
4006+0000eb82@5027
4007+0000ebf2@5028
4008+0000eb72@5030
4009+00006bf0@5031
4010+0000ebf0@5032
4011+0000e140@5033
4012+0000e1c0@5034
4013+000061c0@5035
4014+0000c1c0@5036
4015+0000c140@5037
4016+0000d1c0@5038
4017+000071c2@5040
4018+0000f142@5041
4019+0000fb82@5042
4020+00007b02@5045
4021+0000eb82@5046
4022+0000ebf6@5047
4023+00006bf6@5049
4024+0000ebf4@5050
4025+0000effc@5051
4026+0000ef7c@5052
4027+0000effc@5053
4028+00004ffc@5054
4029+0000cffc@5055
4030+0000df7c@5056
4031+0000dffc@5057
4032+00007ffe@5059
4033+0000fffe@5060
4034+0000fb82@5061
4035+00007b82@5063
4036+0000eb82@5064
4037+0000ebfa@5065
4038+0000eb7a@5067
4039+00006bf8@5068
4040+0000ebf8@5069
4041+0000e140@5070
4042+0000e1c0@5072
4043+000041c0@5073
4044+0000c1c0@5074
4045+0000d1c0@5075
4046+000071c2@5077
4047+0000f142@5078
4048+0000fb02@5079
4049+0000fb82@5080
4050+00007b02@5082
4051+0000eb82@5083
4052+0000ebfe@5084
4053+0000eb7e@5085
4054+00006bfc@5087
4055+0000effc@5088
4056+00004ffc@5091
4057+0000cffc@5092
4058+0000df7c@5093
4059+0000dffc@5094
4060+00007ffe@5096
4061+0000ff7e@5097
4062+0000fb86@5098
4063+0000eb86@5101
4064+0000ebf6@5102
4065+0000ebf2@5103
4066+0000eb72@5104
4067+00006bf2@5105
4068+0000ebf0@5106
4069+0000e1c0@5107
4070+0000e140@5108
4071+0000e1c0@5109
4072+000041c0@5110
4073+0000c1c0@5111
4074+0000d140@5112
4075+0000d1c0@5113
4076+0000f1c2@5115
4077+0000fbc6@5116
4078+0000fb86@5117
4079+00007b06@5119
4080+0000eb86@5120
4081+0000ebf6@5121
4082+0000eb76@5123
4083+00006bf4@5124
4084+0000ebf4@5125
4085+0000effc@5126
4086+0000ef7c@5127
4087+0000effc@5128
4088+0000cffc@5129
4089+0000cf7c@5130
4090+0000dffc@5131
4091+00007ffe@5133
4092+0000ff7e@5134
4093+0000fb06@5135
4094+0000fb86@5136
4095+00007b06@5138
4096+0000eb86@5139
4097+0000ebfa@5140
4098+0000ebf8@5143
4099+0000e140@5145
4100+0000e1c0@5146
4101+000041c0@5147
4102+0000c1c0@5148
4103+0000d140@5149
4104+0000d1c0@5150
4105+000071c2@5152
4106+0000f142@5153
4107+0000fb86@5154
4108+00007b86@5156
4109+0000eb86@5157
4110+0000ebfe@5158
4111+0000eb7e@5160
4112+00006bfe@5161
4113+0000ebfc@5162
4114+0000effc@5163
4115+0000ef7c@5164
4116+0000effc@5165
4117+00004ffc@5166
4118+0000cffc@5167
4119+0000dffc@5168
4120+00007ffe@5170
4121+0000ff7e@5171
4122+0000fffe@5172
4123+0000fb8a@5173
4124+00007b0a@5175
4125+0000eb8a@5176
4126+0000ebf2@5177
4127+0000eb72@5179
4128+00006bf0@5180
4129+0000ebf0@5181
4130+0000e140@5182
4131+0000e1c0@5183
4132+000061c0@5184
4133+0000c1c0@5185
4134+0000c140@5186
4135+0000d1c0@5187
4136+000071c2@5189
4137+0000f142@5190
4138+0000fb8a@5191
4139+00007b0a@5194
4140+0000eb8a@5195
4141+0000ebf6@5196
4142+00006bf6@5198
4143+0000ebf4@5199
4144+0000effc@5200
4145+0000ef7c@5201
4146+0000effc@5202
4147+00004ffc@5203
4148+0000cffc@5204
4149+0000df7c@5205
4150+0000dffc@5206
4151+00007ffe@5208
4152+0000fffe@5209
4153+0000fb8a@5210
4154+00007b8a@5212
4155+0000eb8a@5213
4156+0000ebfa@5214
4157+0000eb7a@5216
4158+00006bf8@5217
4159+0000ebf8@5218
4160+0000e140@5219
4161+0000e1c0@5221
4162+000041c0@5222
4163+0000c1c0@5223
4164+0000d1c0@5224
4165+000071c2@5226
4166+0000f142@5227
4167+0000fb0a@5228
4168+0000fb8a@5229
4169+00007b08@5231
4170+0000fb88@5232
4171+0000fbf8@5233
4172+0000ebf8@5234
4173+0000eb78@5235
4174+00006bf8@5236
4175+0000effc@5237
4176+0000eb7c@5238
4177+0000ebfc@5239
4178+00006bfc@5240
4179+0000ebfc@5241
4180+0000fb78@5242
4181+0000fffc@5243
4182+00007bfe@5245
4183+0000ff7e@5246
4184+0000fb8a@5247
4185+0000eb8a@5250
4186+0000ebfe@5251
4187+00006bfe@5254
4188+0000ebfc@5255
4189+0000effc@5256
4190+0000ef7c@5257
4191+0000effc@5258
4192+00004ffc@5259
4193+0000cffc@5260
4194+0000df7c@5261
4195+0000dffc@5262
4196+0000fffe@5264
4197+0000fb8e@5266
4198+00007b8e@5268
4199+0000eb8e@5269
4200+0000ebf2@5270
4201+0000eb72@5272
4202+00006bf0@5273
4203+0000ebf0@5274
4204+0000e140@5275
4205+0000e1c0@5276
4206+0000c1c0@5278
4207+0000d1c0@5280
4208+000071c2@5282
4209+0000f142@5283
4210+0000fb8e@5284
4211+00007b0e@5287
4212+0000eb8e@5288
4213+0000ebf6@5289
4214+0000ebf4@5292
4215+0000effc@5293
4216+0000ef7c@5294
4217+0000effc@5295
4218+00004ffc@5296
4219+0000cffc@5297
4220+0000df7c@5298
4221+0000dffc@5299
4222+00007ffe@5301
4223+0000ff7e@5302
4224+0000fb8e@5303
4225+0000eb8e@5306
4226+0000ebfa@5307
4227+0000eb7a@5309
4228+00006bfa@5310
4229+0000ebf8@5311
4230+0000e140@5312
4231+0000e1c0@5314
4232+000041c0@5315
4233+0000c1c0@5316
4234+0000d140@5317
4235+0000d1c0@5318
4236+000071c2@5319
4237+0000f142@5320
4238+0000fb0e@5321
4239+0000fb8e@5322
4240+00007b0e@5324
4241+0000eb8e@5325
4242+0000ebfe@5326
4243+0000eb7e@5328
4244+00006bfc@5329
4245+0000ebfc@5330
4246+0000effc@5331
4247+00006ffc@5333
4248+0000cffc@5334
4249+0000cf7c@5335
4250+0000dffc@5336
4251+00007ffe@5338
4252+0000ff7e@5339
4253+0000fb12@5340
4254+0000fb92@5341
4255+00007b12@5343
4256+0000eb92@5344
4257+0000ebf2@5345
4258+00006bf2@5347
4259+0000ebf0@5348
4260+0000e9c0@5349
4261+0000e140@5350
4262+0000e1c0@5351
4263+000041c0@5352
4264+0000c1c0@5353
4265+0000d140@5354
4266+0000d1c0@5355
4267+000071c2@5357
4268+0000f1c2@5358
4269+0000fb92@5359
4270+00007b92@5361
4271+0000eb92@5362
4272+0000ebf6@5363
4273+0000eb76@5365
4274+00006bf4@5366
4275+0000ebf4@5367
4276+0000effc@5368
4277+0000ef7c@5369
4278+0000effc@5370
4279+00004ffc@5371
4280+0000cffc@5372
4281+0000dffc@5373
4282+00007ffe@5375
4283+0000ff7e@5376
4284+0000ff92@5377
4285+0000fb92@5378
4286+00007b12@5380
4287+0000eb92@5381
4288+0000ebfa@5382
4289+0000eb7a@5384
4290+00006bf8@5385
4291+0000ebf8@5386
4292+0000e1c0@5387
4293+000041c0@5389
4294+0000c1c0@5390
4295+0000d140@5391
4296+0000d1c0@5392
4297+000071c2@5394
4298+0000f142@5395
4299+0000fb92@5396
4300+0000eb92@5399
4301+0000ebfe@5400
4302+00006bfe@5403
4303+0000ebfc@5404
4304+0000effc@5405
4305+0000ef7c@5406
4306+0000effc@5407
4307+00004ffc@5408
4308+0000cffc@5409
4309+0000df7c@5410
4310+0000dffc@5411
4311+0000fffe@5413
4312+0000fb96@5415
4313+00007b96@5417
4314+0000eb96@5418
4315+0000ebf2@5419
4316+0000eb72@5421
4317+00006bf0@5422
4318+0000ebf0@5423
4319+0000e140@5424
4320+0000e1c0@5425
4321+0000c1c0@5427
4322+0000c140@5428
4323+0000d1c0@5429
4324+000071c2@5431
4325+0000f142@5432
4326+0000fb96@5433
4327+00007b16@5436
4328+0000eb96@5437
4329+0000ebf6@5438
4330+0000ebf4@5441
4331+0000effc@5442
4332+0000ef7c@5443
4333+0000effc@5444
4334+00004ffc@5445
4335+0000cffc@5446
4336+0000df7c@5447
4337+0000dffc@5448
4338+00007ffe@5450
4339+0000ff7e@5451
4340+0000fb96@5452
4341+0000eb96@5455
4342+0000ebfa@5456
4343+0000eb7a@5458
4344+00006bfa@5459
4345+0000ebf8@5460
4346+0000e140@5461
4347+0000e1c0@5463
4348+000041c0@5464
4349+0000c1c0@5465
4350+0000d140@5466
4351+0000d1c0@5467
4352+000071c2@5468
4353+0000f142@5469
4354+0000fb16@5470
4355+0000fb96@5471
4356+00007b16@5473
4357+0000eb96@5474
4358+0000ebfe@5475
4359+0000eb7e@5477
4360+00006bfc@5478
4361+0000ebfc@5479
4362+0000effc@5480
4363+00006ffc@5482
4364+0000cffc@5483
4365+0000cf7c@5484
4366+0000dffc@5485
4367+00007ffe@5487
4368+0000ff7e@5488
4369+0000fb1a@5489
4370+0000fb9a@5490
4371+00007b1a@5492
4372+0000eb9a@5493
4373+0000ebf2@5494
4374+00006bf2@5496
4375+0000ebf0@5497
4376+0000e9c0@5498
4377+0000e140@5499
4378+0000e1c0@5500
4379+000041c0@5501
4380+0000c1c0@5502
4381+0000d140@5503
4382+0000d1c0@5504
4383+000071c2@5506
4384+0000f1c2@5507
4385+0000fb9a@5508
4386+00007b9a@5510
4387+0000eb9a@5511
4388+0000ebf6@5512
4389+0000eb76@5514
4390+00006bf4@5515
4391+0000ebf4@5516
4392+0000effc@5517
4393+0000ef7c@5518
4394+0000effc@5519
4395+00004ffc@5520
4396+0000cffc@5521
4397+0000dffc@5522
4398+00007ffe@5524
4399+0000ff7e@5525
4400+0000fb9a@5526
4401+00007b1a@5529
4402+0000eb9a@5530
4403+0000ebfa@5531
4404+0000eb7a@5533
4405+00006bf8@5534
4406+0000ebf8@5535
4407+0000e1c0@5536
4408+000041c0@5538
4409+0000c1c0@5539
4410+0000d140@5540
4411+0000d1c0@5541
4412+000071c2@5543
4413+0000f142@5544
4414+0000fb9a@5545
4415+0000eb9a@5548
4416+0000ebfe@5549
4417+00006bfe@5552
4418+0000ebfc@5553
4419+0000effc@5554
4420+0000ef7c@5555
4421+0000effc@5556
4422+00004ffc@5557
4423+0000cffc@5558
4424+0000df7c@5559
4425+0000dffc@5560
4426+0000fffe@5562
4427+0000fb9e@5564
4428+00007b9e@5566
4429+0000eb9e@5567
4430+0000ebf2@5568
4431+0000eb72@5570
4432+00006bf0@5571
4433+0000ebf0@5572
4434+0000e140@5573
4435+0000e1c0@5574
4436+0000c1c0@5576
4437+0000c140@5577
4438+0000d1c0@5578
4439+000071c2@5580
4440+0000f142@5581
4441+0000fb9e@5582
4442+00007b1e@5585
4443+0000eb9e@5586
4444+0000ebf6@5587
4445+0000ebf4@5590
4446+0000effc@5591
4447+0000ef7c@5592
4448+0000effc@5593
4449+00004ffc@5594
4450+0000cffc@5595
4451+0000df7c@5596
4452+0000dffc@5597
4453+00007ffe@5599
4454+0000ff7e@5600
4455+0000fb9e@5601
4456+00007b9e@5603
4457+0000eb9e@5604
4458+0000ebfa@5605
4459+0000eb7a@5607
4460+00006bfa@5608
4461+0000ebf8@5609
4462+0000e140@5610
4463+0000e1c0@5612
4464+000041c0@5613
4465+0000c1c0@5614
4466+0000d1c0@5615
4467+000071c2@5617
4468+0000f142@5618
4469+0000fb1e@5619
4470+0000fb9e@5620
4471+00007b1e@5622
4472+0000eb9e@5623
4473+0000ebfe@5624
4474+0000eb7e@5626
4475+00006bfc@5627
4476+0000ebfc@5628
4477+0000effc@5629
4478+00006ffc@5631
4479+0000cffc@5632
4480+0000cf7c@5633
4481+0000dffc@5634
4482+00007ffe@5636
4483+0000ff7e@5637
4484+0000fb22@5638
4485+0000fba2@5639
4486+00007b22@5641
4487+0000eba2@5642
4488+0000ebf2@5643
4489+00006bf2@5645
4490+0000ebf0@5646
4491+0000e9c0@5647
4492+0000e140@5648
4493+0000e1c0@5649
4494+000041c0@5650
4495+0000c1c0@5651
4496+0000d140@5652
4497+0000d1c0@5653
4498+000071c2@5655
4499+0000f1c2@5656
4500+0000fba2@5657
4501+00007ba2@5659
4502+0000eba2@5660
4503+0000ebf6@5661
4504+0000eb76@5663
4505+00006bf4@5664
4506+0000ebf4@5665
4507+0000effc@5666
4508+0000ef7c@5667
4509+0000effc@5668
4510+00004ffc@5669
4511+0000cffc@5670
4512+0000dffc@5671
4513+00007ffe@5673
4514+0000ff7e@5674
4515+0000ffa2@5675
4516+0000fba2@5676
4517+00007b22@5678
4518+0000eba2@5679
4519+0000ebfa@5680
4520+0000eb7a@5682
4521+00006bf8@5683
4522+0000ebf8@5684
4523+0000e1c0@5685
4524+000041c0@5687
4525+0000c1c0@5688
4526+0000c140@5689
4527+0000d1c0@5690
4528+000071c2@5692
4529+0000f142@5693
4530+0000fba2@5694
4531+0000eba2@5697
4532+0000ebfe@5698
4533+00006bfe@5701
4534+0000ebfc@5702
4535+0000effc@5703
4536+0000ef7c@5704
4537+0000effc@5705
4538+00004ffc@5706
4539+0000cffc@5707
4540+0000df7c@5708
4541+0000dffc@5709
4542+0000fffe@5711
4543+0000fba6@5713
4544+00007ba6@5715
4545+0000eba6@5716
4546+0000ebf2@5717
4547+0000eb72@5719
4548+00006bf0@5720
4549+0000ebf0@5721
4550+0000e140@5722
4551+0000e1c0@5723
4552+0000c1c0@5725
4553+0000c140@5726
4554+0000d1c0@5727
4555+000071c2@5729
4556+0000f142@5730
4557+0000fba6@5731
4558+00007b26@5734
4559+0000eba6@5735
4560+0000ebf6@5736
4561+0000ebf4@5739
4562+0000effc@5740
4563+0000ef7c@5741
4564+0000effc@5742
4565+00004ffc@5743
4566+0000cffc@5744
4567+0000df7c@5745
4568+0000dffc@5746
4569+00007ffe@5748
4570+0000ff7e@5749
4571+0000fba6@5750
4572+00007ba6@5752
4573+0000eba6@5753
4574+0000ebfa@5754
4575+0000eb7a@5756
4576+00006bfa@5757
4577+0000ebf8@5758
4578+0000e140@5759
4579+0000e1c0@5761
4580+000041c0@5762
4581+0000c1c0@5763
4582+0000d1c0@5764
4583+000071c2@5766
4584+0000f142@5767
4585+0000fb26@5768
4586+0000fba6@5769
4587+00007b26@5771
4588+0000eba6@5772
4589+0000ebfe@5773
4590+0000eb7e@5775
4591+00006bfc@5776
4592+0000ebfc@5777
4593+0000effc@5778
4594+00006ffc@5780
4595+0000cffc@5781
4596+0000cf7c@5782
4597+0000dffc@5783
4598+00007ffe@5785
4599+0000ff7e@5786
4600+0000fb2a@5787
4601+0000fbaa@5788
4602+00007b2a@5790
4603+0000ebaa@5791
4604+0000ebf2@5792
4605+00006bf2@5794
4606+0000ebf0@5795
4607+0000e9c0@5796
4608+0000e140@5797
4609+0000e1c0@5798
4610+000041c0@5799
4611+0000c1c0@5800
4612+0000d140@5801
4613+0000d1c0@5802
4614+000071c2@5804
4615+0000f1c2@5805
4616+0000fbaa@5806
4617+00007baa@5808
4618+0000ebaa@5809
4619+0000ebf6@5810
4620+0000eb76@5812
4621+00006bf4@5813
4622+0000ebf4@5814
4623+0000effc@5815
4624+0000ef7c@5816
4625+0000effc@5817
4626+00004ffc@5818
4627+0000cffc@5819
4628+0000dffc@5820
4629+00007ffe@5822
4630+0000ff7e@5823
4631+0000fbaa@5824
4632+00007b28@5827
4633+0000fba8@5828
4634+0000fbf4@5829
4635+0000ebf4@5830
4636+0000eb74@5831
4637+00006bf4@5832
4638+0000ebf4@5833
4639+00006bf4@5836
4640+0000ebf4@5837
4641+0000fb74@5838
4642+0000fbf4@5839
4643+00007bf6@5841
4644+0000fb76@5842
4645+0000fbaa@5843
4646+0000ebaa@5846
4647+0000ebfa@5847
4648+0000eb7a@5849
4649+00006bfa@5850
4650+0000ebf8@5851
4651+0000e1c0@5852
4652+0000e140@5853
4653+0000e1c0@5854
4654+000041c0@5855
4655+0000c1c0@5856
4656+0000d140@5857
4657+0000d1c0@5858
4658+0000f1c2@5860
4659+0000fb6a@5861
4660+0000fbaa@5862
4661+00007b2a@5864
4662+0000ebaa@5865
4663+0000ebfe@5866
4664+0000eb7e@5868
4665+00006bfc@5869
4666+0000ebfc@5870
4667+0000effc@5871
4668+0000ef7c@5872
4669+0000effc@5873
4670+0000cffc@5874
4671+0000cf7c@5875
4672+0000dffc@5876
4673+00007ffe@5878
4674+0000ff7e@5879
4675+0000fbae@5880
4676+00007b2e@5883
4677+0000ebae@5884
4678+0000ebf2@5885
4679+0000ebf0@5888
4680+0000e140@5890
4681+0000e1c0@5891
4682+000041c0@5892
4683+0000c1c0@5893
4684+0000d140@5894
4685+0000d1c0@5895
4686+000071c2@5897
4687+0000f142@5898
4688+0000fbae@5899
4689+00007bae@5901
4690+0000ebae@5902
4691+0000ebf6@5903
4692+0000eb76@5905
4693+00006bf6@5906
4694+0000ebf4@5907
4695+0000effc@5908
4696+0000ef7c@5909
4697+0000effc@5910
4698+00004ffc@5911
4699+0000cffc@5912
4700+0000dffc@5913
4701+00007ffe@5915
4702+0000ff7e@5916
4703+0000fbbe@5917
4704+0000fbae@5918
4705+00007b2e@5920
4706+0000fbae@5921
4707+0000ebfa@5922
4708+0000eb7a@5924
4709+00006bf8@5925
4710+0000ebf8@5926
4711+0000e1c0@5927
4712+000061c0@5929
4713+0000c1c0@5930
4714+0000c140@5931
4715+0000d1c0@5932
4716+000071c2@5934
4717+0000f142@5935
4718+0000fbae@5936
4719+00007b2e@5939
4720+0000ebae@5940
4721+0000ebfe@5941
4722+00006bfe@5943
4723+0000ebfc@5944
4724+0000effc@5945
4725+0000ef7c@5946
4726+0000effc@5947
4727+00004ffc@5948
4728+0000cffc@5949
4729+0000df7c@5950
4730+0000dffc@5951
4731+00007ffe@5953
4732+0000fffe@5954
4733+0000fbb2@5955
4734+00007bb2@5957
4735+0000ebb2@5958
4736+0000ebf2@5959
4737+0000eb72@5961
4738+00006bf0@5962
4739+0000ebf0@5963
4740+0000e140@5964
4741+0000e1c0@5966
4742+000041c0@5967
4743+0000c1c0@5968
4744+0000d1c0@5969
4745+000071c2@5971
4746+0000f142@5972
4747+0000fbb2@5973
4748+00007b32@5976
4749+0000ebb2@5977
4750+0000ebf6@5978
4751+0000eb76@5980
4752+00006bf4@5981
4753+0000effc@5982
4754+0000ef7c@5983
4755+0000effc@5984
4756+00004ffc@5985
4757+0000cffc@5986
4758+0000df7c@5987
4759+0000dffc@5988
4760+00007ffe@5990
4761+0000ff7e@5991
4762+0000fbb2@5992
4763+0000ebb2@5995
4764+0000ebfa@5996
4765+0000eb7a@5998
4766+00006bfa@5999
4767+0000ebf8@6000
4768+0000e1c0@6001
4769+0000e140@6002
4770+0000e1c0@6003
4771+000041c0@6004
4772+0000c1c0@6005
4773+0000d140@6006
4774+0000d1c0@6007
4775+0000f1c2@6009
4776+0000fb72@6010
4777+0000fbb2@6011
4778+00007b32@6013
4779+0000ebb2@6014
4780+0000ebfe@6015
4781+0000eb7e@6017
4782+00006bfc@6018
4783+0000ebfc@6019
4784+0000effc@6020
4785+0000ef7c@6021
4786+0000effc@6022
4787+0000cffc@6023
4788+0000cf7c@6024
4789+0000dffc@6025
4790+00007ffe@6027
4791+0000ff7e@6028
4792+0000fbb6@6029
4793+00007b36@6032
4794+0000ebb6@6033
4795+0000ebf2@6034
4796+0000ebf0@6037
4797+0000e140@6039
4798+0000e1c0@6040
4799+000041c0@6041
4800+0000c1c0@6042
4801+0000d140@6043
4802+0000d1c0@6044
4803+000071c2@6046
4804+0000f142@6047
4805+0000fbb6@6048
4806+00007bb6@6050
4807+0000ebb6@6051
4808+0000ebf6@6052
4809+0000eb76@6054
4810+00006bf6@6055
4811+0000ebf4@6056
4812+0000effc@6057
4813+0000ef7c@6058
4814+0000effc@6059
4815+00004ffc@6060
4816+0000cffc@6061
4817+0000dffc@6062
4818+00007ffe@6064
4819+0000ff7e@6065
4820+0000fbbe@6066
4821+0000fbb6@6067
4822+00007b36@6069
4823+0000fbb6@6070
4824+0000ebfa@6071
4825+0000eb7a@6073
4826+00006bf8@6074
4827+0000ebf8@6075
4828+0000e1c0@6076
4829+000061c0@6078
4830+0000c1c0@6079
4831+0000c140@6080
4832+0000d1c0@6081
4833+000071c2@6083
4834+0000f142@6084
4835+0000fbb6@6085
4836+00007b36@6088
4837+0000ebb6@6089
4838+0000ebfe@6090
4839+00006bfe@6092
4840+0000ebfc@6093
4841+0000effc@6094
4842+0000ef7c@6095
4843+0000effc@6096
4844+00004ffc@6097
4845+0000cffc@6098
4846+0000df7c@6099
4847+0000dffc@6100
4848+00007ffe@6102
4849+0000fffe@6103
4850+0000fbba@6104
4851+00007bba@6106
4852+0000ebba@6107
4853+0000ebf2@6108
4854+0000eb72@6110
4855+00006bf0@6111
4856+0000ebf0@6112
4857+0000e140@6113
4858+0000e1c0@6115
4859+000041c0@6116
4860+0000c1c0@6117
4861+0000d1c0@6118
4862+000071c2@6120
4863+0000f142@6121
4864+0000fbba@6122
4865+00007b3a@6125
4866+0000ebba@6126
4867+0000ebf6@6127
4868+0000eb76@6129
4869+00006bf4@6130
4870+0000effc@6131
4871+0000ef7c@6132
4872+0000effc@6133
4873+00004ffc@6134
4874+0000cffc@6135
4875+0000df7c@6136
4876+0000dffc@6137
4877+00007ffe@6139
4878+0000ff7e@6140
4879+0000fbba@6141
4880+0000ebba@6144
4881+0000ebfa@6145
4882+0000eb7a@6147
4883+00006bfa@6148
4884+0000ebf8@6149
4885+0000e1c0@6150
4886+0000e140@6151
4887+0000e1c0@6152
4888+000041c0@6153
4889+0000c1c0@6154
4890+0000d140@6155
4891+0000d1c0@6156
4892+0000f1c2@6158
4893+0000fb7a@6159
4894+0000fbba@6160
4895+00007b3a@6162
4896+0000ebba@6163
4897+0000ebfe@6164
4898+0000eb7e@6166
4899+00006bfc@6167
4900+0000ebfc@6168
4901+0000effc@6169
4902+0000ef7c@6170
4903+0000effc@6171
4904+0000cffc@6172
4905+0000cf7c@6173
4906+0000dffc@6174
4907+00007ffe@6176
4908+0000ff7e@6177
4909+0000fbbe@6178
4910+00007b3e@6181
4911+0000ebbe@6182
4912+0000ebf2@6183
4913+0000ebf0@6186
4914+0000e140@6188
4915+0000e1c0@6189
4916+000041c0@6190
4917+0000c1c0@6191
4918+0000d140@6192
4919+0000d1c0@6193
4920+000071c2@6195
4921+0000f142@6196
4922+0000fbbe@6197
4923+00007bbe@6199
4924+0000ebbe@6200
4925+0000ebf6@6201
4926+0000eb76@6203
4927+00006bf6@6204
4928+0000ebf4@6205
4929+0000effc@6206
4930+0000ef7c@6207
4931+0000effc@6208
4932+00004ffc@6209
4933+0000cffc@6210
4934+0000dffc@6211
4935+00007ffe@6213
4936+0000ff7e@6214
4937+0000fbbe@6215
4938+00007b3e@6218
4939+0000ebbe@6219
4940+0000ebfa@6220
4941+0000eb7a@6222
4942+00006bf8@6223
4943+0000ebf8@6224
4944+0000e1c0@6225
4945+000061c0@6227
4946+0000c1c0@6228
4947+0000c140@6229
4948+0000d1c0@6230
4949+000071c2@6232
4950+0000f142@6233
4951+0000fbbe@6234
4952+00007b3e@6237
4953+0000ebbe@6238
4954+0000ebfe@6239
4955+00006bfe@6241
4956+0000ebfc@6242
4957+0000effc@6243
4958+0000ef7c@6244
4959+0000effc@6245
4960+00004ffc@6246
4961+0000cffc@6247
4962+0000df7c@6248
4963+0000dffc@6249
4964+00007ffe@6251
4965+0000fffe@6252
4966+0000fd82@6253
4967+00007d82@6255
4968+0000ed82@6256
4969+0000ebf2@6257
4970+0000eb72@6259
4971+00006bf0@6260
4972+0000ebf0@6261
4973+0000e140@6262
4974+0000e1c0@6264
4975+000041c0@6265
4976+0000c1c0@6266
4977+0000d1c0@6267
4978+000071c2@6269
4979+0000f142@6270
4980+0000fd02@6271
4981+0000fd82@6272
4982+00007d02@6274
4983+0000ed82@6275
4984+0000ebf6@6276
4985+0000eb76@6278
4986+00006bf4@6279
4987+0000effc@6280
4988+0000ef7c@6281
4989+0000effc@6282
4990+00004ffc@6283
4991+0000cffc@6284
4992+0000df7c@6285
4993+0000dffc@6286
4994+00007ffe@6288
4995+0000ff7e@6289
4996+0000fd82@6290
4997+0000ed82@6293
4998+0000effa@6294
4999+0000ebfa@6295
5000+0000eb7a@6296
5001+00006bfa@6297
5002+0000ebf8@6298
5003+0000e1c0@6299
5004+0000e140@6300
5005+0000e1c0@6301
5006+000041c0@6302
5007+0000c1c0@6303
5008+0000d140@6304
5009+0000d1c0@6305
5010+0000f1c0@6306
5011+0000f1c2@6307
5012+0000fdc2@6308
5013+0000fd82@6309
5014+00007d02@6311
5015+0000ed82@6312
5016+0000ebfe@6313
5017+0000eb7e@6315
5018+00006bfc@6316
5019+0000ebfc@6317
5020+0000effc@6318
5021+0000ef7c@6319
5022+0000effc@6320
5023+0000cffc@6321
5024+0000cf7c@6322
5025+0000dffc@6323
5026+00007ffe@6325
5027+0000ff7e@6326
5028+0000fd06@6327
5029+0000fd86@6328
5030+00007d06@6330
5031+0000ed86@6331
5032+0000ebf2@6332
5033+0000ebf0@6335
5034+0000e140@6337
5035+0000e1c0@6338
5036+000041c0@6339
5037+0000c1c0@6340
5038+0000d140@6341
5039+0000d1c0@6342
5040+000071c2@6344
5041+0000f142@6345
5042+0000fd86@6346
5043+00007d86@6348
5044+0000ed86@6349
5045+0000ebf6@6350
5046+0000eb76@6352
5047+00006bf6@6353
5048+0000ebf4@6354
5049+0000effc@6355
5050+0000ef7c@6356
5051+0000effc@6357
5052+00004ffc@6358
5053+0000cffc@6359
5054+0000dffc@6360
5055+00007ffe@6362
5056+0000ff7e@6363
5057+0000ff86@6364
5058+0000fc86@6365
5059+00007c06@6367
5060+0000ec86@6368
5061+0000eafa@6369
5062+0000ea7a@6371
5063+00006a78@6372
5064+0000eaf8@6373
5065+0000e0c0@6374
5066+00006040@6376
5067+0000c040@6377
5068+0000c0c0@6378
5069+0000d0c0@6379
5070+0000d040@6380
5071+00007042@6381
5072+0000f0c2@6382
5073+0000fc86@6383
5074+0000fc06@6385
5075+00007c06@6386
5076+0000ec86@6387
5077+0000eafe@6388
5078+00006a7e@6390
5079+0000ea7c@6391
5080+0000eefc@6392
5081+0000ee7c@6394
5082+00004e7c@6395
5083+0000cefc@6396
5084+0000defc@6397
5085+0000de7c@6399
5086+00007e7e@6400
5087+0000fefe@6401
5088+0000fc8a@6402
5089+00007c0a@6404
5090+0000ec8a@6405
5091+0000eaf2@6406
5092+0000ea72@6408
5093+00006a70@6409
5094+0000eaf0@6410
5095+0000e0c0@6411
5096+0000e040@6413
5097+00004040@6414
5098+0000c0c0@6415
5099+0000d0c0@6416
5100+00007042@6418
5101+0000f042@6419
5102+0000fc8a@6420
5103+0000fc0a@6422
5104+00007c0a@6423
5105+0000ec8a@6424
5106+0000eaf6@6425
5107+0000ea76@6427
5108+00006a74@6428
5109+0000eefc@6429
5110+00004e7c@6432
5111+0000cefc@6433
5112+0000defc@6434
5113+0000de7c@6436
5114+00007e7e@6437
5115+0000fefe@6438
5116+0000fc8a@6439
5117+0000ec8a@6442
5118+0000eefa@6443
5119+0000eafa@6444
5120+00006afa@6446
5121+0000eaf8@6447
5122+0000e040@6448
5123+0000e0c0@6450
5124+000040c0@6451
5125+0000c0c0@6452
5126+0000d040@6453
5127+0000f0c0@6455
5128+0000f0c2@6456
5129+0000fc4a@6457
5130+0000fc0a@6458
5131+0000fc8a@6459
5132+00007c8a@6460
5133+0000ec8a@6461
5134+0000eafe@6462
5135+0000ea7e@6463
5136+0000eafe@6464
5137+00006afc@6465
5138+0000eafc@6466
5139+0000ee7c@6467
5140+0000eefc@6469
5141+0000cefc@6470
5142+0000de7c@6472
5143+00007efe@6474
5144+0000fefe@6475
5145+0000fc0e@6476
5146+0000fc8e@6478
5147+00007c8e@6479
5148+0000ec8e@6480
5149+0000ea72@6481
5150+0000eaf2@6483
5151+0000eaf0@6484
5152+0000e040@6486
5153+000040c0@6488
5154+0000c0c0@6489
5155+0000d040@6490
5156+0000d0c0@6492
5157+000070c2@6493
5158+0000f0c2@6494
5159+0000fc0e@6495
5160+00007c8e@6497
5161+0000ec8e@6498
5162+0000eaf6@6499
5163+0000ea76@6500
5164+0000eaf6@6501
5165+00006af6@6502
5166+0000eaf4@6503
5167+0000ee7c@6504
5168+0000eefc@6506
5169+00004efc@6507
5170+0000cefc@6508
5171+0000de7c@6509
5172+00007efe@6511
5173+0000fefe@6512
5174+0000fe8e@6513
5175+0000fc0e@6514
5176+0000fc8e@6515
5177+00007c8e@6516
5178+0000ec8e@6517
5179+0000eafa@6518
5180+00006af8@6521
5181+0000ea78@6522
5182+0000e0c0@6523
5183+000060c0@6525
5184+0000c040@6526
5185+0000d0c0@6528
5186+00007042@6530
5187+0000f042@6531
5188+0000fc8e@6532
5189+00007c0e@6535
5190+0000ec0e@6536
5191+0000eafe@6537
5192+00006afe@6539
5193+0000ea7c@6540
5194+0000ee7c@6541
5195+0000eefc@6542
5196+00004e7c@6544
5197+0000ce7c@6545
5198+0000defc@6546
5199+00007e7e@6549
5200+0000fe7e@6550
5201+0000fc92@6551
5202+00007c92@6553
5203+0000ec12@6554
5204+0000eaf2@6555
5205+00006a70@6558
5206+0000ea70@6559
5207+0000e0c0@6560
5208+00004040@6563
5209+0000c040@6564
5210+0000d0c0@6565
5211+00007042@6567
5212+0000f042@6568
5213+0000fc12@6569
5214+0000fc92@6570
5215+00007c12@6572
5216+0000ec12@6573
5217+0000eaf6@6574
5218+00006a74@6577
5219+0000ee7c@6578
5220+0000eefc@6579
5221+00004efc@6581
5222+0000ce7c@6582
5223+0000de7c@6583
5224+0000defc@6584
5225+00007e7e@6586
5226+0000fe7e@6587
5227+0000fc92@6588
5228+0000ec12@6591
5229+0000ee7a@6592
5230+0000eafa@6593
5231+00006a7a@6595
5232+0000eaf8@6596
5233+0000e0c0@6597
5234+0000e040@6599
5235+000040c0@6600
5236+0000c0c0@6601
5237+0000d0c0@6602
5238+0000d040@6603
5239+0000f040@6604
5240+0000f0c2@6605
5241+0000fcd2@6606
5242+0000fd12@6607
5243+00007d92@6609
5244+0000ed92@6610
5245+0000ebfe@6611
5246+0000eb7e@6612
5247+00006bfc@6614
5248+0000ebfc@6615
5249+0000effc@6616
5250+0000ef7c@6617
5251+0000cffc@6619
5252+0000dffc@6621
5253+0000df7c@6622
5254+00007ffe@6623
5255+0000fffe@6624
5256+0000fd92@6625
5257+0000fd12@6626
5258+00007d90@6628
5259+0000fd90@6629
5260+0000fbfc@6630
5261+0000eb7c@6631
5262+00006b7c@6632
5263+0000ebfc@6633
5264+0000eb7c@6635
5265+00006bfc@6637
5266+0000ebfc@6638
5267+0000fbfc@6639
5268+0000fb7c@6640
5269+00007bfe@6642
5270+0000fbfe@6643
5271+0000fd96@6644
5272+0000fd16@6645
5273+00007d16@6646
5274+0000ed96@6647
5275+0000ebf2@6648
5276+0000eb72@6650
5277+00006b72@6651
5278+0000ebf0@6652
5279+0000e1c0@6653
5280+0000e140@6654
5281+000041c0@6656
5282+0000c1c0@6657
5283+0000d1c0@6658
5284+0000d140@6659
5285+00007142@6660
5286+0000f1c2@6661
5287+0000fd96@6662
5288+0000fd16@6663
5289+00007d96@6665
5290+0000ed96@6666
5291+0000ebf6@6667
5292+0000eb76@6668
5293+00006bf4@6670
5294+0000ebf4@6671
5295+0000effc@6672
5296+00006ffc@6674
5297+0000cffc@6675
5298+0000cf7c@6676
5299+0000dffc@6677
5300+00007ffe@6679
5301+0000ff7e@6680
5302+0000fd16@6681
5303+0000fd96@6682
5304+00007d16@6684
5305+0000ed96@6685
5306+0000ebfa@6686
5307+00006bfa@6688
5308+0000ebf8@6689
5309+0000e9c0@6690
5310+0000e140@6691
5311+0000e1c0@6692
5312+000041c0@6693
5313+0000c1c0@6694
5314+0000d140@6695
5315+0000d1c0@6696
5316+000071c2@6698
5317+0000f5c6@6699
5318+0000fd96@6700
5319+00007d96@6702
5320+0000ed96@6703
5321+0000ebfe@6704
5322+0000eb7e@6706
5323+00006bfc@6707
5324+0000ebfc@6708
5325+0000effc@6709
5326+0000ef7c@6710
5327+0000effc@6711
5328+00004ffc@6712
5329+0000cffc@6713
5330+0000dffc@6714
5331+00007ffe@6716
5332+0000ff7e@6717
5333+0000fd9a@6718
5334+00007d1a@6721
5335+0000ed9a@6722
5336+0000ebf2@6723
5337+0000eb72@6725
5338+00006bf0@6726
5339+0000ebf0@6727
5340+0000e1c0@6728
5341+000041c0@6730
5342+0000c1c0@6731
5343+0000d140@6732
5344+0000d1c0@6733
5345+000071c2@6735
5346+0000f142@6736
5347+0000fd9a@6737
5348+0000ed9a@6740
5349+0000effe@6741
5350+0000ebf6@6742
5351+0000eb76@6743
5352+00006bf6@6744
5353+0000ebf4@6745
5354+0000effc@6746
5355+0000ef7c@6747
5356+0000effc@6748
5357+00004ffc@6749
5358+0000cffc@6750
5359+0000df7c@6751
5360+0000dffc@6752
5361+0000fffc@6753
5362+0000fffe@6754
5363+0000fd9a@6756
5364+00007d1a@6758
5365+0000ed9a@6759
5366+0000ebfa@6760
5367+0000eb7a@6762
5368+00006bf8@6763
5369+0000ebf8@6764
5370+0000e140@6765
5371+0000e1c0@6766
5372+0000c1c0@6768
5373+0000c140@6769
5374+0000d1c0@6770
5375+000071c2@6772
5376+0000f142@6773
5377+0000fd9a@6774
5378+00007d1a@6777
5379+0000ed9a@6778
5380+0000ebfe@6779
5381+00006bfe@6781
5382+0000ebfc@6782
5383+0000effc@6783
5384+0000ef7c@6784
5385+0000effc@6785
5386+00004ffc@6786
5387+0000cffc@6787
5388+0000df7c@6788
5389+0000dffc@6789
5390+00007ffe@6791
5391+0000fffe@6792
5392+0000fd9e@6793
5393+00007d9e@6795
5394+0000ed9e@6796
5395+0000ebf2@6797
5396+0000eb72@6799
5397+00006bf2@6800
5398+0000ebf0@6801
5399+0000e140@6802
5400+0000e1c0@6804
5401+000041c0@6805
5402+0000c1c0@6806
5403+0000d1c0@6807
5404+000071c2@6809
5405+0000f142@6810
5406+0000fd1e@6811
5407+0000fd9e@6812
5408+00007d1e@6814
5409+0000ed9e@6815
5410+0000ebf6@6816
5411+0000eb76@6818
5412+00006bf4@6819
5413+0000ebf4@6820
5414+0000effc@6821
5415+00006ffc@6823
5416+0000cffc@6824
5417+0000cf7c@6825
5418+0000dffc@6826
5419+00007ffe@6828
5420+0000ff7e@6829
5421+0000fd9e@6830
5422+00007d1e@6833
5423+0000ed9e@6834
5424+0000ebfa@6835
5425+00006bfa@6837
5426+0000ebf8@6838
5427+0000e1c0@6839
5428+0000e140@6840
5429+0000e1c0@6841
5430+000041c0@6842
5431+0000c1c0@6843
5432+0000d140@6844
5433+0000d1c0@6845
5434+000071c2@6847
5435+0000f1ce@6848
5436+0000fd9e@6849
5437+00007d1e@6851
5438+0000ed9e@6852
5439+0000ebfe@6853
5440+0000eb7e@6855
5441+00006bfc@6856
5442+0000ebfc@6857
5443+0000effc@6858
5444+0000ef7c@6859
5445+0000effc@6860
5446+00004ffc@6861
5447+0000cffc@6862
5448+0000dffc@6863
5449+00007ffe@6865
5450+0000ff7e@6866
5451+0000fda2@6867
5452+00007d22@6870
5453+0000eda2@6871
5454+0000ebf2@6872
5455+0000eb72@6874
5456+00006bf0@6875
5457+0000ebf0@6876
5458+0000e1c0@6877
5459+000041c0@6879
5460+0000c1c0@6880
5461+0000d140@6881
5462+0000d1c0@6882
5463+000071c2@6884
5464+0000f142@6885
5465+0000fda2@6886
5466+0000eda2@6889
5467+0000eff6@6890
5468+0000ebf6@6891
5469+0000eb76@6892
5470+00006bf6@6893
5471+0000ebf4@6894
5472+0000effc@6895
5473+0000ef7c@6896
5474+0000effc@6897
5475+00004ffc@6898
5476+0000cffc@6899
5477+0000df7c@6900
5478+0000dffc@6901
5479+0000fffc@6902
5480+0000ff7e@6903
5481+0000fffe@6904
5482+0000fda2@6905
5483+00007d22@6907
5484+0000eda2@6908
5485+0000ebfa@6909
5486+0000eb7a@6911
5487+00006bf8@6912
5488+0000ebf8@6913
5489+0000e140@6914
5490+0000e1c0@6915
5491+0000c1c0@6917
5492+0000c140@6918
5493+0000d1c0@6919
5494+000071c2@6921
5495+0000f142@6922
5496+0000fda2@6923
5497+00007d22@6926
5498+0000eda2@6927
5499+0000ebfe@6928
5500+00006bfe@6930
5501+0000ebfc@6931
5502+0000effc@6932
5503+0000ef7c@6933
5504+0000effc@6934
5505+00004ffc@6935
5506+0000cffc@6936
5507+0000df7c@6937
5508+0000dffc@6938
5509+00007ffe@6940
5510+0000ff7e@6941
5511+0000fda6@6942
5512+00007da6@6944
5513+0000eda6@6945
5514+0000ebf2@6946
5515+0000eb72@6948
5516+00006bf2@6949
5517+0000ebf0@6950
5518+0000e140@6951
5519+0000e1c0@6953
5520+000041c0@6954
5521+0000c1c0@6955
5522+0000d1c0@6956
5523+000071c2@6958
5524+0000f142@6959
5525+0000fd26@6960
5526+0000fda6@6961
5527+00007d26@6963
5528+0000eda6@6964
5529+0000ebf6@6965
5530+0000eb76@6967
5531+00006bf4@6968
5532+0000ebf4@6969
5533+0000effc@6970
5534+00006ffc@6972
5535+0000cffc@6973
5536+0000cf7c@6974
5537+0000dffc@6975
5538+00007ffe@6977
5539+0000ff7e@6978
5540+0000fd26@6979
5541+0000fda6@6980
5542+00007d26@6982
5543+0000eda6@6983
5544+0000ebfa@6984
5545+00006bfa@6986
5546+0000ebf8@6987
5547+0000e1c0@6988
5548+0000e140@6989
5549+0000e1c0@6990
5550+000041c0@6991
5551+0000c1c0@6992
5552+0000d140@6993
5553+0000d1c0@6994
5554+000071c2@6996
5555+0000f5c6@6997
5556+0000fda6@6998
5557+00007da6@7000
5558+0000eda6@7001
5559+0000ebfe@7002
5560+0000eb7e@7004
5561+00006bfc@7005
5562+0000ebfc@7006
5563+0000effc@7007
5564+0000ef7c@7008
5565+0000effc@7009
5566+00004ffc@7010
5567+0000cffc@7011
5568+0000dffc@7012
5569+00007ffe@7014
5570+0000ff7e@7015
5571+0000fdaa@7016
5572+00007d2a@7019
5573+0000edaa@7020
5574+0000ebf2@7021
5575+0000eb72@7023
5576+0000ebf0@7024
5577+0000e1c0@7026
5578+000041c0@7028
5579+0000c1c0@7029
5580+0000d140@7030
5581+0000d1c0@7031
5582+000071c2@7033
5583+0000f142@7034
5584+0000fdaa@7035
5585+0000edaa@7038
5586+0000effe@7039
5587+0000ebf6@7040
5588+0000eb76@7041
5589+00006bf6@7042
5590+0000ebf4@7043
5591+0000effc@7044
5592+0000ef7c@7045
5593+0000effc@7046
5594+00004ffc@7047
5595+0000cffc@7048
5596+0000df7c@7049
5597+0000dffc@7050
5598+0000fffc@7051
5599+0000fffe@7052
5600+0000fdaa@7054
5601+00007d2a@7056
5602+0000edaa@7057
5603+0000ebfa@7058
5604+0000eb7a@7060
5605+00006bf8@7061
5606+0000ebf8@7062
5607+0000e140@7063
5608+0000e1c0@7064
5609+0000c1c0@7066
5610+0000c140@7067
5611+0000d1c0@7068
5612+000071c2@7070
5613+0000f142@7071
5614+0000fdaa@7072
5615+00007d2a@7075
5616+0000edaa@7076
5617+0000ebfe@7077
5618+00006bfe@7079
5619+0000ebfc@7080
5620+0000effc@7081
5621+0000ef7c@7082
5622+0000effc@7083
5623+00004ffc@7084
5624+0000cffc@7085
5625+0000df7c@7086
5626+0000dffc@7087
5627+00007ffe@7089
5628+0000fffe@7090
5629+0000fdae@7091
5630+00007dae@7093
5631+0000edae@7094
5632+0000ebf2@7095
5633+0000eb72@7097
5634+00006bf2@7098
5635+0000ebf0@7099
5636+0000e140@7100
5637+0000e1c0@7102
5638+000041c0@7103
5639+0000c1c0@7104
5640+0000d1c0@7105
5641+000071c2@7107
5642+0000f142@7108
5643+0000fd2e@7109
5644+0000fdae@7110
5645+00007d2e@7112
5646+0000edae@7113
5647+0000ebf6@7114
5648+0000eb76@7116
5649+00006bf4@7117
5650+0000ebf4@7118
5651+0000effc@7119
5652+00004ffc@7121
5653+0000cffc@7122
5654+0000cf7c@7123
5655+0000dffc@7124
5656+00007ffe@7126
5657+0000ff7e@7127
5658+0000fdae@7128
5659+00006d2e@7131
5660+0000edae@7132
5661+0000ebfa@7133
5662+00006bfa@7135
5663+0000ebf8@7136
5664+0000e1c0@7137
5665+0000e140@7138
5666+0000e1c0@7139
5667+000041c0@7140
5668+0000c1c0@7141
5669+0000d140@7142
5670+0000d1c0@7143
5671+000071c2@7145
5672+0000f5ce@7146
5673+0000fdae@7147
5674+00007d2e@7149
5675+0000edae@7150
5676+0000ebfe@7151
5677+0000eb7e@7153
5678+00006bfc@7154
5679+0000ebfc@7155
5680+0000effc@7156
5681+0000ef7c@7157
5682+0000effc@7158
5683+00004ffc@7159
5684+0000cffc@7160
5685+0000dffc@7161
5686+00007ffe@7163
5687+0000ff7e@7164
5688+0000fdb2@7165
5689+00007d32@7168
5690+0000edb2@7169
5691+0000ebf2@7170
5692+0000eb72@7172
5693+0000ebf0@7173
5694+0000e1c0@7175
5695+000041c0@7177
5696+0000c1c0@7178
5697+0000d140@7179
5698+0000d1c0@7180
5699+000071c2@7182
5700+0000f142@7183
5701+0000fdb2@7184
5702+0000edb2@7187
5703+0000ebf6@7188
5704+0000eb76@7190
5705+00006bf6@7191
5706+0000ebf4@7192
5707+0000effc@7193
5708+0000ef7c@7194
5709+0000effc@7195
5710+00004ffc@7196
5711+0000cffc@7197
5712+0000df7c@7198
5713+0000dffc@7199
5714+0000fffc@7200
5715+0000fffe@7201
5716+0000fdb2@7203
5717+00007d32@7205
5718+0000edb2@7206
5719+0000ebfa@7207
5720+0000eb7a@7209
5721+00006bf8@7210
5722+0000ebf8@7211
5723+0000e140@7212
5724+0000e1c0@7213
5725+0000c1c0@7215
5726+0000c140@7216
5727+0000d1c0@7217
5728+000071c2@7219
5729+0000f142@7220
5730+0000fdb2@7221
5731+00007d30@7224
5732+0000fdb0@7225
5733+0000fbf8@7226
5734+0000ebf8@7227
5735+00006bf8@7228
5736+0000ebf8@7229
5737+0000eb7c@7231
5738+0000ebfc@7232
5739+00006bfc@7233
5740+0000effc@7234
5741+0000ff78@7235
5742+0000fffc@7236
5743+00007ffe@7238
5744+0000ff7e@7239
5745+0000fdb2@7240
5746+00007db2@7242
5747+0000edb2@7243
5748+0000ebfe@7244
5749+0000eb7e@7246
5750+00006bfc@7247
5751+0000ebfc@7248
5752+0000effc@7249
5753+0000ef7c@7250
5754+0000effc@7251
5755+00004ffc@7252
5756+0000cffc@7253
5757+0000dffc@7254
5758+00007ffe@7256
5759+0000ff7e@7257
5760+0000fdb6@7258
5761+00007d36@7261
5762+0000fdb6@7262
5763+0000ebf2@7263
5764+0000eb72@7265
5765+00006bf0@7266
5766+0000ebf0@7267
5767+0000e1c0@7268
5768+000061c0@7270
5769+0000c1c0@7271
5770+0000c140@7272
5771+0000d1c0@7273
5772+000071c2@7275
5773+0000f142@7276
5774+0000fdb6@7277
5775+00007d36@7280
5776+0000edf6@7281
5777+0000ebf6@7282
5778+00006bf6@7284
5779+0000ebf4@7285
5780+0000effc@7286
5781+0000ef7c@7287
5782+0000effc@7288
5783+00004ffc@7289
5784+0000cffc@7290
5785+0000df7c@7291
5786+0000dffc@7292
5787+00007ffe@7294
5788+0000fffe@7295
5789+0000fdb6@7296
5790+00007db6@7298
5791+0000edb6@7299
5792+0000ebfa@7300
5793+0000eb7a@7302
5794+00006bf8@7303
5795+0000ebf8@7304
5796+0000e140@7305
5797+0000e1c0@7307
5798+000041c0@7308
5799+0000c1c0@7309
5800+0000d1c0@7310
5801+000071c2@7312
5802+0000f142@7313
5803+0000fdb6@7314
5804+00007d36@7317
5805+0000edb6@7318
5806+0000ebfe@7319
5807+0000eb7e@7321
5808+0000ebfc@7322
5809+0000effc@7323
5810+0000ef7c@7324
5811+0000effc@7325
5812+00004ffc@7326
5813+0000cffc@7327
5814+0000df7c@7328
5815+0000dffc@7329
5816+00007ffe@7331
5817+0000ff7e@7332
5818+0000fdba@7333
5819+0000edba@7336
5820+0000eff2@7337
5821+0000ebf2@7338
5822+0000eb72@7339
5823+00006bf2@7340
5824+0000ebf0@7341
5825+0000e1c0@7342
5826+0000e140@7343
5827+0000e1c0@7344
5828+000041c0@7345
5829+0000c1c0@7346
5830+0000d140@7347
5831+0000d1c0@7348
5832+0000f1c0@7349
5833+0000f1c2@7350
5834+0000fd7a@7351
5835+0000fdba@7352
5836+00007d3a@7354
5837+0000edba@7355
5838+0000ebf6@7356
5839+0000eb76@7358
5840+00006bf4@7359
5841+0000ebf4@7360
5842+0000effc@7361
5843+0000ef7c@7362
5844+0000effc@7363
5845+0000cffc@7364
5846+0000cf7c@7365
5847+0000dffc@7366
5848+00007ffe@7368
5849+0000ff7e@7369
5850+0000fdba@7370
5851+00007d3a@7373
5852+0000edba@7374
5853+0000ebfa@7375
5854+00006bfa@7377
5855+0000ebf8@7378
5856+0000ebe8@7379
5857+0000e140@7380
5858+0000e1c0@7381
5859+000041c0@7382
5860+0000c1c0@7383
5861+0000d140@7384
5862+0000d1c0@7385
5863+000071c2@7387
5864+0000f1c2@7388
5865+0000fdba@7389
5866+00007dba@7391
5867+0000edba@7392
5868+0000ebfe@7393
5869+0000eb7e@7395
5870+00006bfc@7396
5871+0000ebfc@7397
5872+0000effc@7398
5873+0000ef7c@7399
5874+0000effc@7400
5875+00004ffc@7401
5876+0000cffc@7402
5877+0000dffc@7403
5878+00007ffe@7405
5879+0000ff7e@7406
5880+0000fdbe@7407
5881+00007d3e@7410
5882+0000fdbe@7411
5883+0000ebf2@7412
5884+0000eb72@7414
5885+00006bf0@7415
5886+0000ebf0@7416
5887+0000e1c0@7417
5888+000061c0@7419
5889+0000c1c0@7420
5890+0000c140@7421
5891+0000d1c0@7422
5892+000071c2@7424
5893+0000f142@7425
5894+0000fdbe@7426
5895+00007d3e@7429
5896+0000edfe@7430
5897+0000ebf6@7431
5898+0000eb76@7432
5899+00006bf6@7433
5900+0000ebf4@7434
5901+0000effc@7435
5902+0000ef7c@7436
5903+0000effc@7437
5904+00004ffc@7438
5905+0000cffc@7439
5906+0000df7c@7440
5907+0000dffc@7441
5908+00007ffe@7443
5909+0000fffe@7444
5910+0000fdbe@7445
5911+00007dbe@7447
5912+0000edbe@7448
5913+0000ebfa@7449
5914+0000eb7a@7451
5915+00006bf8@7452
5916+0000ebf8@7453
5917+0000e140@7454
5918+0000e1c0@7456
5919+000041c0@7457
5920+0000c1c0@7458
5921+0000d1c0@7459
5922+000071c2@7461
5923+0000f142@7462
5924+0000fdbe@7463
5925+00007d3e@7466
5926+0000edbe@7467
5927+0000ebfe@7468
5928+0000eb7e@7470
5929+0000ebfc@7471
5930+0000effc@7472
5931+0000ef7c@7473
5932+0000effc@7474
5933+00004ffc@7475
5934+0000cffc@7476
5935+0000df7c@7477
5936+0000dffc@7478
5937+00007ffe@7480
5938+0000ff7e@7481
5939+0000ff82@7482
5940+0000ef82@7485
5941+0000ebf2@7486
5942+0000eb72@7488
5943+00006bf2@7489
5944+0000ebf0@7490
5945+0000e1c0@7491
5946+0000e140@7492
5947+0000e1c0@7493
5948+000041c0@7494
5949+0000c1c0@7495
5950+0000d140@7496
5951+0000d1c0@7497
5952+0000f1c0@7498
5953+0000f1c2@7499
5954+0000ff42@7500
5955+0000ff82@7501
5956+00007f02@7503
5957+0000ef82@7504
5958+0000ebf6@7505
5959+0000eb76@7507
5960+00006bf4@7508
5961+0000ebf4@7509
5962+0000effc@7510
5963+0000cffc@7513
5964+0000cf7c@7514
5965+0000dffc@7515
5966+00007ffe@7517
5967+0000ff7e@7518
5968+0000ff02@7519
5969+0000ff82@7520
5970+00007f02@7522
5971+0000ef82@7523
5972+0000ebfa@7524
5973+00006bfa@7526
5974+0000ebf8@7527
5975+0000ebc8@7528
5976+0000e140@7529
5977+0000e1c0@7530
5978+000041c0@7531
5979+0000c1c0@7532
5980+0000d140@7533
5981+0000d1c0@7534
5982+000071c2@7536
5983+0000f1c2@7537
5984+0000ff82@7538
5985+00007f82@7540
5986+0000ef82@7541
5987+0000ebfe@7542
5988+0000eb7e@7544
5989+00006bfc@7545
5990+0000ebfc@7546
5991+0000effc@7547
5992+0000ef7c@7548
5993+0000effc@7549
5994+00004ffc@7550
5995+0000cffc@7551
5996+0000dffc@7552
5997+00007ffe@7554
5998+0000ff7e@7555
5999+0000ff86@7556
6000+00007f06@7559
6001+0000ef86@7560
6002+0000ebf2@7561
6003+0000eb72@7563
6004+00006bf0@7564
6005+0000ebf0@7565
6006+0000e1c0@7566
6007+000041c0@7568
6008+0000c1c0@7569
6009+0000c140@7570
6010+0000d1c0@7571
6011+000071c2@7573
6012+0000f142@7574
6013+0000ff86@7575
6014+00007f06@7578
6015+0000efb6@7579
6016+0000ebf6@7580
6017+00006bf6@7582
6018+0000ebf4@7583
6019+0000effc@7584
6020+0000ef7c@7585
6021+0000effc@7586
6022+00004ffc@7587
6023+0000cffc@7588
6024+0000df7c@7589
6025+0000dffc@7590
6026+00007ffe@7592
6027+0000fffe@7593
6028+0000ff86@7594
6029+00007f86@7596
6030+0000ef86@7597
6031+0000ebfa@7598
6032+0000eb7a@7600
6033+00006bf8@7601
6034+0000ebf8@7602
6035+0000e140@7603
6036+0000e1c0@7605
6037+000041c0@7606
6038+0000c1c0@7607
6039+0000d1c0@7608
6040+000071c2@7610
6041+0000f142@7611
6042+0000ff86@7612
6043+00007f06@7615
6044+0000ef86@7616
6045+0000ebfe@7617
6046+0000eb7e@7619
6047+0000ebfc@7620
6048+0000effc@7621
6049+0000ef7c@7622
6050+0000effc@7623
6051+00004ffc@7624
6052+0000cffc@7625
6053+0000df7c@7626
6054+0000dffc@7627
6055+00007ffe@7629
6056+0000ff7e@7630
6057+0000ff8a@7631
6058+0000ef8a@7634
6059+0000ebf2@7635
6060+0000eb72@7637
6061+00006bf2@7638
6062+0000ebf0@7639
6063+0000e1c0@7640
6064+0000e140@7641
6065+0000e1c0@7642
6066+000041c0@7643
6067+0000c1c0@7644
6068+0000d140@7645
6069+0000d1c0@7646
6070+0000f1c0@7647
6071+0000f1c2@7648
6072+0000ff4a@7649
6073+0000ff8a@7650
6074+00007f0a@7652
6075+0000ef8a@7653
6076+0000ebf6@7654
6077+0000eb76@7656
6078+00006bf4@7657
6079+0000ebf4@7658
6080+0000effc@7659
6081+0000cffc@7662
6082+0000cf7c@7663
6083+0000dffc@7664
6084+00007ffe@7666
6085+0000ff7e@7667
6086+0000ff0a@7668
6087+0000ff8a@7669
6088+00007f0a@7671
6089+0000ef8a@7672
6090+0000ebfa@7673
6091+00006bfa@7675
6092+0000ebf8@7676
6093+0000ebc0@7677
6094+0000e140@7678
6095+0000e1c0@7679
6096+000041c0@7680
6097+0000c1c0@7681
6098+0000d140@7682
6099+0000d1c0@7683
6100+000071c2@7685
6101+0000f1c2@7686
6102+0000ff8a@7687
6103+00007f8a@7689
6104+0000ef8a@7690
6105+0000ebfe@7691
6106+0000eb7e@7693
6107+00006bfc@7694
6108+0000ebfc@7695
6109+0000effc@7696
6110+0000ef7c@7697
6111+0000effc@7698
6112+00004ffc@7699
6113+0000cffc@7700
6114+0000dffc@7701
6115+00007ffe@7703
6116+0000ff7e@7704
6117+0000ff8e@7705
6118+00007f0e@7708
6119+0000ff8e@7709
6120+0000ebf2@7710
6121+0000eb72@7712
6122+00006bf0@7713
6123+0000ebf0@7714
6124+0000e1c0@7715
6125+000041c0@7717
6126+0000c1c0@7718
6127+0000c140@7719
6128+0000d1c0@7720
6129+000071c2@7722
6130+0000f142@7723
6131+0000ff8e@7724
6132+00007f0e@7727
6133+0000efee@7728
6134+0000ebf6@7729
6135+00006bf6@7731
6136+0000ebf4@7732
6137+0000effc@7733
6138+0000ef7c@7734
6139+0000effc@7735
6140+00004ffc@7736
6141+0000cffc@7737
6142+0000df7c@7738
6143+0000dffc@7739
6144+00007ffe@7741
6145+0000fffe@7742
6146+0000ff8e@7743
6147+00007f8e@7745
6148+0000ef8e@7746
6149+0000ebfa@7747
6150+0000eb7a@7749
6151+00006bf8@7750
6152+0000ebf8@7751
6153+0000e140@7752
6154+0000e1c0@7753
6155+000041c0@7755
6156+0000c1c0@7756
6157+0000d1c0@7757
6158+000071c2@7759
6159+0000f142@7760
6160+0000ff8e@7761
6161+00007f0e@7764
6162+0000ef8e@7765
6163+0000ebfe@7766
6164+0000eb7e@7768
6165+0000ebfc@7769
6166+0000effc@7770
6167+0000ef7c@7771
6168+0000effc@7772
6169+00004ffc@7773
6170+0000cffc@7774
6171+0000df7c@7775
6172+0000dffc@7776
6173+00007ffe@7778
6174+0000ff7e@7779
6175+0000ff92@7780
6176+0000ef92@7783
6177+0000ebf2@7784
6178+0000eb72@7786
6179+00006bf2@7787
6180+0000ebf0@7788
6181+0000e1c0@7789
6182+0000e140@7790
6183+0000e1c0@7791
6184+000041c0@7792
6185+0000c1c0@7793
6186+0000d140@7794
6187+0000d1c0@7795
6188+0000f1c0@7796
6189+0000f142@7797
6190+0000ff52@7798
6191+0000ff92@7799
6192+00007f12@7801
6193+0000ef92@7802
6194+0000ebf6@7803
6195+0000eb76@7805
6196+00006bf4@7806
6197+0000ebf4@7807
6198+0000effc@7808
6199+0000cffc@7811
6200+0000cf7c@7812
6201+0000dffc@7813
6202+00007ffe@7815
6203+0000ff7e@7816
6204+0000ff12@7817
6205+0000ff92@7818
6206+00007f10@7820
6207+0000ff90@7821
6208+0000fbf4@7822
6209+0000ebf4@7823
6210+00006bf4@7824
6211+0000ebf4@7825
6212+0000eb74@7827
6213+0000ebf4@7828
6214+00006bf4@7829
6215+0000ebf4@7830
6216+0000fb74@7831
6217+0000fbf4@7832
6218+00007bf6@7834
6219+0000fbf6@7835
6220+0000ff92@7836
6221+00007f92@7838
6222+0000ef92@7839
6223+0000ebfa@7840
6224+0000eb7a@7842
6225+00006bf8@7843
6226+0000ebf8@7844
6227+0000e140@7845
6228+0000e1c0@7847
6229+000041c0@7848
6230+0000c1c0@7849
6231+0000d1c0@7850
6232+000071c2@7852
6233+0000f142@7853
6234+0000ff12@7854
6235+0000ff92@7855
6236+00007f12@7857
6237+0000ef92@7858
6238+0000ebfe@7859
6239+0000eb7e@7860
6240+00006bfc@7862
6241+0000effc@7863
6242+00004ffc@7866
6243+0000cffc@7867
6244+0000cf7c@7868
6245+0000dffc@7869
6246+00007ffe@7871
6247+0000ff7e@7872
6248+0000ff96@7873
6249+00006f16@7876
6250+0000eff6@7877
6251+0000ebf2@7878
6252+0000eb72@7879
6253+00006bf2@7880
6254+0000ebf0@7881
6255+0000e1c0@7882
6256+0000e140@7883
6257+0000e1c0@7884
6258+000041c0@7885
6259+0000c1c0@7886
6260+0000d140@7887
6261+0000d1c0@7888
6262+000071c2@7890
6263+0000f5d6@7891
6264+0000ff96@7892
6265+00007f16@7894
6266+0000ef96@7895
6267+0000ebf6@7896
6268+0000eb76@7898
6269+00006bf4@7899
6270+0000ebf4@7900
6271+0000effc@7901
6272+0000ef7c@7902
6273+0000effc@7903
6274+0000cffc@7904
6275+0000dffc@7906
6276+00007ffe@7908
6277+0000ff7e@7909
6278+0000ff96@7910
6279+00007f16@7913
6280+0000ef96@7914
6281+0000ebfa@7915
6282+0000eb7a@7917
6283+0000ebf8@7918
6284+0000e1c0@7920
6285+000041c0@7922
6286+0000c1c0@7923
6287+0000d140@7924
6288+0000d1c0@7925
6289+000071c2@7927
6290+0000f142@7928
6291+0000ff96@7929
6292+0000ef96@7932
6293+0000ebfe@7933
6294+0000eb7e@7935
6295+00006bfe@7936
6296+0000ebfc@7937
6297+0000effc@7938
6298+0000ef7c@7939
6299+0000effc@7940
6300+00004ffc@7941
6301+0000cffc@7942
6302+0000df7c@7943
6303+0000dffc@7944
6304+0000fffc@7945
6305+0000ff7e@7946
6306+0000fffe@7947
6307+0000ff9a@7948
6308+00007f1a@7950
6309+0000ef9a@7951
6310+0000ebf2@7952
6311+0000eb72@7954
6312+00006bf0@7955
6313+0000ebf0@7956
6314+0000e140@7957
6315+0000e1c0@7958
6316+0000c1c0@7960
6317+0000c140@7961
6318+0000d1c0@7962
6319+000071c2@7964
6320+0000f142@7965
6321+0000ff9a@7966
6322+00007f1a@7969
6323+0000ef9a@7970
6324+0000ebf6@7971
6325+00006bf6@7973
6326+0000ebf4@7974
6327+0000effc@7975
6328+0000ef7c@7976
6329+0000effc@7977
6330+00004ffc@7978
6331+0000cffc@7979
6332+0000df7c@7980
6333+0000dffc@7981
6334+00007ffe@7983
6335+0000fffe@7984
6336+0000ff9a@7985
6337+00007f9a@7987
6338+0000ef9a@7988
6339+0000ebfa@7989
6340+0000eb7a@7991
6341+00006bf8@7992
6342+0000ebf8@7993
6343+0000e140@7994
6344+0000e1c0@7996
6345+000041c0@7997
6346+0000c1c0@7998
6347+0000d1c0@7999
6348+000071c2@8001
6349+0000f142@8002
6350+0000ff1a@8003
6351+0000ff9a@8004
6352+00007f1a@8006
6353+0000ef9a@8007
6354+0000ebfe@8008
6355+0000eb7e@8010
6356+00006bfc@8011
6357+0000effc@8012
6358+00004ffc@8015
6359+0000cffc@8016
6360+0000cf7c@8017
6361+0000dffc@8018
6362+00007ffe@8020
6363+0000ff7e@8021
6364+0000ff9e@8022
6365+00007f1e@8025
6366+0000effe@8026
6367+0000ebf2@8027
6368+0000eb72@8028
6369+00006bf2@8029
6370+0000ebf0@8030
6371+0000e1c0@8031
6372+0000e140@8032
6373+0000e1c0@8033
6374+000041c0@8034
6375+0000c1c0@8035
6376+0000d140@8036
6377+0000d1c0@8037
6378+000071c2@8039
6379+0000f5de@8040
6380+0000ff9e@8041
6381+00007f1e@8043
6382+0000ef9e@8044
6383+0000ebf6@8045
6384+0000eb76@8047
6385+00006bf4@8048
6386+0000ebf4@8049
6387+0000effc@8050
6388+0000ef7c@8051
6389+0000effc@8052
6390+0000cffc@8053
6391+0000dffc@8055
6392+00007ffe@8057
6393+0000ff7e@8058
6394+0000ff9e@8059
6395+00007f1e@8062
6396+0000ef9e@8063
6397+0000ebfa@8064
6398+0000ebf8@8067
6399+0000e1c0@8069
6400+000041c0@8071
6401+0000c1c0@8072
6402+0000d140@8073
6403+0000d1c0@8074
6404+000071c2@8076
6405+0000f142@8077
6406+0000ff9e@8078
6407+0000ef9e@8081
6408+0000ebfe@8082
6409+0000eb7e@8084
6410+00006bfe@8085
6411+0000ebfc@8086
6412+0000effc@8087
6413+0000ef7c@8088
6414+0000effc@8089
6415+00004ffc@8090
6416+0000cffc@8091
6417+0000df7c@8092
6418+0000dffc@8093
6419+0000fffc@8094
6420+0000ff7e@8095
6421+0000fffe@8096
6422+0000ffa2@8097
6423+00007f22@8099
6424+0000efa2@8100
6425+0000ebf2@8101
6426+0000eb72@8103
6427+00006bf0@8104
6428+0000ebf0@8105
6429+0000e140@8106
6430+0000e1c0@8107
6431+0000c1c0@8109
6432+0000c140@8110
6433+0000d1c0@8111
6434+000071c2@8113
6435+0000f142@8114
6436+0000ffa2@8115
6437+00007f22@8118
6438+0000efa2@8119
6439+0000ebf6@8120
6440+00006bf6@8122
6441+0000ebf4@8123
6442+0000effc@8124
6443+0000ef7c@8125
6444+0000effc@8126
6445+00004ffc@8127
6446+0000cffc@8128
6447+0000df7c@8129
6448+0000dffc@8130
6449+00007ffe@8132
6450+0000fffe@8133
6451+0000ffa2@8134
6452+00007fa2@8136
6453+0000efa2@8137
6454+0000ebfa@8138
6455+0000eb7a@8140
6456+00006bf8@8141
6457+0000ebf8@8142
6458+0000e140@8143
6459+0000e1c0@8145
6460+000041c0@8146
6461+0000c1c0@8147
6462+0000d1c0@8148
6463+000071c2@8150
6464+0000f142@8151
6465+0000ff22@8152
6466+0000ffa2@8153
6467+00007f22@8155
6468+0000efa2@8156
6469+0000ebfe@8157
6470+0000eb7e@8158
6471+00006bfc@8160
6472+0000effc@8161
6473+00004ffc@8164
6474+0000cffc@8165
6475+0000cf7c@8166
6476+0000dffc@8167
6477+00007ffe@8169
6478+0000ff7e@8170
6479+0000ffa6@8171
6480+00006f26@8174
6481+0000eff6@8175
6482+0000ebf2@8176
6483+0000eb72@8177
6484+00006bf2@8178
6485+0000ebf0@8179
6486+0000e1c0@8180
6487+0000e140@8181
6488+0000e1c0@8182
6489+000041c0@8183
6490+0000c1c0@8184
6491+0000d140@8185
6492+0000d1c0@8186
6493+000071c2@8188
6494+0000f5e6@8189
6495+0000ffa6@8190
6496+00007f26@8192
6497+0000efa6@8193
6498+0000ebf6@8194
6499+0000eb76@8196
6500+00006bf4@8197
6501+0000ebf4@8198
6502+0000effc@8199
6503+0000ef7c@8200
6504+0000effc@8201
6505+0000cffc@8202
6506+0000dffc@8204
6507+00007ffe@8206
6508+0000ff7e@8207
6509+0000ffa6@8208
6510+00007f26@8211
6511+0000efa6@8212
6512+0000ebfa@8213
6513+0000ebf8@8216
6514+0000e1c0@8218
6515+000041c0@8220
6516+0000c1c0@8221
6517+0000d140@8222
6518+0000d1c0@8223
6519+000071c2@8225
6520+0000f142@8226
6521+0000ffa6@8227
6522+0000efa6@8230
6523+0000ebfe@8231
6524+0000eb7e@8233
6525+00006bfe@8234
6526+0000ebfc@8235
6527+0000effc@8236
6528+0000ef7c@8237
6529+0000effc@8238
6530+00004ffc@8239
6531+0000cffc@8240
6532+0000df7c@8241
6533+0000dffc@8242
6534+0000fffc@8243
6535+0000ff7e@8244
6536+0000fffe@8245
6537+0000ffaa@8246
6538+00007f2a@8248
6539+0000efaa@8249
6540+0000ebf2@8250
6541+0000eb72@8252
6542+00006bf0@8253
6543+0000ebf0@8254
6544+0000e140@8255
6545+0000e1c0@8256
6546+000061c0@8257
6547+0000c1c0@8258
6548+0000c140@8259
6549+0000d1c0@8260
6550+000071c2@8262
6551+0000f142@8263
6552+0000ffaa@8264
6553+00007f2a@8267
6554+0000efaa@8268
6555+0000ebf6@8269
6556+00006bf6@8271
6557+0000ebf4@8272
6558+0000effc@8273
6559+0000ef7c@8274
6560+0000effc@8275
6561+00004ffc@8276
6562+0000cffc@8277
6563+0000df7c@8278
6564+0000dffc@8279
6565+00007ffe@8281
6566+0000fffe@8282
6567+0000ffaa@8283
6568+00007faa@8285
6569+0000efaa@8286
6570+0000ebfa@8287
6571+0000eb7a@8289
6572+00006bf8@8290
6573+0000ebf8@8291
6574+0000e140@8292
6575+0000e1c0@8294
6576+000041c0@8295
6577+0000c1c0@8296
6578+0000d1c0@8297
6579+000071c2@8299
6580+0000f142@8300
6581+0000ff2a@8301
6582+0000ffaa@8302
6583+00007f2a@8304
6584+0000efaa@8305
6585+0000ebfe@8306
6586+0000eb7e@8308
6587+00006bfc@8309
6588+0000effc@8310
6589+00004ffc@8313
6590+0000cffc@8314
6591+0000cf7c@8315
6592+0000dffc@8316
6593+00007ffe@8318
6594+0000ff7e@8319
6595+0000ffae@8320
6596+00006f2e@8323
6597+0000effe@8324
6598+0000ebf2@8325
6599+0000eb72@8326
6600+00006bf2@8327
6601+0000ebf0@8328
6602+0000e1c0@8329
6603+0000e140@8330
6604+0000e1c0@8331
6605+000041c0@8332
6606+0000c1c0@8333
6607+0000d140@8334
6608+0000d1c0@8335
6609+000071c2@8337
6610+0000f56e@8338
6611+0000ffae@8339
6612+00007f2e@8341
6613+0000efae@8342
6614+0000ebf6@8343
6615+0000eb76@8345
6616+00006bf4@8346
6617+0000ebf4@8347
6618+0000effc@8348
6619+0000ef7c@8349
6620+0000effc@8350
6621+0000cffc@8351
6622+0000dffc@8353
6623+00007ffe@8355
6624+0000ff7e@8356
6625+0000ffae@8357
6626+00007f2e@8360
6627+0000efae@8361
6628+0000ebfa@8362
6629+0000ebf8@8365
6630+0000e1c0@8367
6631+000041c0@8369
6632+0000c1c0@8370
6633+0000d140@8371
6634+0000d1c0@8372
6635+000071c2@8374
6636+0000f142@8375
6637+0000ffae@8376
6638+0000efae@8379
6639+0000ebfe@8380
6640+0000eb7e@8382
6641+00006bfe@8383
6642+0000ebfc@8384
6643+0000effc@8385
6644+0000ef7c@8386
6645+0000effc@8387
6646+00004ffc@8388
6647+0000cffc@8389
6648+0000df7c@8390
6649+0000dffc@8391
6650+00007ffc@8392
6651+0000ff7e@8393
6652+0000fffe@8394
6653+0000ffb2@8395
6654+00007f32@8397
6655+0000efb2@8398
6656+0000ebf2@8399
6657+0000eb72@8401
6658+00006bf0@8402
6659+0000ebf0@8403
6660+0000e140@8404
6661+0000e1c0@8405
6662+000061c0@8406
6663+0000c1c0@8407
6664+0000c140@8408
6665+0000d1c0@8409
6666+000071c2@8411
6667+0000f142@8412
6668+0000ffb2@8413
6669+00007f30@8416
6670+0000ffb0@8417
6671+0000fbf0@8418
6672+0000ebf0@8419
6673+00006bf0@8420
6674+0000ebf0@8421
6675+0000ebf8@8422
6676+0000eb7c@8423
6677+0000ebfc@8424
6678+00006bfc@8425
6679+0000effc@8426
6680+0000ff7c@8427
6681+0000fffc@8428
6682+00007ffe@8430
6683+0000fffe@8431
6684+0000ffb2@8432
6685+00007fb2@8434
6686+0000efb2@8435
6687+0000ebf6@8436
6688+0000eb76@8438
6689+00006bf4@8439
6690+0000ebf4@8440
6691+0000effc@8441
6692+0000ef7c@8442
6693+0000effc@8443
6694+00004ffc@8444
6695+0000cffc@8445
6696+0000dffc@8446
6697+00007ffe@8448
6698+0000ff7e@8449
6699+0000ffb2@8450
6700+00007f32@8453
6701+0000ffb2@8454
6702+0000ebfa@8455
6703+0000eb7a@8457
6704+00006bf8@8458
6705+0000ebf8@8459
6706+0000e1c0@8460
6707+000041c0@8462
6708+0000c1c0@8463
6709+0000c140@8464
6710+0000d1c0@8465
6711+000071c2@8467
6712+0000f142@8468
6713+0000ffb2@8469
6714+00007f32@8472
6715+0000effe@8473
6716+0000ebfe@8474
6717+00006bfe@8476
6718+0000ebfc@8477
6719+0000effc@8478
6720+0000ef7c@8479
6721+0000effc@8480
6722+00004ffc@8481
6723+0000cffc@8482
6724+0000df7c@8483
6725+0000dffc@8484
6726+00007ffe@8486
6727+0000fffe@8487
6728+0000ffb6@8488
6729+00007fb6@8490
6730+0000efb6@8491
6731+0000ebf2@8492
6732+0000eb72@8494
6733+00006bf0@8495
6734+0000ebf0@8496
6735+0000e140@8497
6736+0000e1c0@8498
6737+0000c1c0@8500
6738+0000d1c0@8502
6739+000071c2@8504
6740+0000f142@8505
6741+0000ffb6@8506
6742+00007f36@8509
6743+0000efb6@8510
6744+0000ebf6@8511
6745+0000ebf4@8514
6746+0000effc@8515
6747+0000ef7c@8516
6748+0000effc@8517
6749+00004ffc@8518
6750+0000cffc@8519
6751+0000df7c@8520
6752+0000dffc@8521
6753+00007ffe@8523
6754+0000ff7e@8524
6755+0000ffb6@8525
6756+0000efb6@8528
6757+0000ebfa@8529
6758+0000eb7a@8531
6759+00006bfa@8532
6760+0000ebf8@8533
6761+0000e1c0@8534
6762+0000e140@8535
6763+0000e1c0@8536
6764+000041c0@8537
6765+0000c1c0@8538
6766+0000d140@8539
6767+0000d1c0@8540
6768+000071c0@8541
6769+0000f142@8542
6770+0000ff76@8543
6771+0000ffb6@8544
6772+00007f36@8546
6773+0000efb6@8547
6774+0000ebfe@8548
6775+0000eb7e@8550
6776+00006bfc@8551
6777+0000ebfc@8552
6778+0000effc@8553
6779+00006ffc@8555
6780+0000cffc@8556
6781+0000cf7c@8557
6782+0000dffc@8558
6783+00007ffe@8560
6784+0000ff7e@8561
6785+0000ffba@8562
6786+00007f3a@8565
6787+0000efba@8566
6788+0000ebf2@8567
6789+00006bf2@8569
6790+0000ebf0@8570
6791+0000ebc0@8571
6792+0000e140@8572
6793+0000e1c0@8573
6794+000041c0@8574
6795+0000c1c0@8575
6796+0000d140@8576
6797+0000d1c0@8577
6798+000071c2@8579
6799+0000f1c2@8580
6800+0000ffba@8581
6801+00007fba@8583
6802+0000efba@8584
6803+0000ebf6@8585
6804+0000eb76@8587
6805+00006bf4@8588
6806+0000ebf4@8589
6807+0000effc@8590
6808+0000ef7c@8591
6809+0000effc@8592
6810+00004ffc@8593
6811+0000cffc@8594
6812+0000dffc@8595
6813+00007ffe@8597
6814+0000ff7e@8598
6815+0000ffba@8599
6816+00007f3a@8602
6817+0000efba@8603
6818+0000ebfa@8604
6819+0000eb7a@8606
6820+00006bf8@8607
6821+0000ebf8@8608
6822+0000e1c0@8609
6823+000041c0@8611
6824+0000c1c0@8612
6825+0000c140@8613
6826+0000d1c0@8614
6827+000071c2@8616
6828+0000f142@8617
6829+0000ffba@8618
6830+00007f3a@8621
6831+0000effe@8622
6832+0000ebfe@8623
6833+00006bfe@8625
6834+0000ebfc@8626
6835+0000effc@8627
6836+0000ef7c@8628
6837+0000effc@8629
6838+00004ffc@8630
6839+0000cffc@8631
6840+0000df7c@8632
6841+0000dffc@8633
6842+00007ffe@8635
6843+0000fffe@8636
6844+0000ffbe@8637
6845+00007fbe@8639
6846+0000efbe@8640
6847+0000ebf2@8641
6848+0000eb72@8643
6849+00006bf0@8644
6850+0000ebf0@8645
6851+0000e140@8646
6852+0000e1c0@8647
6853+0000c1c0@8649
6854+0000d1c0@8651
6855+000071c2@8653
6856+0000f142@8654
6857+0000ffbe@8655
6858+00007f3e@8658
6859+0000efbe@8659
6860+0000ebf6@8660
6861+0000ebf4@8663
6862+0000effc@8664
6863+0000ef7c@8665
6864+0000effc@8666
6865+00004ffc@8667
6866+0000cffc@8668
6867+0000df7c@8669
6868+0000dffc@8670
6869+00007ffe@8672
6870+0000ff7e@8673
6871+0000ffbe@8674
6872+0000efbe@8677
6873+0000ebfa@8678
6874+0000eb7a@8680
6875+00006bfa@8681
6876+0000ebf8@8682
6877+0000e1c0@8683
6878+0000e140@8684
6879+0000e1c0@8685
6880+000041c0@8686
6881+0000c1c0@8687
6882+0000d140@8688
6883+0000d1c0@8689
6884+000071c0@8690
6885+0000f142@8691
6886+0000ff3e@8692
6887+0000ffbe@8693
6888+00007f3e@8695
6889+0000efbe@8696
6890+0000ebfe@8697
6891+0000eb7e@8699
6892+00006bfc@8700
6893+0000ebfc@8701
6894+0000effc@8702
6895+00006ffc@8704
6896+0000cffc@8705
6897+0000cf7c@8706
6898+0000dffc@8707
6899+00007ffe@8709
6900+0000ff7e@8710
6901+0000f142@8711
6902+0000f1c2@8712
6903+00007142@8714
6904+0000e1c2@8715
6905+0000ebf2@8716
6906+00006bf2@8718
6907+0000ebf0@8719
6908+0000ebc0@8720
6909+0000e140@8721
6910+0000e1c0@8722
6911+000041c0@8723
6912+0000c1c0@8724
6913+0000d140@8725
6914+0000d1c0@8726
6915+000071c2@8728
6916+0000f1c2@8729
6917+000071c2@8732
6918+0000e1c2@8733
6919+0000ebf6@8734
6920+0000eb76@8736
6921+00006bf4@8737
6922+0000ebf4@8738
6923+0000effc@8739
6924+0000ef7c@8740
6925+0000effc@8741
6926+00004ffc@8742
6927+0000cffc@8743
6928+0000dffc@8744
6929+00007ffe@8746
6930+0000ff7e@8747
6931+0000f1c2@8748
6932+00007142@8751
6933+0000e1c2@8752
6934+0000ebfa@8753
6935+0000eb7a@8755
6936+00006bf8@8756
6937+0000ebf8@8757
6938+0000e1c0@8758
6939+000041c0@8760
6940+0000c1c0@8761
6941+0000c140@8762
6942+0000d1c0@8763
6943+000071c2@8765
6944+0000f142@8766
6945+0000f1c2@8767
6946+00006142@8770
6947+0000e1fe@8771
6948+0000ebfe@8772
6949+00006bfe@8774
6950+0000ebfc@8775
6951+0000effc@8776
6952+0000ef7c@8777
6953+0000effc@8778
6954+00004ffc@8779
6955+0000cffc@8780
6956+0000df7c@8781
6957+0000dffc@8782
6958+00007ffe@8784
6959+0000fffe@8785
6960+0000f1c6@8786
6961+000071c6@8788
6962+0000e1c6@8789
6963+0000ebf2@8790
6964+0000eb72@8792
6965+00006bf0@8793
6966+0000ebf0@8794
6967+0000e140@8795
6968+0000e1c0@8796
6969+0000c1c0@8798
6970+0000d1c0@8800
6971+000071c2@8802
6972+0000f142@8803
6973+0000f1c6@8804
6974+00007146@8807
6975+0000e1c6@8808
6976+0000ebf6@8809
6977+0000ebf4@8812
6978+0000effc@8813
6979+0000ef7c@8814
6980+0000effc@8815
6981+00004ffc@8816
6982+0000cffc@8817
6983+0000df7c@8818
6984+0000dffc@8819
6985+00007ffe@8821
6986+0000ff7e@8822
6987+0000f1c6@8823
6988+0000e1c6@8826
6989+0000ebfa@8827
6990+0000eb7a@8829
6991+00006bfa@8830
6992+0000ebf8@8831
6993+0000e1c0@8832
6994+0000e140@8833
6995+0000e1c0@8834
6996+000041c0@8835
6997+0000c1c0@8836
6998+0000d140@8837
6999+0000d1c0@8838
7000+000071c0@8839
7001+0000f142@8840
7002+0000f1c6@8841
7003+00007146@8844
7004+0000e1c6@8845
7005+0000ebfe@8846
7006+0000eb7e@8848
7007+00006bfc@8849
7008+0000ebfc@8850
7009+0000effc@8851
7010+00006ffc@8853
7011+0000cffc@8854
7012+0000cf7c@8855
7013+0000dffc@8856
7014+00007ffe@8858
7015+0000ff7e@8859
7016+0000f14a@8860
7017+0000f1ca@8861
7018+0000714a@8863
7019+0000e1ca@8864
7020+0000ebf2@8865
7021+00006bf2@8867
7022+0000ebf0@8868
7023+0000ebc0@8869
7024+0000e140@8870
7025+0000e1c0@8871
7026+000041c0@8872
7027+0000c1c0@8873
7028+0000d140@8874
7029+0000d1c0@8875
7030+000071c2@8877
7031+0000f1c2@8878
7032+0000f1ca@8879
7033+000071ca@8881
7034+0000e1ca@8882
7035+0000ebfe@8883
7036+0000ebf6@8884
7037+0000eb76@8885
7038+00006bf4@8886
7039+0000ebf4@8887
7040+0000effc@8888
7041+0000ef7c@8889
7042+0000effc@8890
7043+00004ffc@8891
7044+0000cffc@8892
7045+0000dffc@8893
7046+00007ffe@8895
7047+0000ff7e@8896
7048+0000f1ce@8897
7049+0000f1ca@8898
7050+0000714a@8900
7051+0000e1ca@8901
7052+0000ebfa@8902
7053+0000eb7a@8904
7054+00006bf8@8905
7055+0000ebf8@8906
7056+0000e1c0@8907
7057+000041c0@8909
7058+0000c1c0@8910
7059+0000c140@8911
7060+0000d1c0@8912
7061+000071c2@8914
7062+0000f142@8915
7063+0000f1ca@8916
7064+0000614a@8919
7065+0000e1fe@8920
7066+0000ebfe@8921
7067+00006bfe@8923
7068+0000ebfc@8924
7069+0000effc@8925
7070+0000ef7c@8926
7071+0000effc@8927
7072+00004ffc@8928
7073+0000cffc@8929
7074+0000df7c@8930
7075+0000dffc@8931
7076+00007ffe@8933
7077+0000fffe@8934
7078+0000f1ce@8935
7079+0000714e@8937
7080+0000e1ce@8938
7081+0000ebf2@8939
7082+0000eb72@8941
7083+00006bf0@8942
7084+0000ebf0@8943
7085+0000e140@8944
7086+0000e1c0@8945
7087+0000c1c0@8947
7088+0000d1c0@8949
7089+000071c2@8951
7090+0000f142@8952
7091+0000f1ce@8953
7092+0000714e@8956
7093+0000e1ce@8957
7094+0000ebf6@8958
7095+0000ebf4@8961
7096+0000effc@8962
7097+0000ef7c@8963
7098+0000effc@8964
7099+00004ffc@8965
7100+0000cffc@8966
7101+0000df7c@8967
7102+0000dffc@8968
7103+00007ffe@8970
7104+0000ff7e@8971
7105+0000f1ce@8972
7106+0000e1ce@8975
7107+0000ebfa@8976
7108+0000eb7a@8978
7109+00006bfa@8979
7110+0000ebf8@8980
7111+0000e1c0@8981
7112+0000e140@8982
7113+0000e1c0@8983
7114+000041c0@8984
7115+0000c1c0@8985
7116+0000d140@8986
7117+0000d1c0@8987
7118+000071c2@8988
7119+0000f142@8989
7120+0000f1ce@8990
7121+0000714e@8993
7122+0000e1ce@8994
7123+0000ebfe@8995
7124+0000eb7e@8997
7125+00006bfc@8998
7126+0000ebfc@8999
7127+0000effc@9000
7128+00006ffc@9002
7129+0000cffc@9003
7130+0000cf7c@9004
7131+0000dffc@9005
7132+00007ffe@9007
7133+0000ff7e@9008
7134+0000f1ce@9009
7135+0000714c@9012
7136+0000f1cc@9013
7137+0000fbfc@9014
7138+0000ebfc@9015
7139+00006bfc@9016
7140+0000ebfc@9017
7141+0000eb7c@9019
7142+0000ebfc@9020
7143+00006bfc@9021
7144+0000ebfc@9022
7145+0000fb7c@9023
7146+0000fbfc@9024
7147+00007bfe@9026
7148+0000fbfe@9027
7149+0000f1d2@9028
7150+000071d2@9030
7151+0000e1d2@9031
7152+0000ebf2@9032
7153+0000eb72@9034
7154+00006bf0@9035
7155+0000ebf0@9036
7156+0000e140@9037
7157+0000e1c0@9039
7158+000041c0@9040
7159+0000c1c0@9041
7160+0000d1c0@9042
7161+000071c2@9044
7162+0000f142@9045
7163+0000f1d2@9046
7164+00007152@9049
7165+0000e1d2@9050
7166+0000ebf6@9051
7167+0000eb76@9053
7168+00006bf4@9054
7169+0000effc@9055
7170+00004ffc@9058
7171+0000cffc@9059
7172+0000cf7c@9060
7173+0000dffc@9061
7174+00007ffe@9063
7175+0000ff7e@9064
7176+0000f152@9065
7177+0000f1d2@9066
7178+00006152@9068
7179+0000e3fa@9069
7180+0000ebfa@9070
7181+00006bfa@9072
7182+0000ebf8@9073
7183+0000e1c0@9074
7184+0000e140@9075
7185+0000e1c0@9076
7186+000041c0@9077
7187+0000c1c0@9078
7188+0000d140@9079
7189+0000d1c0@9080
7190+000071c2@9082
7191+0000f1d2@9083
7192+00007152@9086
7193+0000e1d2@9087
7194+0000ebfe@9088
7195+0000eb7e@9090
7196+00006bfc@9091
7197+0000ebfc@9092
7198+0000effc@9093
7199+0000ef7c@9094
7200+0000effc@9095
7201+0000cffc@9096
7202+0000cf7c@9097
7203+0000dffc@9098
7204+00007ffe@9100
7205+0000ff7e@9101
7206+0000f1d6@9102
7207+00007156@9105
7208+0000e1d6@9106
7209+0000ebf2@9107
7210+0000ebf0@9110
7211+0000e1c0@9112
7212+000041c0@9114
7213+0000c1c0@9115
7214+0000d140@9116
7215+0000d1c0@9117
7216+000071c2@9119
7217+0000f142@9120
7218+0000f1d6@9121
7219+0000e1d6@9124
7220+0000ebf6@9125
7221+0000eb76@9127
7222+00006bf6@9128
7223+0000ebf4@9129
7224+0000effc@9130
7225+0000ef7c@9131
7226+0000effc@9132
7227+00004ffc@9133
7228+0000cffc@9134
7229+0000df7c@9135
7230+0000dffc@9136
7231+00007ffe@9137
7232+0000ff7e@9138
7233+0000fbfe@9139
7234+0000f1d6@9140
7235+00007156@9142
7236+0000e1d6@9143
7237+0000ebfa@9144
7238+0000eb7a@9146
7239+00006bf8@9147
7240+0000ebf8@9148
7241+0000e1c0@9149
7242+000061c0@9151
7243+0000c1c0@9152
7244+0000c140@9153
7245+0000d1c0@9154
7246+000071c2@9156
7247+0000f142@9157
7248+0000f1d6@9158
7249+00007156@9161
7250+0000e1d6@9162
7251+0000ebfe@9163
7252+00006bfe@9165
7253+0000ebfc@9166
7254+0000effc@9167
7255+0000ef7c@9168
7256+0000effc@9169
7257+00004ffc@9170
7258+0000cffc@9171
7259+0000df7c@9172
7260+0000dffc@9173
7261+00007ffe@9175
7262+0000fffe@9176
7263+0000f1da@9177
7264+000071da@9179
7265+0000e1da@9180
7266+0000ebf2@9181
7267+0000eb72@9183
7268+00006bf0@9184
7269+0000ebf0@9185
7270+0000e140@9186
7271+0000e1c0@9188
7272+000041c0@9189
7273+0000c1c0@9190
7274+0000d1c0@9191
7275+000071c2@9193
7276+0000f142@9194
7277+0000f1da@9195
7278+0000715a@9198
7279+0000e1da@9199
7280+0000ebf6@9200
7281+0000eb76@9202
7282+00006bf4@9203
7283+0000effc@9204
7284+00004ffc@9207
7285+0000cffc@9208
7286+0000cf7c@9209
7287+0000dffc@9210
7288+00007ffe@9212
7289+0000ff7e@9213
7290+0000f1da@9214
7291+0000e15a@9217
7292+0000e3fa@9218
7293+0000ebfa@9219
7294+00006bfa@9221
7295+0000ebf8@9222
7296+0000e1c0@9223
7297+0000e140@9224
7298+0000e1c0@9225
7299+000041c0@9226
7300+0000c1c0@9227
7301+0000d140@9228
7302+0000d1c0@9229
7303+0000f1c2@9231
7304+0000f1da@9232
7305+0000715a@9235
7306+0000e1da@9236
7307+0000ebfe@9237
7308+0000eb7e@9239
7309+00006bfc@9240
7310+0000ebfc@9241
7311+0000effc@9242
7312+0000ef7c@9243
7313+0000effc@9244
7314+0000cffc@9245
7315+0000cf7c@9246
7316+0000dffc@9247
7317+00007ffe@9249
7318+0000ff7e@9250
7319+0000f1de@9251
7320+0000715e@9254
7321+0000e1de@9255
7322+0000ebf2@9256
7323+0000ebf0@9259
7324+0000e1c0@9261
7325+000041c0@9263
7326+0000c1c0@9264
7327+0000d140@9265
7328+0000d1c0@9266
7329+000071c2@9268
7330+0000f142@9269
7331+0000f1de@9270
7332+000071de@9272
7333+0000e1de@9273
7334+0000ebf6@9274
7335+0000eb76@9276
7336+00006bf6@9277
7337+0000ebf4@9278
7338+0000effc@9279
7339+0000ef7c@9280
7340+0000effc@9281
7341+00004ffc@9282
7342+0000cffc@9283
7343+0000df7c@9284
7344+0000dffc@9285
7345+00007ffe@9286
7346+0000fffe@9287
7347+0000fbfe@9288
7348+0000f1de@9289
7349+0000715e@9291
7350+0000f1de@9292
7351+0000ebfa@9293
7352+0000eb7a@9295
7353+00006bf8@9296
7354+0000ebf8@9297
7355+0000e1c0@9298
7356+000061c0@9300
7357+0000c1c0@9301
7358+0000c140@9302
7359+0000d1c0@9303
7360+000071c2@9305
7361+0000f142@9306
7362+0000f1de@9307
7363+0000715e@9310
7364+0000e1de@9311
7365+0000ebfe@9312
7366+00006bfe@9314
7367+0000ebfc@9315
7368+0000effc@9316
7369+0000ef7c@9317
7370+0000effc@9318
7371+00004ffc@9319
7372+0000cffc@9320
7373+0000df7c@9321
7374+0000dffc@9322
7375+00007ffe@9324
7376+0000fffe@9325
7377+0000f1e2@9326
7378+000071e2@9328
7379+0000e1e2@9329
7380+0000ebf2@9330
7381+0000eb72@9332
7382+00006bf0@9333
7383+0000ebf0@9334
7384+0000e140@9335
7385+0000e1c0@9337
7386+000041c0@9338
7387+0000c1c0@9339
7388+0000d1c0@9340
7389+000071c2@9342
7390+0000f142@9343
7391+0000f1e2@9344
7392+00007162@9347
7393+0000e1e2@9348
7394+0000ebf6@9349
7395+0000eb76@9351
7396+00006bf4@9352
7397+0000effc@9353
7398+00004ffc@9356
7399+0000cffc@9357
7400+0000cf7c@9358
7401+0000dffc@9359
7402+00007ffe@9361
7403+0000ff7e@9362
7404+0000f1e2@9363
7405+00006162@9366
7406+0000e3fa@9367
7407+0000ebfa@9368
7408+00006bfa@9370
7409+0000ebf8@9371
7410+0000e1c0@9372
7411+0000e140@9373
7412+0000e1c0@9374
7413+000041c0@9375
7414+0000c1c0@9376
7415+0000d140@9377
7416+0000d1c0@9378
7417+0000f1c2@9380
7418+0000f1e2@9381
7419+00007162@9384
7420+0000e1e2@9385
7421+0000ebfe@9386
7422+0000eb7e@9388
7423+00006bfc@9389
7424+0000ebfc@9390
7425+0000effc@9391
7426+0000ef7c@9392
7427+0000effc@9393
7428+0000cffc@9394
7429+0000cf7c@9395
7430+0000dffc@9396
7431+00007ffe@9398
7432+0000ff7e@9399
7433+0000f1e6@9400
7434+00007166@9403
7435+0000e1e6@9404
7436+0000ebf2@9405
7437+0000ebf0@9408
7438+0000e1c0@9410
7439+000041c0@9412
7440+0000c1c0@9413
7441+0000d140@9414
7442+0000d1c0@9415
7443+000071c2@9417
7444+0000f142@9418
7445+0000f1e6@9419
7446+000071e6@9421
7447+0000e1e6@9422
7448+0000ebf6@9423
7449+0000eb76@9425
7450+00006bf6@9426
7451+0000ebf4@9427
7452+0000effc@9428
7453+0000ef7c@9429
7454+0000effc@9430
7455+00004ffc@9431
7456+0000cffc@9432
7457+0000df7c@9433
7458+0000dffc@9434
7459+00007ffe@9435
7460+0000ff7e@9436
7461+0000fbfe@9437
7462+0000f1e6@9438
7463+00007166@9440
7464+0000e1e6@9441
7465+0000ebfa@9442
7466+0000eb7a@9444
7467+00006bf8@9445
7468+0000ebf8@9446
7469+0000e1c0@9447
7470+000061c0@9449
7471+0000c1c0@9450
7472+0000c140@9451
7473+0000d1c0@9452
7474+000071c2@9454
7475+0000f142@9455
7476+0000f1e6@9456
7477+00007166@9459
7478+0000e1e6@9460
7479+0000ebfe@9461
7480+00006bfe@9463
7481+0000ebfc@9464
7482+0000effc@9465
7483+0000ef7c@9466
7484+0000effc@9467
7485+00004ffc@9468
7486+0000cffc@9469
7487+0000df7c@9470
7488+0000dffc@9471
7489+00007ffe@9473
7490+0000fffe@9474
7491+0000f1ea@9475
7492+000071ea@9477
7493+0000e1ea@9478
7494+0000ebf2@9479
7495+0000eb72@9481
7496+00006bf0@9482
7497+0000ebf0@9483
7498+0000e140@9484
7499+0000e1c0@9486
7500+000041c0@9487
7501+0000c1c0@9488
7502+0000d1c0@9489
7503+000071c2@9491
7504+0000f142@9492
7505+0000f1ea@9493
7506+0000716a@9496
7507+0000e1ea@9497
7508+0000ebf6@9498
7509+0000eb76@9500
7510+00006bf4@9501
7511+0000effc@9502
7512+00004ffc@9505
7513+0000cffc@9506
7514+0000cf7c@9507
7515+0000dffc@9508
7516+00007ffe@9510
7517+0000ff7e@9511
7518+0000f1ea@9512
7519+0000e16a@9515
7520+0000e3fa@9516
7521+0000ebfa@9517
7522+00006bfa@9519
7523+0000ebf8@9520
7524+0000e1c0@9521
7525+0000e140@9522
7526+0000e1c0@9523
7527+000041c0@9524
7528+0000c1c0@9525
7529+0000d140@9526
7530+0000d1c0@9527
7531+0000f1c2@9529
7532+0000f1ea@9530
7533+0000716a@9533
7534+0000e1ea@9534
7535+0000ebfe@9535
7536+0000eb7e@9537
7537+00006bfc@9538
7538+0000ebfc@9539
7539+0000effc@9540
7540+0000ef7c@9541
7541+0000effc@9542
7542+0000cffc@9543
7543+0000cf7c@9544
7544+0000dffc@9545
7545+00007ffe@9547
7546+0000ff7e@9548
7547+0000f0ee@9549
7548+0000706e@9552
7549+0000e0ee@9553
7550+0000eaf2@9554
7551+0000ea72@9556
7552+0000ea70@9557
7553+0000eaf0@9558
7554+0000e0c0@9559
7555+0000e040@9560
7556+00004040@9561
7557+0000c0c0@9562
7558+0000d0c0@9563
7559+0000d040@9565
7560+00007042@9566
7561+0000f0c2@9567
7562+0000f0ee@9568
7563+0000706e@9570
7564+0000e06e@9571
7565+0000eaf6@9572
7566+0000ea76@9574
7567+00006a76@9575
7568+0000eaf4@9576
7569+0000eefc@9577
7570+0000ee7c@9579
7571+00004e7c@9580
7572+0000cefc@9581
7573+0000defc@9582
7574+00007e7e@9584
7575+0000fe7e@9585
7576+0000fafe@9586
7577+0000f0ee@9587
7578+0000f06e@9588
7579+0000706e@9589
7580+0000e0ee@9590
7581+0000eafa@9591
7582+0000ea7a@9593
7583+00006a78@9594
7584+0000eaf8@9595
7585+0000e0c0@9596
7586+00006040@9598
7587+0000c040@9599
7588+0000c0c0@9600
7589+0000d0c0@9601
7590+0000d040@9602
7591+00007042@9603
7592+0000f0c2@9604
7593+0000f0ee@9605
7594+0000f06e@9607
7595+0000706e@9608
7596+0000e0ee@9609
7597+0000eafe@9610
7598+00006a7e@9612
7599+0000ea7c@9613
7600+0000eefc@9614
7601+0000ee7c@9616
7602+00004e7c@9617
7603+0000cefc@9618
7604+0000defc@9619
7605+0000de7c@9621
7606+00007e7e@9622
7607+0000fefe@9623
7608+0000f0f2@9624
7609+000070f2@9626
7610+0000e0f2@9627
7611+0000eaf2@9628
7612+0000ea72@9629
7613+0000eaf2@9630
7614+00006af0@9631
7615+0000eaf0@9632
7616+0000e040@9633
7617+0000e0c0@9635
7618+000040c0@9636
7619+0000c0c0@9637
7620+0000d040@9638
7621+000070c2@9640
7622+0000f0c2@9641
7623+0000f072@9642
7624+0000f0f2@9644
7625+000070f2@9645
7626+0000e0f2@9646
7627+0000ea76@9647
7628+0000eaf6@9649
7629+00006af4@9650
7630+0000eefc@9651
7631+0000ee7c@9652
7632+00004efc@9654
7633+0000cefc@9655
7634+0000de7c@9656
7635+0000defc@9658
7636+00007efe@9659
7637+0000fefe@9660
7638+0000f072@9661
7639+0000f0f2@9663
7640+0000e2fa@9665
7641+0000ea7a@9666
7642+00006afa@9668
7643+0000eaf8@9669
7644+0000e040@9670
7645+0000e140@9671
7646+0000e1c0@9672
7647+000041c0@9673
7648+0000c1c0@9674
7649+0000d140@9675
7650+0000d1c0@9677
7651+0000f1c2@9678
7652+0000f1f2@9679
7653+0000f172@9680
7654+000071f2@9682
7655+0000e1f2@9683
7656+0000eb7e@9684
7657+0000ebfe@9686
7658+00006bfc@9687
7659+0000ebfc@9688
7660+0000ef7c@9689
7661+0000effc@9691
7662+0000cffc@9692
7663+0000df7c@9694
7664+00007ffe@9696
7665+0000fffe@9697
7666+0000f176@9698
7667+0000f1f6@9700
7668+000071f6@9701
7669+0000e1f6@9702
7670+0000ebf2@9703
7671+0000ebf0@9706
7672+0000e1c0@9708
7673+00004140@9710
7674+0000c1c0@9711
7675+0000d1c0@9712
7676+0000d140@9714
7677+000071c2@9715
7678+0000f1c2@9716
7679+0000f1f6@9717
7680+000071f6@9719
7681+0000e1f6@9720
7682+0000eb76@9721
7683+0000ebf6@9722
7684+00006bf6@9724
7685+0000eb74@9725
7686+0000effc@9726
7687+00004f7c@9729
7688+0000cffc@9730
7689+0000dffc@9731
7690+00007ffe@9733
7691+0000fffe@9734
7692+0000fbfe@9735
7693+0000f1f6@9736
7694+000071f6@9738
7695+0000e1f6@9739
7696+0000eb7a@9740
7697+0000ebfa@9741
7698+00006bf8@9743
7699+0000ebf8@9744
7700+0000e1c0@9745
7701+000061c0@9747
7702+0000c1c0@9748
7703+0000d1c0@9750
7704+0000d140@9751
7705+000071c2@9752
7706+0000f1c2@9753
7707+0000f1f6@9754
7708+0000f176@9755
7709+0000f1f6@9756
7710+000071f6@9757
7711+0000e1f6@9758
7712+0000ebfe@9759
7713+00006bfe@9761
7714+0000eb7c@9762
7715+0000effc@9763
7716+00004f7c@9766
7717+0000cffc@9767
7718+0000dffc@9768
7719+0000df7c@9770
7720+00007ffe@9771
7721+0000fffe@9772
7722+0000f17a@9773
7723+0000f1fa@9774
7724+000071fa@9775
7725+0000e1fa@9776
7726+0000eb72@9777
7727+0000ebf2@9778
7728+00006bf0@9780
7729+0000eb70@9781
7730+0000e1c0@9782
7731+00004140@9785
7732+0000c1c0@9786
7733+0000d1c0@9787
7734+0000d140@9788
7735+000071c2@9789
7736+0000f1c2@9790
7737+0000f1fa@9791
7738+0000f17a@9792
7739+0000f1fa@9793
7740+000071fa@9794
7741+0000e1fa@9795
7742+0000eb76@9796
7743+0000ebf6@9797
7744+00006bf4@9799
7745+0000effc@9800
7746+00004f7c@9803
7747+0000cffc@9804
7748+0000dffc@9806
7749+0000df7c@9807
7750+00007ffe@9808
7751+0000fffe@9809
7752+0000f17a@9810
7753+0000f1fa@9812
7754+0000f1f8@9813
7755+0000fbfc@9814
7756+0000fbf4@9815
7757+0000ebf4@9816
7758+00006bf4@9817
7759+0000eb74@9818
7760+0000ebf4@9819
7761+00006b74@9822
7762+0000ebf4@9823
7763+0000fbf4@9824
7764+0000fb74@9826
7765+0000fbf6@9827
7766+0000fbfe@9828
7767+0000f17a@9829
7768+0000f1fa@9830
7769+000071fa@9831
7770+0000e1fa@9832
7771+0000eb7a@9833
7772+0000ebfa@9834
7773+00006bf8@9836
7774+0000eb78@9837
7775+0000e1c0@9838
7776+0000c1c0@9841
7777+0000d1c0@9843
7778+0000d140@9844
7779+000071c2@9845
7780+0000f1c2@9846
7781+0000f1fa@9847
7782+0000f17a@9848
7783+0000f1fa@9849
7784+000071fa@9850
7785+0000e1fa@9851
7786+0000ebfe@9852
7787+0000ebfc@9855
7788+0000effc@9856
7789+00004f7c@9859
7790+0000cffc@9860
7791+0000dffc@9861
7792+0000df7c@9863
7793+00007ffe@9864
7794+0000fffe@9865
7795+0000f17e@9866
7796+0000f1fe@9867
7797+0000e1fe@9869
7798+0000eb72@9870
7799+0000ebf2@9872
7800+00006bf2@9873
7801+0000eb70@9874
7802+0000e1c0@9875
7803+00004140@9878
7804+0000c1c0@9879
7805+0000d1c0@9880
7806+000071c2@9882
7807+0000f1c2@9883
7808+0000f1fe@9884
7809+0000f17e@9885
7810+0000f1fe@9886
7811+000071fe@9887
7812+0000e1fe@9888
7813+0000eb76@9889
7814+0000ebf6@9890
7815+00006bf4@9892
7816+0000ebf4@9893
7817+0000effc@9894
7818+00006ffc@9896
7819+0000cffc@9897
7820+0000dffc@9899
7821+0000df7c@9900
7822+00007ffe@9901
7823+0000fffe@9902
7824+0000f1fe@9903
7825+0000f17e@9904
7826+0000f1fe@9905
7827+000071fe@9906
7828+0000e1fe@9907
7829+0000ebfa@9908
7830+00006bfa@9910
7831+0000eb78@9911
7832+0000e9c0@9912
7833+0000e1c0@9913
7834+00004140@9915
7835+0000c1c0@9916
7836+0000d1c0@9917
7837+0000d140@9919
7838+000071c2@9920
7839+0000f1c6@9921
7840+0000f17e@9922
7841+0000f1fe@9923
7842+000071fe@9924
7843+0000e1fe@9925
7844+0000eb7e@9926
7845+0000ebfe@9927
7846+00006bfc@9929
7847+0000eb7c@9930
7848+0000effc@9931
7849+00004f7c@9934
7850+0000cffc@9935
7851+0000dffc@9936
7852+0000df7c@9937
7853+00007ffe@9938
7854+0000fffe@9939
7855+0000f3c2@9940
7856+0000f342@9941
7857+0000f3c2@9942
7858+000073c2@9943
7859+0000e3c2@9944
7860+0000eb72@9945
7861+0000ebf2@9946
7862+00006bf0@9948
7863+0000ebf0@9949
7864+0000e1c0@9950
7865+000041c0@9952
7866+0000c1c0@9953
7867+0000d1c0@9955
7868+0000d140@9956
7869+000071c2@9957
7870+0000f1c2@9958
7871+0000f3c2@9959
7872+0000f342@9960
7873+0000f3c2@9961
7874+0000eb76@9963
7875+0000ebf6@9964
7876+00006bf6@9966
7877+0000eb74@9967
7878+0000effc@9968
7879+00004f7c@9971
7880+0000cffc@9972
7881+0000dffc@9973
7882+0000df7c@9975
7883+0000fffe@9976
7884+0000f3c2@9978
7885+000073c2@9980
7886+0000e3c2@9981
7887+0000eb7a@9982
7888+0000ebfa@9983
7889+00006bf8@9985
7890+0000eb78@9986
7891+0000e1c0@9987
7892+0000c1c0@9990
7893+0000d1c0@9992
7894+0000d140@9993
7895+000071c2@9994
7896+0000f1c2@9995
7897+0000f3c2@9996
7898+0000f342@9997
7899+0000f3c2@9998
7900+000073c2@9999
7901+0000e3c2@10000
7902+0000eb7e@10001
7903+0000ebfe@10002
7904+0000ebfc@10004
7905+0000effc@10005
7906+00004f7c@10008
7907+0000cffc@10009
7908+0000dffc@10010
7909+0000df7c@10012
7910+00007ffe@10013
7911+0000fffe@10014
7912+0000f346@10015
7913+0000f3c6@10016
7914+0000e3c6@10018
7915+0000eb72@10019
7916+0000ebf2@10020
7917+00006bf2@10022
7918+0000eb70@10023
7919+0000e1c0@10024
7920+00004140@10027
7921+0000c1c0@10028
7922+0000d1c0@10029
7923+000071c2@10031
7924+0000f1c2@10032
7925+0000f3c6@10033
7926+0000f346@10034
7927+0000f3c6@10035
7928+000073c6@10036
7929+0000e3c6@10037
7930+0000eb76@10038
7931+0000ebf6@10039
7932+00006bf4@10041
7933+0000ebf4@10042
7934+0000effc@10043
7935+00006ffc@10045
7936+0000cffc@10046
7937+0000dffc@10048
7938+0000df7c@10049
7939+00007ffe@10050
7940+0000fffe@10051
7941+0000f346@10052
7942+0000f3c6@10054
7943+000073c6@10055
7944+0000e3c6@10056
7945+0000ebfa@10057
7946+00006bfa@10059
7947+0000eb78@10060
7948+0000e9c0@10061
7949+0000e1c0@10062
7950+00004140@10064
7951+0000c1c0@10065
7952+0000d1c0@10066
7953+0000d140@10068
7954+000071c2@10069
7955+0000f1c6@10070
7956+0000f3c6@10071
7957+000073c6@10073
7958+0000e3c6@10074
7959+0000eb7e@10075
7960+0000ebfe@10076
7961+00006bfc@10078
7962+0000eb7c@10079
7963+0000effc@10080
7964+00004f7c@10083
7965+0000cffc@10084
7966+0000dffc@10085
7967+00007ffe@10087
7968+0000fffe@10088
7969+0000f3ca@10089
7970+0000f34a@10090
7971+0000f3ca@10091
7972+000073ca@10092
7973+0000e3ca@10093
7974+0000eb72@10094
7975+0000ebf2@10095
7976+00006bf0@10097
7977+0000ebf0@10098
7978+0000e1c0@10099
7979+000041c0@10101
7980+0000c1c0@10102
7981+0000d1c0@10104
7982+0000d140@10105
7983+000071c2@10106
7984+0000f1c2@10107
7985+0000f3ca@10108
7986+0000f34a@10109
7987+0000f3ca@10110
7988+0000eb7e@10112
7989+0000ebf6@10113
7990+00006bf6@10115
7991+0000eb74@10116
7992+0000effc@10117
7993+00004f7c@10120
7994+0000cffc@10121
7995+0000dffc@10122
7996+0000df7c@10124
7997+0000fffe@10125
7998+0000f3ca@10127
7999+000073ca@10129
8000+0000e3ca@10130
8001+0000eb7a@10131
8002+0000ebfa@10132
8003+00006bf8@10134
8004+0000eb78@10135
8005+0000e1c0@10136
8006+0000c1c0@10139
8007+0000d1c0@10141
8008+0000d140@10142
8009+000071c2@10143
8010+0000f1c2@10144
8011+0000f3ca@10145
8012+0000f34a@10146
8013+0000f3ca@10147
8014+000073ca@10148
8015+0000e3ca@10149
8016+0000eb7e@10150
8017+0000ebfe@10151
8018+0000ebfc@10153
8019+0000effc@10154
8020+00004f7c@10157
8021+0000cffc@10158
8022+0000dffc@10159
8023+0000df7c@10161
8024+00007ffe@10162
8025+0000fffe@10163
8026+0000f34e@10164
8027+0000f3ce@10165
8028+0000e3ce@10167
8029+0000eb72@10168
8030+0000ebf2@10169
8031+00006bf2@10171
8032+0000eb70@10172
8033+0000e1c0@10173
8034+00004140@10176
8035+0000c1c0@10177
8036+0000d1c0@10178
8037+000071c2@10180
8038+0000f1c2@10181
8039+0000f3ce@10182
8040+0000f34e@10183
8041+0000f3ce@10184
8042+000073ce@10185
8043+0000e3ce@10186
8044+0000eb76@10187
8045+0000ebf6@10188
8046+00006bf4@10190
8047+0000ebf4@10191
8048+0000effc@10192
8049+00006ffc@10194
8050+0000cffc@10195
8051+0000dffc@10197
8052+0000df7c@10198
8053+00007ffe@10199
8054+0000fffe@10200
8055+0000f34e@10201
8056+0000f3ce@10203
8057+000073ce@10204
8058+0000e3ce@10205
8059+0000ebfa@10206
8060+00006bfa@10208
8061+0000eb78@10209
8062+0000e9c0@10210
8063+0000e1c0@10211
8064+00004140@10213
8065+0000c1c0@10214
8066+0000d1c0@10215
8067+0000d140@10217
8068+000071c2@10218
8069+0000f1c6@10219
8070+0000f34e@10220
8071+0000f3ce@10221
8072+000073ce@10222
8073+0000e3ce@10223
8074+0000eb7e@10224
8075+0000ebfe@10225
8076+00006bfc@10227
8077+0000eb7c@10228
8078+0000effc@10229
8079+00004f7c@10232
8080+0000cffc@10233
8081+0000dffc@10234
8082+00007ffe@10236
8083+0000fffe@10237
8084+0000f3d2@10238
8085+0000f352@10239
8086+0000f3d2@10240
8087+000073d2@10241
8088+0000e3d2@10242
8089+0000eb72@10243
8090+0000ebf2@10244
8091+00006bf0@10246
8092+0000ebf0@10247
8093+0000e1c0@10248
8094+000041c0@10250
8095+0000c1c0@10251
8096+0000d1c0@10253
8097+0000d140@10254
8098+000071c2@10255
8099+0000f1c2@10256
8100+0000f3d2@10257
8101+0000f352@10258
8102+0000f3d2@10259
8103+0000eb76@10261
8104+0000ebf6@10262
8105+00006bf6@10264
8106+0000eb74@10265
8107+0000effc@10266
8108+00004f7c@10269
8109+0000cffc@10270
8110+0000dffc@10271
8111+0000df7c@10273
8112+0000fffe@10274
8113+0000f3d2@10276
8114+000073d2@10278
8115+0000e3d2@10279
8116+0000eb7a@10280
8117+0000ebfa@10281
8118+00006bf8@10283
8119+0000eb78@10284
8120+0000e1c0@10285
8121+0000c1c0@10288
8122+0000d1c0@10290
8123+0000d140@10291
8124+000071c2@10292
8125+0000f1c2@10293
8126+0000f3d2@10294
8127+0000f352@10295
8128+0000f3d2@10296
8129+000073d2@10297
8130+0000e3d2@10298
8131+0000eb7e@10299
8132+0000ebfe@10300
8133+0000ebfc@10302
8134+0000effc@10303
8135+00004f7c@10306
8136+0000cffc@10307
8137+0000dffc@10308
8138+0000df7c@10310
8139+00007ffe@10311
8140+0000fffe@10312
8141+0000f356@10313
8142+0000f3d6@10314
8143+0000e3d6@10316
8144+0000eb72@10317
8145+0000ebf2@10318
8146+00006bf2@10320
8147+0000eb70@10321
8148+0000e1c0@10322
8149+00004140@10325
8150+0000c1c0@10326
8151+0000d1c0@10327
8152+000071c2@10329
8153+0000f1c2@10330
8154+0000f3d6@10331
8155+0000f356@10332
8156+0000f3d6@10333
8157+000073d6@10334
8158+0000e3d6@10335
8159+0000eb76@10336
8160+0000ebf6@10337
8161+00006bf4@10339
8162+0000ebf4@10340
8163+0000effc@10341
8164+00006ffc@10343
8165+0000cffc@10344
8166+0000dffc@10346
8167+0000df7c@10347
8168+00007ffe@10348
8169+0000fffe@10349
8170+0000f356@10350
8171+0000f3d6@10352
8172+000073d6@10353
8173+0000e3d6@10354
8174+0000ebfa@10355
8175+00006bfa@10357
8176+0000eb78@10358
8177+0000e9c0@10359
8178+0000e1c0@10360
8179+00004140@10362
8180+0000c1c0@10363
8181+0000d1c0@10364
8182+0000d140@10366
8183+000071c2@10367
8184+0000f1c6@10368
8185+0000f356@10369
8186+0000f3d6@10370
8187+000073d6@10371
8188+0000e3d6@10372
8189+0000eb7e@10373
8190+0000ebfe@10374
8191+00006bfc@10376
8192+0000eb7c@10377
8193+0000effc@10378
8194+00004f7c@10381
8195+0000cffc@10382
8196+0000dffc@10383
8197+0000df7c@10384
8198+00007ffe@10385
8199+0000fffe@10386
8200+0000f3da@10387
8201+0000f35a@10388
8202+0000f3da@10389
8203+000073da@10390
8204+0000e3da@10391
8205+0000eb72@10392
8206+0000ebf2@10393
8207+00006bf0@10395
8208+0000ebf0@10396
8209+0000e1c0@10397
8210+000041c0@10399
8211+0000c1c0@10400
8212+0000d1c0@10402
8213+0000d140@10403
8214+000071c2@10404
8215+0000f1c2@10405
8216+0000f3da@10406
8217+0000f35a@10407
8218+0000f3da@10408
8219+0000f3d8@10409
8220+0000fbf8@10410
8221+0000fbf0@10411
8222+0000ebf0@10412
8223+00006bf0@10413
8224+0000eb70@10414
8225+0000effc@10415
8226+0000ebfc@10416
8227+00006b7c@10418
8228+0000effc@10419
8229+0000fffc@10420
8230+0000ff7c@10422
8231+0000fffe@10423
8232+0000fbfe@10424
8233+0000f35a@10425
8234+0000f3da@10426
8235+000073da@10427
8236+0000e3da@10428
8237+0000eb76@10429
8238+0000ebf6@10430
8239+00006bf4@10432
8240+0000eb74@10433
8241+0000effc@10434
8242+0000cffc@10437
8243+0000dffc@10439
8244+0000df7c@10440
8245+00007ffe@10441
8246+0000fffe@10442
8247+0000f3da@10443
8248+0000f35a@10444
8249+0000f3da@10445
8250+000073da@10446
8251+0000e3da@10447
8252+0000ebfa@10448
8253+0000ebf8@10451
8254+0000e1c0@10453
8255+00004140@10455
8256+0000c1c0@10456
8257+0000d1c0@10457
8258+0000d140@10459
8259+000071c2@10460
8260+0000f1c2@10461
8261+0000f3da@10462
8262+000073da@10464
8263+0000e3da@10465
8264+0000eb7e@10466
8265+0000ebfe@10467
8266+00006bfe@10469
8267+0000eb7c@10470
8268+0000effc@10471
8269+00004f7c@10474
8270+0000cffc@10475
8271+0000dffc@10476
8272+00007ffe@10478
8273+0000fffe@10479
8274+0000fbde@10480
8275+0000f3de@10481
8276+000073de@10483
8277+0000e3de@10484
8278+0000eb72@10485
8279+0000ebf2@10486
8280+00006bf0@10488
8281+0000ebf0@10489
8282+0000e1c0@10490
8283+000061c0@10492
8284+0000c1c0@10493
8285+0000d1c0@10495
8286+0000d140@10496
8287+000071c2@10497
8288+0000f1c2@10498
8289+0000f3de@10499
8290+0000f35e@10500
8291+0000f3de@10501
8292+000073de@10502
8293+0000e3de@10503
8294+0000ebf6@10504
8295+00006bf6@10506
8296+0000eb74@10507
8297+0000effc@10508
8298+00004f7c@10511
8299+0000cffc@10512
8300+0000dffc@10513
8301+0000df7c@10515
8302+00007ffe@10516
8303+0000fffe@10517
8304+0000f35e@10518
8305+0000f3de@10519
8306+000073de@10520
8307+0000e3de@10521
8308+0000eb7a@10522
8309+0000ebfa@10523
8310+00006bf8@10525
8311+0000eb78@10526
8312+0000e1c0@10527
8313+00004140@10530
8314+0000c1c0@10531
8315+0000d1c0@10532
8316+0000d140@10533
8317+000071c2@10534
8318+0000f1c2@10535
8319+0000f3de@10536
8320+0000f35e@10537
8321+0000f3de@10538
8322+000073de@10539
8323+0000e3de@10540
8324+0000eb7e@10541
8325+0000ebfe@10542
8326+00006bfc@10544
8327+0000effc@10545
8328+00004f7c@10548
8329+0000cffc@10549
8330+0000dffc@10550
8331+0000df7c@10552
8332+00007ffe@10553
8333+0000fffe@10554
8334+0000f362@10555
8335+0000f3e2@10557
8336+0000e3e2@10558
8337+0000eb72@10559
8338+0000ebf2@10560
8339+00006bf2@10562
8340+0000eb70@10563
8341+0000e1c0@10564
8342+00004140@10567
8343+0000c1c0@10568
8344+0000d1c0@10569
8345+0000f1c0@10571
8346+0000f1c2@10572
8347+0000f3e2@10573
8348+0000f362@10574
8349+0000f3e2@10575
8350+000073e2@10576
8351+0000e3e2@10577
8352+0000eb76@10578
8353+0000ebf6@10579
8354+00006bf4@10581
8355+0000eb74@10582
8356+0000effc@10583
8357+0000cffc@10586
8358+0000dffc@10588
8359+0000df7c@10589
8360+00007ffe@10590
8361+0000fffe@10591
8362+0000f3e2@10592
8363+0000f362@10593
8364+0000f3e2@10594
8365+000073e2@10595
8366+0000e3e2@10596
8367+0000eb7a@10597
8368+0000ebfa@10598
8369+0000ebf8@10600
8370+0000e1c0@10602
8371+00004140@10604
8372+0000c1c0@10605
8373+0000d1c0@10606
8374+0000d140@10608
8375+000071c2@10609
8376+0000f1c2@10610
8377+0000f3e2@10611
8378+0000f362@10612
8379+000073e2@10613
8380+0000e3e2@10614
8381+0000eb7e@10615
8382+0000ebfe@10616
8383+00006bfe@10618
8384+0000eb7c@10619
8385+0000effc@10620
8386+00004f7c@10623
8387+0000cffc@10624
8388+0000dffc@10625
8389+00007ffe@10627
8390+0000fffe@10628
8391+0000fbe6@10629
8392+0000f366@10630
8393+0000f3e6@10631
8394+000073e6@10632
8395+0000e3e6@10633
8396+0000eb72@10634
8397+0000ebf2@10635
8398+00006bf0@10637
8399+0000ebf0@10638
8400+0000e1c0@10639
8401+000061c0@10641
8402+0000c1c0@10642
8403+0000d1c0@10644
8404+0000d140@10645
8405+000071c2@10646
8406+0000f1c2@10647
8407+0000f3e6@10648
8408+0000f366@10649
8409+0000f3e6@10650
8410+000073e6@10651
8411+0000e3e6@10652
8412+0000ebf6@10653
8413+00006bf6@10655
8414+0000eb74@10656
8415+0000effc@10657
8416+00004f7c@10660
8417+0000cffc@10661
8418+0000dffc@10662
8419+0000df7c@10664
8420+00007ffe@10665
8421+0000fffe@10666
8422+0000f3e6@10667
8423+000073e6@10669
8424+0000e3e6@10670
8425+0000eb7a@10671
8426+0000ebfa@10672
8427+00006bf8@10674
8428+0000eb78@10675
8429+0000e1c0@10676
8430+00004140@10679
8431+0000c1c0@10680
8432+0000d1c0@10681
8433+0000d140@10682
8434+000071c2@10683
8435+0000f1c2@10684
8436+0000f3e6@10685
8437+0000f366@10686
8438+0000f3e6@10687
8439+000073e6@10688
8440+0000e3e6@10689
8441+0000eb7e@10690
8442+0000ebfe@10691
8443+00006bfc@10693
8444+0000effc@10694
8445+00004f7c@10697
8446+0000cffc@10698
8447+0000dffc@10699
8448+0000df7c@10701
8449+00007ffe@10702
8450+0000fffe@10703
8451+0000f36a@10704
8452+0000f3ea@10706
8453+0000e3ea@10707
8454+0000ebfa@10708
8455+0000ebf2@10709
8456+00006bf2@10711
8457+0000eb70@10712
8458+0000e1c0@10713
8459+00004140@10716
8460+0000c1c0@10717
8461+0000d1c0@10718
8462+0000f140@10720
8463+0000f1c2@10721
8464+0000f3ea@10722
8465+0000f36a@10723
8466+0000f3ea@10724
8467+000073ea@10725
8468+0000e3ea@10726
8469+0000eb76@10727
8470+0000ebf6@10728
8471+00006bf4@10730
8472+0000eb74@10731
8473+0000effc@10732
8474+0000cffc@10735
8475+0000dffc@10737
8476+0000df7c@10738
8477+00007ffe@10739
8478+0000fffe@10740
8479+0000f3ea@10741
8480+0000f36a@10742
8481+0000f3ea@10743
8482+000073ea@10744
8483+0000e3ea@10745
8484+0000ebfa@10746
8485+0000ebf8@10749
8486+0000e1c0@10751
8487+00004140@10753
8488+0000c1c0@10754
8489+0000d1c0@10755
8490+0000d140@10757
8491+000071c2@10758
8492+0000f1c2@10759
8493+0000f3ea@10760
8494+000073ea@10762
8495+0000e3ea@10763
8496+0000eb7e@10764
8497+0000ebfe@10765
8498+00006bfe@10767
8499+0000eb7c@10768
8500+0000effc@10769
8501+00004f7c@10772
8502+0000cffc@10773
8503+0000dffc@10774
8504+00007ffe@10776
8505+0000fffe@10777
8506+0000fbee@10778
8507+0000f36e@10779
8508+0000f3ee@10780
8509+000073ee@10781
8510+0000e3ee@10782
8511+0000eb72@10783
8512+0000ebf2@10784
8513+00006bf0@10786
8514+0000ebf0@10787
8515+0000e1c0@10788
8516+000061c0@10790
8517+0000c1c0@10791
8518+0000d1c0@10793
8519+0000d140@10794
8520+000071c2@10795
8521+0000f1c2@10796
8522+0000f3ee@10797
8523+0000f36e@10798
8524+0000f3ee@10799
8525+000073ee@10800
8526+0000e3ee@10801
8527+0000ebf6@10802
8528+00006bf6@10804
8529+0000eb74@10805
8530+0000effc@10806
8531+00004f7c@10809
8532+0000cffc@10810
8533+0000dffc@10811
8534+0000df7c@10813
8535+00007ffe@10814
8536+0000fffe@10815
8537+0000f36e@10816
8538+0000f3ee@10817
8539+000073ee@10818
8540+0000e3ee@10819
8541+0000eb7a@10820
8542+0000ebfa@10821
8543+00006bf8@10823
8544+0000eb78@10824
8545+0000e1c0@10825
8546+00004140@10828
8547+0000c1c0@10829
8548+0000d1c0@10830
8549+0000d140@10831
8550+000071c2@10832
8551+0000f1c2@10833
8552+0000f3ee@10834
8553+0000f36e@10835
8554+0000f3ee@10836
8555+000073ee@10837
8556+0000e3ee@10838
8557+0000eb7e@10839
8558+0000ebfe@10840
8559+00006bfc@10842
8560+0000effc@10843
8561+00004f7c@10846
8562+0000cffc@10847
8563+0000dffc@10848
8564+0000df7c@10850
8565+00007ffe@10851
8566+0000fffe@10852
8567+0000f372@10853
8568+0000f3f2@10855
8569+0000e3f2@10856
8570+0000ebf2@10857
8571+00006bf2@10860
8572+0000eb70@10861
8573+0000e1c0@10862
8574+00004140@10865
8575+0000c1c0@10866
8576+0000d1c0@10867
8577+0000f1c0@10869
8578+0000f1c2@10870
8579+0000f3f2@10871
8580+0000f372@10872
8581+0000f3f2@10873
8582+000073f2@10874
8583+0000e3f2@10875
8584+0000eb76@10876
8585+0000ebf6@10877
8586+00006bf4@10879
8587+0000eb74@10880
8588+0000effc@10881
8589+0000cffc@10884
8590+0000dffc@10886
8591+0000df7c@10887
8592+00007ffe@10888
8593+0000fffe@10889
8594+0000f3f2@10890
8595+0000f372@10891
8596+0000f3f2@10892
8597+000073f2@10893
8598+0000e3f2@10894
8599+0000ebfa@10895
8600+0000eb78@10898
8601+0000ebf8@10899
8602+0000e1c0@10900
8603+00004140@10902
8604+0000c1c0@10903
8605+0000d1c0@10904
8606+0000d140@10906
8607+000071c2@10907
8608+0000f1c2@10908
8609+0000f3f2@10909
8610+000073f2@10911
8611+0000e3f2@10912
8612+0000eb7e@10913
8613+0000ebfe@10914
8614+00006bfe@10916
8615+0000eb7c@10917
8616+0000effc@10918
8617+00004f7c@10921
8618+0000cffc@10922
8619+0000dffc@10923
8620+00007ffe@10925
8621+0000fffe@10926
8622+0000fbf6@10927
8623+0000f376@10928
8624+0000f3f6@10929
8625+000073f6@10930
8626+0000e3f6@10931
8627+0000eb72@10932
8628+0000ebf2@10933
8629+00006bf0@10935
8630+0000ebf0@10936
8631+0000e1c0@10937
8632+000061c0@10939
8633+0000c1c0@10940
8634+0000d1c0@10942
8635+0000d140@10943
8636+000071c2@10944
8637+0000f1c2@10945
8638+0000f3f6@10946
8639+0000f376@10947
8640+0000f3f6@10948
8641+000073f6@10949
8642+0000e3f6@10950
8643+0000ebf6@10951
8644+00006bf6@10953
8645+0000eb74@10954
8646+0000effc@10955
8647+00004f7c@10958
8648+0000cffc@10959
8649+0000dffc@10960
8650+0000df7c@10962
8651+00007ffe@10963
8652+0000fffe@10964
8653+0000f376@10965
8654+0000f3f6@10966
8655+000073f6@10967
8656+0000e3f6@10968
8657+0000eb7a@10969
8658+0000ebfa@10970
8659+00006bf8@10972
8660+0000eb78@10973
8661+0000e1c0@10974
8662+00004140@10977
8663+0000c1c0@10978
8664+0000d1c0@10979
8665+0000d140@10980
8666+000071c2@10981
8667+0000f1c2@10982
8668+0000f3f6@10983
8669+0000f376@10984
8670+0000f3f6@10985
8671+000073f6@10986
8672+0000e3f6@10987
8673+0000eb7e@10988
8674+0000ebfe@10989
8675+00006bfc@10991
8676+0000effc@10992
8677+00004f7c@10995
8678+0000cffc@10996
8679+0000dffc@10997
8680+0000df7c@10999
8681+00007ffe@11000
8682+0000fffe@11001
8683+0000f376@11002
8684+0000f3f6@11004
8685+0000f3f4@11005
8686+0000fb7c@11006
8687+0000fbfc@11007
8688+0000ebfc@11008
8689+00006bfc@11009
8690+0000eb7c@11010
8691+0000ebfc@11011
8692+00006b7c@11014
8693+0000ebfc@11015
8694+0000fbfc@11016
8695+0000fb7c@11018
8696+0000fbfe@11019
8697+0000f37a@11021
8698+0000f3fa@11022
8699+000073fa@11023
8700+0000e3fa@11024
8701+0000eb72@11025
8702+0000ebf2@11026
8703+00006bf0@11028
8704+0000eb70@11029
8705+0000e1c0@11030
8706+0000c1c0@11033
8707+0000d1c0@11035
8708+0000d140@11036
8709+000071c2@11037
8710+0000f1c2@11038
8711+0000f3fa@11039
8712+0000f37a@11040
8713+0000f3fa@11041
8714+000073fa@11042
8715+0000e3fa@11043
8716+0000ebf6@11044
8717+0000eb74@11047
8718+0000ef7c@11048
8719+0000effc@11049
8720+00004f7c@11051
8721+0000cffc@11052
8722+0000dffc@11053
8723+0000df7c@11055
8724+00007ffe@11056
8725+0000fffe@11057
8726+0000f37a@11058
8727+0000f3fa@11059
8728+000073fa@11060
8729+0000e3fa@11061
8730+0000eb7a@11062
8731+0000ebfa@11063
8732+00006bfa@11065
8733+0000eb78@11066
8734+0000e1c0@11067
8735+00004140@11070
8736+0000c1c0@11071
8737+0000d1c0@11072
8738+000071c2@11074
8739+0000f1c2@11075
8740+0000f3fa@11076
8741+0000f37a@11077
8742+0000f3fa@11078
8743+000073fa@11079
8744+0000e3fa@11080
8745+0000eb7e@11081
8746+0000ebfe@11082
8747+00006bfc@11084
8748+0000ebfc@11085
8749+0000effc@11086
8750+00006ffc@11088
8751+0000cffc@11089
8752+0000dffc@11091
8753+0000df7c@11092
8754+00007ffe@11093
8755+0000fffe@11094
8756+0000f3fe@11095
8757+0000f37e@11096
8758+0000f3fe@11097
8759+000073fe@11098
8760+0000e3fe@11099
8761+0000ebf2@11100
8762+00006bf2@11102
8763+0000eb70@11103
8764+0000e1c0@11104
8765+00004140@11107
8766+0000c1c0@11108
8767+0000d1c0@11109
8768+0000d140@11111
8769+000071c2@11112
8770+0000f1ce@11113
8771+0000f37e@11114
8772+0000f3fe@11115
8773+000073fe@11116
8774+0000e3fe@11117
8775+0000eb76@11118
8776+0000ebf6@11119
8777+00006bf4@11121
8778+0000eb74@11122
8779+0000effc@11123
8780+00004f7c@11126
8781+0000cffc@11127
8782+0000dffc@11128
8783+0000df7c@11129
8784+00007ffe@11130
8785+0000fffe@11131
8786+0000f3fe@11132
8787+0000f37e@11133
8788+0000f3fe@11134
8789+000073fe@11135
8790+0000e3fe@11136
8791+0000eb7a@11137
8792+0000ebfa@11138
8793+00006bf8@11140
8794+0000ebf8@11141
8795+0000e0c0@11142
8796+000040c0@11144
8797+0000c0c0@11145
8798+0000d0c0@11146
8799+0000d040@11148
8800+00007042@11149
8801+0000f0c2@11150
8802+0000f2fe@11151
8803+0000f27e@11153
8804+0000e27e@11154
8805+0000eafe@11155
8806+00006a7e@11158
8807+0000eafc@11159
8808+0000eefc@11160
8809+0000ee7c@11162
8810+00004e7c@11163
8811+0000cefc@11164
8812+0000defc@11165
8813+0000fe7c@11167
8814+0000fe7e@11168
8815+0000fefe@11169
8816+0000f4c2@11170
8817+0000f442@11171
8818+00007442@11172
8819+0000e4c2@11173
8820+0000eaf2@11174
8821+0000ea72@11176
8822+00006a70@11177
8823+0000eaf0@11178
8824+0000e0c0@11179
8825+0000e040@11181
8826+0000c040@11182
8827+0000c0c0@11183
8828+0000d0c0@11184
8829+0000d040@11185
8830+00007042@11186
8831+0000f0c2@11187
8832+0000f4c2@11188
8833+0000f442@11190
8834+00007442@11191
8835+0000e4c2@11192
8836+0000eaf6@11193
8837+00006a76@11195
8838+0000ea74@11196
8839+0000eefc@11197
8840+0000ee7c@11199
8841+00004e7c@11200
8842+0000cefc@11201
8843+0000defc@11202
8844+0000de7c@11204
8845+00007e7e@11205
8846+0000fefe@11206
8847+0000f4c2@11207
8848+00007442@11209
8849+0000e442@11210
8850+0000eafa@11211
8851+0000ea7a@11213
8852+00006a78@11214
8853+0000eaf8@11215
8854+0000e0c0@11216
8855+0000e040@11218
8856+000040c0@11219
8857+0000c0c0@11220
8858+0000d0c0@11221
8859+0000d040@11222
8860+000070c2@11223
8861+0000f0c2@11224
8862+0000f442@11225
8863+0000f4c2@11227
8864+000074c2@11228
8865+0000e4c2@11229
8866+0000eafe@11230
8867+0000ea7e@11231
8868+0000eafe@11232
8869+00006afc@11233
8870+0000eafc@11234
8871+0000ee7c@11235
8872+00006efc@11237
8873+0000cefc@11238
8874+0000ce7c@11239
8875+0000de7c@11240
8876+0000defc@11241
8877+00007efe@11242
8878+0000fefe@11243
8879+0000f446@11244
8880+0000f4c6@11246
8881+000074c6@11247
8882+0000e4c6@11248
8883+0000ea72@11249
8884+00006af2@11251
8885+0000eaf0@11252
8886+0000e0c0@11253
8887+0000e040@11254
8888+0000e0c0@11255
8889+000040c0@11256
8890+0000c0c0@11257
8891+0000d040@11258
8892+0000d0c0@11260
8893+000070c2@11261
8894+0000f4c6@11262
8895+0000f546@11263
8896+000075c6@11265
8897+0000e5c6@11266
8898+0000eb76@11267
8899+0000ebf6@11269
8900+00006bf4@11270
8901+0000ebf4@11271
8902+0000ef7c@11272
8903+0000effc@11274
8904+00004ffc@11275
8905+0000cffc@11276
8906+0000df7c@11277
8907+00007ffe@11279
8908+0000fffe@11280
8909+0000f546@11281
8910+0000f5c6@11283
8911+000075c6@11284
8912+0000e5c6@11285
8913+0000eb7a@11286
8914+0000ebfa@11288
8915+00006bf8@11289
8916+0000ebf8@11290
8917+0000e140@11291
8918+000041c0@11293
8919+0000c1c0@11294
8920+0000d140@11295
8921+0000d1c0@11296
8922+000071c2@11298
8923+0000f142@11299
8924+0000f5c6@11300
8925+0000e546@11303
8926+0000effe@11304
8927+0000ebfe@11305
8928+0000eb7e@11306
8929+00006bfe@11307
8930+0000ebfc@11308
8931+0000effc@11309
8932+0000ef7c@11310
8933+0000effc@11311
8934+00004ffc@11312
8935+0000cffc@11313
8936+0000df7c@11314
8937+0000dffc@11315
8938+0000fffc@11316
8939+0000fffe@11317
8940+0000f5ca@11319
8941+0000754a@11321
8942+0000e5ca@11322
8943+0000ebf2@11323
8944+0000eb72@11325
8945+00006bf0@11326
8946+0000ebf0@11327
8947+0000e140@11328
8948+0000e1c0@11329
8949+0000c1c0@11331
8950+0000c140@11332
8951+0000d1c0@11333
8952+000071c2@11335
8953+0000f142@11336
8954+0000f5ca@11337
8955+0000754a@11340
8956+0000e5ca@11341
8957+0000ebf6@11342
8958+00006bf6@11344
8959+0000ebf4@11345
8960+0000effc@11346
8961+0000ef7c@11347
8962+0000effc@11348
8963+00004ffc@11349
8964+0000cffc@11350
8965+0000df7c@11351
8966+0000dffc@11352
8967+00007ffe@11354
8968+0000fffe@11355
8969+0000f5ca@11356
8970+000075ca@11358
8971+0000e5ca@11359
8972+0000ebfa@11360
8973+0000eb7a@11362
8974+00006bfa@11363
8975+0000ebf8@11364
8976+0000e140@11365
8977+0000e1c0@11367
8978+000041c0@11368
8979+0000c1c0@11369
8980+0000d1c0@11370
8981+000071c2@11372
8982+0000f142@11373
8983+0000f5ca@11374
8984+0000754a@11377
8985+0000e5ca@11378
8986+0000ebfe@11379
8987+0000eb7e@11381
8988+00006bfc@11382
8989+0000ebfc@11383
8990+0000effc@11384
8991+00006ffc@11386
8992+0000cffc@11387
8993+0000cf7c@11388
8994+0000dffc@11389
8995+00007ffe@11391
8996+0000ff7e@11392
8997+0000f5ce@11393
8998+0000754e@11396
8999+0000e5ee@11397
9000+0000ebf2@11398
9001+0000eb72@11399
9002+00006bf2@11400
9003+0000ebf0@11401
9004+0000e1c0@11402
9005+0000e140@11403
9006+0000e1c0@11404
9007+000041c0@11405
9008+0000c1c0@11406
9009+0000d140@11407
9010+0000d1c0@11408
9011+000071c2@11410
9012+0000f5ce@11411
9013+0000754e@11414
9014+0000e5ce@11415
9015+0000ebf6@11416
9016+0000eb76@11418
9017+00006bf4@11419
9018+0000ebf4@11420
9019+0000effc@11421
9020+0000ef7c@11422
9021+0000effc@11423
9022+00004ffc@11424
9023+0000cffc@11425
9024+0000dffc@11426
9025+00007ffe@11428
9026+0000ff7e@11429
9027+0000f5ce@11430
9028+0000754e@11433
9029+0000e5ce@11434
9030+0000ebfa@11435
9031+0000eb7a@11437
9032+00006bf8@11438
9033+0000ebf8@11439
9034+0000e1c0@11440
9035+000041c0@11442
9036+0000c1c0@11443
9037+0000d140@11444
9038+0000d1c0@11445
9039+000071c2@11447
9040+0000f142@11448
9041+0000f5ce@11449
9042+0000e5ce@11452
9043+0000effe@11453
9044+0000ebfe@11454
9045+0000eb7e@11455
9046+00006bfe@11456
9047+0000ebfc@11457
9048+0000effc@11458
9049+0000ef7c@11459
9050+0000effc@11460
9051+00004ffc@11461
9052+0000cffc@11462
9053+0000df7c@11463
9054+0000dffc@11464
9055+0000fffc@11465
9056+0000fffe@11466
9057+0000f5d2@11468
9058+00007552@11470
9059+0000e5d2@11471
9060+0000ebf2@11472
9061+0000eb72@11474
9062+00006bf0@11475
9063+0000ebf0@11476
9064+0000e140@11477
9065+0000e1c0@11478
9066+0000c1c0@11480
9067+0000c140@11481
9068+0000d1c0@11482
9069+000071c2@11484
9070+0000f142@11485
9071+0000f5d2@11486
9072+00007552@11489
9073+0000e5d2@11490
9074+0000ebf6@11491
9075+00006bf6@11493
9076+0000ebf4@11494
9077+0000effc@11495
9078+0000ef7c@11496
9079+0000effc@11497
9080+00004ffc@11498
9081+0000cffc@11499
9082+0000df7c@11500
9083+0000dffc@11501
9084+00007ffe@11503
9085+0000fffe@11504
9086+0000f5d2@11505
9087+000075d2@11507
9088+0000e5d2@11508
9089+0000ebfa@11509
9090+0000eb7a@11511
9091+00006bfa@11512
9092+0000ebf8@11513
9093+0000e140@11514
9094+0000e1c0@11516
9095+000041c0@11517
9096+0000c1c0@11518
9097+0000d1c0@11519
9098+000071c2@11521
9099+0000f142@11522
9100+0000f5d2@11523
9101+00007552@11526
9102+0000e5d2@11527
9103+0000ebfe@11528
9104+0000eb7e@11530
9105+00006bfc@11531
9106+0000ebfc@11532
9107+0000effc@11533
9108+00006ffc@11535
9109+0000cffc@11536
9110+0000cf7c@11537
9111+0000dffc@11538
9112+00007ffe@11540
9113+0000ff7e@11541
9114+0000f5d6@11542
9115+00007556@11545
9116+0000e5d6@11546
9117+0000ebf2@11547
9118+0000eb72@11548
9119+00006bf2@11549
9120+0000ebf0@11550
9121+0000e1c0@11551
9122+0000e140@11552
9123+0000e1c0@11553
9124+000041c0@11554
9125+0000c1c0@11555
9126+0000d140@11556
9127+0000d1c0@11557
9128+000071c2@11559
9129+0000f5c6@11560
9130+0000f5d6@11561
9131+00007556@11563
9132+0000e5d6@11564
9133+0000ebf6@11565
9134+0000eb76@11567
9135+00006bf4@11568
9136+0000ebf4@11569
9137+0000effc@11570
9138+0000ef7c@11571
9139+0000effc@11572
9140+00004ffc@11573
9141+0000cffc@11574
9142+0000dffc@11575
9143+00007ffe@11577
9144+0000ff7e@11578
9145+0000f5d6@11579
9146+00007556@11582
9147+0000e5d6@11583
9148+0000ebfa@11584
9149+0000eb7a@11586
9150+0000ebf8@11587
9151+0000e1c0@11589
9152+000041c0@11591
9153+0000c1c0@11592
9154+0000d140@11593
9155+0000d1c0@11594
9156+000071c2@11596
9157+0000f142@11597
9158+0000f5d6@11598
9159+0000f5d4@11601
9160+0000fffc@11602
9161+0000fbf8@11603
9162+0000eb78@11604
9163+00006bf8@11605
9164+0000ebf8@11606
9165+0000effc@11607
9166+0000eb7c@11608
9167+0000effc@11609
9168+00006bfc@11610
9169+0000effc@11611
9170+0000ff7c@11612
9171+0000fffc@11613
9172+0000ff7e@11615
9173+0000fffe@11616
9174+0000f5d6@11617
9175+00007556@11619
9176+0000e5d6@11620
9177+0000ebfe@11621
9178+0000eb7e@11623
9179+00006bfc@11624
9180+0000ebfc@11625
9181+0000effc@11626
9182+0000ef7c@11627
9183+0000effc@11628
9184+0000cffc@11629
9185+0000cf7c@11630
9186+0000dffc@11631
9187+00007ffe@11633
9188+0000ff7e@11634
9189+0000f5da@11635
9190+0000755a@11638
9191+0000e5da@11639
9192+0000ebf2@11640
9193+00006bf2@11642
9194+0000ebf0@11643
9195+0000ebc0@11644
9196+0000e140@11645
9197+0000e1c0@11646
9198+000041c0@11647
9199+0000c1c0@11648
9200+0000d140@11649
9201+0000d1c0@11650
9202+000071c2@11652
9203+0000f1c2@11653
9204+0000f5da@11654
9205+000075da@11656
9206+0000e5da@11657
9207+0000eff6@11658
9208+0000ebf6@11659
9209+0000eb76@11660
9210+00006bf6@11661
9211+0000ebf4@11662
9212+0000effc@11663
9213+0000ef7c@11664
9214+0000effc@11665
9215+00004ffc@11666
9216+0000cffc@11667
9217+0000dffc@11668
9218+00007ffe@11670
9219+0000ff7e@11671
9220+0000fdfe@11672
9221+0000f5da@11673
9222+0000755a@11675
9223+0000e5da@11676
9224+0000ebfa@11677
9225+0000eb7a@11679
9226+00006bf8@11680
9227+0000ebf8@11681
9228+0000e1c0@11682
9229+000061c0@11684
9230+0000c1c0@11685
9231+0000c140@11686
9232+0000d1c0@11687
9233+000071c2@11689
9234+0000f142@11690
9235+0000f5da@11691
9236+0000755a@11694
9237+0000e5de@11695
9238+0000ebfe@11696
9239+00006bfe@11698
9240+0000ebfc@11699
9241+0000effc@11700
9242+0000ef7c@11701
9243+0000effc@11702
9244+00004ffc@11703
9245+0000cffc@11704
9246+0000df7c@11705
9247+0000dffc@11706
9248+00007ffe@11708
9249+0000fffe@11709
9250+0000f5de@11710
9251+000075de@11712
9252+0000e5de@11713
9253+0000ebf2@11714
9254+0000eb72@11716
9255+00006bf0@11717
9256+0000ebf0@11718
9257+0000e140@11719
9258+0000e1c0@11721
9259+000041c0@11722
9260+0000c1c0@11723
9261+0000d1c0@11724
9262+000071c2@11726
9263+0000f142@11727
9264+0000f5de@11728
9265+0000755e@11731
9266+0000e5de@11732
9267+0000ebf6@11733
9268+0000eb76@11735
9269+0000ebf4@11736
9270+0000effc@11737
9271+0000ef7c@11738
9272+0000effc@11739
9273+00004ffc@11740
9274+0000cffc@11741
9275+0000df7c@11742
9276+0000dffc@11743
9277+00007ffe@11745
9278+0000ff7e@11746
9279+0000f5de@11747
9280+0000e5de@11750
9281+0000effa@11751
9282+0000ebfa@11752
9283+0000eb7a@11753
9284+00006bfa@11754
9285+0000ebf8@11755
9286+0000e1c0@11756
9287+0000e140@11757
9288+0000e1c0@11758
9289+000041c0@11759
9290+0000c1c0@11760
9291+0000d140@11761
9292+0000d1c0@11762
9293+0000f1c0@11763
9294+0000f1c2@11764
9295+0000f55e@11765
9296+0000f5de@11766
9297+0000755e@11768
9298+0000e5de@11769
9299+0000ebfe@11770
9300+0000eb7e@11772
9301+00006bfc@11773
9302+0000ebfc@11774
9303+0000effc@11775
9304+0000ef7c@11776
9305+0000effc@11777
9306+0000cffc@11778
9307+0000cf7c@11779
9308+0000dffc@11780
9309+00007ffe@11782
9310+0000ff7e@11783
9311+0000f5e2@11784
9312+00007562@11787
9313+0000e5e2@11788
9314+0000ebf2@11789
9315+00006bf2@11791
9316+0000ebf0@11792
9317+0000ebc0@11793
9318+0000e140@11794
9319+0000e1c0@11795
9320+000041c0@11796
9321+0000c1c0@11797
9322+0000d140@11798
9323+0000d1c0@11799
9324+000071c2@11801
9325+0000f1c2@11802
9326+0000f5e2@11803
9327+000075e2@11805
9328+0000e5e2@11806
9329+0000ebf6@11807
9330+0000eb76@11809
9331+00006bf4@11810
9332+0000ebf4@11811
9333+0000effc@11812
9334+0000ef7c@11813
9335+0000effc@11814
9336+00004ffc@11815
9337+0000cffc@11816
9338+0000dffc@11817
9339+00007ffe@11819
9340+0000ff7e@11820
9341+0000ffe2@11821
9342+0000f5e2@11822
9343+00007562@11824
9344+0000e5e2@11825
9345+0000ebfa@11826
9346+0000eb7a@11828
9347+00006bf8@11829
9348+0000ebf8@11830
9349+0000e1c0@11831
9350+000061c0@11833
9351+0000c1c0@11834
9352+0000c140@11835
9353+0000d1c0@11836
9354+000071c2@11838
9355+0000f142@11839
9356+0000f5e2@11840
9357+00007562@11843
9358+0000e5ee@11844
9359+0000ebfe@11845
9360+00006bfe@11847
9361+0000ebfc@11848
9362+0000effc@11849
9363+0000ef7c@11850
9364+0000effc@11851
9365+00004ffc@11852
9366+0000cffc@11853
9367+0000df7c@11854
9368+0000dffc@11855
9369+00007ffe@11857
9370+0000fffe@11858
9371+0000f5e6@11859
9372+000075e6@11861
9373+0000e5e6@11862
9374+0000ebf2@11863
9375+0000eb72@11865
9376+00006bf0@11866
9377+0000ebf0@11867
9378+0000e140@11868
9379+0000e1c0@11870
9380+000041c0@11871
9381+0000c1c0@11872
9382+0000d1c0@11873
9383+000071c2@11875
9384+0000f142@11876
9385+0000f5e6@11877
9386+00007566@11880
9387+0000e5e6@11881
9388+0000ebf6@11882
9389+0000eb76@11884
9390+0000ebf4@11885
9391+0000effc@11886
9392+0000ef7c@11887
9393+0000effc@11888
9394+00004ffc@11889
9395+0000cffc@11890
9396+0000df7c@11891
9397+0000dffc@11892
9398+00007ffe@11894
9399+0000ff7e@11895
9400+0000f5e6@11896
9401+0000e5e6@11899
9402+0000effe@11900
9403+0000ebfa@11901
9404+0000eb7a@11902
9405+00006bfa@11903
9406+0000ebf8@11904
9407+0000e1c0@11905
9408+0000e140@11906
9409+0000e1c0@11907
9410+000041c0@11908
9411+0000c1c0@11909
9412+0000d140@11910
9413+0000d1c0@11911
9414+0000f1c0@11912
9415+0000f1c2@11913
9416+0000f5e6@11914
9417+00007566@11917
9418+0000e5e6@11918
9419+0000ebfe@11919
9420+0000eb7e@11921
9421+00006bfc@11922
9422+0000ebfc@11923
9423+0000effc@11924
9424+0000ef7c@11925
9425+0000effc@11926
9426+0000cffc@11927
9427+0000cf7c@11928
9428+0000dffc@11929
9429+00007ffe@11931
9430+0000ff7e@11932
9431+0000f5ea@11933
9432+0000756a@11936
9433+0000e5ea@11937
9434+0000ebf2@11938
9435+00006bf2@11940
9436+0000ebf0@11941
9437+0000ebc0@11942
9438+0000e140@11943
9439+0000e1c0@11944
9440+000041c0@11945
9441+0000c1c0@11946
9442+0000d140@11947
9443+0000d1c0@11948
9444+000071c2@11950
9445+0000f1c2@11951
9446+0000f5ea@11952
9447+000075ea@11954
9448+0000e5ea@11955
9449+0000effe@11956
9450+0000ebf6@11957
9451+0000eb76@11958
9452+00006bf4@11959
9453+0000ebf4@11960
9454+0000effc@11961
9455+0000ef7c@11962
9456+0000effc@11963
9457+00004ffc@11964
9458+0000cffc@11965
9459+0000dffc@11966
9460+00007ffe@11968
9461+0000ff7e@11969
9462+0000fdea@11970
9463+0000f5ea@11971
9464+0000756a@11973
9465+0000e5ea@11974
9466+0000ebfa@11975
9467+0000eb7a@11977
9468+00006bf8@11978
9469+0000ebf8@11979
9470+0000e1c0@11980
9471+000061c0@11982
9472+0000c1c0@11983
9473+0000c140@11984
9474+0000d1c0@11985
9475+000071c2@11987
9476+0000f142@11988
9477+0000f5ea@11989
9478+0000756a@11992
9479+0000e5ee@11993
9480+0000ebfe@11994
9481+00006bfe@11996
9482+0000ebfc@11997
9483+0000effc@11998
9484+0000ef7c@11999
9485+0000effc@12000
9486+00004ffc@12001
9487+0000cffc@12002
9488+0000df7c@12003
9489+0000dffc@12004
9490+00007ffe@12006
9491+0000fffe@12007
9492+0000f5ee@12008
9493+000075ee@12010
9494+0000e5ee@12011
9495+0000ebf2@12012
9496+0000eb72@12014
9497+00006bf0@12015
9498+0000ebf0@12016
9499+0000e140@12017
9500+0000e1c0@12019
9501+000041c0@12020
9502+0000c1c0@12021
9503+0000d1c0@12022
9504+000071c2@12024
9505+0000f142@12025
9506+0000f5ee@12026
9507+0000756e@12029
9508+0000e5ee@12030
9509+0000ebf6@12031
9510+0000eb76@12033
9511+0000ebf4@12034
9512+0000effc@12035
9513+0000ef7c@12036
9514+0000effc@12037
9515+00004ffc@12038
9516+0000cffc@12039
9517+0000df7c@12040
9518+0000dffc@12041
9519+00007ffe@12043
9520+0000ff7e@12044
9521+0000f5ee@12045
9522+0000e5ee@12048
9523+0000effa@12049
9524+0000ebfa@12050
9525+0000eb7a@12051
9526+00006bfa@12052
9527+0000ebf8@12053
9528+0000e1c0@12054
9529+0000e140@12055
9530+0000e1c0@12056
9531+000041c0@12057
9532+0000c1c0@12058
9533+0000d140@12059
9534+0000d1c0@12060
9535+0000f1c0@12061
9536+0000f142@12062
9537+0000f56e@12063
9538+0000f5ee@12064
9539+0000756e@12066
9540+0000e5ee@12067
9541+0000ebfe@12068
9542+0000eb7e@12070
9543+00006bfc@12071
9544+0000ebfc@12072
9545+0000effc@12073
9546+0000ef7c@12074
9547+0000effc@12075
9548+0000cffc@12076
9549+0000cf7c@12077
9550+0000dffc@12078
9551+00007ffe@12080
9552+0000ff7e@12081
9553+0000f5f2@12082
9554+00007572@12085
9555+0000e5f2@12086
9556+0000ebf2@12087
9557+00006bf2@12089
9558+0000ebf0@12090
9559+0000ebc0@12091
9560+0000e140@12092
9561+0000e1c0@12093
9562+000041c0@12094
9563+0000c1c0@12095
9564+0000d140@12096
9565+0000d1c0@12097
9566+000071c2@12099
9567+0000f1c2@12100
9568+0000f5f2@12101
9569+000075f2@12103
9570+0000e5f2@12104
9571+0000eff6@12105
9572+0000ebf6@12106
9573+0000eb76@12107
9574+00006bf4@12108
9575+0000ebf4@12109
9576+0000effc@12110
9577+0000ef7c@12111
9578+0000effc@12112
9579+00004ffc@12113
9580+0000cffc@12114
9581+0000dffc@12115
9582+00007ffe@12117
9583+0000ff7e@12118
9584+0000fdf2@12119
9585+0000f5f2@12120
9586+00007572@12122
9587+0000e5f2@12123
9588+0000ebfa@12124
9589+0000eb7a@12126
9590+00006bf8@12127
9591+0000ebf8@12128
9592+0000e1c0@12129
9593+000041c0@12131
9594+0000c1c0@12132
9595+0000c140@12133
9596+0000d1c0@12134
9597+000071c2@12136
9598+0000f142@12137
9599+0000f5f2@12138
9600+00007572@12141
9601+0000e5fe@12142
9602+0000ebfe@12143
9603+00006bfe@12145
9604+0000ebfc@12146
9605+0000effc@12147
9606+0000ef7c@12148
9607+0000effc@12149
9608+00004ffc@12150
9609+0000cffc@12151
9610+0000df7c@12152
9611+0000dffc@12153
9612+00007ffe@12155
9613+0000fffe@12156
9614+0000f5f6@12157
9615+000075f6@12159
9616+0000e5f6@12160
9617+0000ebf2@12161
9618+0000eb72@12163
9619+00006bf0@12164
9620+0000ebf0@12165
9621+0000e140@12166
9622+0000e1c0@12168
9623+000041c0@12169
9624+0000c1c0@12170
9625+0000d1c0@12171
9626+000071c2@12173
9627+0000f142@12174
9628+0000f5f6@12175
9629+00007576@12178
9630+0000e5f6@12179
9631+0000ebf6@12180
9632+0000eb76@12182
9633+0000ebf4@12183
9634+0000effc@12184
9635+0000ef7c@12185
9636+0000effc@12186
9637+00004ffc@12187
9638+0000cffc@12188
9639+0000df7c@12189
9640+0000dffc@12190
9641+00007ffe@12192
9642+0000ff7e@12193
9643+0000f5f6@12194
9644+0000f5f4@12197
9645+0000fff4@12198
9646+0000fbf4@12199
9647+0000eb74@12200
9648+00006bf4@12201
9649+0000ebf4@12202
9650+0000eb74@12204
9651+0000ebf4@12205
9652+00006bf4@12206
9653+0000ebf4@12207
9654+0000fb74@12208
9655+0000fbf4@12209
9656+0000fbf6@12211
9657+0000fff6@12212
9658+0000f5f6@12213
9659+00007576@12215
9660+0000e5f6@12216
9661+0000ebfa@12217
9662+0000eb7a@12219
9663+00006bf8@12220
9664+0000ebf8@12221
9665+0000e140@12222
9666+0000e1c0@12223
9667+0000c1c0@12225
9668+0000c140@12226
9669+0000d1c0@12227
9670+000071c2@12229
9671+0000f142@12230
9672+0000f5f6@12231
9673+00007576@12234
9674+0000e5f6@12235
9675+0000ebfe@12236
9676+00006bfe@12238
9677+0000ebfc@12239
9678+0000effc@12240
9679+0000ef7c@12241
9680+0000effc@12242
9681+00004ffc@12243
9682+0000cffc@12244
9683+0000df7c@12245
9684+0000dffc@12246
9685+00007ffe@12248
9686+0000fffe@12249
9687+0000f5fa@12250
9688+000075fa@12252
9689+0000e5fa@12253
9690+0000eff2@12254
9691+0000ebf2@12255
9692+0000eb72@12256
9693+00006bf2@12257
9694+0000ebf0@12258
9695+0000e140@12259
9696+0000e1c0@12261
9697+000041c0@12262
9698+0000c1c0@12263
9699+0000d1c0@12264
9700+000071c2@12266
9701+0000f142@12267
9702+0000f5fa@12268
9703+0000757a@12271
9704+0000e5fa@12272
9705+0000ebf6@12273
9706+0000eb76@12275
9707+00006bf4@12276
9708+0000ebf4@12277
9709+0000effc@12278
9710+00004ffc@12280
9711+0000cffc@12281
9712+0000cf7c@12282
9713+0000dffc@12283
9714+00007ffe@12285
9715+0000ff7e@12286
9716+0000f5fa@12287
9717+0000f5fa@12288
A
svp.cpu
+642,
-0
1@@ -0,0 +1,642 @@
2+info
3+ prefix svp_
4+ opcode_size 16
5+ body svp_run_op
6+ header svp.h
7+ include svp_util.c
8+
9+regs
10+ internal 16 scratch2 x y pad0 st pad1 pc
11+ a 32
12+ scratch1 32
13+ rom ptr16
14+ stack 16 stack0 stack1 stack2 stack3 stack4 stack5
15+ stackidx 8
16+ p 32
17+ external 16 pm0 pm1 pm2 xst pm4 ext5 pmc
18+ pointers0 8 r0 r1 r2 r3
19+ pointers1 8 r4 r5 r6 r7
20+ pm_address 32 5
21+ pm_mode 8 5
22+
23+ iram 16 1024
24+ ram0 16 256
25+ ram1 16 256
26+ zflag 8
27+ nflag 8
28+ rpl 16
29+
30+flags
31+ register st
32+ Z 13 zero zflag
33+ N 15 sign nflag
34+ R 0-2 none rpl
35+
36+svp_pop
37+ mov stack.stackidx dst
38+ add 1 stackidx stackidx
39+ switch stackidx
40+ case 6
41+ mov 0 stackidx
42+ end
43+
44+svp_push
45+ arg src 16
46+ sub 1 stackidx stackidx
47+ switch stackidx
48+ case 0xFF
49+ mov 5 stackidx
50+ end
51+ mov src stack.stackidx
52+
53+svp_ram_read
54+ arg mode 16
55+ arg banki 16
56+ arg regi 16
57+ local idx 16
58+
59+ switch banki
60+ case 0
61+ meta bank ram0
62+ meta reg pointers0.regi
63+
64+ default
65+ meta bank ram1
66+ meta reg pointers1.regi
67+ end
68+
69+ mov reg idx
70+ switch mode
71+ case 0
72+ meta modestr ""
73+
74+ case 1
75+ meta modestr +!
76+ add 1 reg reg
77+
78+ case 2
79+ #loop decremenet
80+ meta modestr -
81+
82+ if rpl
83+ local tmp 16
84+ mov reg tmp
85+ lsl 1 rpl rpl
86+ sub 1 rpl rpl
87+ local mask 16
88+ not rpl mask
89+ and reg mask reg
90+ sub 1 tmp tmp
91+ and rpl tmp tmp
92+ or tmp reg reg
93+ else
94+ sub 1 reg reg
95+ end
96+
97+ case 3
98+ #loop increment
99+ meta modestr +
100+
101+ and 7 st rpl
102+ if rpl
103+ local tmp 16
104+ mov reg tmp
105+ lsl 1 rpl rpl
106+ sub 1 rpl rpl
107+ local mask 16
108+ not rpl mask
109+ and reg mask reg
110+ add 1 tmp tmp
111+ and rpl tmp tmp
112+ or tmp reg reg
113+ else
114+ sub 1 reg reg
115+ end
116+ end
117+
118+ and 255 idx idx
119+ meta val bank.idx
120+
121+svp_read_ext
122+ arg regidxr 16
123+ switch regidxr
124+ case 7
125+ meta val a
126+
127+ default
128+ #TODO: PMAR stuff
129+ meta val external.regidxr
130+ end
131+
132+svp_write_ext
133+ arg regidxw 16
134+ switch regidxw
135+ case 7
136+ and 0xFFFF0000 a a
137+ or src a a
138+
139+ default
140+ #TODO: PMAR stuff
141+ mov src external.regidxw
142+ end
143+
144+svp_alu_op
145+ arg P 16
146+ arg param 32
147+
148+ switch P
149+ case 1
150+ dis "sub %s" name
151+ sub param a a
152+
153+ case 3
154+ dis "cmp %s" name
155+ cmp param a
156+
157+ case 4
158+ dis "add %s" name
159+ add param a a
160+
161+ case 5
162+ dis "and %s" name
163+ and param a a
164+
165+ case 6
166+ dis "or %s" name
167+ or param a a
168+
169+ case 7
170+ dis "eor %s" name
171+ xor param a a
172+ end
173+ update_flags ZN
174+
175+svp_check_cond
176+ arg fval 16
177+ arg cond 16
178+ local invert 8
179+ switch cond
180+ case 0
181+ meta flag 1
182+
183+ case 5
184+ meta flag zflag
185+
186+ case 7
187+ meta flag nflag
188+
189+ default
190+ meta flag 0
191+ end
192+
193+ if fval
194+ meta istrue flag
195+
196+ else
197+ lnot flag invert
198+ meta istrue invert
199+
200+ end
201+
202+PPP0000000000000 alu_n1
203+ invalid P 0
204+ invalid P 2
205+ meta name "-"
206+ svp_alu_op P 0xFFFF0000
207+
208+PPP0000000000RRR alu_r
209+ invalid P 0
210+ invalid P 2
211+ local tmp 32
212+ lsl internal.R 16 tmp
213+ meta name internal.R
214+ svp_alu_op P tmp
215+
216+PPP0000000000011 alu_a
217+ invalid P 0
218+ invalid P 2
219+ svp_alu_op P a
220+
221+PPP0000000000101 alu_stack
222+ invalid P 0
223+ invalid P 2
224+ local tmp 32
225+ meta dst tmp
226+ svp_pop
227+ meta name "stack"
228+ svp_alu_op P tmp
229+
230+PPP0000000000111 alu_p
231+ invalid P 0
232+ invalid P 2
233+ meta name p
234+ svp_alu_op P p
235+
236+PPP0000000001RRR alu_ext
237+ invalid P 0
238+ invalid P 2
239+ local tmp 32
240+ svp_read_ext R
241+ lsl val 16 tmp
242+ meta name val
243+ svp_alu_op P tmp
244+
245+PPP0001B0000MMRR alu_ram
246+ invalid P 0
247+ invalid P 2
248+ svp_ram_read M B R
249+ local tmp 32
250+ lsl val 16 tmp
251+
252+ switch P
253+ case 1
254+ dis "sub (%s%s)" reg modestr
255+ sub tmp a a
256+
257+ case 3
258+ dis "cmp (%s%s)" reg modestr
259+ cmp tmp a
260+
261+ case 4
262+ dis "add (%s%s)" reg modestr
263+ add tmp a a
264+
265+ case 5
266+ dis "and (%s%s)" reg modestr
267+ and tmp a a
268+
269+ case 6
270+ dis "or (%s%s)" reg modestr
271+ or tmp a a
272+
273+ case 7
274+ dis "eor (%s%s)" reg modestr
275+ xor tmp a a
276+ end
277+
278+ update_flags ZN
279+
280+PPP0101B0000MMRR alu_ram_indirect
281+ invalid P 0
282+ invalid P 2
283+ svp_ram_read M B R
284+ svp_prog_ram_read val
285+ local tmp 32
286+ lsl scratch1 16 tmp
287+
288+ switch P
289+ case 1
290+ dis "sub ((%s%s))" reg modestr
291+ sub tmp a a
292+
293+ case 3
294+ dis "cmp ((%s%s))" reg modestr
295+ cmp tmp a
296+
297+ case 4
298+ dis "add ((%s%s))" reg modestr
299+ add tmp a a
300+
301+ case 5
302+ dis "and ((%s%s))" reg modestr
303+ and tmp a a
304+
305+ case 6
306+ dis "or ((%s%s))" reg modestr
307+ or tmp a a
308+
309+ case 7
310+ dis "eor ((%s%s))" reg modestr
311+ xor tmp a a
312+ end
313+
314+ update_flags ZN
315+
316+PPP0000000001111 alu_al
317+ invalid P 0
318+ invalid P 2
319+ local tmp 32
320+ lsl a 16 tmp
321+
322+ meta name al
323+ svp_alu_op P tmp
324+
325+PPP0011JAAAAAAAA alu_ram_direct
326+ invalid P 0
327+ invalid P 2
328+ if J
329+ meta src ram1.A
330+ else
331+ meta src ram0.A
332+ end
333+ svp_alu_op P src
334+
335+PPP0010000000000 alu_immed
336+ invalid P 0
337+ invalid P 2
338+ svp_op_fetch
339+ svp_alu_op P scratch1
340+
341+1001000FCCCC0OOO cond_mod
342+ svp_check_cond F C
343+ if istrue
344+
345+ switch O
346+ case 2
347+ asr a 1 a
348+ update_flags ZN
349+
350+ case 3
351+ lsl a 1 a
352+ update_flags ZN
353+
354+ case 6
355+ neg a a
356+ update_flags ZN
357+
358+ case 7
359+ abs a a
360+ update_flags N
361+ end
362+ end
363+
364+000000000DDD0SSS ld_int_int
365+ dis "ld %s, %s" internal.D internal.S
366+ mov internal.S internal.D
367+
368+000000000DDD0101 ld_int_stack
369+ dis "ld %s, stack" internal.D
370+ meta dst internal.D
371+ svp_pop
372+
373+0000000000110101 ld_a_stack
374+ dis "ld a, stack"
375+ local tmp 32
376+ meta dst tmp
377+ svp_pop
378+ lsl tmp 16 tmp
379+ and 0xFFFF a a
380+ or tmp a a
381+
382+0000000001110101 ld_p_stack
383+ dis "ld p, stack"
384+ local tmp 32
385+ meta dst tmp
386+ svp_pop
387+ lsl tmp 16 tmp
388+ and 0xFFFF p p
389+ or tmp p p
390+
391+0000000001010SSS ld_stack_int
392+ dis "ld stack, %s" internal.S
393+ svp_push internal.S
394+
395+0000000001010011 ld_stack_a
396+ dis "ld stack, a"
397+ local tmp 32
398+ lsr a 16 tmp
399+ svp_push tmp
400+
401+0000000001010111 ld_stack_p
402+ dis "ld stack, p"
403+ local tmp 32
404+ lsr p 16 tmp
405+ svp_push tmp
406+
407+0000000000000000 ld_n1_n1
408+ #nop?
409+ dis "ld -, -"
410+
411+0000000000000SSS ld_n1_int
412+ #nop?
413+ dis "nop??"
414+
415+0000000000110111 ld_a_p
416+ dis "ld a, p"
417+ mov p a
418+
419+0000000001110011 ld_p_a
420+ dis "ld p, a"
421+ mov a p
422+
423+0000000000110011 ld_a_a
424+ dis "ld a, a"
425+ mov a a
426+
427+0000000001110111 ld_p_p
428+ dis "ld p, p"
429+ mov p p
430+
431+000000000DDD0111 ld_int_p
432+ local tmp 32
433+ lsr p 16 tmp
434+ mov tmp internal.D
435+ dis "ld %s, p" internal.D
436+
437+000000000DDD0111 ld_int_a
438+ local tmp 32
439+ lsr a 16 tmp
440+ mov tmp internal.D
441+ dis "ld %s, a" internal.D
442+
443+0000000001110SSS ld_p_int
444+ local tmp 32
445+ lsl internal.S 16 tmp
446+ mov tmp p
447+ dis "ld p, %s" internal.S
448+
449+0000000000110SSS ld_a_int
450+ local tmp 32
451+ lsl internal.S 16 tmp
452+ mov tmp a
453+ dis "ld a, %s" internal.S
454+
455+000000000DDD0000 ld_int_n1
456+ dis "ld %s, -" internal.D
457+ mov 0xFFFF internal.D
458+
459+0000000000110000 ld_a_n1
460+ dis "ld a, -"
461+ and 0xFFFF a a
462+ or 0xFFFF0000 a a
463+
464+0000000001110000 ld_p_n1
465+ dis "ld p, -"
466+ and 0xFFFF p p
467+ or 0xFFFF0000 p p
468+
469+000000000DDD1SSS ld_int_ext
470+ svp_read_ext S
471+ dis "ld %s, %s" internal.D val
472+ mov val internal.D
473+
474+0000000000111SSS ld_a_ext
475+ svp_read_ext S
476+ dis "ld a, %s" val
477+ local tmp 32
478+ lsl val 16 tmp
479+ and 0xFFFF a a
480+ or tmp a a
481+
482+0000000001111SSS ld_p_ext
483+ svp_read_ext S
484+ dis "ld p, %s" val
485+ local tmp 32
486+ lsl val 16 tmp
487+ and 0xFFFF p p
488+ or tmp p p
489+
490+000000001DDD0SSS ld_ext_int
491+ meta src internal.S
492+ svp_write_ext D
493+ switch D
494+ case 7
495+ dis "ld al, %s" src
496+
497+ default
498+ dis "ld %s, %s" external.D src
499+ end
500+
501+000000001DDD0011 ld_ext_a
502+ local tmp 32
503+ lsr a 16 tmp
504+ meta src tmp
505+ svp_write_ext D
506+ switch D
507+ case 7
508+ dis "ld al, a"
509+
510+ default
511+ dis "ld %s, a" external.D
512+ end
513+
514+000000001DDD0111 ld_ext_p
515+ local tmp 32
516+ lsr p 16 tmp
517+ meta src tmp
518+ svp_write_ext D
519+ switch D
520+ case 7
521+ dis "ld al, p"
522+
523+ default
524+ dis "ld %s, p" external.D
525+ end
526+
527+
528+000000001DDD1SSS ld_ext_ext
529+ svp_read_ext S
530+ meta src val
531+ svp_write_ext D
532+ switch D
533+ case 7
534+ dis "ld al, %s" src
535+ default
536+ dis "ld %s, %s" external.D src
537+ end
538+
539+0000001B0DDDMMPP ld_int_ram
540+ svp_ram_read M B P
541+ dis "ld %s, (%s%s)" internal.D reg modestr
542+ mov val internal.D
543+
544+0000001B0011MMPP ld_a_ram
545+ svp_ram_read M B P
546+ dis "ld a, (%s%s)" reg modestr
547+ local tmp 32
548+ lsl val 16 tmp
549+ and 0xFFFF a a
550+ or tmp a a
551+
552+0000001B0111MMPP ld_p_ram
553+ svp_ram_read M B P
554+ dis "ld p, (%s%s)" reg modestr
555+ local tmp 32
556+ lsl val 16 tmp
557+ and 0xFFFF p p
558+ or tmp p p
559+
560+0000001B0101MMPP ld_stack_ram
561+ svp_ram_read M B P
562+ dis "ld stack, (%s%s)" reg modestr
563+ svp_push val
564+
565+000010000DDD0000 ld_int_immed
566+ svp_op_fetch
567+ dis "ld %s, %X" internal.D scratch1
568+ mov scratch1 internal.D
569+
570+0000100000000000 ld_n1_immed
571+ svp_op_fetch
572+ dis "ld -, %X" scratch1
573+
574+0000100000110000 ld_a_immed
575+ local tmp 32
576+ svp_op_fetch
577+ dis "ld a, %X" scratch1
578+ lsl 16 scratch1 tmp
579+ and 0xFFFF a a
580+ or tmp a a
581+
582+0000100001010000 ld_stack_immed
583+ svp_op_fetch
584+ dis "ld stack, %X" scratch1
585+ svp_push scratch1
586+
587+0000100001110000 ld_p_immed
588+ local tmp 32
589+ svp_op_fetch
590+ dis "ld p, %X" scratch1
591+ lsl 16 scratch1 tmp
592+ and 0xFFFF p p
593+ or tmp p p
594+
595+000010001DDD0000 ld_ext_immed
596+ svp_op_fetch
597+ dis "ld %s, %X", external.D, scratch1
598+ meta src scratch1
599+ svp_write_ext D
600+ switch D
601+ case 7
602+ dis "ld al, %X" scratch1
603+
604+ default
605+ dis "ld %s, %X" external.D scratch1
606+ end
607+
608+0100100FCCCC0000 call_cond
609+ svp_check_cond F C
610+ svp_op_fetch
611+
612+ if istrue
613+ svp_push pc
614+ mov scratch1 pc
615+ end
616+
617+0100110FCCCC0000 bra_cond
618+ svp_check_cond F C
619+ svp_op_fetch
620+ if istrue
621+ mov scratch1 pc
622+ end
623+
624+svp_prog_ram_read
625+ arg src 16
626+ cycles 1
627+ cmp 1024 src
628+
629+ if >=U
630+ add src src scratch1
631+ ocall prog_read_16
632+
633+ else
634+ mov iram.src scratch1
635+ end
636+
637+svp_op_fetch
638+ svp_prog_ram_read pc
639+ add 1 pc pc
640+
641+svp_run_op
642+ svp_op_fetch
643+ dispatch scratch1
+6,
-0
1@@ -0,0 +1,6 @@
2+
3+void svp_prog_read_16(svp_context *context)
4+{
5+ uint16_t address = context->scratch1 >> 1;
6+ context->scratch1 = context->rom[address];
7+}
A
system.c
+65,
-0
1@@ -0,0 +1,65 @@
2+#include <string.h>
3+#include "system.h"
4+#include "genesis.h"
5+#include "sms.h"
6+
7+uint8_t safe_cmp(char *str, long offset, uint8_t *buffer, long filesize)
8+{
9+ long len = strlen(str);
10+ return filesize >= offset+len && !memcmp(str, buffer + offset, len);
11+}
12+
13+system_type detect_system_type(system_media *media)
14+{
15+ if (safe_cmp("SEGA", 0x100, media->buffer, media->size)) {
16+ //TODO: Differentiate between vanilla Genesis and Sega CD/32X games
17+ return SYSTEM_GENESIS;
18+ }
19+ if (safe_cmp("TMR SEGA", 0x1FF0, media->buffer, media->size)
20+ || safe_cmp("TMR SEGA", 0x3FF0, media->buffer, media->size)
21+ || safe_cmp("TMR SEGA", 0x7FF0, media->buffer, media->size)
22+ ) {
23+ return SYSTEM_SMS;
24+ }
25+ //TODO: Detect Jaguar ROMs here
26+
27+ //Header based detection failed, examine filename for clues
28+ if (media->extension) {
29+ if (!strcmp("md", media->extension) || !strcmp("gen", media->extension)) {
30+ return SYSTEM_GENESIS;
31+ }
32+ if (!strcmp("sms", media->extension)) {
33+ return SYSTEM_SMS;
34+ }
35+ }
36+
37+ //More certain checks failed, look for a valid 68K reset vector
38+ if (media->size >= 8) {
39+ char *rom = media->buffer;
40+ uint32_t reset = rom[4] << 24 | rom[5] << 16 | rom[6] << 8 | rom[7];
41+ if (!(reset & 1) && reset < media->size) {
42+ //we have a valid looking reset vector, assume it's a Genesis ROM
43+ return SYSTEM_GENESIS;
44+ }
45+ }
46+ return SYSTEM_UNKNOWN;
47+}
48+
49+system_header *alloc_config_system(system_type stype, system_media *media, uint32_t opts, uint8_t force_region)
50+{
51+ void *lock_on = NULL;
52+ uint32_t lock_on_size = 0;
53+ if (media->chain) {
54+ lock_on = media->chain->buffer;
55+ lock_on_size = media->chain->size;
56+ }
57+ switch (stype)
58+ {
59+ case SYSTEM_GENESIS:
60+ return &(alloc_config_genesis(media->buffer, media->size, lock_on, lock_on_size, opts, force_region))->header;
61+ case SYSTEM_SMS:
62+ return &(alloc_configure_sms(media, opts, force_region))->header;
63+ default:
64+ return NULL;
65+ }
66+}
A
system.h
+87,
-0
1@@ -0,0 +1,87 @@
2+#ifndef SYSTEM_H_
3+#define SYSTEM_H_
4+#include <stddef.h>
5+#include <stdint.h>
6+
7+typedef struct system_header system_header;
8+typedef struct system_media system_media;
9+
10+typedef enum {
11+ SYSTEM_UNKNOWN,
12+ SYSTEM_GENESIS,
13+ SYSTEM_SMS
14+} system_type;
15+
16+typedef enum {
17+ DEBUGGER_NATIVE,
18+ DEBUGGER_GDB
19+} debugger_type;
20+
21+typedef void (*system_fun)(system_header *);
22+typedef uint16_t (*system_fun_r16)(system_header *);
23+typedef void (*system_str_fun)(system_header *, char *);
24+typedef uint8_t (*system_str_fun_r8)(system_header *, char *);
25+typedef void (*system_u32_fun)(system_header *, uint32_t);
26+typedef void (*system_u8_fun)(system_header *, uint8_t);
27+typedef uint8_t (*system_u8_fun_r8)(system_header *, uint8_t);
28+typedef void (*system_u8_u8_fun)(system_header *, uint8_t, uint8_t);
29+typedef void (*system_mabs_fun)(system_header *, uint8_t, uint16_t, uint16_t);
30+typedef void (*system_mrel_fun)(system_header *, uint8_t, int32_t, int32_t);
31+typedef uint8_t *(*system_ptrszt_fun_rptr8)(system_header *, size_t *);
32+typedef void (*system_ptr8_sizet_fun)(system_header *, uint8_t *, size_t);
33+
34+#include "arena.h"
35+#include "romdb.h"
36+
37+struct system_header {
38+ system_header *next_context;
39+ system_str_fun start_context;
40+ system_fun resume_context;
41+ system_fun load_save;
42+ system_fun persist_save;
43+ system_u8_fun_r8 load_state;
44+ system_fun request_exit;
45+ system_fun soft_reset;
46+ system_fun free_context;
47+ system_fun_r16 get_open_bus_value;
48+ system_u32_fun set_speed_percent;
49+ system_fun inc_debug_mode;
50+ system_u8_u8_fun gamepad_down;
51+ system_u8_u8_fun gamepad_up;
52+ system_u8_u8_fun mouse_down;
53+ system_u8_u8_fun mouse_up;
54+ system_mabs_fun mouse_motion_absolute;
55+ system_mrel_fun mouse_motion_relative;
56+ system_u8_fun keyboard_down;
57+ system_u8_fun keyboard_up;
58+ system_fun config_updated;
59+ system_ptrszt_fun_rptr8 serialize;
60+ system_ptr8_sizet_fun deserialize;
61+ rom_info info;
62+ arena *arena;
63+ char *next_rom;
64+ char *save_dir;
65+ uint8_t enter_debugger;
66+ uint8_t should_exit;
67+ uint8_t save_state;
68+ uint8_t delayed_load_slot;
69+ uint8_t has_keyboard;
70+ debugger_type debugger_type;
71+ system_type type;
72+};
73+
74+struct system_media {
75+ void *buffer;
76+ char *dir;
77+ char *name;
78+ char *extension;
79+ system_media *chain;
80+ uint32_t size;
81+};
82+
83+#define OPT_ADDRESS_LOG (1U << 31U)
84+
85+system_type detect_system_type(system_media *media);
86+system_header *alloc_config_system(system_type stype, system_media *media, uint32_t opts, uint8_t force_region);
87+
88+#endif //SYSTEM_H_
+44,
-0
1@@ -0,0 +1,44 @@
2+#include <sys/types.h>
3+#include <sys/stat.h>
4+#include <fcntl.h>
5+#include <unistd.h>
6+#include <stdlib.h>
7+#include "terminal.h"
8+
9+char buf[4096];
10+
11+void copy_data(int to, int from)
12+{
13+ ssize_t bytes = read(from, buf, sizeof(buf));
14+ while (bytes > 0)
15+ {
16+ ssize_t written = write(to, buf, bytes);
17+ if (written == -1) {
18+ exit(1);
19+ }
20+ bytes -= written;
21+ }
22+}
23+
24+int main(int argc, char **argv)
25+{
26+ //these will block so order is important
27+ int input_fd = open(INPUT_PATH, O_WRONLY);
28+ int output_fd = open(OUTPUT_PATH, O_RDONLY);
29+ fd_set read_fds;
30+ FD_ZERO(&read_fds);
31+ for (;;)
32+ {
33+ FD_SET(STDIN_FILENO, &read_fds);
34+ FD_SET(output_fd, &read_fds);
35+ select(output_fd+1, &read_fds, NULL, NULL, NULL);
36+
37+ if (FD_ISSET(STDIN_FILENO, &read_fds)) {
38+ copy_data(input_fd, STDIN_FILENO);
39+ }
40+ if (FD_ISSET(output_fd, &read_fds)) {
41+ copy_data(STDOUT_FILENO, output_fd);
42+ }
43+ }
44+ return 0;
45+}
+71,
-0
1@@ -0,0 +1,71 @@
2+#include <sys/types.h>
3+#include <sys/stat.h>
4+#include <unistd.h>
5+#include <fcntl.h>
6+#include <stdlib.h>
7+#include <stdint.h>
8+#include <signal.h>
9+#include "util.h"
10+#include "terminal.h"
11+
12+pid_t child;
13+
14+void cleanup_terminal()
15+{
16+ kill(child, SIGKILL);
17+ unlink(INPUT_PATH);
18+ unlink(OUTPUT_PATH);
19+}
20+
21+static char init_done;
22+
23+void force_no_terminal()
24+{
25+ init_done = 1;
26+}
27+
28+void init_terminal()
29+{
30+ if (!init_done) {
31+ if (!(isatty(STDIN_FILENO) && isatty(STDOUT_FILENO))) {
32+#ifndef __APPLE__
33+ //check to see if x-terminal-emulator exists, just use xterm if it doesn't
34+ char *term = system("which x-terminal-emulator > /dev/null") ? "xterm" : "x-terminal-emulator";
35+#endif
36+ //get rid of FIFO's if they already exist
37+ unlink(INPUT_PATH);
38+ unlink(OUTPUT_PATH);
39+ //create FIFOs for talking to helper process in terminal app
40+ mkfifo(INPUT_PATH, 0666);
41+ mkfifo(OUTPUT_PATH, 0666);
42+
43+ //close existing file descriptors
44+ close(STDIN_FILENO);
45+ close(STDOUT_FILENO);
46+ close(STDERR_FILENO);
47+
48+ child = fork();
49+ if (child == -1) {
50+ //error, oh well
51+ warning("Failed to fork for terminal spawn");
52+ } else if (!child) {
53+ //child process, exec our terminal emulator
54+#ifdef __APPLE__
55+ execlp("open", "open", "./termhelper", NULL);
56+#else
57+ execlp(term, term, "-title", "BlastEm Debugger", "-e", "./termhelper", NULL);
58+#endif
59+ } else {
60+ //connect to the FIFOs, these will block so order is important
61+ open(INPUT_PATH, O_RDONLY);
62+ open(OUTPUT_PATH, O_WRONLY);
63+ atexit(cleanup_terminal);
64+ if (-1 == dup(STDOUT_FILENO)) {
65+ fatal_error("failed to dup STDOUT to STDERR after terminal fork");
66+ }
67+ }
68+ }
69+
70+ init_done = 1;
71+ }
72+}
+10,
-0
1@@ -0,0 +1,10 @@
2+#ifndef TERMINAL_H_
3+#define TERMINAL_H_
4+
5+void init_terminal();
6+void force_no_terminal();
7+
8+#define INPUT_PATH "/tmp/blastem_input"
9+#define OUTPUT_PATH "/tmp/blastem_output"
10+
11+#endif //TERMINAL_H_
A
tern.c
+318,
-0
1@@ -0,0 +1,318 @@
2+/*
3+ Copyright 2013 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#include "tern.h"
8+#include <stddef.h>
9+#include <stdlib.h>
10+#include <string.h>
11+#include <stdio.h>
12+#include "util.h"
13+
14+tern_node * tern_insert(tern_node * head, char const * key, tern_val value, uint8_t valtype)
15+{
16+ tern_node ** cur = &head;
17+ while(*key)
18+ {
19+ if (*cur) {
20+ while(*cur && (*cur)->el != *key)
21+ {
22+ if (*key < (*cur)->el) {
23+ cur = &(*cur)->left;
24+ } else {
25+ cur = &(*cur)->right;
26+ }
27+ }
28+ }
29+ if (!*cur) {
30+ *cur = malloc(sizeof(tern_node));
31+ (*cur)->left = NULL;
32+ (*cur)->right = NULL;
33+ (*cur)->straight.next = NULL;
34+ (*cur)->el = *key;
35+ (*cur)->valtype = TVAL_NONE;
36+ }
37+ cur = &((*cur)->straight.next);
38+ key++;
39+ }
40+ while(*cur && (*cur)->el)
41+ {
42+ cur = &(*cur)->left;
43+ }
44+ if (!*cur) {
45+ *cur = malloc(sizeof(tern_node));
46+ (*cur)->left = NULL;
47+ (*cur)->right = NULL;
48+ (*cur)->el = 0;
49+ (*cur)->valtype = TVAL_NONE;
50+ }
51+ if ((*cur)->valtype == TVAL_PTR) {
52+ //not freeing tern nodes can also cause leaks, but handling freeing those here is problematic
53+ //since updating a sub-tree may involve creating a new root node
54+ free((*cur)->straight.value.ptrval);
55+ }
56+ (*cur)->straight.value = value;
57+ (*cur)->valtype = valtype;
58+ return head;
59+}
60+
61+uint8_t tern_find(tern_node * head, char const * key, tern_val *ret)
62+{
63+ tern_node * cur = head;
64+ while (cur)
65+ {
66+ if (cur->el == *key) {
67+ if (*key) {
68+ cur = cur->straight.next;
69+ key++;
70+ } else {
71+ *ret = cur->straight.value;
72+ return cur->valtype;
73+ }
74+ } else if (*key < cur->el) {
75+ cur = cur->left;
76+ } else {
77+ cur = cur->right;
78+ }
79+ }
80+ return TVAL_NONE;
81+}
82+
83+tern_node * tern_find_prefix(tern_node * head, char const * key)
84+{
85+ tern_node * cur = head;
86+ while (cur && *key)
87+ {
88+ if (cur->el == *key) {
89+ cur = cur->straight.next;
90+ key++;
91+ } else if (*key < cur->el) {
92+ cur = cur->left;
93+ } else {
94+ cur = cur->right;
95+ }
96+ }
97+ return cur;
98+}
99+
100+intptr_t tern_find_int(tern_node * head, char const * key, intptr_t def)
101+{
102+ tern_val ret;
103+ uint8_t valtype = tern_find(head, key, &ret);
104+ if (valtype == TVAL_INT) {
105+ return ret.intval;
106+ }
107+ return def;
108+}
109+
110+tern_node * tern_insert_int(tern_node * head, char const * key, intptr_t value)
111+{
112+ tern_val val;
113+ val.intval = value;
114+ return tern_insert(head, key, val, TVAL_INT);
115+}
116+
117+void * tern_find_ptr_default(tern_node * head, char const * key, void * def)
118+{
119+ tern_val ret;
120+ uint8_t valtype = tern_find(head, key, &ret);
121+ if (valtype == TVAL_PTR) {
122+ return ret.ptrval;
123+ }
124+ return def;
125+}
126+
127+void * tern_find_ptr(tern_node * head, char const * key)
128+{
129+ return tern_find_ptr_default(head, key, NULL);
130+}
131+
132+tern_node *tern_find_node(tern_node *head, char const *key)
133+{
134+ tern_val ret;
135+ uint8_t valtype = tern_find(head, key, &ret);
136+ if (valtype == TVAL_NODE) {
137+ return ret.ptrval;
138+ }
139+ return NULL;
140+}
141+
142+uint8_t tern_delete(tern_node **head, char const *key, tern_val *out)
143+{
144+ tern_node *cur = *head, **last = head;
145+ while (cur)
146+ {
147+ if (cur->el == *key) {
148+ if (*key) {
149+ last = &cur->straight.next;
150+ cur = cur->straight.next;
151+ key++;
152+ } else {
153+ break;
154+ }
155+ } else if (*key < cur->el) {
156+ last = &cur->left;
157+ cur = cur->left;
158+ } else {
159+ last = &cur->right;
160+ cur = cur->right;
161+ }
162+ }
163+ if (!cur) {
164+ return TVAL_NONE;
165+ }
166+ *last = cur->right;
167+ uint8_t valtype = cur->valtype;
168+ if (out) {
169+ *out = cur->straight.value;
170+ }
171+ free(cur);
172+ return valtype;
173+}
174+
175+tern_val tern_find_path_default(tern_node *head, char const *key, tern_val def, uint8_t req_valtype)
176+{
177+ tern_val ret;
178+ while (*key)
179+ {
180+ uint8_t valtype = tern_find(head, key, &ret);
181+ if (!valtype) {
182+ return def;
183+ }
184+ key = key + strlen(key) + 1;
185+ if (*key) {
186+ if (valtype != TVAL_NODE) {
187+ return def;
188+ }
189+ head = ret.ptrval;
190+ } else if (req_valtype && req_valtype != valtype) {
191+ return def;
192+ }
193+ }
194+ return ret;
195+}
196+
197+tern_val tern_find_path(tern_node *head, char const *key, uint8_t valtype)
198+{
199+ tern_val def;
200+ def.ptrval = NULL;
201+ return tern_find_path_default(head, key, def, valtype);
202+}
203+
204+tern_node * tern_insert_ptr(tern_node * head, char const * key, void * value)
205+{
206+ tern_val val;
207+ val.ptrval = value;
208+ return tern_insert(head, key, val, TVAL_PTR);
209+}
210+
211+tern_node * tern_insert_node(tern_node *head, char const *key, tern_node *value)
212+{
213+ tern_val val;
214+ val.ptrval = value;
215+ return tern_insert(head, key, val, TVAL_NODE);
216+}
217+
218+tern_node *tern_insert_path(tern_node *head, char const *key, tern_val val, uint8_t valtype)
219+{
220+ const char *next_key = key + strlen(key) + 1;
221+ if (*next_key) {
222+ tern_node *child = tern_find_node(head, key);
223+ child = tern_insert_path(child, next_key, val, valtype);
224+ return tern_insert_node(head, key, child);
225+ } else {
226+ return tern_insert(head, key, val, valtype);
227+ }
228+}
229+
230+uint8_t tern_delete_path(tern_node **head, char const *key, tern_val *out)
231+{
232+ const char *next_key = key + strlen(key) + 1;
233+ if (*next_key) {
234+ tern_node *child = tern_find_node(*head, key);
235+ if (!child) {
236+ return TVAL_NONE;
237+ }
238+ tern_node *tmp = child;
239+ uint8_t valtype = tern_delete_path(&tmp, next_key, out);
240+ if (tmp != child) {
241+ *head = tern_insert_node(*head, key, tmp);
242+ }
243+ return valtype;
244+ } else {
245+ return tern_delete(head, key, out);
246+ }
247+}
248+
249+uint32_t tern_count(tern_node *head)
250+{
251+ uint32_t count = 0;
252+ if (head->left) {
253+ count += tern_count(head->left);
254+ }
255+ if (head->right) {
256+ count += tern_count(head->right);
257+ }
258+ if (!head->el) {
259+ count++;
260+ } else if (head->straight.next) {
261+ count += tern_count(head->straight.next);
262+ }
263+ return count;
264+}
265+
266+#define MAX_ITER_KEY 127
267+void tern_foreach_int(tern_node *head, iter_fun fun, void *data, char *keybuf, int pos)
268+{
269+ if (!head->el) {
270+ keybuf[pos] = 0;
271+ fun(keybuf, head->straight.value, head->valtype, data);
272+ }
273+ if (head->left) {
274+ tern_foreach_int(head->left, fun, data, keybuf, pos);
275+ }
276+ if (head->el && head->straight.next) {
277+ if (pos == MAX_ITER_KEY) {
278+ fatal_error("tern_foreach_int: exceeded maximum key size");
279+ }
280+ keybuf[pos] = head->el;
281+ tern_foreach_int(head->straight.next, fun, data, keybuf, pos+1);
282+ }
283+ if (head->right) {
284+ tern_foreach_int(head->right, fun, data, keybuf, pos);
285+ }
286+}
287+
288+void tern_foreach(tern_node *head, iter_fun fun, void *data)
289+{
290+ //lame, but good enough for my purposes
291+ char key[MAX_ITER_KEY+1];
292+ tern_foreach_int(head, fun, data, key, 0);
293+}
294+
295+char * tern_int_key(uint32_t key, char * buf)
296+{
297+ char * cur = buf;
298+ while (key)
299+ {
300+ *(cur++) = (key & 0x7F) + 1;
301+ key >>= 7;
302+ }
303+ *cur = 0;
304+ return buf;
305+}
306+
307+void tern_free(tern_node *head)
308+{
309+ if (head->left) {
310+ tern_free(head->left);
311+ }
312+ if (head->right) {
313+ tern_free(head->right);
314+ }
315+ if (head->el) {
316+ tern_free(head->straight.next);
317+ }
318+ free(head);
319+}
A
tern.h
+58,
-0
1@@ -0,0 +1,58 @@
2+/*
3+ Copyright 2013 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#ifndef TERN_H_
8+#define TERN_H_
9+
10+#include <stdint.h>
11+
12+#define MAX_INT_KEY_SIZE (sizeof(uint32_t) + 2)
13+
14+typedef union {
15+ void *ptrval;
16+ intptr_t intval;
17+} tern_val;
18+
19+typedef struct tern_node {
20+ struct tern_node *left;
21+ union {
22+ struct tern_node *next;
23+ tern_val value;
24+ } straight;
25+ struct tern_node *right;
26+ char el;
27+ uint8_t valtype;
28+} tern_node;
29+
30+enum {
31+ TVAL_NONE=0,
32+ TVAL_INT,
33+ TVAL_PTR,
34+ TVAL_NODE
35+};
36+
37+typedef void (*iter_fun)(char *key, tern_val val, uint8_t valtype, void *data);
38+
39+tern_node * tern_insert(tern_node * head, char const * key, tern_val value, uint8_t valtype);
40+uint8_t tern_find(tern_node * head, char const * key, tern_val *ret);
41+tern_node * tern_find_prefix(tern_node * head, char const * key);
42+intptr_t tern_find_int(tern_node * head, char const * key, intptr_t def);
43+tern_node * tern_insert_int(tern_node * head, char const * key, intptr_t value);
44+void * tern_find_ptr_default(tern_node * head, char const * key, void * def);
45+void * tern_find_ptr(tern_node * head, char const * key);
46+tern_node *tern_find_node(tern_node *head, char const *key);
47+uint8_t tern_delete(tern_node **head, char const *key, tern_val *out);
48+tern_val tern_find_path_default(tern_node *head, char const *key, tern_val def, uint8_t req_valtype);
49+tern_val tern_find_path(tern_node *head, char const *key, uint8_t valtype);
50+uint8_t tern_delete_path(tern_node **head, char const *key, tern_val *out);
51+tern_node * tern_insert_ptr(tern_node * head, char const * key, void * value);
52+tern_node * tern_insert_node(tern_node *head, char const *key, tern_node *value);
53+tern_node *tern_insert_path(tern_node *head, char const *key, tern_val val, uint8_t valtype);
54+uint32_t tern_count(tern_node *head);
55+void tern_foreach(tern_node *head, iter_fun fun, void *data);
56+char * tern_int_key(uint32_t key, char * buf);
57+void tern_free(tern_node *head);
58+
59+#endif //TERN_H_
A
test.c
+76,
-0
1@@ -0,0 +1,76 @@
2+#include <stdint.h>
3+#include <stdlib.h>
4+#include <string.h>
5+#include <stdio.h>
6+#include "vdp.h"
7+
8+int headless = 1;
9+uint16_t read_dma_value(uint32_t address)
10+{
11+ return 0;
12+}
13+
14+uint32_t render_map_color(uint8_t r, uint8_t g, uint8_t b)
15+{
16+ return 0;
17+}
18+
19+void render_alloc_surfaces(vdp_context * context)
20+{
21+ context->oddbuf = context->framebuf = malloc(512 * 256 * 4 * 2);
22+ memset(context->oddbuf, 0, 512 * 256 * 4 * 2);
23+ context->evenbuf = ((char *)context->oddbuf) + 512 * 256 * 4;
24+}
25+
26+int check_hint_time(vdp_context * v_context)
27+{
28+ uint32_t orig_hint_cycle = vdp_next_hint(v_context);
29+ uint32_t cur_hint_cycle;
30+ printf("hint cycle is %d at vcounter: %d, hslot: %d\n", orig_hint_cycle, v_context->vcounter, v_context->hslot);
31+ int res = 1;
32+ while ((cur_hint_cycle = vdp_next_hint(v_context)) > v_context->cycles)
33+ {
34+ if (cur_hint_cycle != orig_hint_cycle) {
35+ fprintf(stderr, "ERROR: hint cycle changed to %d at vcounter: %d, hslot: %d\n", cur_hint_cycle, v_context->vcounter, v_context->hslot);
36+ orig_hint_cycle = cur_hint_cycle;
37+ res = 0;
38+ }
39+ vdp_run_context(v_context, v_context->cycles + 1);
40+ }
41+ printf("hint fired at cycle: %d, vcounter: %d, hslot: %d\n", cur_hint_cycle, v_context->vcounter, v_context->hslot);
42+ vdp_int_ack(v_context, 4);
43+ return res;
44+}
45+
46+
47+int main(int argc, char ** argv)
48+{
49+ vdp_context v_context;
50+ init_vdp_context(&v_context, 0);
51+ vdp_control_port_write(&v_context, 0x8144);
52+ vdp_control_port_write(&v_context, 0x8C81);
53+ vdp_control_port_write(&v_context, 0x8A7F);
54+ vdp_control_port_write(&v_context, 0x8014);
55+ v_context.hint_counter = 0x7F;
56+ v_context.vcounter = 128;
57+ v_context.hslot = 165;
58+ //check single shot behavior
59+ int res = check_hint_time(&v_context);
60+ //check every line behavior
61+ while (v_context.vcounter < 225)
62+ {
63+ vdp_run_context(&v_context, v_context.cycles + 1);
64+ }
65+ vdp_control_port_write(&v_context, 0x8A00);
66+ int hint_count = 0;
67+ while (res && v_context.vcounter != 224)
68+ {
69+ res = res && check_hint_time(&v_context);
70+ hint_count++;
71+ }
72+ if (res && hint_count != 225) {
73+ fprintf(stderr, "ERROR: hint count should be 225 but was %d instead\n", hint_count);
74+ res = 0;
75+ }
76+ return 0;
77+}
A
test.s68
+123,
-0
1@@ -0,0 +1,123 @@
2+ dc.l $0, start
3+ dc.l start
4+ dc.l start
5+ dc.l start
6+ dc.l start
7+ dc.l start
8+ dc.l start
9+ dc.l start
10+ dc.l start
11+ dc.l start
12+ dc.l start
13+ dc.l start
14+ dc.l start
15+ dc.l start
16+ dc.l start
17+ dc.l start
18+ dc.l start
19+ dc.l start
20+ dc.l start
21+ dc.l start
22+ dc.l start
23+ dc.l start
24+ dc.l start
25+ dc.l after
26+ dc.l after
27+ dc.l after
28+ dc.l after
29+ dc.l after
30+ dc.l after
31+ dc.l after
32+ dc.l after
33+
34+start:
35+ bra after
36+after:
37+ abcd d0, d1
38+ abcd -(a2), -(a3)
39+ add.b #42, d1
40+ add.w d3, d4
41+ add.l d5, (a0)+
42+ addq.w #5, d0
43+ addx d6, d7
44+ addx -(a4), -(a5)
45+ and.w d5, d7
46+ andi.l #5, (a0)+
47+ andi #8, CCR
48+ andi #9, CCR
49+foo:
50+ asl d0, d3
51+ asr #3, d7
52+ bne foo
53+ bchg #5, d0
54+ bclr #7, d0
55+ bset #1, d0
56+ bsr bar
57+ btst #3, d0
58+ chk.w #53, d7
59+ clr d5
60+ cmp d0, d1
61+bar:
62+ dbra d0, bar
63+ divs.w d5, d7
64+ divu.w d3, d4
65+ eor.w d0, d6
66+ eori.l #5, d2
67+ eori #5, ccr
68+ eori #2700, sr
69+ exg d5, d6
70+ ext d2
71+ illegal
72+ jmp (a0)
73+ jsr (a5)
74+ lea (a0, 8), a3
75+ link.w a6, #32
76+ lsl d0, d3
77+ lsr #3, d7
78+ move.b (a0)+, (32, a5)
79+ moveq #5, d0
80+ move #89, ccr
81+ move sr, d0
82+ move #2700, sr
83+ move a5, usp
84+ movem.l d0-d3/a4/a6, -(a7)
85+ movep.w d4, (40, a3)
86+ muls.w d6, d7
87+ mulu.w d2, d4
88+ nbcd -(a2)
89+ neg.l d7
90+ negx.b d5
91+ nop
92+ not.b d3
93+ or.w d5, d7
94+ ori.b #7, d5
95+ ori #5, ccr
96+ ori #2700, sr
97+ pea (24, a3)
98+ reset
99+ rol.l #7, d0
100+ rol.w d5, d0
101+ ror.w d1, d3
102+ roxl.l #7, d0
103+ roxl.w d5, d0
104+ roxr.w d1, d3
105+ rte
106+ rtr
107+ rts
108+ sbcd d0, d1
109+ sbcd -(a2), -(a3)
110+ slt d5
111+ stop #3
112+ sub.b #42, d1
113+ sub.w d3, d4
114+ sub.l d5, (a0)+
115+ subq.w #5, d0
116+ subx d6, d7
117+ subx -(a4), -(a5)
118+ swap d6
119+ tas (a3)
120+ trap #7
121+ trapv
122+ tst.w (a4)+
123+ unlk a6
124+
+29,
-0
1@@ -0,0 +1,29 @@
2+#include <stdio.h>
3+#include "gen_arm.h"
4+
5+typedef int32_t (*fib_fun)(int32_t);
6+
7+int main(int arc, char **argv)
8+{
9+ code_info code;
10+ init_code_info(&code);
11+ uint32_t *fib = code.cur;
12+ subi(&code, r0, r0, 2, SET_COND);
13+ movi_cc(&code, r0, 1, NO_COND, CC_LT);
14+ bx_cc(&code, lr, CC_LT);
15+ pushm(&code, LR | R4);
16+ mov(&code, r4, r0, NO_COND);
17+ bl(&code, fib);
18+ mov(&code, r1, r0, NO_COND);
19+ addi(&code, r0, r4, 1, NO_COND);
20+ mov(&code, r4, r1, NO_COND);
21+ bl(&code, fib);
22+ add(&code, r0, r4, r0, NO_COND);
23+ popm(&code, LR | R4);
24+ bx(&code, lr);
25+
26+ fib_fun fibc = (fib_fun)fib;
27+ printf("fib(10): %d\n", fibc(10));
28+
29+ return 0;
30+}
+101,
-0
1@@ -0,0 +1,101 @@
2+/*
3+ Copyright 2017 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#include <stdio.h>
8+#include "vdp.h"
9+
10+int headless = 1;
11+
12+uint32_t render_map_color(uint8_t r, uint8_t g, uint8_t b)
13+{
14+ return 0;
15+}
16+
17+uint16_t read_dma_value(uint32_t address)
18+{
19+ return 0;
20+}
21+
22+uint32_t *render_get_video_buffer(uint8_t which, int *pitch)
23+{
24+ *pitch = 0;
25+ return NULL;
26+}
27+
28+void render_video_buffer_updated(uint8_t which, int width)
29+{
30+}
31+
32+void warning(char *format, ...)
33+{
34+}
35+
36+
37+int main(int argc, char **argv)
38+{
39+ vdp_context context;
40+ int ret = 0;
41+ init_vdp_context(&context, 0);
42+ vdp_control_port_write(&context, 0x8000 | BIT_PAL_SEL);
43+ vdp_control_port_write(&context, 0x8100 | BIT_DISP_EN | BIT_VINT_EN | BIT_MODE_5);
44+ puts("Testing H32 Mode");
45+ while (!(context.flags2 & FLAG2_VINT_PENDING))
46+ {
47+ vdp_run_context(&context, context.cycles + 1);
48+ }
49+ vdp_int_ack(&context);
50+ uint32_t vint_cycle = vdp_next_vint(&context);
51+ while (!(context.flags2 & FLAG2_VINT_PENDING))
52+ {
53+ vdp_run_context(&context, context.cycles + 1);
54+ uint32_t vint_cycle2 = vdp_next_vint(&context);
55+ if (vint_cycle2 != vint_cycle) {
56+ printf("VINT Cycle changed from %d to %d @ line %d, slot %d\n", vint_cycle, vint_cycle2, context.vcounter, context.hslot);;
57+ ret = 1;
58+ vint_cycle = vint_cycle2;
59+ }
60+ }
61+ vdp_int_ack(&context);
62+ puts("Testing H40 Mode");
63+ vdp_control_port_write(&context, 0x8C81);
64+ while (!(context.flags2 & FLAG2_VINT_PENDING))
65+ {
66+ vdp_run_context(&context, context.cycles + 1);
67+ }
68+ vdp_int_ack(&context);
69+ vint_cycle = vdp_next_vint(&context);
70+ while (!(context.flags2 & FLAG2_VINT_PENDING))
71+ {
72+ vdp_run_context(&context, context.cycles + 1);
73+ uint32_t vint_cycle2 = vdp_next_vint(&context);
74+ if (vint_cycle2 != vint_cycle) {
75+ printf("VINT Cycle changed from %d to %d @ line %d, slot %d\n", vint_cycle, vint_cycle2, context.vcounter, context.hslot);;
76+ ret = 1;
77+ vint_cycle = vint_cycle2;
78+ }
79+ }
80+ vdp_int_ack(&context);
81+ puts("Testing Mode 4");
82+ vdp_control_port_write(&context, 0x8C00);
83+ vdp_control_port_write(&context, 0x8100 | BIT_DISP_EN | BIT_VINT_EN);
84+ while (!(context.flags2 & FLAG2_VINT_PENDING))
85+ {
86+ vdp_run_context(&context, context.cycles + 1);
87+ }
88+ context.flags2 &= ~FLAG2_VINT_PENDING;
89+ vint_cycle = vdp_next_vint(&context);
90+ while (!(context.flags2 & FLAG2_VINT_PENDING))
91+ {
92+ vdp_run_context(&context, context.cycles + 1);
93+ uint32_t vint_cycle2 = vdp_next_vint(&context);
94+ if (vint_cycle2 != vint_cycle) {
95+ printf("VINT Cycle changed from %d to %d @ line %d, slot %d\n", vint_cycle, vint_cycle2, context.vcounter, context.hslot);;
96+ ret = 1;
97+ vint_cycle = vint_cycle2;
98+ }
99+ }
100+ printf("Result: %s\n", ret ? "failure" : "success");
101+ return ret;
102+}
+48,
-0
1@@ -0,0 +1,48 @@
2+/*
3+ Copyright 2013 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#include "gen_x86.h"
8+#include "m68k_core.h"
9+#include <stdio.h>
10+#include <stddef.h>
11+
12+int main(int argc, char ** argv)
13+{
14+ uint8_t foo[512];
15+ uint8_t *cur = foo, *end;
16+ cur = mov_rr(cur, RAX, RBX, SZ_B);
17+ cur = mov_rr(cur, RCX, RDX, SZ_B);
18+ cur = mov_rr(cur, R8, R9, SZ_B);
19+ cur = mov_rr(cur, R8, RAX, SZ_B);
20+ cur = mov_rr(cur, RAX, RBX, SZ_W);
21+ cur = mov_rr(cur, R11, R12, SZ_W);
22+ cur = mov_rr(cur, RAX, RBX, SZ_D);
23+ cur = mov_rr(cur, RAX, RBX, SZ_Q);
24+ cur = mov_ir(cur, 5, RAX, SZ_D);
25+ cur = mov_ir(cur, 3, R8, SZ_D);
26+ cur = mov_ir(cur, 4, RSP, SZ_B);
27+ cur = add_rr(cur, RAX, RBX, SZ_D);
28+ cur = add_ir(cur, 5, RAX, SZ_B);
29+ cur = add_ir(cur, 5, RBX, SZ_B);
30+ cur = add_ir(cur, 5, RBP, SZ_B);
31+ cur = pushf(cur);
32+ cur = popf(cur);
33+ cur = setcc_r(cur, CC_S, RBX);
34+ cur = setcc_r(cur, CC_Z, RDX);
35+ cur = setcc_r(cur, CC_O, BH);
36+ cur = setcc_r(cur, CC_C, DH);
37+ cur = setcc_rind(cur, CC_C, RSI);
38+ cur = mov_rrdisp8(cur, RCX, RSI, offsetof(m68k_context, dregs) + 4 * sizeof(uint32_t), SZ_D);
39+ cur = mov_rdisp8r(cur, RSI, offsetof(m68k_context, dregs) + 5 * sizeof(uint32_t), RCX, SZ_D);
40+ cur = mov_rrind(cur, DH, RSI, SZ_B);
41+ cur = jcc(cur, CC_NZ, -2);
42+ cur = jcc(cur, CC_Z, 0);
43+ cur = jcc(cur, CC_LE, 0x7CA);
44+ for (end = cur, cur = foo; cur != end; cur++) {
45+ printf(" %X", *cur);
46+ }
47+ puts("");
48+ return 0;
49+}
+88,
-0
1@@ -0,0 +1,88 @@
2+Name Sizes Src Modes Dst Modes
3+add bwl d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d
4+add bwl d (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
5+adda wl d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) a
6+addi bwl #n d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
7+addq bwl #(1-8) d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
8+addx bwl d d
9+addx bwl -(a) -(a)
10+and bwl d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d
11+and bwl d (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
12+andi bwl #n d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
13+asl bwl d;#(1-8) d
14+asr bwl d;#(1-8) d
15+lsl bwl d;#(1-8) d
16+lsr bwl d;#(1-8) d
17+sub bwl d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d
18+sub bwl d (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
19+suba wl d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) a
20+subi bwl #n d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
21+subq bwl #(1-8) d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
22+subx bwl d d
23+subx bwl -(a) -(a)
24+bchg b d;#(0-255) (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
25+bchg l d;#(0-255) d
26+bset b d;#(0-255) (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
27+bset l d;#(0-255) d
28+bclr b d;#(0-255) (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
29+bclr l d;#(0-255) d
30+btst b d;#(0-255) (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
31+btst l d;#(0-255) d
32+rol bwl d;#(1-8) d
33+ror bwl d;#(1-8) d
34+abcd b d d
35+abcd b -(a) -(a)
36+sbcd b d d
37+sbcd b -(a) -(a)
38+muls w d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d
39+mulu w d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d
40+move bwl d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
41+movea wl d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) a
42+moveq l #(-128-127) d
43+roxl bwl d;#(1-8) d
44+roxr bwl d;#(1-8) d
45+divs w d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d
46+divu w d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d
47+chk w d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d
48+cmp bwl d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d
49+cmpa wl d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) a
50+cmpi bwl #n d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
51+cmpm bwl (a)+ (a)+
52+eor bwl d d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
53+eori bwl #n d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
54+exg l d d;a
55+exg l a a
56+link w a #n
57+or bwl d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d
58+or bwl d (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
59+ori bwl #n d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
60+clr bwl d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
61+ext wl d
62+neg bwl d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
63+negx bwl d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
64+not bwl d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
65+pea l (a);(n,a);(n,a,x);(n).w;(n).l;(n,pc);(n,pc,x)
66+rol w (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
67+ror w (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
68+roxl w (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
69+roxr w (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
70+st b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
71+sf b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
72+shi b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
73+sls b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
74+scc b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
75+scs b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
76+sne b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
77+seq b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
78+svc b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
79+svs b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
80+spl b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
81+smi b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
82+sge b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
83+slt b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
84+sgt b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
85+sle b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
86+swap w d
87+tst bwl d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l
88+lea l (a);(n,a);(n,a,x);(n).w;(n).l;(n,pc);(n,pc,x) a
89+
+81,
-0
1@@ -0,0 +1,81 @@
2+/*
3+ Copyright 2013 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#include "gst.h"
8+#include <string.h>
9+#include <stdlib.h>
10+
11+uint8_t busreq;
12+uint8_t reset;
13+
14+void latch_mode(vdp_context * context)
15+{
16+}
17+void ym_data_write(ym2612_context * context, uint8_t value)
18+{
19+ if (context->selected_reg >= YM_REG_END) {
20+ return;
21+ }
22+ if (context->selected_part) {
23+ if (context->selected_reg < YM_PART2_START) {
24+ return;
25+ }
26+ context->part2_regs[context->selected_reg - YM_PART2_START] = value;
27+ } else {
28+ if (context->selected_reg < YM_PART1_START) {
29+ return;
30+ }
31+ context->part1_regs[context->selected_reg - YM_PART1_START] = value;
32+ }
33+}
34+
35+void ym_address_write_part1(ym2612_context * context, uint8_t address)
36+{
37+ //printf("address_write_part1: %X\n", address);
38+ context->selected_reg = address;
39+ context->selected_part = 0;
40+}
41+
42+void ym_address_write_part2(ym2612_context * context, uint8_t address)
43+{
44+ //printf("address_write_part2: %X\n", address);
45+ context->selected_reg = address;
46+ context->selected_part = 1;
47+}
48+
49+uint16_t ram[64*1024];
50+uint8_t zram[8*1024];
51+
52+
53+int main(int argc, char ** argv)
54+{
55+ vdp_context vdp;
56+ ym2612_context ym;
57+ psg_context psg;
58+ m68k_context m68k;
59+ z80_context z80;
60+ genesis_context gen;
61+ if (argc < 3) {
62+ fputs("Usage: testgst infile outfile\n", stderr);
63+ return 1;
64+ }
65+ memset(&gen, 0, sizeof(gen));
66+ memset(&m68k, 0, sizeof(m68k));
67+ memset(&z80, 0, sizeof(z80));
68+ memset(&ym, 0, sizeof(ym));
69+ memset(&vdp, 0, sizeof(vdp));
70+ memset(&psg, 0, sizeof(psg));
71+ m68k.mem_pointers[1] = ram;
72+ z80.mem_pointers[0] = zram;
73+ vdp.vdpmem = malloc(VRAM_SIZE);
74+ gen.vdp = &vdp;
75+ gen.ym = &ym;
76+ gen.psg = &psg;
77+ gen.m68k = &m68k;
78+ gen.z80 = &z80;
79+ uint32_t pc = load_gst(&gen, argv[1]);
80+ save_gst(&gen, argv[2], pc);
81+ return 0;
82+}
+26,
-0
1@@ -0,0 +1,26 @@
2+/*
3+ Copyright 2013 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#include "tern.h"
8+#include <stdio.h>
9+#include <stddef.h>
10+
11+int main(int argc, char ** argv)
12+{
13+ tern_node * tree = tern_insert_ptr(NULL, "foo", "bar");
14+ tree = tern_insert_ptr(tree, "foobar", "baz");
15+ tree = tern_insert_ptr(tree, "goobar", "qux");
16+ tree = tern_insert_int(tree, "foobarbaz", 42);
17+ tree = tern_insert_int(tree, "goobarbaz", 21);
18+ printf("foo: %s\n", (char *)tern_find_ptr(tree, "foo"));
19+ printf("foobar: %s\n", (char *)tern_find_ptr(tree, "foobar"));
20+ printf("goobar: %s\n", (char *)tern_find_ptr(tree, "goobar"));
21+ printf("foob: %s\n", (char *)tern_find_ptr(tree, "foob"));
22+ printf("foobarbaz: %d\n", (int)tern_find_int(tree, "foobarbaz", 0));
23+ printf("goobarbaz: %d\n", (int)tern_find_int(tree, "goobarbaz", 0));
24+ printf("foobarb: %d\n", (int)tern_find_int(tree, "foobarb", 0));
25+ return 0;
26+}
27+
A
todo.txt
+45,
-0
1@@ -0,0 +1,45 @@
2+0.5.0 TODO List
3+----------------
4+Fix DIVU/DIVS timing
5+Implement SSG-EG Mode
6+Implement CSM Mode
7+Provide an option to save SRAM/save states relative to ROM
8+SMS region handling
9+Update README
10+ - New controller mapping stuff
11+ - Overscan
12+ - Full screen toggle
13+ - Aspect ratio control
14+ - Soft Reset
15+Update Changelog
16+SMS Pause NMI
17+
18+0.5.0 Nice to Haves
19+-------------------
20+Basic GG support
21+Horizontal border emulation
22+Integrate Jaguar emulation into main executable
23+Realtec mapper support
24+64-bit Windows Build
25+
26+Future Releases (no particular order)
27+---------------
28+MegaWIFI
29+32X
30+Sega CD
31+Full SMS/GG VDP emulation
32+Improve internal CPU debugger
33+Allow "debug windows" so VDP debug output can be viewed simultaneously with normal output
34+YM2413 emulation
35+Laser Active
36+Finish Jaguar emulation
37+Multitap
38+Light Guns
39+XE-1 AP
40+Cheat Codes
41+Controller Mapping UI
42+SVP emulation
43+Rewind
44+Netplay
45+Rewrite CPUs with dynarec DSL
46+ARM support
A
trans.c
+84,
-0
1@@ -0,0 +1,84 @@
2+/*
3+ Copyright 2013 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#include "68kinst.h"
8+#include "m68k_core.h"
9+#include "mem.h"
10+#include <stdio.h>
11+#include <stdlib.h>
12+#include <string.h>
13+
14+int headless = 1;
15+void render_errorbox(char * title, char * buf)
16+{
17+}
18+
19+void render_infobox(char * title, char * buf)
20+{
21+}
22+
23+m68k_context * sync_components(m68k_context * context, uint32_t address)
24+{
25+ if (context->current_cycle > 0x80000000) {
26+ context->current_cycle -= 0x80000000;
27+ }
28+ if (context->status & M68K_STATUS_TRACE || context->trace_pending) {
29+ context->target_cycle = context->current_cycle;
30+ }
31+ return context;
32+}
33+
34+m68k_context *reset_handler(m68k_context *context)
35+{
36+ m68k_print_regs(context);
37+ exit(0);
38+ //unreachable
39+ return context;
40+}
41+
42+int main(int argc, char ** argv)
43+{
44+ long filesize;
45+ unsigned short *filebuf;
46+ char disbuf[1024];
47+ unsigned short * cur;
48+ m68k_options opts;
49+ FILE * f = fopen(argv[1], "rb");
50+ fseek(f, 0, SEEK_END);
51+ filesize = ftell(f);
52+ fseek(f, 0, SEEK_SET);
53+ filebuf = malloc(0x400000);
54+ memset(filebuf, 0, 0x400000);
55+ fread(filebuf, 2, filesize/2 > 0x200000 ? 0x200000 : filesize/2, f);
56+ fclose(f);
57+ for(cur = filebuf; cur - filebuf < (filesize/2); ++cur)
58+ {
59+ *cur = (*cur >> 8) | (*cur << 8);
60+ }
61+ memmap_chunk memmap[2];
62+ memset(memmap, 0, sizeof(memmap_chunk)*2);
63+ memmap[0].end = 0x400000;
64+ memmap[0].mask = 0xFFFFFF;
65+ memmap[0].flags = MMAP_READ;
66+ memmap[0].buffer = filebuf;
67+
68+ memmap[1].start = 0xE00000;
69+ memmap[1].end = 0x1000000;
70+ memmap[1].mask = 0xFFFF;
71+ memmap[1].flags = MMAP_READ | MMAP_WRITE | MMAP_CODE;
72+ memmap[1].buffer = malloc(64 * 1024);
73+ memset(memmap[1].buffer, 0, 64 * 1024);
74+ init_m68k_opts(&opts, memmap, 2, 1);
75+ m68k_context * context = init_68k_context(&opts, reset_handler);
76+ context->mem_pointers[0] = memmap[0].buffer;
77+ context->mem_pointers[1] = memmap[1].buffer;
78+ context->target_cycle = context->sync_cycle = 0x80000000;
79+ uint32_t address;
80+ address = filebuf[2] << 16 | filebuf[3];
81+ translate_m68k_stream(address, context);
82+ m68k_reset(context);
83+ return 0;
84+}
85+
A
util.c
+748,
-0
1@@ -0,0 +1,748 @@
2+#include <string.h>
3+#include <stdlib.h>
4+#include <stdio.h>
5+#include <ctype.h>
6+#include <stdint.h>
7+#include <stdarg.h>
8+
9+#include <sys/types.h>
10+#include <sys/stat.h>
11+#include <unistd.h>
12+#include <errno.h>
13+
14+#define info_puts(msg) fputs(msg, stdout);
15+#define warning_puts(msg) fputs(msg, stderr);
16+#define fatal_puts(msg) fputs(msg, stderr);
17+
18+#define info_printf(msg, args) vprintf(msg, args)
19+#define warning_printf(msg, args) vfprintf(stderr, msg, args)
20+#define fatal_printf(msg, args) vfprintf(stderr, msg, args)
21+#include "blastem.h" //for headless global
22+#include "render.h" //for render_errorbox
23+#include "util.h"
24+
25+char * alloc_concat(char const * first, char const * second)
26+{
27+ int flen = strlen(first);
28+ int slen = strlen(second);
29+ char * ret = malloc(flen + slen + 1);
30+ memcpy(ret, first, flen);
31+ memcpy(ret+flen, second, slen+1);
32+ return ret;
33+}
34+
35+char * alloc_concat_m(int num_parts, char const ** parts)
36+{
37+ int total = 0;
38+ for (int i = 0; i < num_parts; i++) {
39+ total += strlen(parts[i]);
40+ }
41+ char * ret = malloc(total + 1);
42+ *ret = 0;
43+ for (int i = 0; i < num_parts; i++) {
44+ strcat(ret, parts[i]);
45+ }
46+ return ret;
47+}
48+
49+typedef struct {
50+ uint32_t start;
51+ uint32_t end;
52+ char *value;
53+} var_pos;
54+
55+char *replace_vars(char *base, tern_node *vars, uint8_t allow_env)
56+{
57+ uint32_t num_vars = 0;
58+ for (char *cur = base; *cur; ++cur)
59+ {
60+ //TODO: Support escaping $ and allow brace syntax
61+ if (*cur == '$') {
62+ num_vars++;
63+ }
64+ }
65+ var_pos *positions = calloc(num_vars, sizeof(var_pos));
66+ num_vars = 0;
67+ uint8_t in_var = 0;
68+ uint32_t max_var_len = 0;
69+ for (char *cur = base; *cur; ++cur)
70+ {
71+ if (in_var) {
72+ if (!(*cur == '_' || isalnum(*cur))) {
73+ positions[num_vars].end = cur-base;
74+ if (positions[num_vars].end - positions[num_vars].start > max_var_len) {
75+ max_var_len = positions[num_vars].end - positions[num_vars].start;
76+ }
77+ num_vars++;
78+ in_var = 0;
79+ }
80+ } else if (*cur == '$') {
81+ positions[num_vars].start = cur-base+1;
82+ in_var = 1;
83+ }
84+ }
85+ if (in_var) {
86+ positions[num_vars].end = strlen(base);
87+ if (positions[num_vars].end - positions[num_vars].start > max_var_len) {
88+ max_var_len = positions[num_vars].end - positions[num_vars].start;
89+ }
90+ num_vars++;
91+ }
92+ char *varname = malloc(max_var_len+1);
93+ uint32_t total_len = 0;
94+ uint32_t cur = 0;
95+ for (uint32_t i = 0; i < num_vars; i++)
96+ {
97+ total_len += (positions[i].start - 1) - cur;
98+ cur = positions[i].start;
99+ memcpy(varname, base + positions[i].start, positions[i].end-positions[i].start);
100+ varname[positions[i].end-positions[i].start] = 0;
101+ positions[i].value = tern_find_ptr(vars, varname);
102+ if (!positions[i].value && allow_env) {
103+ positions[i].value = getenv(varname);
104+ }
105+ if (positions[i].value) {
106+ total_len += strlen(positions[i].value);
107+ }
108+ }
109+ total_len += strlen(base+cur);
110+ free(varname);
111+ char *output = malloc(total_len+1);
112+ cur = 0;
113+ char *curout = output;
114+ for (uint32_t i = 0; i < num_vars; i++)
115+ {
116+ if (positions[i].start-1 > cur) {
117+ memcpy(curout, base + cur, (positions[i].start-1) - cur);
118+ curout += (positions[i].start-1) - cur;
119+ }
120+ if (positions[i].value) {
121+ strcpy(curout, positions[i].value);
122+ curout += strlen(curout);
123+ }
124+ cur = positions[i].end;
125+ };
126+ if (base[cur]) {
127+ strcpy(curout, base+cur);
128+ } else {
129+ *curout = 0;
130+ }
131+ free(positions);
132+ return output;
133+}
134+
135+void byteswap_rom(int filesize, uint16_t *cart)
136+{
137+ for(uint16_t *cur = cart; cur - cart < filesize/2; ++cur)
138+ {
139+ *cur = (*cur >> 8) | (*cur << 8);
140+ }
141+}
142+
143+
144+long file_size(FILE * f)
145+{
146+ fseek(f, 0, SEEK_END);
147+ long fsize = ftell(f);
148+ fseek(f, 0, SEEK_SET);
149+ return fsize;
150+}
151+
152+char * strip_ws(char * text)
153+{
154+ while (*text && (!isprint(*text) || isblank(*text)))
155+ {
156+ text++;
157+ }
158+ char * ret = text;
159+ text = ret + strlen(ret) - 1;
160+ while (text > ret && (!isprint(*text) || isblank(*text)))
161+ {
162+ *text = 0;
163+ text--;
164+ }
165+ return ret;
166+}
167+
168+char * split_keyval(char * text)
169+{
170+ while (*text && !isblank(*text))
171+ {
172+ text++;
173+ }
174+ if (!*text) {
175+ return text;
176+ }
177+ *text = 0;
178+ return text+1;
179+}
180+
181+uint8_t startswith(const char *haystack, const char *prefix)
182+{
183+ return !strncmp(haystack, prefix, strlen(prefix));
184+}
185+
186+void bin_to_hex(uint8_t *output, uint8_t *input, uint64_t size)
187+{
188+ while (size)
189+ {
190+ uint8_t digit = *input >> 4;
191+ digit += digit > 9 ? 'a' - 0xa : '0';
192+ *(output++) = digit;
193+ digit = *(input++) & 0xF;
194+ digit += digit > 9 ? 'a' - 0xa : '0';
195+ *(output++) = digit;
196+ size--;
197+ }
198+ *(output++) = 0;
199+}
200+
201+char *utf16be_to_utf8(uint8_t *buf, uint32_t max_size)
202+{
203+ uint8_t *cur = buf;
204+ uint32_t converted_size = 0;
205+ for (uint32_t i = 0; i < max_size; i++, cur+=2)
206+ {
207+ uint16_t code = *cur << 16 | cur[1];
208+ if (!code) {
209+ break;
210+ }
211+ if (code < 0x80) {
212+ converted_size++;
213+ } else if (code < 0x800) {
214+ converted_size += 2;
215+ } else {
216+ //TODO: Deal with surrogate pairs
217+ converted_size += 3;
218+ }
219+ }
220+ char *out = malloc(converted_size + 1);
221+ char *cur_out = out;
222+ cur = buf;
223+ for (uint32_t i = 0; i < max_size; i++, cur+=2)
224+ {
225+ uint16_t code = *cur << 16 | cur[1];
226+ if (!code) {
227+ break;
228+ }
229+ if (code < 0x80) {
230+ *(cur_out++) = code;
231+ } else if (code < 0x800) {
232+ *(cur_out++) = 0xC0 | code >> 6;
233+ *(cur_out++) = 0x80 | (code & 0x3F);
234+ } else {
235+ //TODO: Deal with surrogate pairs
236+ *(cur_out++) = 0xF0 | code >> 12;
237+ *(cur_out++) = 0x80 | (code >> 6 & 0x3F);
238+ *(cur_out++) = 0x80 | (code & 0x3F);
239+ }
240+ }
241+ *cur_out = 0;
242+ return out;
243+}
244+
245+int utf8_codepoint(const char **text)
246+{
247+ uint8_t initial = **text;
248+ (*text)++;
249+ if (initial < 0x80) {
250+ return initial;
251+ }
252+ int base = 0;
253+ uint8_t extended_bytes = 0;
254+ if ((initial & 0xE0) == 0xC0) {
255+ base = 0x80;
256+ initial &= 0x1F;
257+ extended_bytes = 1;
258+ } else if ((initial & 0xF0) == 0xE0) {
259+ base = 0x800;
260+ initial &= 0xF;
261+ extended_bytes = 2;
262+ } else if ((initial & 0xF8) == 0xF0) {
263+ base = 0x10000;
264+ initial &= 0x7;
265+ extended_bytes = 3;
266+ }
267+ int value = initial;
268+ for (uint8_t i = 0; i < extended_bytes; i++)
269+ {
270+ if ((**text & 0xC0) != 0x80) {
271+ return -1;
272+ }
273+ value = value << 6;
274+ value |= (**text) & 0x3F;
275+ (*text)++;
276+ }
277+ return value + base;
278+}
279+
280+char is_path_sep(char c)
281+{
282+ return c == '/';
283+}
284+
285+char is_absolute_path(char *path)
286+{
287+ return is_path_sep(path[0]);
288+}
289+
290+char * basename_no_extension(const char *path)
291+{
292+ const char *lastdot = NULL;
293+ const char *lastslash = NULL;
294+ const char *cur;
295+ for (cur = path; *cur; cur++)
296+ {
297+ if (*cur == '.') {
298+ lastdot = cur;
299+ } else if (is_path_sep(*cur)) {
300+ lastslash = cur + 1;
301+ }
302+ }
303+ if (!lastdot) {
304+ lastdot = cur;
305+ }
306+ if (!lastslash) {
307+ lastslash = path;
308+ }
309+ char *barename = malloc(lastdot-lastslash+1);
310+ memcpy(barename, lastslash, lastdot-lastslash);
311+ barename[lastdot-lastslash] = 0;
312+
313+ return barename;
314+}
315+
316+char *path_extension(char const *path)
317+{
318+ char const *lastdot = NULL;
319+ char const *lastslash = NULL;
320+ char const *cur;
321+ for (cur = path; *cur; cur++)
322+ {
323+ if (*cur == '.') {
324+ lastdot = cur;
325+ } else if (is_path_sep(*cur)) {
326+ lastslash = cur + 1;
327+ }
328+ }
329+ if (!lastdot || (lastslash && lastslash > lastdot)) {
330+ //no extension
331+ return NULL;
332+ }
333+ return strdup(lastdot+1);
334+}
335+
336+uint8_t path_matches_extensions(char *path, char **ext_list, uint32_t num_exts)
337+{
338+ char *ext = path_extension(path);
339+ if (!ext) {
340+ return 0;
341+ }
342+ uint32_t extidx;
343+ for (extidx = 0; extidx < num_exts; extidx++)
344+ {
345+ if (!strcasecmp(ext, ext_list[extidx])) {
346+ free(ext);
347+ return 1;
348+ }
349+ }
350+ free(ext);
351+ return 0;
352+}
353+
354+char * path_dirname(const char *path)
355+{
356+ const char *lastslash = NULL;
357+ const char *cur;
358+ for (cur = path; *cur; cur++)
359+ {
360+ if (is_path_sep(*cur)) {
361+ lastslash = cur;
362+ }
363+ }
364+ if (!lastslash) {
365+ return NULL;
366+ }
367+ char *dir = malloc(lastslash-path+1);
368+ memcpy(dir, path, lastslash-path);
369+ dir[lastslash-path] = 0;
370+
371+ return dir;
372+}
373+
374+uint32_t nearest_pow2(uint32_t val)
375+{
376+ uint32_t ret = 1;
377+ while (ret < val)
378+ {
379+ ret = ret << 1;
380+ }
381+ return ret;
382+}
383+
384+static char * exe_str;
385+
386+void set_exe_str(char * str)
387+{
388+ exe_str = str;
389+}
390+
391+void fatal_error(char *format, ...)
392+{
393+ va_list args;
394+ va_start(args, format);
395+ if (!headless) {
396+ //take a guess at the final size
397+ int32_t size = strlen(format) * 2;
398+ char *buf = malloc(size);
399+ int32_t actual = vsnprintf(buf, size, format, args);
400+ if (actual >= size || actual < 0) {
401+ if (actual < 0) {
402+ //seems on windows, vsnprintf is returning -1 when the buffer is too small
403+ //since we don't know the proper size, a generous multiplier will hopefully suffice
404+ actual = size * 4;
405+ } else {
406+ actual++;
407+ }
408+ free(buf);
409+ buf = malloc(actual);
410+ va_end(args);
411+ va_start(args, format);
412+ vsnprintf(buf, actual, format, args);
413+ }
414+ fatal_puts(buf);
415+ render_errorbox("Fatal Error", buf);
416+ free(buf);
417+ } else {
418+ fatal_printf(format, args);
419+ }
420+ va_end(args);
421+ exit(1);
422+}
423+
424+void warning(char *format, ...)
425+{
426+ va_list args;
427+ va_start(args, format);
428+ if (headless || (isatty(STDERR_FILENO) && isatty(STDIN_FILENO))) {
429+ warning_printf(format, args);
430+ } else {
431+ int32_t size = strlen(format) * 2;
432+ char *buf = malloc(size);
433+ int32_t actual = vsnprintf(buf, size, format, args);
434+ if (actual >= size || actual < 0) {
435+ if (actual < 0) {
436+ //seems on windows, vsnprintf is returning -1 when the buffer is too small
437+ //since we don't know the proper size, a generous multiplier will hopefully suffice
438+ actual = size * 4;
439+ } else {
440+ actual++;
441+ }
442+ free(buf);
443+ buf = malloc(actual);
444+ va_end(args);
445+ va_start(args, format);
446+ vsnprintf(buf, actual, format, args);
447+ }
448+ warning_puts(buf);
449+ render_infobox("BlastEm Info", buf);
450+ free(buf);
451+ }
452+ va_end(args);
453+}
454+
455+static uint8_t output_enabled = 1;
456+void info_message(char *format, ...)
457+{
458+ va_list args;
459+ va_start(args, format);
460+ if (headless || (isatty(STDOUT_FILENO) && isatty(STDIN_FILENO))) {
461+ if (output_enabled) {
462+ info_printf(format, args);
463+ }
464+ } else {
465+ int32_t size = strlen(format) * 2;
466+ char *buf = malloc(size);
467+ int32_t actual = vsnprintf(buf, size, format, args);
468+ if (actual >= size || actual < 0) {
469+ if (actual < 0) {
470+ //seems on windows, vsnprintf is returning -1 when the buffer is too small
471+ //since we don't know the proper size, a generous multiplier will hopefully suffice
472+ actual = size * 4;
473+ } else {
474+ actual++;
475+ }
476+ free(buf);
477+ buf = malloc(actual);
478+ va_end(args);
479+ va_start(args, format);
480+ vsnprintf(buf, actual, format, args);
481+ }
482+ if (output_enabled) {
483+ info_puts(buf);
484+ }
485+ render_infobox("BlastEm Info", buf);
486+ free(buf);
487+ }
488+ va_end(args);
489+}
490+
491+void debug_message(char *format, ...)
492+{
493+ va_list args;
494+ va_start(args, format);
495+ if (output_enabled) {
496+ info_printf(format, args);
497+ }
498+}
499+
500+void disable_stdout_messages(void)
501+{
502+ output_enabled = 0;
503+}
504+
505+char * get_home_dir()
506+{
507+ return getenv("HOME");
508+}
509+
510+char * readlink_alloc(char * path)
511+{
512+ char * linktext = NULL;
513+ ssize_t linksize = 512;
514+ ssize_t cursize = 0;
515+ do {
516+ if (linksize > cursize) {
517+ cursize = linksize;
518+ if (linktext) {
519+ free(linktext);
520+ }
521+ }
522+ linktext = malloc(cursize);
523+ linksize = readlink(path, linktext, cursize-1);
524+ if (linksize == -1) {
525+ perror("readlink");
526+ free(linktext);
527+ return NULL;
528+ }
529+ } while ((linksize+1) > cursize);
530+ linktext[linksize] = 0;
531+ return linktext;
532+}
533+
534+char * get_exe_dir()
535+{
536+ static char * exe_dir;
537+ if (!exe_dir) {
538+ char * cur;
539+ char * linktext = readlink_alloc("/proc/self/exe");
540+ if (!linktext) {
541+ goto fallback;
542+ }
543+ int linksize = strlen(linktext);
544+ for(cur = linktext + linksize - 1; cur != linktext; cur--)
545+ {
546+ if (is_path_sep(*cur)) {
547+ *cur = 0;
548+ break;
549+ }
550+ }
551+ if (cur == linktext) {
552+ free(linktext);
553+fallback:
554+ if (!exe_str) {
555+ fputs("/proc/self/exe is not available and set_exe_str was not called!", stderr);
556+ }
557+ int pathsize = strlen(exe_str);
558+ for(cur = exe_str + pathsize - 1; cur != exe_str; cur--)
559+ {
560+ if (is_path_sep(*cur)) {
561+ exe_dir = malloc(cur-exe_str+1);
562+ memcpy(exe_dir, exe_str, cur-exe_str);
563+ exe_dir[cur-exe_str] = 0;
564+ break;
565+ }
566+ }
567+ } else {
568+ exe_dir = linktext;
569+ }
570+ }
571+ return exe_dir;
572+}
573+#include <dirent.h>
574+
575+dir_entry *get_dir_list(char *path, size_t *numret)
576+{
577+ DIR *d = opendir(path);
578+ if (!d) {
579+ if (numret) {
580+ *numret = 0;
581+ }
582+ return NULL;
583+ }
584+ size_t storage = 64;
585+ dir_entry *ret = malloc(sizeof(dir_entry) * storage);
586+ size_t pos = 0;
587+ struct dirent* entry;
588+ while (entry = readdir(d))
589+ {
590+ if (entry->d_type != DT_REG && entry->d_type != DT_LNK && entry->d_type != DT_DIR) {
591+ continue;
592+ }
593+ if (pos == storage) {
594+ storage = storage * 2;
595+ ret = realloc(ret, sizeof(dir_entry) * storage);
596+ }
597+ ret[pos].name = strdup(entry->d_name);
598+ ret[pos++].is_dir = entry->d_type == DT_DIR;
599+ }
600+ if (numret) {
601+ *numret = pos;
602+ }
603+ closedir(d);
604+ return ret;
605+}
606+
607+time_t get_modification_time(char *path)
608+{
609+ struct stat st;
610+ if (stat(path, &st)) {
611+ return 0;
612+ }
613+#ifdef __APPLE__
614+ return st.st_mtimespec.tv_sec;
615+#else
616+ //Android's Bionic doesn't support the new style so we'll use the old one instead
617+ return st.st_mtime;
618+#endif
619+}
620+
621+int ensure_dir_exists(const char *path)
622+{
623+ struct stat st;
624+ if (stat(path, &st)) {
625+ if (errno == ENOENT) {
626+ char *parent = strdup(path);
627+ char *sep = strrchr(parent, '/');
628+ if (sep && sep != parent) {
629+ *sep = 0;
630+ if (!ensure_dir_exists(parent)) {
631+ free(parent);
632+ return 0;
633+ }
634+ free(parent);
635+ }
636+ return mkdir(path, 0777) == 0;
637+ } else {
638+ char buf[80];
639+ strerror_r(errno, buf, sizeof(buf));
640+ warning("stat failed with error: %s", buf);
641+ return 0;
642+ }
643+ }
644+ return S_ISDIR(st.st_mode);
645+}
646+
647+
648+void free_dir_list(dir_entry *list, size_t numentries)
649+{
650+ for (size_t i = 0; i < numentries; i++)
651+ {
652+ free(list[i].name);
653+ }
654+ free(list);
655+}
656+
657+static int sort_dir_alpha(const void *a, const void *b)
658+{
659+ const dir_entry *da, *db;
660+ da = a;
661+ db = b;
662+ if (da->is_dir != db->is_dir) {
663+ return db->is_dir - da->is_dir;
664+ }
665+ return strcasecmp(((dir_entry *)a)->name, ((dir_entry *)b)->name);
666+}
667+
668+void sort_dir_list(dir_entry *list, size_t num_entries)
669+{
670+ qsort(list, num_entries, sizeof(dir_entry), sort_dir_alpha);
671+}
672+
673+char *read_bundled_file(char *name, uint32_t *sizeret)
674+{
675+#ifdef DATA_PATH
676+ char *data_dir = DATA_PATH;
677+#else
678+ char *data_dir = get_exe_dir();
679+ if (!data_dir) {
680+ if (sizeret) {
681+ *sizeret = -1;
682+ }
683+ return NULL;
684+ }
685+ char const *pieces[] = {data_dir, PATH_SEP, name};
686+ char *path = alloc_concat_m(3, pieces);
687+ FILE *f = fopen(path, "rb");
688+ free(path);
689+ if (!f) {
690+ if (sizeret) {
691+ *sizeret = -1;
692+ }
693+ return NULL;
694+ }
695+
696+ long fsize = file_size(f);
697+ if (sizeret) {
698+ *sizeret = fsize;
699+ }
700+ char *ret;
701+ if (fsize) {
702+ //reserve an extra byte in case caller wants
703+ //to null terminate the data
704+ ret = malloc(fsize+1);
705+ if (fread(ret, 1, fsize, f) != fsize) {
706+ free(ret);
707+ ret = NULL;
708+ }
709+ } else {
710+ ret = NULL;
711+ }
712+ fclose(f);
713+ return ret;
714+}
715+
716+
717+
718+#define CONFIG_PREFIX "/.config"
719+#define USERDATA_SUFFIX "/.local/share"
720+
721+char const *get_config_dir()
722+{
723+ static char* confdir;
724+ if (!confdir) {
725+ char const *base = get_home_dir();
726+ if (base) {
727+ confdir = alloc_concat(base, CONFIG_PREFIX PATH_SEP "blastem");
728+ }
729+ }
730+ return confdir;
731+}
732+
733+char const *get_userdata_dir()
734+{
735+ static char* savedir;
736+ if (!savedir) {
737+ char const *base = get_home_dir();
738+ if (base) {
739+ savedir = alloc_concat(base, USERDATA_SUFFIX);
740+ }
741+ }
742+ return savedir;
743+}
744+
745+
746+
747+
748+
749+#endif
A
util.h
+88,
-0
1@@ -0,0 +1,88 @@
2+#ifndef UTIL_H_
3+#define UTIL_H_
4+
5+#include <stdio.h>
6+#include <time.h>
7+#include "tern.h"
8+
9+typedef struct {
10+ char *name;
11+ uint8_t is_dir;
12+} dir_entry;
13+
14+#define PATH_SEP "/"
15+
16+//Utility functions
17+
18+//Allocates a new string containing the concatenation of first and second
19+char * alloc_concat(char const * first, char const * second);
20+//Allocates a new string containing the concatenation of the strings pointed to by parts
21+char * alloc_concat_m(int num_parts, char const ** parts);
22+//Returns a newly allocated string in which all variables in based are replaced with values from vars or the environment
23+char *replace_vars(char *base, tern_node *vars, uint8_t allow_env);
24+//Byteswaps a ROM image in memory
25+void byteswap_rom(int filesize, uint16_t *cart);
26+//Returns the size of a file using fseek and ftell
27+long file_size(FILE * f);
28+//Strips whitespace and non-printable characters from the beginning and end of a string
29+char * strip_ws(char * text);
30+//Inserts a null after the first word, returns a pointer to the second word
31+char * split_keyval(char * text);
32+//Checks if haystack starts with prefix
33+uint8_t startswith(const char *haystack, const char *prefix);
34+//Takes a binary byte buffer and produces a lowercase hex string
35+void bin_to_hex(uint8_t *output, uint8_t *input, uint64_t size);
36+//Takes an (optionally) null-terminated UTF16-BE string and converts a maximum of max_size code-units to UTF-8
37+char *utf16be_to_utf8(uint8_t *buf, uint32_t max_size);
38+//Returns the next Unicode codepoint from a utf-8 string
39+int utf8_codepoint(const char **text);
40+//Determines whether a character is a valid path separator for the current platform
41+char is_path_sep(char c);
42+//Determines whether a path is considered an absolute path on the current platform
43+char is_absolute_path(char *path);
44+//Returns the basename of a path with th extension (if any) stripped
45+char * basename_no_extension(const char *path);
46+//Returns the extension from a path or NULL if there is no extension
47+char *path_extension(char const *path);
48+//Returns true if the given path matches one of the extensions in the list
49+uint8_t path_matches_extensions(char *path, char **ext_list, uint32_t num_exts);
50+//Returns the directory portion of a path or NULL if there is no directory part
51+char *path_dirname(const char *path);
52+//Gets the smallest power of two that is >= a certain value, won't work for values > 0x80000000
53+uint32_t nearest_pow2(uint32_t val);
54+//Should be called by main with the value of argv[0] for use by get_exe_dir
55+void set_exe_str(char * str);
56+//Returns the directory the executable is in
57+char * get_exe_dir();
58+//Returns the user's home directory
59+char * get_home_dir();
60+//Returns an appropriate path for storing config files
61+char const *get_config_dir();
62+//Returns an appropriate path for saving non-config data like savestates
63+char const *get_userdata_dir();
64+//Reads a file bundled with the executable
65+char *read_bundled_file(char *name, uint32_t *sizeret);
66+//Retunrs an array of normal files and directories residing in a directory
67+dir_entry *get_dir_list(char *path, size_t *numret);
68+//Frees a dir list returned by get_dir_list
69+void free_dir_list(dir_entry *list, size_t numentries);
70+//Performs a case-insensitive sort by file name on a dir list
71+void sort_dir_list(dir_entry *list, size_t num_entries);
72+//Gets the modification time of a file
73+time_t get_modification_time(char *path);
74+//Recusrively creates a directory if it does not exist
75+int ensure_dir_exists(const char *path);
76+//Returns the contents of a symlink in a newly allocated string
77+char * readlink_alloc(char * path);
78+//Prints an error message to stderr and to a message box if not in headless mode and then exits
79+void fatal_error(char *format, ...);
80+//Prints an information message to stdout and to a message box if not in headless mode and not attached to a console
81+void info_message(char *format, ...);
82+//Prints an information message to stderr and to a message box if not in headless mode and not attached to a console
83+void warning(char *format, ...);
84+//Prints a debug message to stdout
85+void debug_message(char *format, ...);
86+//Disables output of info and debug messages to stdout
87+void disable_stdout_messages(void);
88+
89+#endif //UTIL_H_
A
vdp.c
+4159,
-0
1@@ -0,0 +1,4159 @@
2+/*
3+ Copyright 2013 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#include "vdp.h"
8+#include "blastem.h"
9+#include <stdlib.h>
10+#include <string.h>
11+#include "render.h"
12+#include "util.h"
13+
14+#define NTSC_INACTIVE_START 224
15+#define PAL_INACTIVE_START 240
16+#define MODE4_INACTIVE_START 192
17+#define BUF_BIT_PRIORITY 0x40
18+#define MAP_BIT_PRIORITY 0x8000
19+#define MAP_BIT_H_FLIP 0x800
20+#define MAP_BIT_V_FLIP 0x1000
21+
22+#define SCROLL_BUFFER_MASK (SCROLL_BUFFER_SIZE-1)
23+#define SCROLL_BUFFER_DRAW (SCROLL_BUFFER_SIZE/2)
24+
25+#define MCLKS_SLOT_H40 16
26+#define MCLKS_SLOT_H32 20
27+#define VINT_SLOT_H40 0 //21 slots before HSYNC, 16 during, 10 after
28+#define VINT_SLOT_H32 0 //old value was 23, but recent tests suggest the actual value is close to the H40 one
29+#define VINT_SLOT_MODE4 4
30+#define HSYNC_SLOT_H40 230
31+#define HSYNC_END_H40 (HSYNC_SLOT_H40+17)
32+#define HBLANK_START_H40 178 //should be 179 according to Nemesis, but 178 seems to fit slightly better with my test ROM results
33+#define HBLANK_END_H40 0 //should be 5.5 according to Nemesis, but 0 seems to fit better with my test ROM results
34+#define HBLANK_START_H32 233 //should be 147 according to Nemesis which is very different from my test ROM result
35+#define HBLANK_END_H32 0 //should be 5 according to Nemesis, but 0 seems to fit better with my test ROM results
36+#define LINE_CHANGE_H40 165
37+#define LINE_CHANGE_H32 133
38+#define LINE_CHANGE_MODE4 249
39+#define VBLANK_START_H40 (LINE_CHANGE_H40+2)
40+#define VBLANK_START_H32 (LINE_CHANGE_H32+2)
41+#define FIFO_LATENCY 3
42+
43+#define BORDER_TOP_V24 27
44+#define BORDER_TOP_V28 11
45+#define BORDER_TOP_V24_PAL 54
46+#define BORDER_TOP_V28_PAL 38
47+#define BORDER_TOP_V30_PAL 30
48+
49+#define BORDER_BOT_V24 24
50+#define BORDER_BOT_V28 8
51+#define BORDER_BOT_V24_PAL 48
52+#define BORDER_BOT_V28_PAL 32
53+#define BORDER_BOT_V30_PAL 24
54+
55+#define INVALID_LINE (PAL_INACTIVE_START+BORDER_TOP_V30_PAL+BORDER_BOT_V30_PAL)
56+
57+enum {
58+ INACTIVE = 0,
59+ PREPARING, //used for line 0x1FF
60+ ACTIVE
61+};
62+
63+static int32_t color_map[1 << 12];
64+static uint16_t mode4_address_map[0x4000];
65+static uint32_t planar_to_chunky[256];
66+static uint8_t levels[] = {0, 27, 49, 71, 87, 103, 119, 130, 146, 157, 174, 190, 206, 228, 255};
67+
68+static uint8_t debug_base[][3] = {
69+ {127, 127, 127}, //BG
70+ {0, 0, 127}, //A
71+ {127, 0, 0}, //Window
72+ {0, 127, 0}, //B
73+ {127, 0, 127} //Sprites
74+};
75+
76+static void update_video_params(vdp_context *context)
77+{
78+ if (context->regs[REG_MODE_2] & BIT_MODE_5) {
79+ if (context->regs[REG_MODE_2] & BIT_PAL) {
80+ if (context->flags2 & FLAG2_REGION_PAL) {
81+ context->inactive_start = PAL_INACTIVE_START;
82+ context->border_top = BORDER_TOP_V30_PAL;
83+ context->border_bot = BORDER_BOT_V30_PAL;
84+ } else {
85+ //the behavior here is rather weird and needs more investigation
86+ context->inactive_start = 0xF0;
87+ context->border_top = 1;
88+ context->border_bot = 3;
89+ }
90+ } else {
91+ context->inactive_start = NTSC_INACTIVE_START;
92+ if (context->flags2 & FLAG2_REGION_PAL) {
93+ context->border_top = BORDER_TOP_V28_PAL;
94+ context->border_bot = BORDER_BOT_V28_PAL;
95+ } else {
96+ context->border_top = BORDER_TOP_V28;
97+ context->border_bot = BORDER_TOP_V28;
98+ }
99+ }
100+ if (context->regs[REG_MODE_4] & BIT_H40) {
101+ context->max_sprites_frame = MAX_SPRITES_FRAME;
102+ context->max_sprites_line = MAX_SPRITES_LINE;
103+ } else {
104+ context->max_sprites_frame = MAX_SPRITES_FRAME_H32;
105+ context->max_sprites_line = MAX_SPRITES_LINE_H32;
106+ }
107+ if (context->state == INACTIVE) {
108+ //Undo forced INACTIVE state due to neither Mode 4 nor Mode 5 being active
109+ if (context->vcounter < context->inactive_start) {
110+ context->state = ACTIVE;
111+ } else if (context->vcounter == 0x1FF) {
112+ context->state = PREPARING;
113+ }
114+ }
115+ } else {
116+ context->inactive_start = MODE4_INACTIVE_START;
117+ if (context->flags2 & FLAG2_REGION_PAL) {
118+ context->border_top = BORDER_TOP_V24_PAL;
119+ context->border_bot = BORDER_BOT_V24_PAL;
120+ } else {
121+ context->border_top = BORDER_TOP_V24;
122+ context->border_bot = BORDER_BOT_V24;
123+ }
124+ if (!(context->regs[REG_MODE_1] & BIT_MODE_4)){
125+ context->state = INACTIVE;
126+ } else if (context->state == INACTIVE) {
127+ //Undo forced INACTIVE state due to neither Mode 4 nor Mode 5 being active
128+ if (context->vcounter < context->inactive_start) {
129+ context->state = ACTIVE;
130+ }
131+ else if (context->vcounter == 0x1FF) {
132+ context->state = PREPARING;
133+ }
134+ }
135+ }
136+}
137+
138+static uint8_t color_map_init_done;
139+
140+vdp_context *init_vdp_context(uint8_t region_pal)
141+{
142+ vdp_context *context = calloc(1, sizeof(vdp_context) + VRAM_SIZE);
143+ if (headless) {
144+ context->output = malloc(LINEBUF_SIZE * sizeof(uint32_t));
145+ context->output_pitch = 0;
146+ } else {
147+ context->cur_buffer = VIDEO_BUFFER_ODD;
148+ context->fb = render_get_video_buffer(VIDEO_BUFFER_ODD, &context->output_pitch);
149+ }
150+ context->sprite_draws = MAX_DRAWS;
151+ context->fifo_write = 0;
152+ context->fifo_read = -1;
153+ context->regs[REG_HINT] = context->hint_counter = 0xFF;
154+
155+ if (!color_map_init_done) {
156+ uint8_t b,g,r;
157+ for (uint16_t color = 0; color < (1 << 12); color++) {
158+ if (color & FBUF_SHADOW) {
159+ b = levels[(color >> 9) & 0x7];
160+ g = levels[(color >> 5) & 0x7];
161+ r = levels[(color >> 1) & 0x7];
162+ } else if(color & FBUF_HILIGHT) {
163+ b = levels[((color >> 9) & 0x7) + 7];
164+ g = levels[((color >> 5) & 0x7) + 7];
165+ r = levels[((color >> 1) & 0x7) + 7];
166+ } else if(color & FBUF_MODE4) {
167+ b = levels[(color >> 4 & 0xC) | (color >> 6 & 0x2)];
168+ g = levels[(color >> 2 & 0x8) | (color >> 1 & 0x4) | (color >> 4 & 0x2)];
169+ r = levels[(color << 1 & 0xC) | (color >> 1 & 0x2)];
170+ } else {
171+ b = levels[(color >> 8) & 0xE];
172+ g = levels[(color >> 4) & 0xE];
173+ r = levels[color & 0xE];
174+ }
175+ color_map[color] = render_map_color(r, g, b);
176+ }
177+ for (uint16_t mode4_addr = 0; mode4_addr < 0x4000; mode4_addr++)
178+ {
179+ uint16_t mode5_addr = mode4_addr & 0x3DFD;
180+ mode5_addr |= mode4_addr << 8 & 0x200;
181+ mode5_addr |= mode4_addr >> 8 & 2;
182+ mode4_address_map[mode4_addr] = mode5_addr;
183+ }
184+ for (uint32_t planar = 0; planar < 256; planar++)
185+ {
186+ uint32_t chunky = 0;
187+ for (int bit = 7; bit >= 0; bit--)
188+ {
189+ chunky = chunky << 4;
190+ chunky |= planar >> bit & 1;
191+ }
192+ planar_to_chunky[planar] = chunky;
193+ }
194+ color_map_init_done = 1;
195+ }
196+ for (uint8_t color = 0; color < (1 << (3 + 1 + 1 + 1)); color++)
197+ {
198+ uint8_t src = color & DBG_SRC_MASK;
199+ if (src > DBG_SRC_S) {
200+ context->debugcolors[color] = 0;
201+ } else {
202+ uint8_t r,g,b;
203+ b = debug_base[src][0];
204+ g = debug_base[src][1];
205+ r = debug_base[src][2];
206+ if (color & DBG_PRIORITY)
207+ {
208+ if (b) {
209+ b += 48;
210+ }
211+ if (g) {
212+ g += 48;
213+ }
214+ if (r) {
215+ r += 48;
216+ }
217+ }
218+ if (color & DBG_SHADOW) {
219+ b /= 2;
220+ g /= 2;
221+ r /=2 ;
222+ }
223+ if (color & DBG_HILIGHT) {
224+ if (b) {
225+ b += 72;
226+ }
227+ if (g) {
228+ g += 72;
229+ }
230+ if (r) {
231+ r += 72;
232+ }
233+ }
234+ context->debugcolors[color] = render_map_color(r, g, b);
235+ }
236+ }
237+ if (region_pal) {
238+ context->flags2 |= FLAG2_REGION_PAL;
239+ }
240+ update_video_params(context);
241+ if (!headless) {
242+ context->output = (uint32_t *)(((char *)context->fb) + context->output_pitch * context->border_top);
243+ }
244+ return context;
245+}
246+
247+void vdp_free(vdp_context *context)
248+{
249+ free(context);
250+}
251+
252+static int is_refresh(vdp_context * context, uint32_t slot)
253+{
254+ if (context->regs[REG_MODE_4] & BIT_H40) {
255+ return slot == 250 || slot == 26 || slot == 59 || slot == 90 || slot == 122 || slot == 154;
256+ } else {
257+ //TODO: Figure out which slots are refresh when display is off in 32-cell mode
258+ //These numbers are guesses based on H40 numbers
259+ return slot == 243 || slot == 19 || slot == 51 || slot == 83 || slot == 115;
260+ //The numbers below are the refresh slots during active display
261+ //return (slot == 29 || slot == 61 || slot == 93 || slot == 125);
262+ }
263+}
264+
265+static void increment_address(vdp_context *context)
266+{
267+ context->address += context->regs[REG_AUTOINC];
268+ if (!(context->regs[REG_MODE_2] & BIT_MODE_5)) {
269+ context->address++;
270+ }
271+}
272+
273+static void render_sprite_cells(vdp_context * context)
274+{
275+ sprite_draw * d = context->sprite_draw_list + context->cur_slot;
276+ context->serial_address = d->address;
277+ if (context->cur_slot >= context->sprite_draws) {
278+
279+ uint16_t dir;
280+ int16_t x;
281+ if (d->h_flip) {
282+ x = d->x_pos + 7;
283+ dir = -1;
284+ } else {
285+ x = d->x_pos;
286+ dir = 1;
287+ }
288+ //printf("Draw Slot %d of %d, Rendering sprite cell from %X to x: %d\n", context->cur_slot, context->sprite_draws, d->address, x);
289+ context->cur_slot--;
290+ for (uint16_t address = d->address; address != ((d->address+4) & 0xFFFF); address++) {
291+ if (x >= 0 && x < 320) {
292+ if (!(context->linebuf[x] & 0xF)) {
293+ context->linebuf[x] = (context->vdpmem[address] >> 4) | d->pal_priority;
294+ } else if (context->vdpmem[address] >> 4) {
295+ context->flags2 |= FLAG2_SPRITE_COLLIDE;
296+ }
297+ }
298+ x += dir;
299+ if (x >= 0 && x < 320) {
300+ if (!(context->linebuf[x] & 0xF)) {
301+ context->linebuf[x] = (context->vdpmem[address] & 0xF) | d->pal_priority;
302+ } else if (context->vdpmem[address] & 0xF) {
303+ context->flags2 |= FLAG2_SPRITE_COLLIDE;
304+ }
305+ }
306+ x += dir;
307+ }
308+ } else {
309+ context->cur_slot--;
310+ }
311+}
312+
313+static void fetch_sprite_cells_mode4(vdp_context * context)
314+{
315+ if (context->sprite_index >= context->sprite_draws) {
316+ sprite_draw * d = context->sprite_draw_list + context->sprite_index;
317+ uint32_t address = mode4_address_map[d->address & 0x3FFF];
318+ context->fetch_tmp[0] = context->vdpmem[address];
319+ context->fetch_tmp[1] = context->vdpmem[address + 1];
320+ }
321+}
322+
323+static void render_sprite_cells_mode4(vdp_context * context)
324+{
325+ if (context->sprite_index >= context->sprite_draws) {
326+ sprite_draw * d = context->sprite_draw_list + context->sprite_index;
327+ uint32_t pixels = planar_to_chunky[context->fetch_tmp[0]] << 1;
328+ pixels |= planar_to_chunky[context->fetch_tmp[1]];
329+ uint32_t address = mode4_address_map[(d->address + 2) & 0x3FFF];
330+ pixels |= planar_to_chunky[context->vdpmem[address]] << 3;
331+ pixels |= planar_to_chunky[context->vdpmem[address + 1]] << 2;
332+ int x = d->x_pos & 0xFF;
333+ for (int i = 28; i >= 0; i -= 4, x++)
334+ {
335+ if (context->linebuf[x] && (pixels >> i & 0xF)) {
336+ if (
337+ ((context->regs[REG_MODE_1] & BIT_SPRITE_8PX) && x > 8)
338+ || ((!(context->regs[REG_MODE_1] & BIT_SPRITE_8PX)) && x < 256)
339+ ) {
340+ context->flags2 |= FLAG2_SPRITE_COLLIDE;
341+ }
342+ } else {
343+ context->linebuf[x] = pixels >> i & 0xF;
344+ }
345+ }
346+ context->sprite_index--;
347+ }
348+}
349+
350+static uint32_t mode5_sat_address(vdp_context *context)
351+{
352+ uint32_t addr = context->regs[REG_SAT] << 9;
353+ if (!(context->regs[REG_MODE_2] & BIT_128K_VRAM)) {
354+ addr &= 0xFFFF;
355+ }
356+ if (context->regs[REG_MODE_4] & BIT_H40) {
357+ addr &= 0x1FC00;
358+ }
359+ return addr;
360+}
361+
362+void vdp_print_sprite_table(vdp_context * context)
363+{
364+ if (context->regs[REG_MODE_2] & BIT_MODE_5) {
365+ uint16_t sat_address = mode5_sat_address(context);
366+ uint16_t current_index = 0;
367+ uint8_t count = 0;
368+ do {
369+ uint16_t address = current_index * 8 + sat_address;
370+ uint16_t cache_address = current_index * 4;
371+ uint8_t height = ((context->sat_cache[cache_address+2] & 0x3) + 1) * 8;
372+ uint8_t width = (((context->sat_cache[cache_address+2] >> 2) & 0x3) + 1) * 8;
373+ int16_t y = ((context->sat_cache[cache_address] & 0x3) << 8 | context->sat_cache[cache_address+1]) & 0x1FF;
374+ int16_t x = ((context->vdpmem[address+ 6] & 0x3) << 8 | context->vdpmem[address + 7]) & 0x1FF;
375+ uint16_t link = context->sat_cache[cache_address+3] & 0x7F;
376+ uint8_t pal = context->vdpmem[address + 4] >> 5 & 0x3;
377+ uint8_t pri = context->vdpmem[address + 4] >> 7;
378+ uint16_t pattern = ((context->vdpmem[address + 4] << 8 | context->vdpmem[address + 5]) & 0x7FF) << 5;
379+ printf("Sprite %d: X=%d(%d), Y=%d(%d), Width=%u, Height=%u, Link=%u, Pal=%u, Pri=%u, Pat=%X\n", current_index, x, x-128, y, y-128, width, height, link, pal, pri, pattern);
380+ current_index = link;
381+ count++;
382+ } while (current_index != 0 && count < 80);
383+ } else {
384+ uint16_t sat_address = (context->regs[REG_SAT] & 0x7E) << 7;
385+ for (int i = 0; i < 64; i++)
386+ {
387+ uint8_t y = context->vdpmem[mode4_address_map[sat_address + (i ^ 1)]];
388+ if (y == 0xD0) {
389+ break;
390+ }
391+ uint8_t x = context->vdpmem[mode4_address_map[sat_address + 0x80 + i*2 + 1]];
392+ uint16_t tile_address = context->vdpmem[mode4_address_map[sat_address + 0x80 + i*2]] * 32
393+ + (context->regs[REG_STILE_BASE] << 11 & 0x2000);
394+ if (context->regs[REG_MODE_2] & BIT_SPRITE_SZ) {
395+ tile_address &= ~32;
396+ }
397+ printf("Sprite %d: X=%d, Y=%d, Pat=%X\n", i, x, y, tile_address);
398+ }
399+ }
400+}
401+
402+#define VRAM_READ 0 //0000
403+#define VRAM_WRITE 1 //0001
404+//2 would trigger register write 0010
405+#define CRAM_WRITE 3 //0011
406+#define VSRAM_READ 4 //0100
407+#define VSRAM_WRITE 5//0101
408+//6 would trigger regsiter write 0110
409+//7 is a mystery //0111
410+#define CRAM_READ 8 //1000
411+//9 is also a mystery //1001
412+//A would trigger register write 1010
413+//B is a mystery 1011
414+#define VRAM_READ8 0xC //1100
415+//D is a mystery 1101
416+//E would trigger register write 1110
417+//F is a mystery 1111
418+
419+//Possible theory on how bits work
420+//CD0 = Read/Write flag
421+//CD2,(CD1|CD3) = RAM type
422+// 00 = VRAM
423+// 01 = CRAM
424+// 10 = VSRAM
425+// 11 = VRAM8
426+//Would result in
427+// 7 = VRAM8 write
428+// 9 = CRAM write alias
429+// B = CRAM write alias
430+// D = VRAM8 write alias
431+// F = VRAM8 write alais
432+
433+#define DMA_START 0x20
434+
435+static const char * cd_name(uint8_t cd)
436+{
437+ switch (cd & 0xF)
438+ {
439+ case VRAM_READ:
440+ return "VRAM read";
441+ case VRAM_WRITE:
442+ return "VRAM write";
443+ case CRAM_WRITE:
444+ return "CRAM write";
445+ case VSRAM_READ:
446+ return "VSRAM read";
447+ case VSRAM_WRITE:
448+ return "VSRAM write";
449+ case VRAM_READ8:
450+ return "VRAM read (undocumented 8-bit mode)";
451+ default:
452+ return "invalid";
453+ }
454+}
455+
456+void vdp_print_reg_explain(vdp_context * context)
457+{
458+ char * hscroll[] = {"full", "7-line", "cell", "line"};
459+ printf("**Mode Group**\n"
460+ "00: %.2X | H-ints %s, Pal Select %d, HVC latch %s, Display gen %s\n"
461+ "01: %.2X | Display %s, V-ints %s, Height: %d, Mode %d, %dK VRAM\n"
462+ "0B: %.2X | E-ints %s, V-Scroll: %s, H-Scroll: %s\n"
463+ "0C: %.2X | Width: %d, Shadow/Highlight: %s\n",
464+ context->regs[REG_MODE_1], context->regs[REG_MODE_1] & BIT_HINT_EN ? "enabled" : "disabled", (context->regs[REG_MODE_1] & BIT_PAL_SEL) != 0,
465+ context->regs[REG_MODE_1] & BIT_HVC_LATCH ? "enabled" : "disabled", context->regs[REG_MODE_1] & BIT_DISP_DIS ? "disabled" : "enabled",
466+ context->regs[REG_MODE_2], context->regs[REG_MODE_2] & BIT_DISP_EN ? "enabled" : "disabled", context->regs[REG_MODE_2] & BIT_VINT_EN ? "enabled" : "disabled",
467+ context->regs[REG_MODE_2] & BIT_PAL ? 30 : 28, context->regs[REG_MODE_2] & BIT_MODE_5 ? 5 : 4, context->regs[REG_MODE_1] & BIT_128K_VRAM ? 128 : 64,
468+ context->regs[REG_MODE_3], context->regs[REG_MODE_3] & BIT_EINT_EN ? "enabled" : "disabled", context->regs[REG_MODE_3] & BIT_VSCROLL ? "2 cell" : "full",
469+ hscroll[context->regs[REG_MODE_3] & 0x3],
470+ context->regs[REG_MODE_4], context->regs[REG_MODE_4] & BIT_H40 ? 40 : 32, context->regs[REG_MODE_4] & BIT_HILIGHT ? "enabled" : "disabled");
471+ if (context->regs[REG_MODE_2] & BIT_MODE_5) {
472+ printf("\n**Table Group**\n"
473+ "02: %.2X | Scroll A Name Table: $%.4X\n"
474+ "03: %.2X | Window Name Table: $%.4X\n"
475+ "04: %.2X | Scroll B Name Table: $%.4X\n"
476+ "05: %.2X | Sprite Attribute Table: $%.4X\n"
477+ "0D: %.2X | HScroll Data Table: $%.4X\n",
478+ context->regs[REG_SCROLL_A], (context->regs[REG_SCROLL_A] & 0x38) << 10,
479+ context->regs[REG_WINDOW], (context->regs[REG_WINDOW] & (context->regs[REG_MODE_4] & BIT_H40 ? 0x3C : 0x3E)) << 10,
480+ context->regs[REG_SCROLL_B], (context->regs[REG_SCROLL_B] & 0x7) << 13,
481+ context->regs[REG_SAT], mode5_sat_address(context),
482+ context->regs[REG_HSCROLL], (context->regs[REG_HSCROLL] & 0x3F) << 10);
483+ } else {
484+ printf("\n**Table Group**\n"
485+ "02: %.2X | Background Name Table: $%.4X\n"
486+ "05: %.2X | Sprite Attribute Table: $%.4X\n"
487+ "06: %.2X | Sprite Tile Base: $%.4X\n"
488+ "08: %.2X | Background X Scroll: %d\n"
489+ "09: %.2X | Background Y Scroll: %d\n",
490+ context->regs[REG_SCROLL_A], (context->regs[REG_SCROLL_A] & 0xE) << 10,
491+ context->regs[REG_SAT], (context->regs[REG_SAT] & 0x7E) << 7,
492+ context->regs[REG_STILE_BASE], (context->regs[REG_STILE_BASE] & 2) << 11,
493+ context->regs[REG_X_SCROLL], context->regs[REG_X_SCROLL],
494+ context->regs[REG_Y_SCROLL], context->regs[REG_Y_SCROLL]);
495+
496+ }
497+ char * sizes[] = {"32", "64", "invalid", "128"};
498+ printf("\n**Misc Group**\n"
499+ "07: %.2X | Backdrop Color: $%X\n"
500+ "0A: %.2X | H-Int Counter: %u\n"
501+ "0F: %.2X | Auto-increment: $%X\n"
502+ "10: %.2X | Scroll A/B Size: %sx%s\n",
503+ context->regs[REG_BG_COLOR], context->regs[REG_BG_COLOR],
504+ context->regs[REG_HINT], context->regs[REG_HINT],
505+ context->regs[REG_AUTOINC], context->regs[REG_AUTOINC],
506+ context->regs[REG_SCROLL], sizes[context->regs[REG_SCROLL] & 0x3], sizes[context->regs[REG_SCROLL] >> 4 & 0x3]);
507+ char * src_types[] = {"68K", "68K", "Copy", "Fill"};
508+ printf("\n**DMA Group**\n"
509+ "13: %.2X |\n"
510+ "14: %.2X | DMA Length: $%.4X words\n"
511+ "15: %.2X |\n"
512+ "16: %.2X |\n"
513+ "17: %.2X | DMA Source Address: $%.6X, Type: %s\n",
514+ context->regs[REG_DMALEN_L],
515+ context->regs[REG_DMALEN_H], context->regs[REG_DMALEN_H] << 8 | context->regs[REG_DMALEN_L],
516+ context->regs[REG_DMASRC_L],
517+ context->regs[REG_DMASRC_M],
518+ context->regs[REG_DMASRC_H],
519+ context->regs[REG_DMASRC_H] << 17 | context->regs[REG_DMASRC_M] << 9 | context->regs[REG_DMASRC_L] << 1,
520+ src_types[context->regs[REG_DMASRC_H] >> 6 & 3]);
521+ uint8_t old_flags = context->flags;
522+ uint8_t old_flags2 = context->flags2;
523+ printf("\n**Internal Group**\n"
524+ "Address: %X\n"
525+ "CD: %X - %s\n"
526+ "Pending: %s\n"
527+ "VCounter: %d\n"
528+ "HCounter: %d\n"
529+ "VINT Pending: %s\n"
530+ "HINT Pending: %s\n"
531+ "Status: %X\n",
532+ context->address, context->cd, cd_name(context->cd),
533+ (context->flags & FLAG_PENDING) ? "word" : (context->flags2 & FLAG2_BYTE_PENDING) ? "byte" : "none",
534+ context->vcounter, context->hslot*2, (context->flags2 & FLAG2_VINT_PENDING) ? "true" : "false",
535+ (context->flags2 & FLAG2_HINT_PENDING) ? "true" : "false", vdp_control_port_read(context));
536+ //restore flags as calling vdp_control_port_read can change them
537+ context->flags = old_flags;
538+ context->flags2 = old_flags2;
539+}
540+
541+static uint8_t is_active(vdp_context *context)
542+{
543+ return context->state != INACTIVE && (context->regs[REG_MODE_2] & BIT_DISP_EN) != 0;
544+}
545+
546+static void scan_sprite_table(uint32_t line, vdp_context * context)
547+{
548+ if (context->sprite_index && ((uint8_t)context->slot_counter) < context->max_sprites_line) {
549+ line += 1;
550+ uint16_t ymask, ymin;
551+ uint8_t height_mult;
552+ if (context->double_res) {
553+ line *= 2;
554+ if (context->flags2 & FLAG2_EVEN_FIELD) {
555+ line++;
556+ }
557+ ymask = 0x3FF;
558+ ymin = 256;
559+ height_mult = 16;
560+ } else {
561+ ymask = 0x1FF;
562+ ymin = 128;
563+ height_mult = 8;
564+ }
565+ context->sprite_index &= 0x7F;
566+ //TODO: Implement squirelly behavior documented by Kabuto
567+ if (context->sprite_index >= context->max_sprites_frame) {
568+ context->sprite_index = 0;
569+ return;
570+ }
571+ uint16_t address = context->sprite_index * 4;
572+ line += ymin;
573+ line &= ymask;
574+ uint16_t y = ((context->sat_cache[address] & 0x3) << 8 | context->sat_cache[address+1]) & ymask;
575+ uint8_t height = ((context->sat_cache[address+2] & 0x3) + 1) * height_mult;
576+ //printf("Sprite %d | y: %d, height: %d\n", context->sprite_index, y, height);
577+ if (y <= line && line < (y + height)) {
578+ //printf("Sprite %d at y: %d with height %d is on line %d\n", context->sprite_index, y, height, line);
579+ context->sprite_info_list[context->slot_counter].size = context->sat_cache[address+2];
580+ context->sprite_info_list[context->slot_counter++].index = context->sprite_index;
581+ }
582+ context->sprite_index = context->sat_cache[address+3] & 0x7F;
583+ if (context->sprite_index && ((uint8_t)context->slot_counter) < context->max_sprites_line)
584+ {
585+ //TODO: Implement squirelly behavior documented by Kabuto
586+ if (context->sprite_index >= context->max_sprites_frame) {
587+ context->sprite_index = 0;
588+ return;
589+ }
590+ address = context->sprite_index * 4;
591+ y = ((context->sat_cache[address] & 0x3) << 8 | context->sat_cache[address+1]) & ymask;
592+ height = ((context->sat_cache[address+2] & 0x3) + 1) * height_mult;
593+ //printf("Sprite %d | y: %d, height: %d\n", context->sprite_index, y, height);
594+ if (y <= line && line < (y + height)) {
595+ //printf("Sprite %d at y: %d with height %d is on line %d\n", context->sprite_index, y, height, line);
596+ context->sprite_info_list[context->slot_counter].size = context->sat_cache[address+2];
597+ context->sprite_info_list[context->slot_counter++].index = context->sprite_index;
598+ }
599+ context->sprite_index = context->sat_cache[address+3] & 0x7F;
600+ }
601+ }
602+ //TODO: Seems like the overflow flag should be set here if we run out of sprite info slots without hitting the end of the list
603+}
604+
605+static void scan_sprite_table_mode4(vdp_context * context)
606+{
607+ if (context->sprite_index < MAX_SPRITES_FRAME_H32) {
608+ uint32_t line = context->vcounter;
609+ line &= 0xFF;
610+
611+ uint32_t sat_address = mode4_address_map[(context->regs[REG_SAT] << 7 & 0x3F00) + context->sprite_index];
612+ uint32_t y = context->vdpmem[sat_address+1];
613+ uint32_t size = (context->regs[REG_MODE_2] & BIT_SPRITE_SZ) ? 16 : 8;
614+
615+ if (y == 0xd0) {
616+ context->sprite_index = MAX_SPRITES_FRAME_H32;
617+ return;
618+ } else {
619+ if (y <= line && line < (y + size)) {
620+ if (!context->slot_counter) {
621+ context->sprite_index = MAX_SPRITES_FRAME_H32;
622+ context->flags |= FLAG_DOT_OFLOW;
623+ return;
624+ }
625+ context->sprite_info_list[--(context->slot_counter)].size = size;
626+ context->sprite_info_list[context->slot_counter].index = context->sprite_index;
627+ context->sprite_info_list[context->slot_counter].y = y;
628+ }
629+ context->sprite_index++;
630+ }
631+
632+ if (context->sprite_index < MAX_SPRITES_FRAME_H32) {
633+ y = context->vdpmem[sat_address];
634+ if (y == 0xd0) {
635+ context->sprite_index = MAX_SPRITES_FRAME_H32;
636+ return;
637+ } else {
638+ if (y <= line && line < (y + size)) {
639+ if (!context->slot_counter) {
640+ context->sprite_index = MAX_SPRITES_FRAME_H32;
641+ context->flags |= FLAG_DOT_OFLOW;
642+ return;
643+ }
644+ context->sprite_info_list[--(context->slot_counter)].size = size;
645+ context->sprite_info_list[context->slot_counter].index = context->sprite_index;
646+ context->sprite_info_list[context->slot_counter].y = y;
647+ }
648+ context->sprite_index++;
649+ }
650+ }
651+
652+ }
653+}
654+
655+static void read_sprite_x(uint32_t line, vdp_context * context)
656+{
657+ if (context->cur_slot == context->max_sprites_line) {
658+ context->cur_slot = 0;
659+ }
660+ if (context->cur_slot < context->slot_counter) {
661+ if (context->sprite_draws) {
662+ line += 1;
663+ //in tiles
664+ uint8_t width = ((context->sprite_info_list[context->cur_slot].size >> 2) & 0x3) + 1;
665+ //in pixels
666+ uint8_t height = ((context->sprite_info_list[context->cur_slot].size & 0x3) + 1) * 8;
667+ if (context->double_res) {
668+ line *= 2;
669+ if (context->flags2 & FLAG2_EVEN_FIELD) {
670+ line++;
671+ }
672+ height *= 2;
673+ }
674+ uint16_t ymask, ymin;
675+ if (context->double_res) {
676+ ymask = 0x3FF;
677+ ymin = 256;
678+ } else {
679+ ymask = 0x1FF;
680+ ymin = 128;
681+ }
682+ uint16_t att_addr = mode5_sat_address(context) + context->sprite_info_list[context->cur_slot].index * 8 + 4;
683+ uint16_t tileinfo = (context->vdpmem[att_addr] << 8) | context->vdpmem[att_addr+1];
684+ uint8_t pal_priority = (tileinfo >> 9) & 0x70;
685+ uint8_t row;
686+ uint16_t cache_addr = context->sprite_info_list[context->cur_slot].index * 4;
687+ line = (line + ymin) & ymask;
688+ int16_t y = ((context->sat_cache[cache_addr] << 8 | context->sat_cache[cache_addr+1]) & ymask)/* - ymin*/;
689+ if (tileinfo & MAP_BIT_V_FLIP) {
690+ row = (y + height - 1) - line;
691+ } else {
692+ row = line-y;
693+ }
694+ row &= ymask >> 4;
695+ uint16_t address;
696+ if (context->double_res) {
697+ address = ((tileinfo & 0x3FF) << 6) + row * 4;
698+ } else {
699+ address = ((tileinfo & 0x7FF) << 5) + row * 4;
700+ }
701+ int16_t x = ((context->vdpmem[att_addr+ 2] & 0x3) << 8 | context->vdpmem[att_addr + 3]) & 0x1FF;
702+ if (x) {
703+ context->flags |= FLAG_CAN_MASK;
704+ } else if(context->flags & (FLAG_CAN_MASK | FLAG_DOT_OFLOW)) {
705+ context->flags |= FLAG_MASKED;
706+ }
707+
708+ context->flags &= ~FLAG_DOT_OFLOW;
709+ int16_t i;
710+ if (context->flags & FLAG_MASKED) {
711+ for (i=0; i < width && context->sprite_draws; i++) {
712+ --context->sprite_draws;
713+ context->sprite_draw_list[context->sprite_draws].x_pos = -128;
714+ context->sprite_draw_list[context->sprite_draws].address = address + i * height * 4;
715+ }
716+ } else {
717+ x -= 128;
718+ int16_t base_x = x;
719+ int16_t dir;
720+ if (tileinfo & MAP_BIT_H_FLIP) {
721+ x += (width-1) * 8;
722+ dir = -8;
723+ } else {
724+ dir = 8;
725+ }
726+ //printf("Sprite %d | x: %d, y: %d, width: %d, height: %d, pal_priority: %X, row: %d, tile addr: %X\n", context->sprite_info_list[context->cur_slot].index, x, context->sprite_info_list[context->cur_slot].y, width, height, pal_priority, row, address);
727+ for (i=0; i < width && context->sprite_draws; i++, x += dir) {
728+ --context->sprite_draws;
729+ context->sprite_draw_list[context->sprite_draws].address = address + i * height * 4;
730+ context->sprite_draw_list[context->sprite_draws].x_pos = x;
731+ context->sprite_draw_list[context->sprite_draws].pal_priority = pal_priority;
732+ context->sprite_draw_list[context->sprite_draws].h_flip = (tileinfo & MAP_BIT_H_FLIP) ? 1 : 0;
733+ }
734+ }
735+ //Used to be i < width
736+ //TODO: Confirm this is the right condition on hardware
737+ if (!context->sprite_draws) {
738+ context->flags |= FLAG_DOT_OFLOW;
739+ }
740+ } else {
741+ context->flags |= FLAG_DOT_OFLOW;
742+ }
743+ }
744+ context->cur_slot++;
745+}
746+
747+static void read_sprite_x_mode4(vdp_context * context)
748+{
749+ if (context->cur_slot >= context->slot_counter) {
750+ uint32_t address = (context->regs[REG_SAT] << 7 & 0x3F00) + 0x80 + context->sprite_info_list[context->cur_slot].index * 2;
751+ address = mode4_address_map[address];
752+ --context->sprite_draws;
753+ uint32_t tile_address = context->vdpmem[address] * 32 + (context->regs[REG_STILE_BASE] << 11 & 0x2000);
754+ if (context->regs[REG_MODE_2] & BIT_SPRITE_SZ) {
755+ tile_address &= ~32;
756+ }
757+ tile_address += (context->vcounter - context->sprite_info_list[context->cur_slot].y)* 4;
758+ context->sprite_draw_list[context->sprite_draws].x_pos = context->vdpmem[address + 1];
759+ context->sprite_draw_list[context->sprite_draws].address = tile_address;
760+ context->cur_slot--;
761+ }
762+}
763+
764+#define CRAM_BITS 0xEEE
765+#define VSRAM_BITS 0x7FF
766+#define VSRAM_DIRTY_BITS 0xF800
767+
768+//rough estimate of slot number at which border display starts
769+#define BG_START_SLOT 6
770+
771+static void update_color_map(vdp_context *context, uint16_t index, uint16_t value)
772+{
773+ context->colors[index] = color_map[value & CRAM_BITS];
774+ context->colors[index + SHADOW_OFFSET] = color_map[(value & CRAM_BITS) | FBUF_SHADOW];
775+ context->colors[index + HIGHLIGHT_OFFSET] = color_map[(value & CRAM_BITS) | FBUF_HILIGHT];
776+ context->colors[index + MODE4_OFFSET] = color_map[(value & CRAM_BITS) | FBUF_MODE4];
777+}
778+
779+void write_cram_internal(vdp_context * context, uint16_t addr, uint16_t value)
780+{
781+ context->cram[addr] = value;
782+ update_color_map(context, addr, value);
783+}
784+
785+static void write_cram(vdp_context * context, uint16_t address, uint16_t value)
786+{
787+ uint16_t addr;
788+ if (context->regs[REG_MODE_2] & BIT_MODE_5) {
789+ addr = (address/2) & (CRAM_SIZE-1);
790+ } else {
791+ addr = address & 0x1F;
792+ value = (value << 1 & 0xE) | (value << 2 & 0xE0) | (value & 0xE00);
793+ }
794+ write_cram_internal(context, addr, value);
795+
796+ if (context->hslot >= BG_START_SLOT && (
797+ context->vcounter < context->inactive_start + context->border_bot
798+ || context->vcounter > 0x200 - context->border_top
799+ )) {
800+ uint8_t bg_end_slot = BG_START_SLOT + (context->regs[REG_MODE_4] & BIT_H40) ? LINEBUF_SIZE/2 : (256+HORIZ_BORDER)/2;
801+ if (context->hslot < bg_end_slot) {
802+ uint32_t color = (context->regs[REG_MODE_2] & BIT_MODE_5) ? context->colors[addr] : context->colors[addr + MODE4_OFFSET];
803+ context->output[(context->hslot - BG_START_SLOT)*2 + 1] = color;
804+ }
805+ }
806+}
807+
808+static void vdp_advance_dma(vdp_context * context)
809+{
810+ context->regs[REG_DMASRC_L] += 1;
811+ if (!context->regs[REG_DMASRC_L]) {
812+ context->regs[REG_DMASRC_M] += 1;
813+ }
814+ context->address += context->regs[REG_AUTOINC];
815+ uint16_t dma_len = ((context->regs[REG_DMALEN_H] << 8) | context->regs[REG_DMALEN_L]) - 1;
816+ context->regs[REG_DMALEN_H] = dma_len >> 8;
817+ context->regs[REG_DMALEN_L] = dma_len;
818+ if (!dma_len) {
819+ context->flags &= ~FLAG_DMA_RUN;
820+ context->cd &= 0xF;
821+ }
822+}
823+
824+static void vdp_check_update_sat(vdp_context *context, uint32_t address, uint16_t value)
825+{
826+ if (context->regs[REG_MODE_2] & BIT_MODE_5) {
827+ if (!(address & 4)) {
828+ uint32_t sat_address = mode5_sat_address(context);
829+ if(address >= sat_address && address < (sat_address + SAT_CACHE_SIZE*2)) {
830+ uint16_t cache_address = address - sat_address;
831+ cache_address = (cache_address & 3) | (cache_address >> 1 & 0x1FC);
832+ context->sat_cache[cache_address] = value >> 8;
833+ context->sat_cache[cache_address^1] = value;
834+ }
835+ }
836+ }
837+}
838+
839+void vdp_check_update_sat_byte(vdp_context *context, uint32_t address, uint8_t value)
840+{
841+ if (context->regs[REG_MODE_2] & BIT_MODE_5) {
842+ if (!(address & 4)) {
843+ uint32_t sat_address = mode5_sat_address(context);
844+ if(address >= sat_address && address < (sat_address + SAT_CACHE_SIZE*2)) {
845+ uint16_t cache_address = address - sat_address;
846+ cache_address = (cache_address & 3) | (cache_address >> 1 & 0x1FC);
847+ context->sat_cache[cache_address] = value;
848+ }
849+ }
850+ }
851+}
852+
853+static void write_vram_word(vdp_context *context, uint32_t address, uint16_t value)
854+{
855+ address = (address & 0x3FC) | (address >> 1 & 0xFC01) | (address >> 9 & 0x2);
856+ address ^= 1;
857+ //TODO: Support an option to actually have 128KB of VRAM
858+ context->vdpmem[address] = value;
859+}
860+
861+static void write_vram_byte(vdp_context *context, uint32_t address, uint8_t value)
862+{
863+ if (context->regs[REG_MODE_2] & BIT_MODE_5) {
864+ address &= 0xFFFF;
865+ } else {
866+ address = mode4_address_map[address & 0x3FFF];
867+ }
868+ context->vdpmem[address] = value;
869+}
870+
871+#define DMA_FILL 0x80
872+#define DMA_COPY 0xC0
873+#define DMA_TYPE_MASK 0xC0
874+static void external_slot(vdp_context * context)
875+{
876+ if ((context->flags & FLAG_DMA_RUN) && (context->regs[REG_DMASRC_H] & DMA_TYPE_MASK) == DMA_FILL && context->fifo_read < 0) {
877+ context->fifo_read = (context->fifo_write-1) & (FIFO_SIZE-1);
878+ fifo_entry * cur = context->fifo + context->fifo_read;
879+ cur->cycle = context->cycles;
880+ cur->address = context->address;
881+ cur->partial = 1;
882+ vdp_advance_dma(context);
883+ }
884+ fifo_entry * start = context->fifo + context->fifo_read;
885+ if (context->fifo_read >= 0 && start->cycle <= context->cycles) {
886+ switch (start->cd & 0xF)
887+ {
888+ case VRAM_WRITE:
889+ if ((context->regs[REG_MODE_2] & (BIT_128K_VRAM|BIT_MODE_5)) == (BIT_128K_VRAM|BIT_MODE_5)) {
890+ vdp_check_update_sat(context, start->address, start->value);
891+ write_vram_word(context, start->address, start->value);
892+ } else {
893+ uint8_t byte = start->partial == 1 ? start->value >> 8 : start->value;
894+ vdp_check_update_sat_byte(context, start->address ^ 1, byte);
895+ write_vram_byte(context, start->address ^ 1, byte);
896+ if (!start->partial) {
897+ start->address = start->address ^ 1;
898+ start->partial = 1;
899+ //skip auto-increment and removal of entry from fifo
900+ return;
901+ }
902+ }
903+ break;
904+ case CRAM_WRITE: {
905+ //printf("CRAM Write | %X to %X\n", start->value, (start->address/2) & (CRAM_SIZE-1));
906+ if (start->partial == 3) {
907+ uint16_t val;
908+ if ((start->address & 1) && (context->regs[REG_MODE_2] & BIT_MODE_5)) {
909+ val = (context->cram[start->address >> 1 & (CRAM_SIZE-1)] & 0xFF) | start->value << 8;
910+ } else {
911+ uint16_t address = (context->regs[REG_MODE_2] & BIT_MODE_5) ? start->address >> 1 & (CRAM_SIZE-1) : start->address & 0x1F;
912+ val = (context->cram[address] & 0xFF00) | start->value;
913+ }
914+ write_cram(context, start->address, val);
915+ } else {
916+ write_cram(context, start->address, start->partial ? context->fifo[context->fifo_write].value : start->value);
917+ }
918+ break;
919+ }
920+ case VSRAM_WRITE:
921+ if (((start->address/2) & 63) < VSRAM_SIZE) {
922+ //printf("VSRAM Write: %X to %X @ frame: %d, vcounter: %d, hslot: %d, cycle: %d\n", start->value, start->address, context->frame, context->vcounter, context->hslot, context->cycles);
923+ if (start->partial == 3) {
924+ if (start->address & 1) {
925+ context->vsram[(start->address/2) & 63] &= 0xFF;
926+ context->vsram[(start->address/2) & 63] |= start->value << 8;
927+ } else {
928+ context->vsram[(start->address/2) & 63] &= 0xFF00;
929+ context->vsram[(start->address/2) & 63] |= start->value;
930+ }
931+ } else {
932+ context->vsram[(start->address/2) & 63] = start->partial ? context->fifo[context->fifo_write].value : start->value;
933+ }
934+ }
935+
936+ break;
937+ }
938+ context->fifo_read = (context->fifo_read+1) & (FIFO_SIZE-1);
939+ if (context->fifo_read == context->fifo_write) {
940+ if ((context->cd & 0x20) && (context->regs[REG_DMASRC_H] & DMA_TYPE_MASK) == DMA_FILL) {
941+ context->flags |= FLAG_DMA_RUN;
942+ }
943+ context->fifo_read = -1;
944+ }
945+ } else if ((context->flags & FLAG_DMA_RUN) && (context->regs[REG_DMASRC_H] & DMA_TYPE_MASK) == DMA_COPY) {
946+ if (context->flags & FLAG_READ_FETCHED) {
947+ write_vram_byte(context, context->address ^ 1, context->prefetch);
948+
949+ //Update DMA state
950+ vdp_advance_dma(context);
951+
952+ context->flags &= ~FLAG_READ_FETCHED;
953+ } else {
954+ context->prefetch = context->vdpmem[(context->regs[REG_DMASRC_M] << 8) | context->regs[REG_DMASRC_L] ^ 1];
955+
956+ context->flags |= FLAG_READ_FETCHED;
957+ }
958+ } else if (!(context->cd & 1) && !(context->flags & (FLAG_READ_FETCHED|FLAG_PENDING))) {
959+ switch(context->cd & 0xF)
960+ {
961+ case VRAM_READ:
962+ if (context->flags2 & FLAG2_READ_PENDING) {
963+ context->prefetch |= context->vdpmem[context->address | 1];
964+ context->flags |= FLAG_READ_FETCHED;
965+ context->flags2 &= ~FLAG2_READ_PENDING;
966+ //Should this happen after the prefetch or after the read?
967+ increment_address(context);
968+ } else {
969+ //TODO: 128K VRAM Mode
970+ context->prefetch = context->vdpmem[context->address & 0xFFFE] << 8;
971+ context->flags2 |= FLAG2_READ_PENDING;
972+ }
973+ break;
974+ case VRAM_READ8: {
975+ uint32_t address = context->address ^ 1;
976+ if (!(context->regs[REG_MODE_2] & BIT_MODE_5)) {
977+ address = mode4_address_map[address & 0x3FFF];
978+ }
979+ context->prefetch = context->vdpmem[address];
980+ context->prefetch |= context->fifo[context->fifo_write].value & 0xFF00;
981+ context->flags |= FLAG_READ_FETCHED;
982+ //Should this happen after the prefetch or after the read?
983+ increment_address(context);
984+ break;
985+ }
986+ case CRAM_READ:
987+ context->prefetch = context->cram[(context->address/2) & (CRAM_SIZE-1)] & CRAM_BITS;
988+ context->prefetch |= context->fifo[context->fifo_write].value & ~CRAM_BITS;
989+ context->flags |= FLAG_READ_FETCHED;
990+ //Should this happen after the prefetch or after the read?
991+ increment_address(context);
992+ break;
993+ case VSRAM_READ: {
994+ uint16_t address = (context->address /2) & 63;
995+ if (address >= VSRAM_SIZE) {
996+ address = 0;
997+ }
998+ context->prefetch = context->vsram[address] & VSRAM_BITS;
999+ context->prefetch |= context->fifo[context->fifo_write].value & VSRAM_DIRTY_BITS;
1000+ context->flags |= FLAG_READ_FETCHED;
1001+ //Should this happen after the prefetch or after the read?
1002+ increment_address(context);
1003+ break;
1004+ }
1005+ }
1006+ }
1007+}
1008+
1009+static void run_dma_src(vdp_context * context, int32_t slot)
1010+{
1011+ //TODO: Figure out what happens if CD bit 4 is not set in DMA copy mode
1012+ //TODO: Figure out what happens when CD:0-3 is not set to a write mode in DMA operations
1013+ if (context->fifo_write == context->fifo_read) {
1014+ return;
1015+ }
1016+ fifo_entry * cur = NULL;
1017+ if (!(context->regs[REG_DMASRC_H] & 0x80))
1018+ {
1019+ //68K -> VDP
1020+ if (slot == -1 || !is_refresh(context, slot-1)) {
1021+ cur = context->fifo + context->fifo_write;
1022+ cur->cycle = context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20)*FIFO_LATENCY;
1023+ cur->address = context->address;
1024+ cur->value = read_dma_value((context->regs[REG_DMASRC_H] << 16) | (context->regs[REG_DMASRC_M] << 8) | context->regs[REG_DMASRC_L]);
1025+ cur->cd = context->cd;
1026+ cur->partial = 0;
1027+ if (context->fifo_read < 0) {
1028+ context->fifo_read = context->fifo_write;
1029+ }
1030+ context->fifo_write = (context->fifo_write + 1) & (FIFO_SIZE-1);
1031+ vdp_advance_dma(context);
1032+ }
1033+ }
1034+}
1035+
1036+#define WINDOW_RIGHT 0x80
1037+#define WINDOW_DOWN 0x80
1038+
1039+static void read_map_scroll(uint16_t column, uint16_t vsram_off, uint32_t line, uint16_t address, uint16_t hscroll_val, vdp_context * context)
1040+{
1041+ uint16_t window_line_shift, v_offset_mask, vscroll_shift;
1042+ if (context->double_res) {
1043+ line *= 2;
1044+ if (context->flags2 & FLAG2_EVEN_FIELD) {
1045+ line++;
1046+ }
1047+ window_line_shift = 4;
1048+ v_offset_mask = 0xF;
1049+ vscroll_shift = 4;
1050+ } else {
1051+ window_line_shift = 3;
1052+ v_offset_mask = 0x7;
1053+ vscroll_shift = 3;
1054+ }
1055+ //TODO: Further research on vscroll latch behavior and the "first column bug"
1056+ if (context->regs[REG_MODE_3] & BIT_VSCROLL) {
1057+ if (!column) {
1058+ if (context->regs[REG_MODE_4] & BIT_H40) {
1059+ //Based on observed behavior documented by Eke-Eke, I'm guessing the VDP
1060+ //ends up fetching the last value on the VSRAM bus in the H40 case
1061+ //getting the last latched value should be close enough for now
1062+ if (!vsram_off) {
1063+ context->vscroll_latch[0] = context->vscroll_latch[1];
1064+ }
1065+ } else {
1066+ //supposedly it's always forced to 0 in the H32 case
1067+ context->vscroll_latch[0] = context->vscroll_latch[1] = 0;
1068+ }
1069+ } else if (context->regs[REG_MODE_3] & BIT_VSCROLL) {
1070+ context->vscroll_latch[vsram_off] = context->vsram[column - 2 + vsram_off];
1071+ }
1072+ }
1073+ if (!vsram_off) {
1074+ uint16_t left_col, right_col;
1075+ if (context->regs[REG_WINDOW_H] & WINDOW_RIGHT) {
1076+ left_col = (context->regs[REG_WINDOW_H] & 0x1F) * 2 + 2;
1077+ right_col = 42;
1078+ } else {
1079+ left_col = 0;
1080+ right_col = (context->regs[REG_WINDOW_H] & 0x1F) * 2;
1081+ if (right_col) {
1082+ right_col += 2;
1083+ }
1084+ }
1085+ uint16_t top_line, bottom_line;
1086+ if (context->regs[REG_WINDOW_V] & WINDOW_DOWN) {
1087+ top_line = (context->regs[REG_WINDOW_V] & 0x1F) << window_line_shift;
1088+ bottom_line = context->double_res ? 481 : 241;
1089+ } else {
1090+ top_line = 0;
1091+ bottom_line = (context->regs[REG_WINDOW_V] & 0x1F) << window_line_shift;
1092+ }
1093+ if ((column >= left_col && column < right_col) || (line >= top_line && line < bottom_line)) {
1094+ uint16_t address = context->regs[REG_WINDOW] << 10;
1095+ uint16_t line_offset, offset, mask;
1096+ if (context->regs[REG_MODE_4] & BIT_H40) {
1097+ address &= 0xF000;
1098+ line_offset = (((line) >> vscroll_shift) * 64 * 2) & 0xFFF;
1099+ mask = 0x7F;
1100+
1101+ } else {
1102+ address &= 0xF800;
1103+ line_offset = (((line) >> vscroll_shift) * 32 * 2) & 0xFFF;
1104+ mask = 0x3F;
1105+ }
1106+ if (context->double_res) {
1107+ mask <<= 1;
1108+ mask |= 1;
1109+ }
1110+ offset = address + line_offset + (((column - 2) * 2) & mask);
1111+ context->col_1 = (context->vdpmem[offset] << 8) | context->vdpmem[offset+1];
1112+ //printf("Window | top: %d, bot: %d, left: %d, right: %d, base: %X, line: %X offset: %X, tile: %X, reg: %X\n", top_line, bottom_line, left_col, right_col, address, line_offset, offset, ((context->col_1 & 0x3FF) << 5), context->regs[REG_WINDOW]);
1113+ offset = address + line_offset + (((column - 1) * 2) & mask);
1114+ context->col_2 = (context->vdpmem[offset] << 8) | context->vdpmem[offset+1];
1115+ context->v_offset = (line) & v_offset_mask;
1116+ context->flags |= FLAG_WINDOW;
1117+ return;
1118+ }
1119+ context->flags &= ~FLAG_WINDOW;
1120+ }
1121+ //TODO: Verify behavior for 0x20 case
1122+ uint16_t vscroll = 0xFF | (context->regs[REG_SCROLL] & 0x30) << 4;
1123+ if (context->double_res) {
1124+ vscroll <<= 1;
1125+ vscroll |= 1;
1126+ }
1127+ vscroll &= context->vscroll_latch[vsram_off] + line;
1128+ context->v_offset = vscroll & v_offset_mask;
1129+ //printf("%s | line %d, vsram: %d, vscroll: %d, v_offset: %d\n",(vsram_off ? "B" : "A"), line, context->vsram[context->regs[REG_MODE_3] & 0x4 ? column : 0], vscroll, context->v_offset);
1130+ vscroll >>= vscroll_shift;
1131+ uint16_t hscroll_mask;
1132+ uint16_t v_mul;
1133+ switch(context->regs[REG_SCROLL] & 0x3)
1134+ {
1135+ case 0:
1136+ hscroll_mask = 0x1F;
1137+ v_mul = 64;
1138+ break;
1139+ case 0x1:
1140+ hscroll_mask = 0x3F;
1141+ v_mul = 128;
1142+ break;
1143+ case 0x2:
1144+ //TODO: Verify this behavior
1145+ hscroll_mask = 0x1F;
1146+ v_mul = 0;
1147+ break;
1148+ case 0x3:
1149+ hscroll_mask = 0x7F;
1150+ v_mul = 256;
1151+ break;
1152+ }
1153+ uint16_t hscroll, offset;
1154+ for (int i = 0; i < 2; i++) {
1155+ hscroll = (column - 2 + i - ((hscroll_val/8) & 0xFFFE)) & hscroll_mask;
1156+ offset = address + ((vscroll * v_mul + hscroll*2) & 0x1FFF);
1157+ //printf("%s | line: %d, col: %d, x: %d, hs_mask %X, scr reg: %X, tbl addr: %X\n", (vsram_off ? "B" : "A"), line, (column-2+i), hscroll, hscroll_mask, context->regs[REG_SCROLL], offset);
1158+ uint16_t col_val = (context->vdpmem[offset] << 8) | context->vdpmem[offset+1];
1159+ if (i) {
1160+ context->col_2 = col_val;
1161+ } else {
1162+ context->col_1 = col_val;
1163+ }
1164+ }
1165+}
1166+
1167+static void read_map_scroll_a(uint16_t column, uint32_t line, vdp_context * context)
1168+{
1169+ read_map_scroll(column, 0, line, (context->regs[REG_SCROLL_A] & 0x38) << 10, context->hscroll_a, context);
1170+}
1171+
1172+static void read_map_scroll_b(uint16_t column, uint32_t line, vdp_context * context)
1173+{
1174+ read_map_scroll(column, 1, line, (context->regs[REG_SCROLL_B] & 0x7) << 13, context->hscroll_b, context);
1175+}
1176+
1177+static void read_map_mode4(uint16_t column, uint32_t line, vdp_context * context)
1178+{
1179+ uint32_t address = (context->regs[REG_SCROLL_A] & 0xE) << 10;
1180+ //add row
1181+ uint32_t vscroll = line;
1182+ if (column < 24 || !(context->regs[REG_MODE_1] & BIT_VSCRL_LOCK)) {
1183+ vscroll += context->regs[REG_Y_SCROLL];
1184+ }
1185+ if (vscroll > 223) {
1186+ vscroll -= 224;
1187+ }
1188+ address += (vscroll >> 3) * 2 * 32;
1189+ //add column
1190+ address += ((column - (context->hscroll_a >> 3)) & 31) * 2;
1191+ //adjust for weird VRAM mapping in Mode 4
1192+ address = mode4_address_map[address];
1193+ context->col_1 = (context->vdpmem[address] << 8) | context->vdpmem[address+1];
1194+}
1195+
1196+static void render_map(uint16_t col, uint8_t * tmp_buf, uint8_t offset, vdp_context * context)
1197+{
1198+ uint16_t address;
1199+ uint16_t vflip_base;
1200+ if (context->double_res) {
1201+ address = ((col & 0x3FF) << 6);
1202+ vflip_base = 60;
1203+ } else {
1204+ address = ((col & 0x7FF) << 5);
1205+ vflip_base = 28;
1206+ }
1207+ if (col & MAP_BIT_V_FLIP) {
1208+ address += vflip_base - 4 * context->v_offset;
1209+ } else {
1210+ address += 4 * context->v_offset;
1211+ }
1212+ uint8_t pal_priority = (col >> 9) & 0x70;
1213+ uint32_t bits = *((uint32_t *)(&context->vdpmem[address]));
1214+ if (col & MAP_BIT_H_FLIP) {
1215+ uint32_t shift = 28;
1216+ for (int i = 0; i < 4; i++)
1217+ {
1218+ uint8_t right = pal_priority | ((bits >> shift) & 0xF);
1219+ shift -= 4;
1220+ tmp_buf[offset++] = pal_priority | ((bits >> shift) & 0xF);
1221+ shift -= 4;
1222+ offset &= SCROLL_BUFFER_MASK;
1223+ tmp_buf[offset++] = right;
1224+ offset &= SCROLL_BUFFER_MASK;
1225+ }
1226+ } else {
1227+ for (int i = 0; i < 4; i++)
1228+ {
1229+ uint8_t right = pal_priority | (bits & 0xF);
1230+ bits >>= 4;
1231+ tmp_buf[offset++] = pal_priority | (bits & 0xF);
1232+ offset &= SCROLL_BUFFER_MASK;
1233+ bits >>= 4;
1234+ tmp_buf[offset++] = right;
1235+ offset &= SCROLL_BUFFER_MASK;
1236+ }
1237+ }
1238+}
1239+
1240+static void render_map_1(vdp_context * context)
1241+{
1242+ render_map(context->col_1, context->tmp_buf_a, context->buf_a_off, context);
1243+}
1244+
1245+static void render_map_2(vdp_context * context)
1246+{
1247+ render_map(context->col_2, context->tmp_buf_a, context->buf_a_off+8, context);
1248+}
1249+
1250+static void render_map_3(vdp_context * context)
1251+{
1252+ render_map(context->col_1, context->tmp_buf_b, context->buf_b_off, context);
1253+}
1254+
1255+static void fetch_map_mode4(uint16_t col, uint32_t line, vdp_context *context)
1256+{
1257+ //calculate pixel row to fetch
1258+ uint32_t vscroll = line;
1259+ if (col < 24 || !(context->regs[REG_MODE_1] & BIT_VSCRL_LOCK)) {
1260+ vscroll += context->regs[REG_Y_SCROLL];
1261+ }
1262+ if (vscroll > 223) {
1263+ vscroll -= 224;
1264+ }
1265+ vscroll &= 7;
1266+ if (context->col_1 & 0x400) {
1267+ vscroll = 7 - vscroll;
1268+ }
1269+
1270+ uint32_t address = mode4_address_map[((context->col_1 & 0x1FF) * 32) + vscroll * 4];
1271+ context->fetch_tmp[0] = context->vdpmem[address];
1272+ context->fetch_tmp[1] = context->vdpmem[address+1];
1273+}
1274+
1275+static uint8_t composite_normal(vdp_context *context, uint8_t *debug_dst, uint8_t sprite, uint8_t plane_a, uint8_t plane_b, uint8_t bg_index)
1276+{
1277+ uint8_t pixel = bg_index;
1278+ uint8_t src = DBG_SRC_BG;
1279+ if (plane_b & 0xF) {
1280+ pixel = plane_b;
1281+ src = DBG_SRC_B;
1282+ }
1283+ if (plane_a & 0xF && (plane_a & BUF_BIT_PRIORITY) >= (pixel & BUF_BIT_PRIORITY)) {
1284+ pixel = plane_a;
1285+ src = DBG_SRC_A;
1286+ }
1287+ if (sprite & 0xF && (sprite & BUF_BIT_PRIORITY) >= (pixel & BUF_BIT_PRIORITY)) {
1288+ pixel = sprite;
1289+ src = DBG_SRC_S;
1290+ }
1291+ *debug_dst = src;
1292+ return pixel;
1293+}
1294+typedef struct {
1295+ uint8_t index, intensity;
1296+} sh_pixel;
1297+
1298+static sh_pixel composite_highlight(vdp_context *context, uint8_t *debug_dst, uint8_t sprite, uint8_t plane_a, uint8_t plane_b, uint8_t bg_index)
1299+{
1300+ uint8_t pixel = bg_index;
1301+ uint8_t src = DBG_SRC_BG;
1302+ uint8_t intensity = 0;
1303+ if (plane_b & 0xF) {
1304+ pixel = plane_b;
1305+ src = DBG_SRC_B;
1306+ }
1307+ intensity = plane_b & BUF_BIT_PRIORITY;
1308+ if (plane_a & 0xF && (plane_a & BUF_BIT_PRIORITY) >= (pixel & BUF_BIT_PRIORITY)) {
1309+ pixel = plane_a;
1310+ src = DBG_SRC_A;
1311+ }
1312+ intensity |= plane_a & BUF_BIT_PRIORITY;
1313+ if (sprite & 0xF && (sprite & BUF_BIT_PRIORITY) >= (pixel & BUF_BIT_PRIORITY)) {
1314+ if ((sprite & 0x3F) == 0x3E) {
1315+ intensity += BUF_BIT_PRIORITY;
1316+ } else if ((sprite & 0x3F) == 0x3F) {
1317+ intensity = 0;
1318+ } else {
1319+ pixel = sprite;
1320+ src = DBG_SRC_S;
1321+ if ((pixel & 0xF) == 0xE) {
1322+ intensity = BUF_BIT_PRIORITY;
1323+ } else {
1324+ intensity |= pixel & BUF_BIT_PRIORITY;
1325+ }
1326+ }
1327+ }
1328+ *debug_dst = src;
1329+ return (sh_pixel){.index = pixel, .intensity = intensity};
1330+}
1331+
1332+static void render_normal(vdp_context *context, int32_t col, uint32_t *dst, uint8_t *debug_dst, int plane_a_off, int plane_b_off)
1333+{
1334+ int start = 0;
1335+ if (!col && (context->regs[REG_MODE_1] & BIT_COL0_MASK)) {
1336+ uint32_t bgcolor = context->colors[context->regs[REG_BG_COLOR] & 0x3F];
1337+ for (int i = 0; i < 8; ++i)
1338+ {
1339+ *(dst++) = bgcolor;
1340+ *(debug_dst++) = DBG_SRC_BG;
1341+ }
1342+ start = 8;
1343+ }
1344+ uint8_t *sprite_buf = context->linebuf + col * 8 + start;
1345+ for (int i = start; i < 16; ++plane_a_off, ++plane_b_off, ++sprite_buf, ++i)
1346+ {
1347+ uint8_t sprite, plane_a, plane_b;
1348+ plane_a = context->tmp_buf_a[plane_a_off & SCROLL_BUFFER_MASK];
1349+ plane_b = context->tmp_buf_b[plane_b_off & SCROLL_BUFFER_MASK];
1350+ sprite = *sprite_buf;
1351+ uint8_t pixel = composite_normal(context, debug_dst, sprite, plane_a, plane_b, context->regs[REG_BG_COLOR]);
1352+ debug_dst++;
1353+ *(dst++) = context->colors[pixel & 0x3F];
1354+ }
1355+}
1356+
1357+static void render_highlight(vdp_context *context, int32_t col, uint32_t *dst, uint8_t *debug_dst, int plane_a_off, int plane_b_off)
1358+{
1359+ int start = 0;
1360+ if (!col && (context->regs[REG_MODE_1] & BIT_COL0_MASK)) {
1361+ uint32_t bgcolor = context->colors[SHADOW_OFFSET + (context->regs[REG_BG_COLOR] & 0x3F)];
1362+ for (int i = 0; i < 8; ++i)
1363+ {
1364+ *(dst++) = bgcolor;
1365+ *(debug_dst++) = DBG_SRC_BG | DBG_SHADOW;
1366+ }
1367+ start = 8;
1368+ }
1369+ uint8_t *sprite_buf = context->linebuf + col * 8 + start;
1370+ for (int i = start; i < 16; ++plane_a_off, ++plane_b_off, ++sprite_buf, ++i)
1371+ {
1372+ uint8_t sprite, plane_a, plane_b;
1373+ plane_a = context->tmp_buf_a[plane_a_off & SCROLL_BUFFER_MASK];
1374+ plane_b = context->tmp_buf_b[plane_b_off & SCROLL_BUFFER_MASK];
1375+ sprite = *sprite_buf;
1376+ sh_pixel pixel = composite_highlight(context, debug_dst, sprite, plane_a, plane_b, context->regs[REG_BG_COLOR]);
1377+ uint32_t *colors;
1378+ if (pixel.intensity == BUF_BIT_PRIORITY << 1) {
1379+ colors = context->colors + HIGHLIGHT_OFFSET;
1380+ } else if (pixel.intensity) {
1381+ colors = context->colors;
1382+ } else {
1383+ colors = context->colors + SHADOW_OFFSET;
1384+ }
1385+ debug_dst++;
1386+ *(dst++) = colors[pixel.index & 0x3F];
1387+ }
1388+}
1389+
1390+static void render_testreg(vdp_context *context, int32_t col, uint32_t *dst, uint8_t *debug_dst, int plane_a_off, int plane_b_off, uint8_t output_disabled, uint8_t test_layer)
1391+{
1392+ if (output_disabled) {
1393+ switch (test_layer)
1394+ {
1395+ case 0:
1396+ for (int i = 0; i < 16; i++)
1397+ {
1398+ *(dst++) = 0x3F; //TODO: confirm this on hardware
1399+ *(debug_dst++) = DBG_SRC_BG;
1400+ }
1401+ break;
1402+ case 1: {
1403+ uint8_t *sprite_buf = context->linebuf + col * 8;
1404+ for (int i = 0; i < 16; i++)
1405+ {
1406+ *(dst++) = context->colors[*(sprite_buf++) & 0x3F];
1407+ *(debug_dst++) = DBG_SRC_S;
1408+ }
1409+ break;
1410+ }
1411+ case 2:
1412+ for (int i = 0; i < 16; i++)
1413+ {
1414+ *(dst++) = context->colors[context->tmp_buf_a[(plane_a_off++) & SCROLL_BUFFER_MASK] & 0x3F];
1415+ *(debug_dst++) = DBG_SRC_A;
1416+ }
1417+ break;
1418+ case 3:
1419+ for (int i = 0; i < 16; i++)
1420+ {
1421+ *(dst++) = context->colors[context->tmp_buf_b[(plane_b_off++) & SCROLL_BUFFER_MASK] & 0x3F];
1422+ *(debug_dst++) = DBG_SRC_B;
1423+ }
1424+ break;
1425+ }
1426+ } else {
1427+ int start = 0;
1428+ uint8_t *sprite_buf = context->linebuf + col * 8;
1429+ if (!col && (context->regs[REG_MODE_1] & BIT_COL0_MASK)) {
1430+ //TODO: Confirm how test register interacts with column 0 blanking
1431+ uint8_t pixel = context->regs[REG_BG_COLOR] & 0x3F;
1432+ uint8_t src = DBG_SRC_BG;
1433+ for (int i = 0; i < 8; ++i)
1434+ {
1435+ switch (test_layer)
1436+ {
1437+ case 1:
1438+ pixel &= sprite_buf[i];
1439+ if (pixel) {
1440+ src = DBG_SRC_S;
1441+ }
1442+ break;
1443+ case 2:
1444+ pixel &= context->tmp_buf_a[(plane_a_off + i) & SCROLL_BUFFER_MASK];
1445+ if (pixel) {
1446+ src = DBG_SRC_A;
1447+ }
1448+ break;
1449+ case 3:
1450+ pixel &= context->tmp_buf_b[(plane_b_off + i) & SCROLL_BUFFER_MASK];
1451+ if (pixel) {
1452+ src = DBG_SRC_B;
1453+ }
1454+ break;
1455+ }
1456+
1457+ *(dst++) = context->colors[pixel & 0x3F];
1458+ *(debug_dst++) = src;
1459+ }
1460+ plane_a_off += 8;
1461+ plane_b_off += 8;
1462+ sprite_buf += 8;
1463+ start = 8;
1464+ }
1465+ for (int i = start; i < 16; ++plane_a_off, ++plane_b_off, ++sprite_buf, ++i)
1466+ {
1467+ uint8_t sprite, plane_a, plane_b;
1468+ plane_a = context->tmp_buf_a[plane_a_off & SCROLL_BUFFER_MASK];
1469+ plane_b = context->tmp_buf_b[plane_b_off & SCROLL_BUFFER_MASK];
1470+ sprite = *sprite_buf;
1471+ uint8_t pixel = composite_normal(context, debug_dst, sprite, plane_a, plane_b, 0x3F);
1472+ switch (test_layer)
1473+ {
1474+ case 1:
1475+ pixel &= sprite;
1476+ if (pixel) {
1477+ *debug_dst = DBG_SRC_S;
1478+ }
1479+ break;
1480+ case 2:
1481+ pixel &= plane_a;
1482+ if (pixel) {
1483+ *debug_dst = DBG_SRC_A;
1484+ }
1485+ break;
1486+ case 3:
1487+ pixel &= plane_b;
1488+ if (pixel) {
1489+ *debug_dst = DBG_SRC_B;
1490+ }
1491+ break;
1492+ }
1493+ debug_dst++;
1494+ *(dst++) = context->colors[pixel & 0x3F];
1495+ }
1496+ }
1497+}
1498+
1499+static void render_testreg_highlight(vdp_context *context, int32_t col, uint32_t *dst, uint8_t *debug_dst, int plane_a_off, int plane_b_off, uint8_t output_disabled, uint8_t test_layer)
1500+{
1501+ int start = 0;
1502+ uint8_t *sprite_buf = context->linebuf + col * 8;
1503+ if (!col && (context->regs[REG_MODE_1] & BIT_COL0_MASK)) {
1504+ //TODO: Confirm how test register interacts with column 0 blanking
1505+ uint8_t pixel = context->regs[REG_BG_COLOR] & 0x3F;
1506+ uint8_t src = DBG_SRC_BG | DBG_SHADOW;
1507+ for (int i = 0; i < 8; ++i)
1508+ {
1509+ switch (test_layer)
1510+ {
1511+ case 1:
1512+ pixel &= sprite_buf[i];
1513+ if (pixel) {
1514+ src = DBG_SRC_S | DBG_SHADOW;
1515+ }
1516+ break;
1517+ case 2:
1518+ pixel &= context->tmp_buf_a[(plane_a_off + i) & SCROLL_BUFFER_MASK];
1519+ if (pixel) {
1520+ src = DBG_SRC_A | DBG_SHADOW;
1521+ }
1522+ break;
1523+ case 3:
1524+ pixel &= context->tmp_buf_b[(plane_b_off + i) & SCROLL_BUFFER_MASK];
1525+ if (pixel) {
1526+ src = DBG_SRC_B | DBG_SHADOW;
1527+ }
1528+ break;
1529+ }
1530+
1531+ *(dst++) = context->colors[SHADOW_OFFSET + (pixel & 0x3F)];
1532+ *(debug_dst++) = src;
1533+ }
1534+ plane_a_off += 8;
1535+ plane_b_off += 8;
1536+ sprite_buf += 8;
1537+ start = 8;
1538+ }
1539+ for (int i = start; i < 16; ++plane_a_off, ++plane_b_off, ++sprite_buf, ++i)
1540+ {
1541+ uint8_t sprite, plane_a, plane_b;
1542+ plane_a = context->tmp_buf_a[plane_a_off & SCROLL_BUFFER_MASK];
1543+ plane_b = context->tmp_buf_b[plane_b_off & SCROLL_BUFFER_MASK];
1544+ sprite = *sprite_buf;
1545+ sh_pixel pixel = composite_highlight(context, debug_dst, sprite, plane_a, plane_b, 0x3F);
1546+ uint32_t *colors;
1547+ if (pixel.intensity == BUF_BIT_PRIORITY << 1) {
1548+ colors = context->colors + HIGHLIGHT_OFFSET;
1549+ } else if (pixel.intensity) {
1550+ colors = context->colors;
1551+ } else {
1552+ colors = context->colors + SHADOW_OFFSET;
1553+ }
1554+ if (output_disabled) {
1555+ pixel.index = 0x3F;
1556+ }
1557+ switch (test_layer)
1558+ {
1559+ case 1:
1560+ pixel.index &= sprite;
1561+ if (pixel.index) {
1562+ *debug_dst = DBG_SRC_S;
1563+ }
1564+ break;
1565+ case 2:
1566+ pixel.index &= plane_a;
1567+ if (pixel.index) {
1568+ *debug_dst = DBG_SRC_A;
1569+ }
1570+ break;
1571+ case 3:
1572+ pixel.index &= plane_b;
1573+ if (pixel.index) {
1574+ *debug_dst = DBG_SRC_B;
1575+ }
1576+ break;
1577+ }
1578+ debug_dst++;
1579+ *(dst++) = colors[pixel.index & 0x3F];
1580+ }
1581+}
1582+
1583+static void render_map_output(uint32_t line, int32_t col, vdp_context * context)
1584+{
1585+ uint32_t *dst;
1586+ uint8_t *debug_dst;
1587+ uint8_t output_disabled = (context->test_port & TEST_BIT_DISABLE) != 0;
1588+ uint8_t test_layer = context->test_port >> 7 & 3;
1589+ if (context->state == PREPARING && !test_layer) {
1590+ if (col) {
1591+ col -= 2;
1592+ dst = context->output + BORDER_LEFT + col * 8;
1593+ } else {
1594+ dst = context->output;
1595+ uint32_t bg_color = context->colors[context->regs[REG_BG_COLOR] & 0x3F];
1596+ for (int i = 0; i < BORDER_LEFT; i++, dst++)
1597+ {
1598+ *dst = bg_color;
1599+ }
1600+ context->done_output = dst;
1601+ return;
1602+ }
1603+ uint32_t color = context->colors[context->regs[REG_BG_COLOR] & 0x3F];
1604+ for (int i = 0; i < 16; i++)
1605+ {
1606+ *(dst++) = color;
1607+ }
1608+ context->done_output = dst;
1609+ return;
1610+ }
1611+ line &= 0xFF;
1612+ render_map(context->col_2, context->tmp_buf_b, context->buf_b_off+8, context);
1613+ uint8_t *sprite_buf;
1614+ uint8_t sprite, plane_a, plane_b;
1615+ int plane_a_off, plane_b_off;
1616+ if (col)
1617+ {
1618+ col-=2;
1619+ dst = context->output + BORDER_LEFT + col * 8;
1620+ debug_dst = context->layer_debug_buf + BORDER_LEFT + col * 8;
1621+
1622+
1623+ uint8_t a_src, src;
1624+ if (context->flags & FLAG_WINDOW) {
1625+ plane_a_off = context->buf_a_off;
1626+ a_src = DBG_SRC_W;
1627+ } else {
1628+ plane_a_off = context->buf_a_off - (context->hscroll_a & 0xF);
1629+ a_src = DBG_SRC_A;
1630+ }
1631+ plane_b_off = context->buf_b_off - (context->hscroll_b & 0xF);
1632+ //printf("A | tmp_buf offset: %d\n", 8 - (context->hscroll_a & 0x7));
1633+
1634+ if (context->regs[REG_MODE_4] & BIT_HILIGHT) {
1635+ if (output_disabled || test_layer) {
1636+ render_testreg_highlight(context, col, dst, debug_dst, plane_a_off, plane_b_off, output_disabled, test_layer);
1637+ } else {
1638+ render_highlight(context, col, dst, debug_dst, plane_a_off, plane_b_off);
1639+ }
1640+ } else {
1641+ if (output_disabled || test_layer) {
1642+ render_testreg(context, col, dst, debug_dst, plane_a_off, plane_b_off, output_disabled, test_layer);
1643+ } else {
1644+ render_normal(context, col, dst, debug_dst, plane_a_off, plane_b_off);
1645+ }
1646+ }
1647+ dst += 16;
1648+ } else {
1649+ dst = context->output;
1650+ debug_dst = context->layer_debug_buf;
1651+ uint8_t pixel = context->regs[REG_BG_COLOR] & 0x3F;
1652+ if (output_disabled) {
1653+ pixel = 0x3F;
1654+ }
1655+ uint32_t bg_color = context->colors[pixel];
1656+ if (test_layer) {
1657+ switch(test_layer)
1658+ {
1659+ case 1:
1660+ bg_color = context->colors[0];
1661+ for (int i = 0; i < BORDER_LEFT; i++, dst++, debug_dst++)
1662+ {
1663+ *dst = bg_color;
1664+ *debug_dst = DBG_SRC_BG;
1665+
1666+ }
1667+ break;
1668+ case 2: {
1669+ //plane A
1670+ //TODO: Deal with Window layer
1671+ int i;
1672+ i = 0;
1673+ uint8_t buf_off = context->buf_a_off - (context->hscroll_a & 0xF) + (16 - BORDER_LEFT);
1674+ //uint8_t *src = context->tmp_buf_a + ((context->buf_a_off + (i ? 0 : (16 - BORDER_LEFT) - (context->hscroll_a & 0xF))) & SCROLL_BUFFER_MASK);
1675+ for (; i < BORDER_LEFT; buf_off++, i++, dst++, debug_dst++)
1676+ {
1677+ *dst = context->colors[context->tmp_buf_a[buf_off & SCROLL_BUFFER_MASK]];
1678+ *debug_dst = DBG_SRC_A;
1679+ }
1680+ break;
1681+ }
1682+ case 3: {
1683+ //plane B
1684+ int i;
1685+ i = 0;
1686+ uint8_t buf_off = context->buf_b_off - (context->hscroll_b & 0xF) + (16 - BORDER_LEFT);
1687+ //uint8_t *src = context->tmp_buf_b + ((context->buf_b_off + (i ? 0 : (16 - BORDER_LEFT) - (context->hscroll_b & 0xF))) & SCROLL_BUFFER_MASK);
1688+ for (; i < BORDER_LEFT; buf_off++, i++, dst++, debug_dst++)
1689+ {
1690+ *dst = context->colors[context->tmp_buf_b[buf_off & SCROLL_BUFFER_MASK]];
1691+ *debug_dst = DBG_SRC_B;
1692+ }
1693+ break;
1694+ }
1695+ }
1696+ } else {
1697+ for (int i = 0; i < BORDER_LEFT; i++, dst++, debug_dst++)
1698+ {
1699+ *dst = bg_color;
1700+ *debug_dst = DBG_SRC_BG;
1701+ }
1702+ }
1703+ }
1704+ context->done_output = dst;
1705+ context->buf_a_off = (context->buf_a_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_MASK;
1706+ context->buf_b_off = (context->buf_b_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_MASK;
1707+}
1708+
1709+static void render_map_mode4(uint32_t line, int32_t col, vdp_context * context)
1710+{
1711+ uint32_t vscroll = line;
1712+ if (col < 24 || !(context->regs[REG_MODE_1] & BIT_VSCRL_LOCK)) {
1713+ vscroll += context->regs[REG_Y_SCROLL];
1714+ }
1715+ if (vscroll > 223) {
1716+ vscroll -= 224;
1717+ }
1718+ vscroll &= 7;
1719+ if (context->col_1 & 0x400) {
1720+ //vflip
1721+ vscroll = 7 - vscroll;
1722+ }
1723+
1724+ uint32_t pixels = planar_to_chunky[context->fetch_tmp[0]] << 1;
1725+ pixels |= planar_to_chunky[context->fetch_tmp[1]];
1726+
1727+ uint32_t address = mode4_address_map[((context->col_1 & 0x1FF) * 32) + vscroll * 4 + 2];
1728+ pixels |= planar_to_chunky[context->vdpmem[address]] << 3;
1729+ pixels |= planar_to_chunky[context->vdpmem[address+1]] << 2;
1730+
1731+ int i, i_inc, i_limit;
1732+ if (context->col_1 & 0x200) {
1733+ //hflip
1734+ i = 0;
1735+ i_inc = 4;
1736+ i_limit = 32;
1737+ } else {
1738+ i = 28;
1739+ i_inc = -4;
1740+ i_limit = -4;
1741+ }
1742+ uint8_t pal_priority = (context->col_1 >> 7 & 0x10) | (context->col_1 >> 6 & 0x40);
1743+ for (uint8_t *dst = context->tmp_buf_a + context->buf_a_off; i != i_limit; i += i_inc, dst++)
1744+ {
1745+ *dst = (pixels >> i & 0xF) | pal_priority;
1746+ }
1747+ context->buf_a_off = (context->buf_a_off + 8) & 15;
1748+
1749+ uint8_t bgcolor = 0x10 | (context->regs[REG_BG_COLOR] & 0xF) + MODE4_OFFSET;
1750+ uint32_t *dst = context->output + col * 8 + BORDER_LEFT;
1751+ uint8_t *debug_dst = context->layer_debug_buf + col * 8 + BORDER_LEFT;
1752+ if (context->state == PREPARING) {
1753+ for (int i = 0; i < 16; i++)
1754+ {
1755+ *(dst++) = context->colors[bgcolor];
1756+ }
1757+ context->done_output = dst;
1758+ return;
1759+ }
1760+
1761+ if (col || !(context->regs[REG_MODE_1] & BIT_COL0_MASK)) {
1762+ uint8_t *sprite_src = context->linebuf + col * 8;
1763+ if (context->regs[REG_MODE_1] & BIT_SPRITE_8PX) {
1764+ sprite_src += 8;
1765+ }
1766+ for (int i = 0; i < 8; i++, sprite_src++)
1767+ {
1768+ uint8_t *bg_src = context->tmp_buf_a + ((8 + i + col * 8 - (context->hscroll_a & 0x7)) & 15);
1769+ if ((*bg_src & 0x4F) > 0x40 || !*sprite_src) {
1770+ //background plane has priority and is opaque or sprite layer is transparent
1771+ *(dst++) = context->colors[(*bg_src & 0x1F) + MODE4_OFFSET];
1772+ *(debug_dst++) = DBG_SRC_A;
1773+ } else {
1774+ //sprite layer is opaque and not covered by high priority BG pixels
1775+ *(dst++) = context->colors[*sprite_src | 0x10 + MODE4_OFFSET];
1776+ *(debug_dst++) = DBG_SRC_S;
1777+ }
1778+ }
1779+ } else {
1780+ for (int i = 0; i < 8; i++)
1781+ {
1782+ *(dst++) = context->colors[bgcolor];
1783+ *(debug_dst++) = DBG_SRC_BG;
1784+ }
1785+ }
1786+ context->done_output = dst;
1787+}
1788+
1789+static uint32_t const h40_hsync_cycles[] = {19, 20, 20, 20, 18, 20, 20, 20, 18, 20, 20, 20, 18, 20, 20, 20, 19};
1790+
1791+static void vdp_advance_line(vdp_context *context)
1792+{
1793+#ifdef TIMING_DEBUG
1794+ static uint32_t last_line = 0xFFFFFFFF;
1795+ if (last_line != 0xFFFFFFFF) {
1796+ uint32_t diff = context->cycles - last_line;
1797+ if (diff != MCLKS_LINE) {
1798+ printf("Line %d took %d cycles\n", context->vcounter, diff);
1799+ }
1800+ }
1801+ last_line = context->cycles;
1802+#endif
1803+ uint16_t jump_start, jump_end;
1804+ uint8_t is_mode_5 = context->regs[REG_MODE_2] & BIT_MODE_5;
1805+ if (is_mode_5) {
1806+ if (context->flags2 & FLAG2_REGION_PAL) {
1807+ if (context->regs[REG_MODE_2] & BIT_PAL) {
1808+ jump_start = 0x10B;
1809+ jump_end = 0x1D2;
1810+ } else {
1811+ jump_start = 0x103;
1812+ jump_end = 0x1CA;
1813+ }
1814+ } else if (context->regs[REG_MODE_2] & BIT_PAL) {
1815+ jump_start = 0x100;
1816+ jump_end = 0x1FA;
1817+ } else {
1818+ jump_start = 0xEB;
1819+ jump_end = 0x1E5;
1820+ }
1821+ } else {
1822+ jump_start = 0xDB;
1823+ jump_end = 0x1D5;
1824+ }
1825+
1826+ if (context->enabled_debuggers & (1 << VDP_DEBUG_CRAM | 1 << VDP_DEBUG_COMPOSITE)) {
1827+ uint32_t line = context->vcounter;
1828+ if (line >= jump_end) {
1829+ line -= jump_end - jump_start;
1830+ }
1831+ uint32_t total_lines = (context->flags2 & FLAG2_REGION_PAL) ? 313 : 262;
1832+
1833+ if (total_lines - line <= context->border_top) {
1834+ line -= total_lines - context->border_top;
1835+ } else {
1836+ line += context->border_top;
1837+ }
1838+ if (context->enabled_debuggers & (1 << VDP_DEBUG_CRAM)) {
1839+ uint32_t *fb = context->debug_fbs[VDP_DEBUG_CRAM] + context->debug_fb_pitch[VDP_DEBUG_CRAM] * line / sizeof(uint32_t);
1840+ for (int i = 0; i < 64; i++)
1841+ {
1842+ for (int x = 0; x < 8; x++)
1843+ {
1844+ *(fb++) = context->colors[i];
1845+ }
1846+ }
1847+ }
1848+ if (
1849+ context->enabled_debuggers & (1 << VDP_DEBUG_COMPOSITE)
1850+ && line < (context->inactive_start + context->border_bot + context->border_top)
1851+ ) {
1852+ uint32_t *fb = context->debug_fbs[VDP_DEBUG_COMPOSITE] + context->debug_fb_pitch[VDP_DEBUG_COMPOSITE] * line / sizeof(uint32_t);
1853+ for (int i = 0; i < LINEBUF_SIZE; i++)
1854+ {
1855+ *(fb++) = context->debugcolors[context->layer_debug_buf[i]];
1856+ }
1857+ }
1858+ }
1859+
1860+ context->vcounter++;
1861+ if (context->vcounter == jump_start) {
1862+ context->vcounter = jump_end;
1863+ } else {
1864+ context->vcounter &= 0x1FF;
1865+ }
1866+ if (context->state == PREPARING) {
1867+ context->state = ACTIVE;
1868+ }
1869+ if (context->vcounter == 0x1FF) {
1870+ context->flags2 &= ~FLAG2_PAUSE;
1871+ }
1872+
1873+ if (context->state != ACTIVE) {
1874+ context->hint_counter = context->regs[REG_HINT];
1875+ } else if (context->hint_counter) {
1876+ context->hint_counter--;
1877+ } else {
1878+ context->flags2 |= FLAG2_HINT_PENDING;
1879+ context->pending_hint_start = context->cycles;
1880+ context->hint_counter = context->regs[REG_HINT];
1881+ }
1882+}
1883+
1884+static void vdp_update_per_frame_debug(vdp_context *context)
1885+{
1886+ if (context->enabled_debuggers & (1 << VDP_DEBUG_PLANE)) {
1887+ uint32_t pitch;
1888+ uint32_t *fb = render_get_video_buffer(context->debug_fb_indices[VDP_DEBUG_PLANE], &pitch);
1889+ uint16_t hscroll_mask;
1890+ uint16_t v_mul;
1891+ uint16_t vscroll_mask = 0x1F | (context->regs[REG_SCROLL] & 0x30) << 1;
1892+ switch(context->regs[REG_SCROLL] & 0x3)
1893+ {
1894+ case 0:
1895+ hscroll_mask = 0x1F;
1896+ v_mul = 64;
1897+ break;
1898+ case 0x1:
1899+ hscroll_mask = 0x3F;
1900+ v_mul = 128;
1901+ break;
1902+ case 0x2:
1903+ //TODO: Verify this behavior
1904+ hscroll_mask = 0x1F;
1905+ v_mul = 0;
1906+ break;
1907+ case 0x3:
1908+ hscroll_mask = 0x7F;
1909+ v_mul = 256;
1910+ break;
1911+ }
1912+ uint16_t table_address;
1913+ switch(context->debug_modes[VDP_DEBUG_PLANE] % 3)
1914+ {
1915+ case 0:
1916+ table_address = context->regs[REG_SCROLL_A] << 10 & 0xE000;
1917+ break;
1918+ case 1:
1919+ table_address = context->regs[REG_SCROLL_B] << 13 & 0xE000;
1920+ break;
1921+ case 2:
1922+ table_address = context->regs[REG_WINDOW] << 10;
1923+ if (context->regs[REG_MODE_4] & BIT_H40) {
1924+ table_address &= 0xF000;
1925+ v_mul = 128;
1926+ hscroll_mask = 0x3F;
1927+ } else {
1928+ table_address &= 0xF800;
1929+ v_mul = 64;
1930+ hscroll_mask = 0x1F;
1931+ }
1932+ vscroll_mask = 0x1F;
1933+ break;
1934+ }
1935+ uint32_t bg_color = context->colors[context->regs[REG_BG_COLOR & 0x3F]];
1936+ for (uint16_t row = 0; row < 128; row++)
1937+ {
1938+ uint16_t row_address = table_address + (row & vscroll_mask) * v_mul;
1939+ for (uint16_t col = 0; col < 128; col++)
1940+ {
1941+ uint16_t address = row_address + (col & hscroll_mask) * 2;
1942+ //pccv hnnn nnnn nnnn
1943+ //
1944+ uint16_t entry = context->vdpmem[address] << 8 | context->vdpmem[address + 1];
1945+ uint8_t pal = entry >> 9 & 0x30;
1946+
1947+ uint32_t *dst = fb + (row * pitch * 8 / sizeof(uint32_t)) + col * 8;
1948+ address = (entry & 0x7FF) * 32;
1949+ int y_diff = 4;
1950+ if (entry & 0x1000) {
1951+ y_diff = -4;
1952+ address += 7 * 4;
1953+ }
1954+ int x_diff = 1;
1955+ if (entry & 0x800) {
1956+ x_diff = -1;
1957+ address += 3;
1958+ }
1959+ for (int y = 0; y < 8; y++)
1960+ {
1961+ uint16_t trow_address = address;
1962+ uint32_t *row_dst = dst;
1963+ for (int x = 0; x < 4; x++)
1964+ {
1965+ uint8_t byte = context->vdpmem[trow_address];
1966+ trow_address += x_diff;
1967+ uint8_t left, right;
1968+ if (x_diff > 0) {
1969+ left = byte >> 4;
1970+ right = byte & 0xF;
1971+ } else {
1972+ left = byte & 0xF;
1973+ right = byte >> 4;
1974+ }
1975+ *(row_dst++) = left ? context->colors[left|pal] : bg_color;
1976+ *(row_dst++) = right ? context->colors[right|pal] : bg_color;
1977+ }
1978+ address += y_diff;
1979+ dst += pitch / sizeof(uint32_t);
1980+ }
1981+ }
1982+ }
1983+ render_video_buffer_updated(context->debug_fb_indices[VDP_DEBUG_PLANE], 1024);
1984+ }
1985+
1986+ if (context->enabled_debuggers & (1 << VDP_DEBUG_VRAM)) {
1987+ uint32_t pitch;
1988+ uint32_t *fb = render_get_video_buffer(context->debug_fb_indices[VDP_DEBUG_VRAM], &pitch);
1989+
1990+ uint8_t pal = (context->debug_modes[VDP_DEBUG_VRAM] % 4) << 4;
1991+ for (int y = 0; y < 512; y++)
1992+ {
1993+ uint32_t *line = fb + y * pitch / sizeof(uint32_t);
1994+ int row = y >> 4;
1995+ int yoff = y >> 1 & 7;
1996+ for (int col = 0; col < 64; col++)
1997+ {
1998+ uint16_t address = (row * 64 + col) * 32 + yoff * 4;
1999+ for (int x = 0; x < 4; x++)
2000+ {
2001+ uint8_t byte = context->vdpmem[address++];
2002+ uint8_t left = byte >> 4 | pal;
2003+ uint8_t right = byte & 0xF | pal;
2004+ *(line++) = context->colors[left];
2005+ *(line++) = context->colors[left];
2006+ *(line++) = context->colors[right];
2007+ *(line++) = context->colors[right];
2008+ }
2009+ }
2010+ }
2011+
2012+ render_video_buffer_updated(context->debug_fb_indices[VDP_DEBUG_VRAM], 1024);
2013+ }
2014+
2015+ if (context->enabled_debuggers & (1 << VDP_DEBUG_CRAM)) {
2016+ uint32_t starting_line = 512 - 32*4;
2017+ uint32_t *line = context->debug_fbs[VDP_DEBUG_CRAM]
2018+ + context->debug_fb_pitch[VDP_DEBUG_CRAM] * starting_line / sizeof(uint32_t);
2019+ for (int pal = 0; pal < 4; pal ++)
2020+ {
2021+ uint32_t *cur;
2022+ for (int y = 0; y < 31; y++)
2023+ {
2024+ cur = line;
2025+ for (int offset = 0; offset < 16; offset++)
2026+ {
2027+ for (int x = 0; x < 31; x++)
2028+ {
2029+ *(cur++) = context->colors[pal * 16 + offset];
2030+ }
2031+ *(cur++) = 0xFF000000;
2032+ }
2033+ line += context->debug_fb_pitch[VDP_DEBUG_CRAM] / sizeof(uint32_t);
2034+ }
2035+ cur = line;
2036+ for (int x = 0; x < 512; x++)
2037+ {
2038+ *(cur++) = 0xFF000000;
2039+ }
2040+ line += context->debug_fb_pitch[VDP_DEBUG_CRAM] / sizeof(uint32_t);
2041+ }
2042+ render_video_buffer_updated(context->debug_fb_indices[VDP_DEBUG_CRAM], 512);
2043+ context->debug_fbs[VDP_DEBUG_CRAM] = render_get_video_buffer(context->debug_fb_indices[VDP_DEBUG_CRAM], &context->debug_fb_pitch[VDP_DEBUG_CRAM]);
2044+ }
2045+ if (context->enabled_debuggers & (1 << VDP_DEBUG_COMPOSITE)) {
2046+ render_video_buffer_updated(context->debug_fb_indices[VDP_DEBUG_COMPOSITE], LINEBUF_SIZE);
2047+ context->debug_fbs[VDP_DEBUG_COMPOSITE] = render_get_video_buffer(context->debug_fb_indices[VDP_DEBUG_COMPOSITE], &context->debug_fb_pitch[VDP_DEBUG_COMPOSITE]);
2048+ }
2049+}
2050+
2051+void vdp_force_update_framebuffer(vdp_context *context)
2052+{
2053+ uint16_t lines_max = (context->flags2 & FLAG2_REGION_PAL)
2054+ ? 240 + BORDER_TOP_V30_PAL + BORDER_BOT_V30_PAL
2055+ : 224 + BORDER_TOP_V28 + BORDER_BOT_V28;
2056+
2057+ uint16_t to_fill = lines_max - context->output_lines;
2058+ memset(
2059+ ((char *)context->fb) + context->output_pitch * context->output_lines,
2060+ 0,
2061+ to_fill * context->output_pitch
2062+ );
2063+ render_video_buffer_updated(context->cur_buffer, context->h40_lines > context->output_lines / 2 ? LINEBUF_SIZE : (256+HORIZ_BORDER));
2064+ context->fb = render_get_video_buffer(context->cur_buffer, &context->output_pitch);
2065+ vdp_update_per_frame_debug(context);
2066+}
2067+
2068+static void advance_output_line(vdp_context *context)
2069+{
2070+ if (headless) {
2071+ if (context->vcounter == context->inactive_start) {
2072+ context->frame++;
2073+ }
2074+ context->vcounter &= 0x1FF;
2075+ } else {
2076+ uint16_t lines_max = (context->flags2 & FLAG2_REGION_PAL)
2077+ ? 240 + BORDER_TOP_V30_PAL + BORDER_BOT_V30_PAL
2078+ : 224 + BORDER_TOP_V28 + BORDER_BOT_V28;
2079+
2080+ if (context->output_lines == lines_max) {
2081+ render_video_buffer_updated(context->cur_buffer, context->h40_lines > (context->inactive_start + context->border_top) / 2 ? LINEBUF_SIZE : (256+HORIZ_BORDER));
2082+ context->cur_buffer = context->flags2 & FLAG2_EVEN_FIELD ? VIDEO_BUFFER_EVEN : VIDEO_BUFFER_ODD;
2083+ context->fb = render_get_video_buffer(context->cur_buffer, &context->output_pitch);
2084+ vdp_update_per_frame_debug(context);
2085+ context->h40_lines = 0;
2086+ context->frame++;
2087+ context->output_lines = 0;
2088+ }
2089+ uint32_t output_line = context->vcounter;
2090+ if (!(context->regs[REG_MODE_2] & BIT_MODE_5)) {
2091+ //vcounter increment occurs much later in Mode 4
2092+ output_line++;
2093+ }
2094+ if (output_line < context->inactive_start + context->border_bot && context->output_lines > 0) {
2095+ output_line = context->output_lines++;//context->border_top + context->vcounter;
2096+ } else if (output_line >= 0x200 - context->border_top) {
2097+ if (output_line == 0x200 - context->border_top) {
2098+ //We're at the top of the display, force context->output_lines to be zero to avoid
2099+ //potential screen rolling if the mode is changed at an inopportune time
2100+ context->output_lines = 0;
2101+ }
2102+ output_line = context->output_lines++;//context->vcounter - (0x200 - context->border_top);
2103+ } else {
2104+ output_line = INVALID_LINE;
2105+ }
2106+ context->output = (uint32_t *)(((char *)context->fb) + context->output_pitch * output_line);
2107+ context->done_output = context->output;
2108+#ifdef DEBUG_FB_FILL
2109+ for (int i = 0; i < LINEBUF_SIZE; i++)
2110+ {
2111+ context->output[i] = 0xFFFF00FF;
2112+ }
2113+#endif
2114+ if (output_line != INVALID_LINE && (context->regs[REG_MODE_4] & BIT_H40)) {
2115+ context->h40_lines++;
2116+ }
2117+ }
2118+}
2119+
2120+void vdp_release_framebuffer(vdp_context *context)
2121+{
2122+ render_video_buffer_updated(context->cur_buffer, context->h40_lines > (context->inactive_start + context->border_top) / 2 ? LINEBUF_SIZE : (256+HORIZ_BORDER));
2123+ context->output = context->fb = NULL;
2124+}
2125+
2126+void vdp_reacquire_framebuffer(vdp_context *context)
2127+{
2128+ context->fb = render_get_video_buffer(context->cur_buffer, &context->output_pitch);
2129+ uint16_t lines_max = (context->flags2 & FLAG2_REGION_PAL)
2130+ ? 240 + BORDER_TOP_V30_PAL + BORDER_BOT_V30_PAL
2131+ : 224 + BORDER_TOP_V28 + BORDER_BOT_V28;
2132+ if (context->output_lines <= lines_max && context->output_lines > 0) {
2133+ context->output = (uint32_t *)(((char *)context->fb) + context->output_pitch * (context->output_lines - 1));
2134+ } else {
2135+ context->output = (uint32_t *)(((char *)context->fb) + context->output_pitch * INVALID_LINE);
2136+ }
2137+}
2138+
2139+static void render_border_garbage(vdp_context *context, uint32_t address, uint8_t *buf, uint8_t buf_off, uint16_t col)
2140+{
2141+ uint8_t base = col >> 9 & 0x30;
2142+ for (int i = 0; i < 4; i++, address++)
2143+ {
2144+ uint8_t byte = context->vdpmem[address & 0xFFFF];
2145+ buf[(buf_off++) & SCROLL_BUFFER_MASK] = base | byte >> 4;
2146+ buf[(buf_off++) & SCROLL_BUFFER_MASK] = base | byte & 0xF;
2147+ }
2148+}
2149+
2150+static void draw_right_border(vdp_context *context)
2151+{
2152+ uint32_t *dst = context->output + BORDER_LEFT + ((context->regs[REG_MODE_4] & BIT_H40) ? 320 : 256);
2153+ uint8_t pixel = context->regs[REG_BG_COLOR] & 0x3F;
2154+ if ((context->test_port & TEST_BIT_DISABLE) != 0) {
2155+ pixel = 0x3F;
2156+ }
2157+ uint32_t bg_color = context->colors[pixel];
2158+ uint8_t test_layer = context->test_port >> 7 & 3;
2159+ if (test_layer) {
2160+ switch(test_layer)
2161+ {
2162+ case 1:
2163+ bg_color = context->colors[0];
2164+ for (int i = 0; i < BORDER_RIGHT; i++, dst++)
2165+ {
2166+ *dst = bg_color;
2167+ }
2168+ break;
2169+ case 2: {
2170+ //plane A
2171+ //TODO: Deal with Window layer
2172+ int i;
2173+ i = 0;
2174+ uint8_t buf_off = context->buf_a_off - (context->hscroll_a & 0xF);
2175+ //uint8_t *src = context->tmp_buf_a + ((context->buf_a_off + (i ? 0 : (16 - BORDER_LEFT) - (context->hscroll_a & 0xF))) & SCROLL_BUFFER_MASK);
2176+ for (; i < BORDER_RIGHT; buf_off++, i++, dst++)
2177+ {
2178+ *dst = context->colors[context->tmp_buf_a[buf_off & SCROLL_BUFFER_MASK] & 0x3F];
2179+ }
2180+ break;
2181+ }
2182+ case 3: {
2183+ //plane B
2184+ int i;
2185+ i = 0;
2186+ uint8_t buf_off = context->buf_b_off - (context->hscroll_b & 0xF);
2187+ //uint8_t *src = context->tmp_buf_b + ((context->buf_b_off + (i ? 0 : (16 - BORDER_LEFT) - (context->hscroll_b & 0xF))) & SCROLL_BUFFER_MASK);
2188+ for (; i < BORDER_RIGHT; buf_off++, i++, dst++)
2189+ {
2190+ *dst = context->colors[context->tmp_buf_b[buf_off & SCROLL_BUFFER_MASK] & 0x3F];
2191+ }
2192+ break;
2193+ }
2194+ }
2195+ } else {
2196+ for (int i = 0; i < BORDER_RIGHT; i++, dst++)
2197+ {
2198+ *dst = bg_color;
2199+ }
2200+ }
2201+ context->done_output = dst;
2202+ context->buf_a_off = (context->buf_a_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_MASK;
2203+ context->buf_b_off = (context->buf_b_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_MASK;
2204+}
2205+
2206+#define CHECK_ONLY if (context->cycles >= target_cycles) { return; }
2207+#define CHECK_LIMIT if (context->flags & FLAG_DMA_RUN) { run_dma_src(context, -1); } context->hslot++; context->cycles += slot_cycles; CHECK_ONLY
2208+
2209+#define COLUMN_RENDER_BLOCK(column, startcyc) \
2210+ case startcyc:\
2211+ read_map_scroll_a(column, context->vcounter, context);\
2212+ CHECK_LIMIT\
2213+ case ((startcyc+1)&0xFF):\
2214+ external_slot(context);\
2215+ CHECK_LIMIT\
2216+ case ((startcyc+2)&0xFF):\
2217+ render_map_1(context);\
2218+ CHECK_LIMIT\
2219+ case ((startcyc+3)&0xFF):\
2220+ render_map_2(context);\
2221+ CHECK_LIMIT\
2222+ case ((startcyc+4)&0xFF):\
2223+ read_map_scroll_b(column, context->vcounter, context);\
2224+ CHECK_LIMIT\
2225+ case ((startcyc+5)&0xFF):\
2226+ read_sprite_x(context->vcounter, context);\
2227+ CHECK_LIMIT\
2228+ case ((startcyc+6)&0xFF):\
2229+ render_map_3(context);\
2230+ CHECK_LIMIT\
2231+ case ((startcyc+7)&0xFF):\
2232+ render_map_output(context->vcounter, column, context);\
2233+ CHECK_LIMIT
2234+
2235+#define COLUMN_RENDER_BLOCK_REFRESH(column, startcyc) \
2236+ case startcyc:\
2237+ read_map_scroll_a(column, context->vcounter, context);\
2238+ CHECK_LIMIT\
2239+ case (startcyc+1):\
2240+ /* refresh, no don't run dma src */\
2241+ context->hslot++;\
2242+ context->cycles += slot_cycles;\
2243+ CHECK_ONLY\
2244+ case (startcyc+2):\
2245+ render_map_1(context);\
2246+ CHECK_LIMIT\
2247+ case (startcyc+3):\
2248+ render_map_2(context);\
2249+ CHECK_LIMIT\
2250+ case (startcyc+4):\
2251+ read_map_scroll_b(column, context->vcounter, context);\
2252+ CHECK_LIMIT\
2253+ case (startcyc+5):\
2254+ read_sprite_x(context->vcounter, context);\
2255+ CHECK_LIMIT\
2256+ case (startcyc+6):\
2257+ render_map_3(context);\
2258+ CHECK_LIMIT\
2259+ case (startcyc+7):\
2260+ render_map_output(context->vcounter, column, context);\
2261+ CHECK_LIMIT
2262+
2263+#define COLUMN_RENDER_BLOCK_MODE4(column, startcyc) \
2264+ case startcyc:\
2265+ read_map_mode4(column, context->vcounter, context);\
2266+ CHECK_LIMIT\
2267+ case ((startcyc+1)&0xFF):\
2268+ if (column & 3) {\
2269+ scan_sprite_table_mode4(context);\
2270+ } else {\
2271+ external_slot(context);\
2272+ }\
2273+ CHECK_LIMIT\
2274+ case ((startcyc+2)&0xFF):\
2275+ fetch_map_mode4(column, context->vcounter, context);\
2276+ CHECK_LIMIT\
2277+ case ((startcyc+3)&0xFF):\
2278+ render_map_mode4(context->vcounter, column, context);\
2279+ CHECK_LIMIT
2280+
2281+#define CHECK_LIMIT_HSYNC(slot) \
2282+ if (context->flags & FLAG_DMA_RUN) { run_dma_src(context, -1); } \
2283+ if (slot >= HSYNC_SLOT_H40 && slot < HSYNC_END_H40) {\
2284+ context->cycles += h40_hsync_cycles[slot - HSYNC_SLOT_H40];\
2285+ } else {\
2286+ context->cycles += slot_cycles;\
2287+ }\
2288+ if (slot == 182) {\
2289+ context->hslot = 229;\
2290+ } else {\
2291+ context->hslot++;\
2292+ }\
2293+ CHECK_ONLY
2294+
2295+#define SPRITE_RENDER_H40(slot) \
2296+ case slot:\
2297+ if ((slot) == BG_START_SLOT + LINEBUF_SIZE/2) {\
2298+ advance_output_line(context);\
2299+ }\
2300+ if (slot == 168 || slot == 247 || slot == 248) {\
2301+ render_border_garbage(\
2302+ context,\
2303+ context->sprite_draw_list[context->cur_slot].address,\
2304+ context->tmp_buf_b,\
2305+ context->buf_b_off + (slot == 247 ? 0 : 8),\
2306+ slot == 247 ? context->col_1 : context->col_2\
2307+ );\
2308+ if (slot == 248) {\
2309+ context->buf_a_off = (context->buf_a_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_MASK;\
2310+ context->buf_b_off = (context->buf_b_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_MASK;\
2311+ }\
2312+ } else if (slot == 243) {\
2313+ render_border_garbage(\
2314+ context,\
2315+ context->sprite_draw_list[context->cur_slot].address,\
2316+ context->tmp_buf_a,\
2317+ context->buf_a_off,\
2318+ context->col_1\
2319+ );\
2320+ } else if (slot == 169) {\
2321+ draw_right_border(context);\
2322+ }\
2323+ render_sprite_cells( context);\
2324+ scan_sprite_table(context->vcounter, context);\
2325+ CHECK_LIMIT_HSYNC(slot)
2326+
2327+//Note that the line advancement check will fail if BG_START_SLOT is > 6
2328+//as we're bumping up against the hcounter jump
2329+#define SPRITE_RENDER_H32(slot) \
2330+ case slot:\
2331+ if ((slot) == BG_START_SLOT + (256+HORIZ_BORDER)/2) {\
2332+ advance_output_line(context);\
2333+ }\
2334+ if (slot == 136 || slot == 247 || slot == 248) {\
2335+ render_border_garbage(\
2336+ context,\
2337+ context->sprite_draw_list[context->cur_slot].address,\
2338+ context->tmp_buf_b,\
2339+ context->buf_b_off + (slot == 247 ? 0 : 8),\
2340+ slot == 247 ? context->col_1 : context->col_2\
2341+ );\
2342+ if (slot == 248) {\
2343+ context->buf_a_off = (context->buf_a_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_MASK;\
2344+ context->buf_b_off = (context->buf_b_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_MASK;\
2345+ }\
2346+ } else if (slot == 137) {\
2347+ draw_right_border(context);\
2348+ }\
2349+ render_sprite_cells( context);\
2350+ scan_sprite_table(context->vcounter, context);\
2351+ if (context->flags & FLAG_DMA_RUN) { run_dma_src(context, -1); } \
2352+ if (slot == 147) {\
2353+ context->hslot = 233;\
2354+ } else {\
2355+ context->hslot++;\
2356+ }\
2357+ context->cycles += slot_cycles;\
2358+ CHECK_ONLY
2359+
2360+#define MODE4_CHECK_SLOT_LINE(slot) \
2361+ if (context->flags & FLAG_DMA_RUN) { run_dma_src(context, -1); } \
2362+ if ((slot) == BG_START_SLOT + (256+HORIZ_BORDER)/2) {\
2363+ advance_output_line(context);\
2364+ }\
2365+ if ((slot) == 147) {\
2366+ context->hslot = 233;\
2367+ } else {\
2368+ context->hslot++;\
2369+ }\
2370+ context->cycles += slot_cycles;\
2371+ if ((slot+1) == LINE_CHANGE_MODE4) {\
2372+ vdp_advance_line(context);\
2373+ if (context->vcounter == 192) {\
2374+ return;\
2375+ }\
2376+ }\
2377+ CHECK_ONLY
2378+
2379+#define CALC_SLOT(slot, increment) ((slot+increment) > 147 && (slot+increment) < 233 ? (slot+increment-148+233): (slot+increment))
2380+
2381+#define SPRITE_RENDER_H32_MODE4(slot) \
2382+ case slot:\
2383+ read_sprite_x_mode4(context);\
2384+ MODE4_CHECK_SLOT_LINE(slot)\
2385+ case CALC_SLOT(slot, 1):\
2386+ read_sprite_x_mode4(context);\
2387+ MODE4_CHECK_SLOT_LINE(CALC_SLOT(slot,1))\
2388+ case CALC_SLOT(slot, 2):\
2389+ fetch_sprite_cells_mode4(context);\
2390+ MODE4_CHECK_SLOT_LINE(CALC_SLOT(slot, 2))\
2391+ case CALC_SLOT(slot, 3):\
2392+ if ((slot + 3) == 140) {\
2393+ uint32_t *dst = context->output + BORDER_LEFT + 256 + 8;\
2394+ uint32_t bgcolor = context->colors[0x10 | (context->regs[REG_BG_COLOR] & 0xF) + MODE4_OFFSET];\
2395+ for (int i = 0; i < BORDER_RIGHT-8; i++, dst++)\
2396+ {\
2397+ *dst = bgcolor;\
2398+ }\
2399+ context->done_output = dst;\
2400+ }\
2401+ render_sprite_cells_mode4(context);\
2402+ MODE4_CHECK_SLOT_LINE(CALC_SLOT(slot, 3))\
2403+ case CALC_SLOT(slot, 4):\
2404+ fetch_sprite_cells_mode4(context);\
2405+ MODE4_CHECK_SLOT_LINE(CALC_SLOT(slot, 4))\
2406+ case CALC_SLOT(slot, 5):\
2407+ render_sprite_cells_mode4(context);\
2408+ MODE4_CHECK_SLOT_LINE(CALC_SLOT(slot, 5))
2409+
2410+static void vdp_h40(vdp_context * context, uint32_t target_cycles)
2411+{
2412+ uint16_t address;
2413+ uint32_t mask;
2414+ uint32_t const slot_cycles = MCLKS_SLOT_H40;
2415+ switch(context->hslot)
2416+ {
2417+ for (;;)
2418+ {
2419+ case 165:
2420+ if (!(context->regs[REG_MODE_3] & BIT_VSCROLL)) {
2421+ //TODO: Develop some tests on hardware to see when vscroll latch actually happens for full plane mode
2422+ //See note in vdp_h32 for why this was originally moved out of read_map_scroll
2423+ //Skitchin' has a similar problem, but uses H40 mode. It seems to be able to hit the extern slot at 232
2424+ //pretty consistently
2425+ context->vscroll_latch[0] = context->vsram[0];
2426+ context->vscroll_latch[1] = context->vsram[1];
2427+ }
2428+ if (context->state == PREPARING) {
2429+ uint32_t bg_color = context->colors[context->regs[REG_BG_COLOR] & 0x3F];
2430+ uint32_t *dst = context->output + (context->hslot - BG_START_SLOT) * 2;
2431+ if (dst >= context->done_output) {
2432+ *dst = bg_color;
2433+ }
2434+ dst++;
2435+ if (dst >= context->done_output) {
2436+ *dst = bg_color;
2437+ }
2438+ external_slot(context);
2439+ } else {
2440+ render_sprite_cells(context);
2441+ }
2442+ CHECK_LIMIT
2443+ case 166:
2444+ if (context->state == PREPARING) {
2445+ uint32_t bg_color = context->colors[context->regs[REG_BG_COLOR] & 0x3F];
2446+ uint32_t *dst = context->output + (context->hslot - BG_START_SLOT) * 2;
2447+ if (dst >= context->done_output) {
2448+ *dst = bg_color;
2449+ }
2450+ dst++;
2451+ if (dst >= context->done_output) {
2452+ *dst = bg_color;
2453+ }
2454+ external_slot(context);
2455+ } else {
2456+ render_sprite_cells(context);
2457+ }
2458+ if (context->vcounter == context->inactive_start) {
2459+ context->hslot++;
2460+ context->cycles += slot_cycles;
2461+ return;
2462+ }
2463+ CHECK_LIMIT
2464+ //sprite attribute table scan starts
2465+ case 167:
2466+ if (context->state == PREPARING) {
2467+ uint32_t bg_color = context->colors[context->regs[REG_BG_COLOR] & 0x3F];
2468+ uint32_t *dst = context->output + (context->hslot - BG_START_SLOT) * 2;
2469+ for (int i = 0; i < LINEBUF_SIZE - 2 * (context->hslot - BG_START_SLOT); i++, dst++)
2470+ {
2471+ if (dst >= context->done_output) {
2472+ *dst = bg_color;
2473+ }
2474+ }
2475+ }
2476+ context->sprite_index = 0x80;
2477+ context->slot_counter = 0;
2478+ render_border_garbage(
2479+ context,
2480+ context->sprite_draw_list[context->cur_slot].address,
2481+ context->tmp_buf_b, context->buf_b_off,
2482+ context->col_1
2483+ );
2484+ render_sprite_cells(context);
2485+ scan_sprite_table(context->vcounter, context);
2486+ CHECK_LIMIT
2487+ SPRITE_RENDER_H40(168)
2488+ SPRITE_RENDER_H40(169)
2489+ SPRITE_RENDER_H40(170)
2490+ SPRITE_RENDER_H40(171)
2491+ SPRITE_RENDER_H40(172)
2492+ SPRITE_RENDER_H40(173)
2493+ SPRITE_RENDER_H40(174)
2494+ SPRITE_RENDER_H40(175)
2495+ SPRITE_RENDER_H40(176)
2496+ SPRITE_RENDER_H40(177)//End of border?
2497+ SPRITE_RENDER_H40(178)
2498+ SPRITE_RENDER_H40(179)
2499+ SPRITE_RENDER_H40(180)
2500+ SPRITE_RENDER_H40(181)
2501+ SPRITE_RENDER_H40(182)
2502+ SPRITE_RENDER_H40(229)
2503+ //!HSYNC asserted
2504+ SPRITE_RENDER_H40(230)
2505+ SPRITE_RENDER_H40(231)
2506+ case 232:
2507+ external_slot(context);
2508+ CHECK_LIMIT_HSYNC(232)
2509+ SPRITE_RENDER_H40(233)
2510+ SPRITE_RENDER_H40(234)
2511+ SPRITE_RENDER_H40(235)
2512+ SPRITE_RENDER_H40(236)
2513+ SPRITE_RENDER_H40(237)
2514+ SPRITE_RENDER_H40(238)
2515+ SPRITE_RENDER_H40(239)
2516+ SPRITE_RENDER_H40(240)
2517+ SPRITE_RENDER_H40(241)
2518+ SPRITE_RENDER_H40(242)
2519+ SPRITE_RENDER_H40(243) //provides "garbage" for border when plane A selected
2520+ case 244:
2521+ address = (context->regs[REG_HSCROLL] & 0x3F) << 10;
2522+ mask = 0;
2523+ if (context->regs[REG_MODE_3] & 0x2) {
2524+ mask |= 0xF8;
2525+ }
2526+ if (context->regs[REG_MODE_3] & 0x1) {
2527+ mask |= 0x7;
2528+ }
2529+ render_border_garbage(context, address, context->tmp_buf_a, context->buf_a_off+8, context->col_2);
2530+ address += (context->vcounter & mask) * 4;
2531+ context->hscroll_a = context->vdpmem[address] << 8 | context->vdpmem[address+1];
2532+ context->hscroll_b = context->vdpmem[address+2] << 8 | context->vdpmem[address+3];
2533+ //printf("%d: HScroll A: %d, HScroll B: %d\n", context->vcounter, context->hscroll_a, context->hscroll_b);
2534+ if (context->flags & FLAG_DMA_RUN) { run_dma_src(context, -1); }
2535+ context->hslot++;
2536+ context->cycles += h40_hsync_cycles[14];
2537+ CHECK_ONLY //provides "garbage" for border when plane A selected
2538+ //!HSYNC high
2539+ SPRITE_RENDER_H40(245)
2540+ SPRITE_RENDER_H40(246)
2541+ SPRITE_RENDER_H40(247) //provides "garbage" for border when plane B selected
2542+ SPRITE_RENDER_H40(248) //provides "garbage" for border when plane B selected
2543+ case 249:
2544+ read_map_scroll_a(0, context->vcounter, context);
2545+ CHECK_LIMIT
2546+ SPRITE_RENDER_H40(250)
2547+ case 251:
2548+ render_map_1(context);
2549+ scan_sprite_table(context->vcounter, context);//Just a guess
2550+ CHECK_LIMIT
2551+ case 252:
2552+ render_map_2(context);
2553+ scan_sprite_table(context->vcounter, context);//Just a guess
2554+ CHECK_LIMIT
2555+ case 253:
2556+ read_map_scroll_b(0, context->vcounter, context);
2557+ CHECK_LIMIT
2558+ SPRITE_RENDER_H40(254)
2559+ case 255:
2560+ render_map_3(context);
2561+ scan_sprite_table(context->vcounter, context);//Just a guess
2562+ CHECK_LIMIT
2563+ case 0:
2564+ render_map_output(context->vcounter, 0, context);
2565+ scan_sprite_table(context->vcounter, context);//Just a guess
2566+ //seems like the sprite table scan fills a shift register
2567+ //values are FIFO, but unused slots precede used slots
2568+ //so we set cur_slot to slot_counter and let it wrap around to
2569+ //the beginning of the list
2570+ context->cur_slot = context->slot_counter;
2571+ context->sprite_draws = MAX_DRAWS;
2572+ context->flags &= (~FLAG_CAN_MASK & ~FLAG_MASKED);
2573+ CHECK_LIMIT
2574+ COLUMN_RENDER_BLOCK(2, 1)
2575+ COLUMN_RENDER_BLOCK(4, 9)
2576+ COLUMN_RENDER_BLOCK(6, 17)
2577+ COLUMN_RENDER_BLOCK_REFRESH(8, 25)
2578+ COLUMN_RENDER_BLOCK(10, 33)
2579+ COLUMN_RENDER_BLOCK(12, 41)
2580+ COLUMN_RENDER_BLOCK(14, 49)
2581+ COLUMN_RENDER_BLOCK_REFRESH(16, 57)
2582+ COLUMN_RENDER_BLOCK(18, 65)
2583+ COLUMN_RENDER_BLOCK(20, 73)
2584+ COLUMN_RENDER_BLOCK(22, 81)
2585+ COLUMN_RENDER_BLOCK_REFRESH(24, 89)
2586+ COLUMN_RENDER_BLOCK(26, 97)
2587+ COLUMN_RENDER_BLOCK(28, 105)
2588+ COLUMN_RENDER_BLOCK(30, 113)
2589+ COLUMN_RENDER_BLOCK_REFRESH(32, 121)
2590+ COLUMN_RENDER_BLOCK(34, 129)
2591+ COLUMN_RENDER_BLOCK(36, 137)
2592+ COLUMN_RENDER_BLOCK(38, 145)
2593+ COLUMN_RENDER_BLOCK_REFRESH(40, 153)
2594+ case 161:
2595+ external_slot(context);
2596+ CHECK_LIMIT
2597+ case 162:
2598+ external_slot(context);
2599+ CHECK_LIMIT
2600+ //sprite render to line buffer starts
2601+ case 163:
2602+ context->cur_slot = MAX_DRAWS-1;
2603+ memset(context->linebuf, 0, LINEBUF_SIZE);
2604+ render_border_garbage(
2605+ context,
2606+ context->sprite_draw_list[context->cur_slot].address,
2607+ context->tmp_buf_a, context->buf_a_off,
2608+ context->col_1
2609+ );
2610+ render_sprite_cells(context);
2611+ CHECK_LIMIT
2612+ case 164:
2613+ render_border_garbage(
2614+ context,
2615+ context->sprite_draw_list[context->cur_slot].address,
2616+ context->tmp_buf_a, context->buf_a_off + 8,
2617+ context->col_2
2618+ );
2619+ render_sprite_cells(context);
2620+ if (context->flags & FLAG_DMA_RUN) {
2621+ run_dma_src(context, -1);
2622+ }
2623+ context->hslot++;
2624+ context->cycles += slot_cycles;
2625+ vdp_advance_line(context);
2626+ CHECK_ONLY
2627+ }
2628+ default:
2629+ context->hslot++;
2630+ context->cycles += slot_cycles;
2631+ return;
2632+ }
2633+}
2634+
2635+static void vdp_h32(vdp_context * context, uint32_t target_cycles)
2636+{
2637+ uint16_t address;
2638+ uint32_t mask;
2639+ uint32_t const slot_cycles = MCLKS_SLOT_H32;
2640+ switch(context->hslot)
2641+ {
2642+ for (;;)
2643+ {
2644+ case 133:
2645+ if (context->state == PREPARING) {
2646+ uint32_t bg_color = context->colors[context->regs[REG_BG_COLOR] & 0x3F];
2647+ uint32_t *dst = context->output + (context->hslot - BG_START_SLOT) * 2;
2648+ if (dst >= context->done_output) {
2649+ *dst = bg_color;
2650+ }
2651+ dst++;
2652+ if (dst >= context->done_output) {
2653+ *dst = bg_color;
2654+ }
2655+ external_slot(context);
2656+ } else {
2657+ render_sprite_cells(context);
2658+ }
2659+ CHECK_LIMIT
2660+ case 134:
2661+ if (context->state == PREPARING) {
2662+ uint32_t bg_color = context->colors[context->regs[REG_BG_COLOR] & 0x3F];
2663+ uint32_t *dst = context->output + (context->hslot - BG_START_SLOT) * 2;
2664+ if (dst >= context->done_output) {
2665+ *dst = bg_color;
2666+ }
2667+ dst++;
2668+ if (dst >= context->done_output) {
2669+ *dst = bg_color;
2670+ }
2671+ external_slot(context);
2672+ } else {
2673+ render_sprite_cells(context);
2674+ }
2675+ if (context->vcounter == context->inactive_start) {
2676+ context->hslot++;
2677+ context->cycles += slot_cycles;
2678+ return;
2679+ }
2680+ CHECK_LIMIT
2681+ //sprite attribute table scan starts
2682+ case 135:
2683+ if (context->state == PREPARING) {
2684+ uint32_t bg_color = context->colors[context->regs[REG_BG_COLOR] & 0x3F];
2685+ uint32_t *dst = context->output + (context->hslot - BG_START_SLOT) * 2;
2686+ for (int i = 0; i < (256+HORIZ_BORDER) - 2 * (context->hslot - BG_START_SLOT); i++)
2687+ {
2688+ if (dst >= context->done_output) {
2689+ *(dst++) = bg_color;
2690+ }
2691+ }
2692+ }
2693+ context->sprite_index = 0x80;
2694+ context->slot_counter = 0;
2695+ render_border_garbage(
2696+ context,
2697+ context->sprite_draw_list[context->cur_slot].address,
2698+ context->tmp_buf_b, context->buf_b_off,
2699+ context->col_1
2700+ );
2701+ render_sprite_cells(context);
2702+ scan_sprite_table(context->vcounter, context);
2703+ CHECK_LIMIT
2704+ SPRITE_RENDER_H32(136)
2705+ SPRITE_RENDER_H32(137)
2706+ SPRITE_RENDER_H32(138)
2707+ SPRITE_RENDER_H32(139)
2708+ SPRITE_RENDER_H32(140)
2709+ SPRITE_RENDER_H32(141)
2710+ SPRITE_RENDER_H32(142)
2711+ SPRITE_RENDER_H32(143)
2712+ SPRITE_RENDER_H32(144)
2713+ case 145:
2714+ external_slot(context);
2715+ CHECK_LIMIT
2716+ SPRITE_RENDER_H32(146)
2717+ SPRITE_RENDER_H32(147)
2718+ SPRITE_RENDER_H32(233)
2719+ SPRITE_RENDER_H32(234)
2720+ SPRITE_RENDER_H32(235)
2721+ //HSYNC start
2722+ SPRITE_RENDER_H32(236)
2723+ SPRITE_RENDER_H32(237)
2724+ SPRITE_RENDER_H32(238)
2725+ SPRITE_RENDER_H32(239)
2726+ SPRITE_RENDER_H32(240)
2727+ SPRITE_RENDER_H32(241)
2728+ SPRITE_RENDER_H32(242)
2729+ case 243:
2730+ if (!(context->regs[REG_MODE_3] & BIT_VSCROLL)) {
2731+ //TODO: Develop some tests on hardware to see when vscroll latch actually happens for full plane mode
2732+ //Top Gear 2 has a very efficient HINT routine that can occassionally hit this slot with a VSRAM write
2733+ //Since CRAM-updatnig HINT routines seem to indicate that my HINT latency is perhaps slightly too high
2734+ //the most reasonable explanation is that vscroll is latched before this slot, but tests are needed
2735+ //to confirm that one way or another
2736+ context->vscroll_latch[0] = context->vsram[0];
2737+ context->vscroll_latch[1] = context->vsram[1];
2738+ }
2739+ external_slot(context);
2740+ //provides "garbage" for border when plane A selected
2741+ render_border_garbage(
2742+ context,
2743+ context->sprite_draw_list[context->cur_slot].address,
2744+ context->tmp_buf_a,
2745+ context->buf_a_off,
2746+ context->col_1
2747+ );
2748+ CHECK_LIMIT
2749+ case 244:
2750+ address = (context->regs[REG_HSCROLL] & 0x3F) << 10;
2751+ mask = 0;
2752+ if (context->regs[REG_MODE_3] & 0x2) {
2753+ mask |= 0xF8;
2754+ }
2755+ if (context->regs[REG_MODE_3] & 0x1) {
2756+ mask |= 0x7;
2757+ }
2758+ render_border_garbage(context, address, context->tmp_buf_a, context->buf_a_off+8, context->col_2);
2759+ address += (context->vcounter & mask) * 4;
2760+ context->hscroll_a = context->vdpmem[address] << 8 | context->vdpmem[address+1];
2761+ context->hscroll_b = context->vdpmem[address+2] << 8 | context->vdpmem[address+3];
2762+ //printf("%d: HScroll A: %d, HScroll B: %d\n", context->vcounter, context->hscroll_a, context->hscroll_b);
2763+ CHECK_LIMIT //provides "garbage" for border when plane A selected
2764+ SPRITE_RENDER_H32(245)
2765+ SPRITE_RENDER_H32(246)
2766+ SPRITE_RENDER_H32(247) //provides "garbage" for border when plane B selected
2767+ SPRITE_RENDER_H32(248) //provides "garbage" for border when plane B selected
2768+ //!HSYNC high
2769+ case 249:
2770+ read_map_scroll_a(0, context->vcounter, context);
2771+ CHECK_LIMIT
2772+ SPRITE_RENDER_H32(250)
2773+ case 251:
2774+ render_map_1(context);
2775+ scan_sprite_table(context->vcounter, context);//Just a guess
2776+ CHECK_LIMIT
2777+ case 252:
2778+ render_map_2(context);
2779+ scan_sprite_table(context->vcounter, context);//Just a guess
2780+ CHECK_LIMIT
2781+ case 253:
2782+ read_map_scroll_b(0, context->vcounter, context);
2783+ CHECK_LIMIT
2784+ case 254:
2785+ render_sprite_cells(context);
2786+ scan_sprite_table(context->vcounter, context);
2787+ CHECK_LIMIT
2788+ case 255:
2789+ render_map_3(context);
2790+ scan_sprite_table(context->vcounter, context);//Just a guess
2791+ CHECK_LIMIT
2792+ case 0:
2793+ render_map_output(context->vcounter, 0, context);
2794+ scan_sprite_table(context->vcounter, context);//Just a guess
2795+ //reverse context slot counter so it counts the number of sprite slots
2796+ //filled rather than the number of available slots
2797+ //context->slot_counter = MAX_SPRITES_LINE - context->slot_counter;
2798+ context->cur_slot = context->slot_counter;
2799+ context->sprite_draws = MAX_DRAWS_H32;
2800+ context->flags &= (~FLAG_CAN_MASK & ~FLAG_MASKED);
2801+ CHECK_LIMIT
2802+ COLUMN_RENDER_BLOCK(2, 1)
2803+ COLUMN_RENDER_BLOCK(4, 9)
2804+ COLUMN_RENDER_BLOCK(6, 17)
2805+ COLUMN_RENDER_BLOCK_REFRESH(8, 25)
2806+ COLUMN_RENDER_BLOCK(10, 33)
2807+ COLUMN_RENDER_BLOCK(12, 41)
2808+ COLUMN_RENDER_BLOCK(14, 49)
2809+ COLUMN_RENDER_BLOCK_REFRESH(16, 57)
2810+ COLUMN_RENDER_BLOCK(18, 65)
2811+ COLUMN_RENDER_BLOCK(20, 73)
2812+ COLUMN_RENDER_BLOCK(22, 81)
2813+ COLUMN_RENDER_BLOCK_REFRESH(24, 89)
2814+ COLUMN_RENDER_BLOCK(26, 97)
2815+ COLUMN_RENDER_BLOCK(28, 105)
2816+ COLUMN_RENDER_BLOCK(30, 113)
2817+ COLUMN_RENDER_BLOCK_REFRESH(32, 121)
2818+ case 129:
2819+ external_slot(context);
2820+ CHECK_LIMIT
2821+ case 130: {
2822+ external_slot(context);
2823+ CHECK_LIMIT
2824+ }
2825+ //sprite render to line buffer starts
2826+ case 131:
2827+ context->cur_slot = MAX_DRAWS_H32-1;
2828+ memset(context->linebuf, 0, LINEBUF_SIZE);
2829+ render_border_garbage(
2830+ context,
2831+ context->sprite_draw_list[context->cur_slot].address,
2832+ context->tmp_buf_a, context->buf_a_off,
2833+ context->col_1
2834+ );
2835+ render_sprite_cells(context);
2836+ CHECK_LIMIT
2837+ case 132:
2838+ render_border_garbage(
2839+ context,
2840+ context->sprite_draw_list[context->cur_slot].address,
2841+ context->tmp_buf_a, context->buf_a_off + 8,
2842+ context->col_2
2843+ );
2844+ render_sprite_cells(context);
2845+ if (context->flags & FLAG_DMA_RUN) {
2846+ run_dma_src(context, -1);
2847+ }
2848+ context->hslot++;
2849+ context->cycles += slot_cycles;
2850+ vdp_advance_line(context);
2851+ CHECK_ONLY
2852+ }
2853+ default:
2854+ context->hslot++;
2855+ context->cycles += MCLKS_SLOT_H32;
2856+ }
2857+}
2858+
2859+static void vdp_h32_mode4(vdp_context * context, uint32_t target_cycles)
2860+{
2861+ uint16_t address;
2862+ uint32_t mask;
2863+ uint32_t const slot_cycles = MCLKS_SLOT_H32;
2864+ switch(context->hslot)
2865+ {
2866+ for (;;)
2867+ {
2868+ //sprite rendering starts
2869+ SPRITE_RENDER_H32_MODE4(137)
2870+ SPRITE_RENDER_H32_MODE4(143)
2871+ case 234:
2872+ external_slot(context);
2873+ CHECK_LIMIT
2874+ case 235:
2875+ external_slot(context);
2876+ CHECK_LIMIT
2877+ //!HSYNC low
2878+ case 236:
2879+ external_slot(context);
2880+ CHECK_LIMIT
2881+ case 237:
2882+ external_slot(context);
2883+ CHECK_LIMIT
2884+ case 238:
2885+ external_slot(context);
2886+ CHECK_LIMIT
2887+ SPRITE_RENDER_H32_MODE4(239)
2888+ SPRITE_RENDER_H32_MODE4(245)
2889+ case 251:
2890+ external_slot(context);
2891+ CHECK_LIMIT
2892+ case 252:
2893+ external_slot(context);
2894+ if (context->regs[REG_MODE_1] & BIT_HSCRL_LOCK && context->vcounter < 16) {
2895+ context->hscroll_a = 0;
2896+ } else {
2897+ context->hscroll_a = context->regs[REG_X_SCROLL];
2898+ }
2899+ CHECK_LIMIT
2900+ case 253:
2901+ context->sprite_index = 0;
2902+ context->slot_counter = MAX_DRAWS_H32_MODE4;
2903+ scan_sprite_table_mode4(context);
2904+ CHECK_LIMIT
2905+ case 254:
2906+ scan_sprite_table_mode4(context);
2907+ CHECK_LIMIT
2908+ case 255:
2909+ scan_sprite_table_mode4(context);
2910+ CHECK_LIMIT
2911+ case 0: {
2912+ scan_sprite_table_mode4(context);
2913+ uint32_t *dst = context->output;;
2914+ uint32_t bgcolor = context->colors[0x10 | (context->regs[REG_BG_COLOR] & 0xF) + MODE4_OFFSET];
2915+ for (int i = 0; i < BORDER_LEFT-8; i++, dst++)
2916+ {
2917+ *dst = bgcolor;
2918+ }
2919+ context->done_output = dst;
2920+ CHECK_LIMIT
2921+ }
2922+ case 1:
2923+ scan_sprite_table_mode4(context);
2924+ CHECK_LIMIT
2925+ case 2:
2926+ scan_sprite_table_mode4(context);
2927+ CHECK_LIMIT
2928+ case 3:
2929+ scan_sprite_table_mode4(context);
2930+ CHECK_LIMIT
2931+ case 4: {
2932+ scan_sprite_table_mode4(context);
2933+ context->buf_a_off = 8;
2934+ memset(context->tmp_buf_a, 0, 8);
2935+ uint32_t *dst = context->output + BORDER_LEFT - 8;
2936+ uint32_t bgcolor = context->colors[0x10 | (context->regs[REG_BG_COLOR] & 0xF) + MODE4_OFFSET];
2937+ for (int i = 0; i < 8; i++, dst++)
2938+ {
2939+ *dst = bgcolor;
2940+ }
2941+ context->done_output = dst;
2942+ CHECK_LIMIT
2943+ }
2944+ COLUMN_RENDER_BLOCK_MODE4(0, 5)
2945+ COLUMN_RENDER_BLOCK_MODE4(1, 9)
2946+ COLUMN_RENDER_BLOCK_MODE4(2, 13)
2947+ COLUMN_RENDER_BLOCK_MODE4(3, 17)
2948+ COLUMN_RENDER_BLOCK_MODE4(4, 21)
2949+ COLUMN_RENDER_BLOCK_MODE4(5, 25)
2950+ COLUMN_RENDER_BLOCK_MODE4(6, 29)
2951+ COLUMN_RENDER_BLOCK_MODE4(7, 33)
2952+ COLUMN_RENDER_BLOCK_MODE4(8, 37)
2953+ COLUMN_RENDER_BLOCK_MODE4(9, 41)
2954+ COLUMN_RENDER_BLOCK_MODE4(10, 45)
2955+ COLUMN_RENDER_BLOCK_MODE4(11, 49)
2956+ COLUMN_RENDER_BLOCK_MODE4(12, 53)
2957+ COLUMN_RENDER_BLOCK_MODE4(13, 57)
2958+ COLUMN_RENDER_BLOCK_MODE4(14, 61)
2959+ COLUMN_RENDER_BLOCK_MODE4(15, 65)
2960+ COLUMN_RENDER_BLOCK_MODE4(16, 69)
2961+ COLUMN_RENDER_BLOCK_MODE4(17, 73)
2962+ COLUMN_RENDER_BLOCK_MODE4(18, 77)
2963+ COLUMN_RENDER_BLOCK_MODE4(19, 81)
2964+ COLUMN_RENDER_BLOCK_MODE4(20, 85)
2965+ COLUMN_RENDER_BLOCK_MODE4(21, 89)
2966+ COLUMN_RENDER_BLOCK_MODE4(22, 93)
2967+ COLUMN_RENDER_BLOCK_MODE4(23, 97)
2968+ COLUMN_RENDER_BLOCK_MODE4(24, 101)
2969+ COLUMN_RENDER_BLOCK_MODE4(25, 105)
2970+ COLUMN_RENDER_BLOCK_MODE4(26, 109)
2971+ COLUMN_RENDER_BLOCK_MODE4(27, 113)
2972+ COLUMN_RENDER_BLOCK_MODE4(28, 117)
2973+ COLUMN_RENDER_BLOCK_MODE4(29, 121)
2974+ COLUMN_RENDER_BLOCK_MODE4(30, 125)
2975+ COLUMN_RENDER_BLOCK_MODE4(31, 129)
2976+ case 133:
2977+ external_slot(context);
2978+ CHECK_LIMIT
2979+ case 134:
2980+ external_slot(context);
2981+ CHECK_LIMIT
2982+ case 135:
2983+ external_slot(context);
2984+ CHECK_LIMIT
2985+ case 136: {
2986+ external_slot(context);
2987+ //set things up for sprite rendering in the next slot
2988+ memset(context->linebuf, 0, LINEBUF_SIZE);
2989+ context->cur_slot = context->sprite_index = MAX_DRAWS_H32_MODE4-1;
2990+ context->sprite_draws = MAX_DRAWS_H32_MODE4;
2991+ uint32_t *dst = context->output + BORDER_LEFT + 256;
2992+ uint32_t bgcolor = context->colors[0x10 | (context->regs[REG_BG_COLOR] & 0xF) + MODE4_OFFSET];
2993+ for (int i = 0; i < 8; i++, dst++)
2994+ {
2995+ *dst = bgcolor;
2996+ }
2997+ context->done_output = dst;
2998+ CHECK_LIMIT
2999+ }}
3000+ default:
3001+ context->hslot++;
3002+ context->cycles += MCLKS_SLOT_H32;
3003+ }
3004+}
3005+
3006+static void inactive_test_output(vdp_context *context, uint8_t is_h40, uint8_t test_layer)
3007+{
3008+ uint8_t max_slot = is_h40 ? 169 : 136;
3009+ if (context->hslot > max_slot) {
3010+ return;
3011+ }
3012+ uint32_t *dst = context->output + (context->hslot >> 3) * SCROLL_BUFFER_DRAW;
3013+ int32_t len;
3014+ uint32_t src_off;
3015+ if (context->hslot) {
3016+ dst -= SCROLL_BUFFER_DRAW - BORDER_LEFT;
3017+ src_off = 0;
3018+ len = context->hslot == max_slot ? BORDER_RIGHT : SCROLL_BUFFER_DRAW;
3019+ } else {
3020+ src_off = SCROLL_BUFFER_DRAW - BORDER_LEFT;
3021+ len = BORDER_LEFT;
3022+ }
3023+ uint8_t *src;
3024+ if (test_layer == 2) {
3025+ //plane A
3026+ src_off += context->buf_a_off + context->hscroll_a;
3027+ src = context->tmp_buf_a;
3028+ } else if (test_layer == 3){
3029+ //plane B
3030+ src_off += context->buf_b_off + context->hscroll_b;
3031+ src = context->tmp_buf_b;
3032+ } else {
3033+ //sprite layer
3034+ for (; len >=0; len--, dst++, src_off++)
3035+ {
3036+ *dst = context->colors[0];
3037+ }
3038+ }
3039+ for (; len >=0; len--, dst++, src_off++)
3040+ {
3041+ *dst = context->colors[src[src_off & SCROLL_BUFFER_MASK] & 0x3F];
3042+ }
3043+ context->done_output = dst;
3044+ context->buf_a_off = (context->buf_a_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_DRAW;
3045+ context->buf_b_off = (context->buf_b_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_DRAW;
3046+}
3047+
3048+static void check_switch_inactive(vdp_context *context, uint8_t is_h40)
3049+{
3050+ //technically the second hcounter check should be different for H40, but this is probably close enough for now
3051+ if (context->state == ACTIVE && context->vcounter == context->inactive_start && (context->hslot >= (is_h40 ? 167 : 135) || context->hslot < 133)) {
3052+ context->state = INACTIVE;
3053+ }
3054+}
3055+
3056+static void vdp_inactive(vdp_context *context, uint32_t target_cycles, uint8_t is_h40, uint8_t mode_5)
3057+{
3058+ uint8_t buf_clear_slot, index_reset_slot, bg_end_slot, vint_slot, line_change, jump_start, jump_dest, latch_slot;
3059+ uint8_t index_reset_value, max_draws, max_sprites;
3060+ uint16_t vint_line, active_line;
3061+ uint32_t bg_color;
3062+
3063+ if (mode_5) {
3064+ if (is_h40) {
3065+ latch_slot = 165;
3066+ buf_clear_slot = 163;
3067+ index_reset_slot = 167;
3068+ bg_end_slot = BG_START_SLOT + LINEBUF_SIZE/2;
3069+ max_draws = MAX_DRAWS-1;
3070+ max_sprites = MAX_SPRITES_LINE;
3071+ index_reset_value = 0x80;
3072+ vint_slot = VINT_SLOT_H40;
3073+ line_change = LINE_CHANGE_H40;
3074+ jump_start = 182;
3075+ jump_dest = 229;
3076+ } else {
3077+ bg_end_slot = BG_START_SLOT + (256+HORIZ_BORDER)/2;
3078+ max_draws = MAX_DRAWS_H32-1;
3079+ max_sprites = MAX_SPRITES_LINE_H32;
3080+ buf_clear_slot = 128;
3081+ index_reset_slot = 132;
3082+ index_reset_value = 0x80;
3083+ vint_slot = VINT_SLOT_H32;
3084+ line_change = LINE_CHANGE_H32;
3085+ jump_start = 147;
3086+ jump_dest = 233;
3087+ latch_slot = 243;
3088+ }
3089+ vint_line = context->inactive_start;
3090+ active_line = 0x1FF;
3091+ if (context->regs[REG_MODE_3] & BIT_VSCROLL) {
3092+ latch_slot = 220;
3093+ }
3094+ } else {
3095+ latch_slot = 220;
3096+ bg_end_slot = BG_START_SLOT + (256+HORIZ_BORDER)/2;
3097+ max_draws = MAX_DRAWS_H32_MODE4;
3098+ max_sprites = 8;
3099+ buf_clear_slot = 136;
3100+ index_reset_slot = 253;
3101+ index_reset_value = 0;
3102+ vint_line = context->inactive_start + 1;
3103+ vint_slot = VINT_SLOT_MODE4;
3104+ line_change = LINE_CHANGE_MODE4;
3105+ bg_color = render_map_color(0, 0, 0);
3106+ jump_start = 147;
3107+ jump_dest = 233;
3108+ if (context->regs[REG_MODE_1] & BIT_MODE_4) {
3109+ active_line = 0x1FF;
3110+ } else {
3111+ //never active unless either mode 4 or mode 5 is turned on
3112+ active_line = 0x200;
3113+ }
3114+ }
3115+ uint32_t *dst;
3116+ uint8_t *debug_dst;
3117+ if (
3118+ (
3119+ context->vcounter < context->inactive_start + context->border_bot
3120+ || context->vcounter >= 0x200 - context->border_top
3121+ ) && context->hslot >= BG_START_SLOT && context->hslot < bg_end_slot
3122+ ) {
3123+ dst = context->output + 2 * (context->hslot - BG_START_SLOT);
3124+ debug_dst = context->layer_debug_buf + 2 * (context->hslot - BG_START_SLOT);
3125+ } else {
3126+ dst = NULL;
3127+ }
3128+
3129+ if (
3130+ !dst && context->vcounter == context->inactive_start + context->border_bot
3131+ && context->hslot >= line_change && context->hslot < bg_end_slot
3132+ ) {
3133+ dst = context->output + 2 * (context->hslot - BG_START_SLOT);
3134+ debug_dst = context->layer_debug_buf + 2 * (context->hslot - BG_START_SLOT);
3135+ }
3136+
3137+ uint8_t test_layer = context->test_port >> 7 & 3;
3138+ if (test_layer) {
3139+ dst = NULL;
3140+ }
3141+
3142+ while(context->cycles < target_cycles)
3143+ {
3144+ check_switch_inactive(context, is_h40);
3145+ if (context->hslot == BG_START_SLOT && !test_layer && (
3146+ context->vcounter < context->inactive_start + context->border_bot
3147+ || context->vcounter >= 0x200 - context->border_top
3148+ )) {
3149+ dst = context->output + (context->hslot - BG_START_SLOT) * 2;
3150+ debug_dst = context->layer_debug_buf + 2 * (context->hslot - BG_START_SLOT);
3151+ } else if (context->hslot == bg_end_slot) {
3152+ advance_output_line(context);
3153+ dst = NULL;
3154+ }
3155+ //this will need some tweaking to properly interact with 128K mode,
3156+ //but this should be good enough for now
3157+ context->serial_address += 1024;
3158+ if (test_layer) {
3159+ switch (context->hslot & 7)
3160+ {
3161+ case 3:
3162+ render_border_garbage(context, context->serial_address, context->tmp_buf_a, context->buf_a_off, context->col_1);
3163+ break;
3164+ case 4:
3165+ render_border_garbage(context, context->serial_address, context->tmp_buf_a, context->buf_a_off+8, context->col_2);
3166+ break;
3167+ case 7:
3168+ render_border_garbage(context, context->serial_address, context->tmp_buf_b, context->buf_b_off, context->col_1);
3169+ break;
3170+ case 0:
3171+ render_border_garbage(context, context->serial_address, context->tmp_buf_b, context->buf_b_off+8, context->col_2);
3172+ inactive_test_output(context, is_h40, test_layer);
3173+ break;
3174+ }
3175+ }
3176+
3177+ if (context->hslot == buf_clear_slot) {
3178+ if (mode_5) {
3179+ context->cur_slot = max_draws;
3180+ } else {
3181+ context->cur_slot = context->sprite_index = MAX_DRAWS_H32_MODE4-1;
3182+ context->sprite_draws = MAX_DRAWS_H32_MODE4;
3183+ }
3184+ memset(context->linebuf, 0, LINEBUF_SIZE);
3185+ } else if (context->hslot == index_reset_slot) {
3186+ context->sprite_index = index_reset_value;
3187+ context->slot_counter = mode_5 ? 0 : max_sprites;
3188+ } else if (context->hslot == latch_slot) {
3189+ //it seems unlikely to me that vscroll actually gets latched when the display is off
3190+ //but it's the only straightforward way to reconcile what I'm seeing between Skitchin
3191+ //(which seems to expect vscroll to be latched early) and the intro of Gunstar Heroes
3192+ //(which disables the display and ends up with garbage if vscroll is latched during that period)
3193+ //without it. Some more tests are definitely needed
3194+ context->vscroll_latch[0] = context->vsram[0];
3195+ context->vscroll_latch[1] = context->vsram[1];
3196+ } else if (context->vcounter == vint_line && context->hslot == vint_slot) {
3197+ context->flags2 |= FLAG2_VINT_PENDING;
3198+ context->pending_vint_start = context->cycles;
3199+ } else if (context->vcounter == context->inactive_start && context->hslot == 1 && (context->regs[REG_MODE_4] & BIT_INTERLACE)) {
3200+ context->flags2 ^= FLAG2_EVEN_FIELD;
3201+ }
3202+
3203+ if (dst) {
3204+ if (mode_5) {
3205+ bg_color = context->colors[context->regs[REG_BG_COLOR] & 0x3F];
3206+ } else if (context->regs[REG_MODE_1] & BIT_MODE_4) {
3207+ bg_color = context->colors[MODE4_OFFSET + 0x10 + (context->regs[REG_BG_COLOR] & 0xF)];
3208+ }
3209+ if (dst >= context->done_output) {
3210+ *(dst++) = bg_color;
3211+ *(debug_dst++) = DBG_SRC_BG;
3212+ } else {
3213+ dst++;
3214+ debug_dst++;
3215+ }
3216+ if (dst >= context->done_output) {
3217+ *(dst++) = bg_color;
3218+ *(debug_dst++) = DBG_SRC_BG;
3219+ context->done_output = dst;
3220+ } else {
3221+ dst++;
3222+ debug_dst++;
3223+ }
3224+ if (context->hslot == (bg_end_slot-1)) {
3225+ *(dst++) = bg_color;
3226+ *(debug_dst++) = DBG_SRC_BG;
3227+ context->done_output = dst;
3228+ }
3229+ }
3230+
3231+ if (!is_refresh(context, context->hslot)) {
3232+ external_slot(context);
3233+ if (context->flags & FLAG_DMA_RUN && !is_refresh(context, context->hslot)) {
3234+ run_dma_src(context, context->hslot);
3235+ }
3236+ }
3237+
3238+ if (is_h40) {
3239+ if (context->hslot >= HSYNC_SLOT_H40 && context->hslot < HSYNC_END_H40) {
3240+ context->cycles += h40_hsync_cycles[context->hslot - HSYNC_SLOT_H40];
3241+ } else {
3242+ context->cycles += MCLKS_SLOT_H40;
3243+ }
3244+ } else {
3245+ context->cycles += MCLKS_SLOT_H32;
3246+ }
3247+ if (context->hslot == jump_start) {
3248+ context->hslot = jump_dest;
3249+ } else {
3250+ context->hslot++;
3251+ }
3252+ if (context->hslot == line_change) {
3253+ vdp_advance_line(context);
3254+ if (context->vcounter == active_line) {
3255+ context->state = PREPARING;
3256+ return;
3257+ }
3258+ }
3259+ }
3260+}
3261+
3262+void vdp_run_context_full(vdp_context * context, uint32_t target_cycles)
3263+{
3264+ uint8_t is_h40 = context->regs[REG_MODE_4] & BIT_H40;
3265+ uint8_t mode_5 = context->regs[REG_MODE_2] & BIT_MODE_5;
3266+ while(context->cycles < target_cycles)
3267+ {
3268+ check_switch_inactive(context, is_h40);
3269+
3270+ if (is_active(context)) {
3271+ if (mode_5) {
3272+ if (is_h40) {
3273+ vdp_h40(context, target_cycles);
3274+ } else {
3275+ vdp_h32(context, target_cycles);
3276+ }
3277+ } else {
3278+ vdp_h32_mode4(context, target_cycles);
3279+ }
3280+ } else {
3281+ vdp_inactive(context, target_cycles, is_h40, mode_5);
3282+ }
3283+ }
3284+}
3285+
3286+void vdp_run_context(vdp_context *context, uint32_t target_cycles)
3287+{
3288+ //TODO: Deal with H40 hsync shenanigans
3289+ uint32_t slot_cyc = context->regs[REG_MODE_4] & BIT_H40 ? 15 : 19;
3290+ if (target_cycles < slot_cyc) {
3291+ //avoid overflow
3292+ return;
3293+ }
3294+ vdp_run_context_full(context, target_cycles - slot_cyc);
3295+}
3296+
3297+uint32_t vdp_run_to_vblank(vdp_context * context)
3298+{
3299+ uint32_t old_frame = context->frame;
3300+ while (context->frame == old_frame) {
3301+ vdp_run_context_full(context, context->cycles + MCLKS_LINE);
3302+ }
3303+ return context->cycles;
3304+}
3305+
3306+void vdp_run_dma_done(vdp_context * context, uint32_t target_cycles)
3307+{
3308+ for(;;) {
3309+ uint32_t dmalen = (context->regs[REG_DMALEN_H] << 8) | context->regs[REG_DMALEN_L];
3310+ if (!dmalen) {
3311+ dmalen = 0x10000;
3312+ }
3313+ uint32_t min_dma_complete = dmalen * (context->regs[REG_MODE_4] & BIT_H40 ? 16 : 20);
3314+ if (
3315+ (context->regs[REG_DMASRC_H] & DMA_TYPE_MASK) == DMA_COPY
3316+ || (((context->cd & 0xF) == VRAM_WRITE) && !(context->regs[REG_MODE_2] & BIT_128K_VRAM))) {
3317+ //DMA copies take twice as long to complete since they require a read and a write
3318+ //DMA Fills and transfers to VRAM also take twice as long as it requires 2 writes for a single word
3319+ //unless 128KB mode is enabled
3320+ min_dma_complete *= 2;
3321+ }
3322+ min_dma_complete += context->cycles;
3323+ if (target_cycles < min_dma_complete) {
3324+ vdp_run_context_full(context, target_cycles);
3325+ return;
3326+ } else {
3327+ vdp_run_context_full(context, min_dma_complete);
3328+ if (!(context->flags & FLAG_DMA_RUN)) {
3329+ return;
3330+ }
3331+ }
3332+ }
3333+}
3334+
3335+static uint16_t get_ext_vcounter(vdp_context *context)
3336+{
3337+ uint16_t line= context->vcounter;
3338+ if (context->regs[REG_MODE_4] & BIT_INTERLACE) {
3339+ if (context->double_res) {
3340+ line <<= 1;
3341+ } else {
3342+ line &= 0x1FE;
3343+ }
3344+ if (line & 0x100) {
3345+ line |= 1;
3346+ }
3347+ }
3348+ return line << 8;
3349+}
3350+
3351+void vdp_latch_hv(vdp_context *context)
3352+{
3353+ context->hv_latch = context->hslot | get_ext_vcounter(context);
3354+}
3355+
3356+uint16_t vdp_hv_counter_read(vdp_context * context)
3357+{
3358+ if ((context->regs[REG_MODE_2] & BIT_MODE_5) && (context->regs[REG_MODE_1] & BIT_HVC_LATCH)) {
3359+ return context->hv_latch;
3360+ }
3361+ uint16_t hv;
3362+ if (context->regs[REG_MODE_2] & BIT_MODE_5) {
3363+ hv = context->hslot;
3364+ } else {
3365+ hv = context->hv_latch & 0xFF;
3366+ }
3367+ hv |= get_ext_vcounter(context);
3368+
3369+ return hv;
3370+}
3371+
3372+int vdp_control_port_write(vdp_context * context, uint16_t value)
3373+{
3374+ //printf("control port write: %X at %d\n", value, context->cycles);
3375+ if (context->flags & FLAG_DMA_RUN) {
3376+ return -1;
3377+ }
3378+ if (context->flags & FLAG_PENDING) {
3379+ context->address = (context->address & 0x3FFF) | (value << 14 & 0x1C000);
3380+ //It seems like the DMA enable bit doesn't so much enable DMA so much
3381+ //as it enables changing CD5 from control port writes
3382+ uint8_t preserve = (context->regs[REG_MODE_2] & BIT_DMA_ENABLE) ? 0x3 : 0x23;
3383+ context->cd = (context->cd & preserve) | ((value >> 2) & ~preserve & 0xFF);
3384+ context->flags &= ~FLAG_PENDING;
3385+ //Should these be taken care of here or after the first write?
3386+ context->flags &= ~FLAG_READ_FETCHED;
3387+ context->flags2 &= ~FLAG2_READ_PENDING;
3388+ //printf("New Address: %X, New CD: %X\n", context->address, context->cd);
3389+ if (context->cd & 0x20) {
3390+ //
3391+ if((context->regs[REG_DMASRC_H] & DMA_TYPE_MASK) != DMA_FILL) {
3392+ //DMA copy or 68K -> VDP, transfer starts immediately
3393+ //printf("DMA start (length: %X) at cycle %d, frame: %d, vcounter: %d, hslot: %d\n", (context->regs[REG_DMALEN_H] << 8) | context->regs[REG_DMALEN_L], context->cycles, context->frame, context->vcounter, context->hslot);
3394+ if (!(context->regs[REG_DMASRC_H] & 0x80)) {
3395+ //printf("DMA Address: %X, New CD: %X, Source: %X, Length: %X\n", context->address, context->cd, (context->regs[REG_DMASRC_H] << 17) | (context->regs[REG_DMASRC_M] << 9) | (context->regs[REG_DMASRC_L] << 1), context->regs[REG_DMALEN_H] << 8 | context->regs[REG_DMALEN_L]);
3396+ //68K -> VDP DMA takes a few slots to actually start reading even though it acquires the bus immediately
3397+ //logic analyzer captures made it seem like the proper value is 4 slots, but that seems to cause trouble with the Nemesis' FIFO Wait State test
3398+ //only captures are from a direct color DMA demo which will generally start DMA at a very specific point in display so other values are plausible
3399+ //sticking with 3 slots for now until I can do some more captures
3400+ vdp_run_context_full(context, context->cycles + 12 * ((context->regs[REG_MODE_2] & BIT_MODE_5) && (context->regs[REG_MODE_4] & BIT_H40) ? 4 : 5));
3401+ context->flags |= FLAG_DMA_RUN;
3402+ return 1;
3403+ } else {
3404+ context->flags |= FLAG_DMA_RUN;
3405+ //printf("DMA Copy Address: %X, New CD: %X, Source: %X\n", context->address, context->cd, (context->regs[REG_DMASRC_M] << 8) | context->regs[REG_DMASRC_L]);
3406+ }
3407+ } else {
3408+ //printf("DMA Fill Address: %X, New CD: %X\n", context->address, context->cd);
3409+ }
3410+ }
3411+ } else {
3412+ uint8_t mode_5 = context->regs[REG_MODE_2] & BIT_MODE_5;
3413+ context->address = (context->address &0xC000) | (value & 0x3FFF);
3414+ context->cd = (context->cd & 0x3C) | (value >> 14);
3415+ if ((value & 0xC000) == 0x8000) {
3416+ //Register write
3417+ uint8_t reg = (value >> 8) & 0x1F;
3418+ if (reg < (mode_5 ? VDP_REGS : 0xB)) {
3419+ //printf("register %d set to %X\n", reg, value & 0xFF);
3420+ if (reg == REG_MODE_1 && (value & BIT_HVC_LATCH) && !(context->regs[reg] & BIT_HVC_LATCH)) {
3421+ vdp_latch_hv(context);
3422+ }
3423+ if (reg == REG_BG_COLOR) {
3424+ value &= 0x3F;
3425+ }
3426+ /*if (reg == REG_MODE_4 && ((value ^ context->regs[reg]) & BIT_H40)) {
3427+ printf("Mode changed from H%d to H%d @ %d, frame: %d\n", context->regs[reg] & BIT_H40 ? 40 : 32, value & BIT_H40 ? 40 : 32, context->cycles, context->frame);
3428+ }*/
3429+ context->regs[reg] = value;
3430+ if (reg == REG_MODE_4) {
3431+ context->double_res = (value & (BIT_INTERLACE | BIT_DOUBLE_RES)) == (BIT_INTERLACE | BIT_DOUBLE_RES);
3432+ if (!context->double_res) {
3433+ context->flags2 &= ~FLAG2_EVEN_FIELD;
3434+ }
3435+ }
3436+ if (reg == REG_MODE_1 || reg == REG_MODE_2 || reg == REG_MODE_4) {
3437+ update_video_params(context);
3438+ }
3439+ }
3440+ } else if (mode_5) {
3441+ context->flags |= FLAG_PENDING;
3442+ //Should these be taken care of here or after the second write?
3443+ //context->flags &= ~FLAG_READ_FETCHED;
3444+ //context->flags2 &= ~FLAG2_READ_PENDING;
3445+ } else {
3446+ context->flags &= ~FLAG_READ_FETCHED;
3447+ context->flags2 &= ~FLAG2_READ_PENDING;
3448+ }
3449+ }
3450+ return 0;
3451+}
3452+
3453+void vdp_control_port_write_pbc(vdp_context *context, uint8_t value)
3454+{
3455+ if (context->flags2 & FLAG2_BYTE_PENDING) {
3456+ uint16_t full_val = value << 8 | context->pending_byte;
3457+ context->flags2 &= ~FLAG2_BYTE_PENDING;
3458+ //TODO: Deal with fact that Vbus->VDP DMA doesn't do anything in PBC mode
3459+ vdp_control_port_write(context, full_val);
3460+ if (context->cd == VRAM_READ) {
3461+ context->cd = VRAM_READ8;
3462+ }
3463+ } else {
3464+ context->pending_byte = value;
3465+ context->flags2 |= FLAG2_BYTE_PENDING;
3466+ }
3467+}
3468+
3469+int vdp_data_port_write(vdp_context * context, uint16_t value)
3470+{
3471+ //printf("data port write: %X at %d\n", value, context->cycles);
3472+ if (context->flags & FLAG_DMA_RUN && (context->regs[REG_DMASRC_H] & DMA_TYPE_MASK) != DMA_FILL) {
3473+ return -1;
3474+ }
3475+ if (context->flags & FLAG_PENDING) {
3476+ context->flags &= ~FLAG_PENDING;
3477+ //Should these be cleared here?
3478+ context->flags &= ~FLAG_READ_FETCHED;
3479+ context->flags2 &= ~FLAG2_READ_PENDING;
3480+ }
3481+ /*if (context->fifo_cur == context->fifo_end) {
3482+ printf("FIFO full, waiting for space before next write at cycle %X\n", context->cycles);
3483+ }*/
3484+ if (context->cd & 0x20 && (context->regs[REG_DMASRC_H] & DMA_TYPE_MASK) == DMA_FILL) {
3485+ context->flags &= ~FLAG_DMA_RUN;
3486+ }
3487+ while (context->fifo_write == context->fifo_read) {
3488+ vdp_run_context_full(context, context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20));
3489+ }
3490+ fifo_entry * cur = context->fifo + context->fifo_write;
3491+ cur->cycle = context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20)*FIFO_LATENCY;
3492+ cur->address = context->address;
3493+ cur->value = value;
3494+ if (context->regs[REG_MODE_2] & BIT_MODE_5) {
3495+ cur->cd = context->cd;
3496+ } else {
3497+ cur->cd = (context->cd & 2) | 1;
3498+ }
3499+ cur->partial = 0;
3500+ if (context->fifo_read < 0) {
3501+ context->fifo_read = context->fifo_write;
3502+ }
3503+ context->fifo_write = (context->fifo_write + 1) & (FIFO_SIZE-1);
3504+ increment_address(context);
3505+ return 0;
3506+}
3507+
3508+void vdp_data_port_write_pbc(vdp_context * context, uint8_t value)
3509+{
3510+ if (context->flags & FLAG_PENDING) {
3511+ context->flags &= ~FLAG_PENDING;
3512+ //Should these be cleared here?
3513+ context->flags &= ~FLAG_READ_FETCHED;
3514+ context->flags2 &= ~FLAG2_READ_PENDING;
3515+ }
3516+ context->flags2 &= ~FLAG2_BYTE_PENDING;
3517+ /*if (context->fifo_cur == context->fifo_end) {
3518+ printf("FIFO full, waiting for space before next write at cycle %X\n", context->cycles);
3519+ }*/
3520+ if (context->cd & 0x20 && (context->regs[REG_DMASRC_H] & DMA_TYPE_MASK) == DMA_FILL) {
3521+ context->flags &= ~FLAG_DMA_RUN;
3522+ }
3523+ while (context->fifo_write == context->fifo_read) {
3524+ vdp_run_context_full(context, context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20));
3525+ }
3526+ fifo_entry * cur = context->fifo + context->fifo_write;
3527+ cur->cycle = context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20)*FIFO_LATENCY;
3528+ cur->address = context->address;
3529+ cur->value = value;
3530+ if (context->regs[REG_MODE_2] & BIT_MODE_5) {
3531+ cur->cd = context->cd;
3532+ } else {
3533+ cur->cd = (context->cd & 2) | 1;
3534+ }
3535+ cur->partial = 3;
3536+ if (context->fifo_read < 0) {
3537+ context->fifo_read = context->fifo_write;
3538+ }
3539+ context->fifo_write = (context->fifo_write + 1) & (FIFO_SIZE-1);
3540+ increment_address(context);
3541+}
3542+
3543+void vdp_test_port_write(vdp_context * context, uint16_t value)
3544+{
3545+ context->test_port = value;
3546+}
3547+
3548+uint16_t vdp_control_port_read(vdp_context * context)
3549+{
3550+ context->flags &= ~FLAG_PENDING;
3551+ context->flags2 &= ~FLAG2_BYTE_PENDING;
3552+ //Bits 15-10 are not fixed like Charles MacDonald's doc suggests, but instead open bus values that reflect 68K prefetch
3553+ uint16_t value = context->system->get_open_bus_value(context->system) & 0xFC00;
3554+ if (context->fifo_read < 0) {
3555+ value |= 0x200;
3556+ }
3557+ if (context->fifo_read == context->fifo_write) {
3558+ value |= 0x100;
3559+ }
3560+ if (context->flags2 & FLAG2_VINT_PENDING) {
3561+ value |= 0x80;
3562+ }
3563+ if (context->flags & FLAG_DOT_OFLOW) {
3564+ value |= 0x40;
3565+ context->flags &= ~FLAG_DOT_OFLOW;
3566+ }
3567+ if (context->flags2 & FLAG2_SPRITE_COLLIDE) {
3568+ value |= 0x20;
3569+ context->flags2 &= ~FLAG2_SPRITE_COLLIDE;
3570+ }
3571+ if ((context->regs[REG_MODE_4] & BIT_INTERLACE) && !(context->flags2 & FLAG2_EVEN_FIELD)) {
3572+ value |= 0x10;
3573+ }
3574+ uint32_t slot = context->hslot;
3575+ if (!is_active(context)) {
3576+ value |= 0x8;
3577+ }
3578+ if (context->regs[REG_MODE_4] & BIT_H40) {
3579+ if (slot < HBLANK_END_H40 || slot > HBLANK_START_H40) {
3580+ value |= 0x4;
3581+ }
3582+ } else {
3583+ if (slot < HBLANK_END_H32 || slot > HBLANK_START_H32) {
3584+ value |= 0x4;
3585+ }
3586+ }
3587+ if (context->cd & 0x20) {
3588+ value |= 0x2;
3589+ }
3590+ if (context->flags2 & FLAG2_REGION_PAL) {
3591+ value |= 0x1;
3592+ }
3593+ //printf("status read at cycle %d returned %X\n", context->cycles, value);
3594+ return value;
3595+}
3596+
3597+uint16_t vdp_data_port_read(vdp_context * context)
3598+{
3599+ if (context->flags & FLAG_PENDING) {
3600+ context->flags &= ~FLAG_PENDING;
3601+ //Should these be cleared here?
3602+ context->flags &= ~FLAG_READ_FETCHED;
3603+ context->flags2 &= ~FLAG2_READ_PENDING;
3604+ }
3605+ if (context->cd & 1) {
3606+ warning("Read from VDP data port while writes are configured, CPU is now frozen. VDP Address: %X, CD: %X\n", context->address, context->cd);
3607+ }
3608+ while (!(context->flags & FLAG_READ_FETCHED)) {
3609+ vdp_run_context_full(context, context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20));
3610+ }
3611+ context->flags &= ~FLAG_READ_FETCHED;
3612+ return context->prefetch;
3613+}
3614+
3615+uint8_t vdp_data_port_read_pbc(vdp_context * context)
3616+{
3617+ context->flags &= ~(FLAG_PENDING | FLAG_READ_FETCHED);
3618+ context->flags2 &= ~FLAG2_BYTE_PENDING;
3619+
3620+ context->cd = VRAM_READ8;
3621+ return context->prefetch;
3622+}
3623+
3624+uint16_t vdp_test_port_read(vdp_context * context)
3625+{
3626+ //TODO: Find out what actually gets returned here
3627+ return context->test_port;
3628+}
3629+
3630+void vdp_adjust_cycles(vdp_context * context, uint32_t deduction)
3631+{
3632+ context->cycles -= deduction;
3633+ if (context->pending_vint_start >= deduction) {
3634+ context->pending_vint_start -= deduction;
3635+ } else {
3636+ context->pending_vint_start = 0;
3637+ }
3638+ if (context->pending_hint_start >= deduction) {
3639+ context->pending_hint_start -= deduction;
3640+ } else {
3641+ context->pending_hint_start = 0;
3642+ }
3643+ if (context->fifo_read >= 0) {
3644+ int32_t idx = context->fifo_read;
3645+ do {
3646+ if (context->fifo[idx].cycle >= deduction) {
3647+ context->fifo[idx].cycle -= deduction;
3648+ } else {
3649+ context->fifo[idx].cycle = 0;
3650+ }
3651+ idx = (idx+1) & (FIFO_SIZE-1);
3652+ } while(idx != context->fifo_write);
3653+ }
3654+}
3655+
3656+static uint32_t vdp_cycles_hslot_wrap_h40(vdp_context * context)
3657+{
3658+ if (context->hslot < 183) {
3659+ return MCLKS_LINE - context->hslot * MCLKS_SLOT_H40;
3660+ } else if (context->hslot < HSYNC_END_H40) {
3661+ uint32_t before_hsync = context->hslot < HSYNC_SLOT_H40 ? (HSYNC_SLOT_H40 - context->hslot) * MCLKS_SLOT_H40 : 0;
3662+ uint32_t hsync = 0;
3663+ for (int i = context->hslot <= HSYNC_SLOT_H40 ? 0 : context->hslot - HSYNC_SLOT_H40; i < sizeof(h40_hsync_cycles)/sizeof(uint32_t); i++)
3664+ {
3665+ hsync += h40_hsync_cycles[i];
3666+ }
3667+ uint32_t after_hsync = (256- HSYNC_END_H40) * MCLKS_SLOT_H40;
3668+ return before_hsync + hsync + after_hsync;
3669+ } else {
3670+ return (256-context->hslot) * MCLKS_SLOT_H40;
3671+ }
3672+}
3673+
3674+static uint32_t vdp_cycles_next_line(vdp_context * context)
3675+{
3676+ if (context->regs[REG_MODE_4] & BIT_H40) {
3677+ //TODO: Handle "illegal" Mode 4/H40 combo
3678+ if (context->hslot < LINE_CHANGE_H40) {
3679+ return (LINE_CHANGE_H40 - context->hslot) * MCLKS_SLOT_H40;
3680+ } else {
3681+ return vdp_cycles_hslot_wrap_h40(context) + LINE_CHANGE_H40 * MCLKS_SLOT_H40;
3682+ }
3683+ } else {
3684+ if (context->regs[REG_MODE_2] & BIT_MODE_5) {
3685+ if (context->hslot < LINE_CHANGE_H32) {
3686+ return (LINE_CHANGE_H32 - context->hslot) * MCLKS_SLOT_H32;
3687+ } else if (context->hslot < 148) {
3688+ return MCLKS_LINE - (context->hslot - LINE_CHANGE_H32) * MCLKS_SLOT_H32;
3689+ } else {
3690+ return (256-context->hslot + LINE_CHANGE_H32) * MCLKS_SLOT_H32;
3691+ }
3692+ } else {
3693+ if (context->hslot < 148) {
3694+ return (148 - context->hslot + LINE_CHANGE_MODE4 - 233) * MCLKS_SLOT_H32;
3695+ } else if (context->hslot < LINE_CHANGE_MODE4) {
3696+ return (LINE_CHANGE_MODE4 - context->hslot) * MCLKS_SLOT_H32;
3697+ } else {
3698+ return MCLKS_LINE - (context->hslot - LINE_CHANGE_MODE4) * MCLKS_SLOT_H32;
3699+ }
3700+ }
3701+ }
3702+}
3703+
3704+static void get_jump_params(vdp_context *context, uint32_t *jump_start, uint32_t *jump_dst)
3705+{
3706+ if (context->regs[REG_MODE_2] & BIT_MODE_5) {
3707+ if (context->flags2 & FLAG2_REGION_PAL) {
3708+ if (context->regs[REG_MODE_2] & BIT_PAL) {
3709+ *jump_start = 0x10B;
3710+ *jump_dst = 0x1D2;
3711+ } else {
3712+ *jump_start = 0x103;
3713+ *jump_dst = 0x1CA;
3714+ }
3715+ } else {
3716+ if (context->regs[REG_MODE_2] & BIT_PAL) {
3717+ *jump_start = 0x100;
3718+ *jump_dst = 0x1FA;
3719+ } else {
3720+ *jump_start = 0xEB;
3721+ *jump_dst = 0x1E5;
3722+ }
3723+ }
3724+ } else {
3725+ *jump_start = 0xDB;
3726+ *jump_dst = 0x1D5;
3727+ }
3728+}
3729+
3730+static uint32_t vdp_cycles_to_line(vdp_context * context, uint32_t target)
3731+{
3732+ uint32_t jump_start, jump_dst;
3733+ get_jump_params(context, &jump_start, &jump_dst);
3734+ uint32_t lines;
3735+ if (context->vcounter < target) {
3736+ if (target < jump_start || context->vcounter > jump_start) {
3737+ lines = target - context->vcounter;
3738+ } else {
3739+ lines = jump_start - context->vcounter + target - jump_dst;
3740+ }
3741+ } else {
3742+ if (context->vcounter < jump_start) {
3743+ lines = jump_start - context->vcounter + 512 - jump_dst;
3744+ } else {
3745+ lines = 512 - context->vcounter;
3746+ }
3747+ if (target < jump_start) {
3748+ lines += target;
3749+ } else {
3750+ lines += jump_start + target - jump_dst;
3751+ }
3752+ }
3753+ return MCLKS_LINE * (lines - 1) + vdp_cycles_next_line(context);
3754+}
3755+
3756+uint32_t vdp_cycles_to_frame_end(vdp_context * context)
3757+{
3758+ return context->cycles + vdp_cycles_to_line(context, context->inactive_start);
3759+}
3760+
3761+uint32_t vdp_next_hint(vdp_context * context)
3762+{
3763+ if (!(context->regs[REG_MODE_1] & BIT_HINT_EN)) {
3764+ return 0xFFFFFFFF;
3765+ }
3766+ if (context->flags2 & FLAG2_HINT_PENDING) {
3767+ return context->pending_hint_start;
3768+ }
3769+ uint32_t hint_line;
3770+ if (context->state != ACTIVE) {
3771+ hint_line = context->regs[REG_HINT];
3772+ if (hint_line > context->inactive_start) {
3773+ return 0xFFFFFFFF;
3774+ }
3775+ } else {
3776+ hint_line = context->vcounter + context->hint_counter + 1;
3777+ if (context->vcounter < context->inactive_start) {
3778+ if (hint_line > context->inactive_start) {
3779+ hint_line = context->regs[REG_HINT];
3780+ if (hint_line > context->inactive_start) {
3781+ return 0xFFFFFFFF;
3782+ }
3783+ if (hint_line >= context->vcounter) {
3784+ //Next interrupt is for a line in the next frame that
3785+ //is higher than the line we're on now so just passing
3786+ //that line number to vdp_cycles_to_line will yield the wrong
3787+ //result
3788+ return context->cycles + vdp_cycles_to_line(context, 0) + hint_line * MCLKS_LINE;
3789+ }
3790+ }
3791+ } else {
3792+ uint32_t jump_start, jump_dst;
3793+ get_jump_params(context, &jump_start, &jump_dst);
3794+ if (hint_line >= jump_start && context->vcounter < jump_dst) {
3795+ hint_line = (hint_line + jump_dst - jump_start) & 0x1FF;
3796+ }
3797+ if (hint_line < context->vcounter && hint_line > context->inactive_start) {
3798+ return 0xFFFFFFFF;
3799+ }
3800+ }
3801+ }
3802+ return context->cycles + vdp_cycles_to_line(context, hint_line);
3803+}
3804+
3805+static uint32_t vdp_next_vint_real(vdp_context * context)
3806+{
3807+ if (!(context->regs[REG_MODE_2] & BIT_VINT_EN)) {
3808+ return 0xFFFFFFFF;
3809+ }
3810+ if (context->flags2 & FLAG2_VINT_PENDING) {
3811+ return context->pending_vint_start;
3812+ }
3813+
3814+
3815+ return vdp_next_vint_z80(context);
3816+}
3817+
3818+uint32_t vdp_next_vint(vdp_context *context)
3819+{
3820+ uint32_t ret = vdp_next_vint_real(context);
3821+#ifdef TIMING_DEBUG
3822+ static uint32_t last = 0xFFFFFFFF;
3823+ if (last != ret) {
3824+ printf("vdp_next_vint is %d at frame %d, line %d, hslot %d\n", ret, context->frame, context->vcounter, context->hslot);
3825+ }
3826+ last = ret;
3827+#endif
3828+ return ret;
3829+}
3830+
3831+uint32_t vdp_next_vint_z80(vdp_context * context)
3832+{
3833+ uint16_t vint_line = (context->regs[REG_MODE_2] & BIT_MODE_5) ? context->inactive_start : context->inactive_start + 1;
3834+ if (context->vcounter == vint_line) {
3835+ if (context->regs[REG_MODE_2] & BIT_MODE_5) {
3836+ if (context->regs[REG_MODE_4] & BIT_H40) {
3837+ if (context->hslot >= LINE_CHANGE_H40 || context->hslot <= VINT_SLOT_H40) {
3838+ uint32_t cycles = context->cycles;
3839+ if (context->hslot >= LINE_CHANGE_H40) {
3840+ if (context->hslot < 183) {
3841+ cycles += (183 - context->hslot) * MCLKS_SLOT_H40;
3842+ }
3843+
3844+ if (context->hslot < HSYNC_SLOT_H40) {
3845+ cycles += (HSYNC_SLOT_H40 - (context->hslot >= 229 ? context->hslot : 229)) * MCLKS_SLOT_H40;
3846+ }
3847+ for (int slot = context->hslot <= HSYNC_SLOT_H40 ? HSYNC_SLOT_H40 : context->hslot; slot < HSYNC_END_H40; slot++ )
3848+ {
3849+ cycles += h40_hsync_cycles[slot - HSYNC_SLOT_H40];
3850+ }
3851+ cycles += (256 - (context->hslot > HSYNC_END_H40 ? context->hslot : HSYNC_END_H40)) * MCLKS_SLOT_H40;
3852+ }
3853+
3854+ cycles += (VINT_SLOT_H40 - (context->hslot >= LINE_CHANGE_H40 ? 0 : context->hslot)) * MCLKS_SLOT_H40;
3855+ return cycles;
3856+ }
3857+ } else {
3858+ if (context->hslot >= LINE_CHANGE_H32 || context->hslot <= VINT_SLOT_H32) {
3859+ if (context->hslot <= VINT_SLOT_H32) {
3860+ return context->cycles + (VINT_SLOT_H32 - context->hslot) * MCLKS_SLOT_H32;
3861+ } else if (context->hslot < 233) {
3862+ return context->cycles + (VINT_SLOT_H32 + 256 - 233 + 148 - context->hslot) * MCLKS_SLOT_H32;
3863+ } else {
3864+ return context->cycles + (VINT_SLOT_H32 + 256 - context->hslot) * MCLKS_SLOT_H32;
3865+ }
3866+ }
3867+ }
3868+ } else {
3869+ if (context->hslot >= LINE_CHANGE_MODE4) {
3870+ return context->cycles + (VINT_SLOT_MODE4 + 256 - context->hslot) * MCLKS_SLOT_H32;
3871+ }
3872+ if (context->hslot <= VINT_SLOT_MODE4) {
3873+ return context->cycles + (VINT_SLOT_MODE4 - context->hslot) * MCLKS_SLOT_H32;
3874+ }
3875+ }
3876+ }
3877+ int32_t cycles_to_vint = vdp_cycles_to_line(context, vint_line);
3878+ if (context->regs[REG_MODE_2] & BIT_MODE_5) {
3879+ if (context->regs[REG_MODE_4] & BIT_H40) {
3880+ cycles_to_vint += MCLKS_LINE - (LINE_CHANGE_H40 - VINT_SLOT_H40) * MCLKS_SLOT_H40;
3881+ } else {
3882+ cycles_to_vint += (VINT_SLOT_H32 + 256 - 233 + 148 - LINE_CHANGE_H32) * MCLKS_SLOT_H32;
3883+ }
3884+ } else {
3885+ cycles_to_vint += (256 - LINE_CHANGE_MODE4 + VINT_SLOT_MODE4) * MCLKS_SLOT_H32;
3886+ }
3887+ return context->cycles + cycles_to_vint;
3888+}
3889+
3890+uint32_t vdp_next_nmi(vdp_context *context)
3891+{
3892+ if (!(context->flags2 & FLAG2_PAUSE)) {
3893+ return 0xFFFFFFFF;
3894+ }
3895+ return context->cycles + vdp_cycles_to_line(context, 0x1FF);
3896+}
3897+
3898+void vdp_pbc_pause(vdp_context *context)
3899+{
3900+ context->flags2 |= FLAG2_PAUSE;
3901+}
3902+
3903+void vdp_int_ack(vdp_context * context)
3904+{
3905+ //CPU interrupt acknowledge is only used in Mode 5
3906+ if (context->regs[REG_MODE_2] & BIT_MODE_5) {
3907+ //Apparently the VDP interrupt controller is not very smart
3908+ //Instead of paying attention to what interrupt is being acknowledged it just
3909+ //clears the pending flag for whatever interrupt it is currently asserted
3910+ //which may be different from the interrupt it was asserting when the 68k
3911+ //started the interrupt process. The window for this is narrow and depends
3912+ //on the latency between the int enable register write and the interrupt being
3913+ //asserted, but Fatal Rewind depends on this due to some buggy code
3914+ if ((context->flags2 & FLAG2_VINT_PENDING) && (context->regs[REG_MODE_2] & BIT_VINT_EN)) {
3915+ context->flags2 &= ~FLAG2_VINT_PENDING;
3916+ } else if((context->flags2 & FLAG2_HINT_PENDING) && (context->regs[REG_MODE_1] & BIT_HINT_EN)) {
3917+ context->flags2 &= ~FLAG2_HINT_PENDING;
3918+ }
3919+ }
3920+}
3921+
3922+void vdp_serialize(vdp_context *context, serialize_buffer *buf)
3923+{
3924+ save_int8(buf, VRAM_SIZE / 1024);//VRAM size in KB, needed for future proofing
3925+ save_buffer8(buf, context->vdpmem, VRAM_SIZE);
3926+ save_buffer16(buf, context->cram, CRAM_SIZE);
3927+ save_buffer16(buf, context->vsram, VSRAM_SIZE);
3928+ save_buffer8(buf, context->sat_cache, SAT_CACHE_SIZE);
3929+ for (int i = 0; i <= REG_DMASRC_H; i++)
3930+ {
3931+ save_int8(buf, context->regs[i]);
3932+ }
3933+ save_int32(buf, context->address);
3934+ save_int32(buf, context->serial_address);
3935+ save_int8(buf, context->cd);
3936+ uint8_t fifo_size;
3937+ if (context->fifo_read < 0) {
3938+ fifo_size = 0;
3939+ } else if (context->fifo_write > context->fifo_read) {
3940+ fifo_size = context->fifo_write - context->fifo_read;
3941+ } else {
3942+ fifo_size = context->fifo_write + FIFO_SIZE - context->fifo_read;
3943+ }
3944+ save_int8(buf, fifo_size);
3945+ for (int i = 0, cur = context->fifo_read; i < fifo_size; i++)
3946+ {
3947+ fifo_entry *entry = context->fifo + cur;
3948+ cur = (cur + 1) & (FIFO_SIZE - 1);
3949+ save_int32(buf, entry->cycle);
3950+ save_int32(buf, entry->address);
3951+ save_int16(buf, entry->value);
3952+ save_int8(buf, entry->cd);
3953+ save_int8(buf, entry->partial);
3954+ }
3955+ //FIXME: Flag bits should be rearranged for maximum correspondence to status reg
3956+ save_int16(buf, context->flags2 << 8 | context->flags);
3957+ save_int32(buf, context->frame);
3958+ save_int16(buf, context->vcounter);
3959+ save_int8(buf, context->hslot);
3960+ save_int16(buf, context->hv_latch);
3961+ save_int8(buf, context->state);
3962+ save_int16(buf, context->hscroll_a);
3963+ save_int16(buf, context->hscroll_b);
3964+ save_int16(buf, context->vscroll_latch[0]);
3965+ save_int16(buf, context->vscroll_latch[1]);
3966+ save_int16(buf, context->col_1);
3967+ save_int16(buf, context->col_2);
3968+ save_int16(buf, context->test_port);
3969+ save_buffer8(buf, context->tmp_buf_a, SCROLL_BUFFER_SIZE);
3970+ save_buffer8(buf, context->tmp_buf_b, SCROLL_BUFFER_SIZE);
3971+ save_int8(buf, context->buf_a_off);
3972+ save_int8(buf, context->buf_b_off);
3973+ //FIXME: Sprite rendering state is currently a mess
3974+ save_int8(buf, context->sprite_index);
3975+ save_int8(buf, context->sprite_draws);
3976+ save_int8(buf, context->slot_counter);
3977+ save_int8(buf, context->cur_slot);
3978+ for (int i = 0; i < MAX_DRAWS; i++)
3979+ {
3980+ sprite_draw *draw = context->sprite_draw_list + i;
3981+ save_int16(buf, draw->address);
3982+ save_int16(buf, draw->x_pos);
3983+ save_int8(buf, draw->pal_priority);
3984+ save_int8(buf, draw->h_flip);
3985+ }
3986+ for (int i = 0; i < MAX_SPRITES_LINE; i++)
3987+ {
3988+ sprite_info *info = context->sprite_info_list + i;
3989+ save_int8(buf, info->size);
3990+ save_int8(buf, info->index);
3991+ save_int16(buf, info->y);
3992+ }
3993+ save_buffer8(buf, context->linebuf, LINEBUF_SIZE);
3994+
3995+ save_int32(buf, context->cycles);
3996+ save_int32(buf, context->pending_vint_start);
3997+ save_int32(buf, context->pending_hint_start);
3998+}
3999+
4000+void vdp_deserialize(deserialize_buffer *buf, void *vcontext)
4001+{
4002+ vdp_context *context = vcontext;
4003+ uint8_t vramk = load_int8(buf);
4004+ load_buffer8(buf, context->vdpmem, (vramk * 1024) <= VRAM_SIZE ? vramk * 1024 : VRAM_SIZE);
4005+ if ((vramk * 1024) > VRAM_SIZE) {
4006+ buf->cur_pos += (vramk * 1024) - VRAM_SIZE;
4007+ }
4008+ load_buffer16(buf, context->cram, CRAM_SIZE);
4009+ for (int i = 0; i < CRAM_SIZE; i++)
4010+ {
4011+ update_color_map(context, i, context->cram[i]);
4012+ }
4013+ load_buffer16(buf, context->vsram, VSRAM_SIZE);
4014+ load_buffer8(buf, context->sat_cache, SAT_CACHE_SIZE);
4015+ for (int i = 0; i <= REG_DMASRC_H; i++)
4016+ {
4017+ context->regs[i] = load_int8(buf);
4018+ }
4019+ context->address = load_int32(buf);
4020+ context->serial_address = load_int32(buf);
4021+ context->cd = load_int8(buf);
4022+ uint8_t fifo_size = load_int8(buf);
4023+ if (fifo_size > FIFO_SIZE) {
4024+ fatal_error("Invalid fifo size %d", fifo_size);
4025+ }
4026+ if (fifo_size) {
4027+ context->fifo_read = 0;
4028+ context->fifo_write = fifo_size & (FIFO_SIZE - 1);
4029+ for (int i = 0; i < fifo_size; i++)
4030+ {
4031+ fifo_entry *entry = context->fifo + i;
4032+ entry->cycle = load_int32(buf);
4033+ entry->address = load_int32(buf);
4034+ entry->value = load_int16(buf);
4035+ entry->cd = load_int8(buf);
4036+ entry->partial = load_int8(buf);
4037+ }
4038+ } else {
4039+ context->fifo_read = -1;
4040+ context->fifo_write = 0;
4041+ }
4042+ uint16_t flags = load_int16(buf);
4043+ context->flags2 = flags >> 8;
4044+ context->flags = flags;
4045+ context->frame = load_int32(buf);
4046+ context->vcounter = load_int16(buf);
4047+ context->hslot = load_int8(buf);
4048+ context->hv_latch = load_int16(buf);
4049+ context->state = load_int8(buf);
4050+ context->hscroll_a = load_int16(buf);
4051+ context->hscroll_b = load_int16(buf);
4052+ context->vscroll_latch[0] = load_int16(buf);
4053+ context->vscroll_latch[1] = load_int16(buf);
4054+ context->col_1 = load_int16(buf);
4055+ context->col_2 = load_int16(buf);
4056+ context->test_port = load_int16(buf);
4057+ load_buffer8(buf, context->tmp_buf_a, SCROLL_BUFFER_SIZE);
4058+ load_buffer8(buf, context->tmp_buf_b, SCROLL_BUFFER_SIZE);
4059+ context->buf_a_off = load_int8(buf) & SCROLL_BUFFER_MASK;
4060+ context->buf_b_off = load_int8(buf) & SCROLL_BUFFER_MASK;
4061+ context->sprite_index = load_int8(buf);
4062+ context->sprite_draws = load_int8(buf);
4063+ context->slot_counter = load_int8(buf);
4064+ context->cur_slot = load_int8(buf);
4065+ for (int i = 0; i < MAX_DRAWS; i++)
4066+ {
4067+ sprite_draw *draw = context->sprite_draw_list + i;
4068+ draw->address = load_int16(buf);
4069+ draw->x_pos = load_int16(buf);
4070+ draw->pal_priority = load_int8(buf);
4071+ draw->h_flip = load_int8(buf);
4072+ }
4073+ for (int i = 0; i < MAX_SPRITES_LINE; i++)
4074+ {
4075+ sprite_info *info = context->sprite_info_list + i;
4076+ info->size = load_int8(buf);
4077+ info->index = load_int8(buf);
4078+ info->y = load_int16(buf);
4079+ }
4080+ load_buffer8(buf, context->linebuf, LINEBUF_SIZE);
4081+
4082+ context->cycles = load_int32(buf);
4083+ context->pending_vint_start = load_int32(buf);
4084+ context->pending_hint_start = load_int32(buf);
4085+ update_video_params(context);
4086+}
4087+
4088+static vdp_context *current_vdp;
4089+static void vdp_debug_window_close(uint8_t which)
4090+{
4091+ //TODO: remove need for current_vdp global, and find the VDP via current_system instead
4092+ for (int i = 0; i < VDP_NUM_DEBUG_TYPES; i++)
4093+ {
4094+ if (current_vdp->enabled_debuggers & (1 << i) && which == current_vdp->debug_fb_indices[i]) {
4095+ vdp_toggle_debug_view(current_vdp, i);
4096+ break;
4097+ }
4098+ }
4099+}
4100+
4101+void vdp_toggle_debug_view(vdp_context *context, uint8_t debug_type)
4102+{
4103+ if (context->enabled_debuggers & 1 << debug_type) {
4104+ render_destroy_window(context->debug_fb_indices[debug_type]);
4105+ context->enabled_debuggers &= ~(1 << debug_type);
4106+ } else {
4107+ uint32_t width,height;
4108+ uint8_t fetch_immediately = 0;
4109+ char *caption;
4110+ switch(debug_type)
4111+ {
4112+ case VDP_DEBUG_PLANE:
4113+ caption = "BlastEm - VDP Plane Debugger";
4114+ width = height = 1024;
4115+ break;
4116+ case VDP_DEBUG_VRAM:
4117+ caption = "BlastEm - VDP VRAM Debugger";
4118+ width = 1024;
4119+ height = 512;
4120+ break;
4121+ case VDP_DEBUG_CRAM:
4122+ caption = "BlastEm - VDP CRAM Debugger";
4123+ width = 512;
4124+ height = 512;
4125+ fetch_immediately = 1;
4126+ break;
4127+ case VDP_DEBUG_COMPOSITE:
4128+ caption = "BlastEm - VDP Plane Composition Debugger";
4129+ width = LINEBUF_SIZE;
4130+ height = context->inactive_start + context->border_top + context->border_bot;
4131+ fetch_immediately = 1;
4132+ break;
4133+ default:
4134+ return;
4135+ }
4136+ current_vdp = context;
4137+ context->debug_fb_indices[debug_type] = render_create_window(caption, width, height, vdp_debug_window_close);
4138+ if (context->debug_fb_indices[debug_type]) {
4139+ context->enabled_debuggers |= 1 << debug_type;
4140+ }
4141+ if (fetch_immediately) {
4142+ context->debug_fbs[debug_type] = render_get_video_buffer(context->debug_fb_indices[debug_type], &context->debug_fb_pitch[debug_type]);
4143+ }
4144+ }
4145+}
4146+
4147+void vdp_inc_debug_mode(vdp_context *context)
4148+{
4149+ uint8_t active = render_get_active_video_buffer();
4150+ if (active < VIDEO_BUFFER_USER_START) {
4151+ return;
4152+ }
4153+ for (int i = 0; i < VDP_NUM_DEBUG_TYPES; i++)
4154+ {
4155+ if (context->enabled_debuggers & (1 << i) && context->debug_fb_indices[i] == active) {
4156+ context->debug_modes[i]++;
4157+ return;
4158+ }
4159+ }
4160+}
A
vdp.h
+280,
-0
1@@ -0,0 +1,280 @@
2+/*
3+ Copyright 2013 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#ifndef VDP_H_
8+#define VDP_H_
9+
10+#include <stdint.h>
11+#include <stdio.h>
12+#include "system.h"
13+#include "serialize.h"
14+
15+#define VDP_REGS 24
16+#define CRAM_SIZE 64
17+#define SHADOW_OFFSET CRAM_SIZE
18+#define HIGHLIGHT_OFFSET (SHADOW_OFFSET+CRAM_SIZE)
19+#define MODE4_OFFSET (HIGHLIGHT_OFFSET+CRAM_SIZE)
20+#define VSRAM_SIZE 40
21+#define VRAM_SIZE (64*1024)
22+#define BORDER_LEFT 13
23+#define BORDER_RIGHT 14
24+#define HORIZ_BORDER (BORDER_LEFT+BORDER_RIGHT)
25+#define LINEBUF_SIZE (320+HORIZ_BORDER) //H40 + full border
26+#define SCROLL_BUFFER_SIZE 32
27+#define BORDER_BOTTOM 13 //TODO: Replace with actual value
28+#define MAX_DRAWS 40
29+#define MAX_DRAWS_H32 32
30+#define MAX_DRAWS_H32_MODE4 8
31+#define MAX_SPRITES_LINE 20
32+#define MAX_SPRITES_LINE_H32 16
33+#define MAX_SPRITES_FRAME 80
34+#define MAX_SPRITES_FRAME_H32 64
35+#define SAT_CACHE_SIZE (MAX_SPRITES_FRAME * 4)
36+
37+#define FBUF_SHADOW 0x0001
38+#define FBUF_HILIGHT 0x0010
39+#define FBUF_MODE4 0x0100
40+#define DBG_SHADOW 0x10
41+#define DBG_HILIGHT 0x20
42+#define DBG_PRIORITY 0x8
43+#define DBG_SRC_MASK 0x7
44+#define DBG_SRC_A 0x1
45+#define DBG_SRC_W 0x2
46+#define DBG_SRC_B 0x3
47+#define DBG_SRC_S 0x4
48+#define DBG_SRC_BG 0x0
49+
50+#define MCLKS_LINE 3420
51+
52+#define FLAG_DOT_OFLOW 0x01
53+#define FLAG_CAN_MASK 0x02
54+#define FLAG_MASKED 0x04
55+#define FLAG_WINDOW 0x08
56+#define FLAG_PENDING 0x10
57+#define FLAG_READ_FETCHED 0x20
58+#define FLAG_DMA_RUN 0x40
59+#define FLAG_DMA_PROG 0x80
60+
61+#define FLAG2_VINT_PENDING 0x01
62+#define FLAG2_HINT_PENDING 0x02
63+#define FLAG2_READ_PENDING 0x04
64+#define FLAG2_SPRITE_COLLIDE 0x08
65+#define FLAG2_REGION_PAL 0x10
66+#define FLAG2_EVEN_FIELD 0x20
67+#define FLAG2_BYTE_PENDING 0x40
68+#define FLAG2_PAUSE 0x80
69+
70+#define DISPLAY_ENABLE 0x40
71+
72+enum {
73+ REG_MODE_1=0,
74+ REG_MODE_2,
75+ REG_SCROLL_A,
76+ REG_WINDOW,
77+ REG_SCROLL_B,
78+ REG_SAT,
79+ REG_STILE_BASE,
80+ REG_BG_COLOR,
81+ REG_X_SCROLL,
82+ REG_Y_SCROLL,
83+ REG_HINT,
84+ REG_MODE_3,
85+ REG_MODE_4,
86+ REG_HSCROLL,
87+ REG_BGTILE_BASE,
88+ REG_AUTOINC,
89+ REG_SCROLL,
90+ REG_WINDOW_H,
91+ REG_WINDOW_V,
92+ REG_DMALEN_L,
93+ REG_DMALEN_H,
94+ REG_DMASRC_L,
95+ REG_DMASRC_M,
96+ REG_DMASRC_H
97+};
98+
99+//Mode reg 1
100+#define BIT_VSCRL_LOCK 0x80
101+#define BIT_HSCRL_LOCK 0x40
102+#define BIT_COL0_MASK 0x20
103+#define BIT_HINT_EN 0x10
104+#define BIT_SPRITE_8PX 0x08
105+#define BIT_PAL_SEL 0x04
106+#define BIT_MODE_4 BIT_PAL_SEL
107+#define BIT_HVC_LATCH 0x02
108+#define BIT_DISP_DIS 0x01
109+
110+//Mode reg 2
111+#define BIT_128K_VRAM 0x80
112+#define BIT_DISP_EN 0x40
113+#define BIT_VINT_EN 0x20
114+#define BIT_DMA_ENABLE 0x10
115+#define BIT_PAL 0x08
116+#define BIT_MODE_5 0x04
117+#define BIT_SPRITE_SZ 0x02
118+
119+//Mode reg 3
120+#define BIT_EINT_EN 0x10
121+#define BIT_VSCROLL 0x04
122+
123+//Mode reg 4
124+#define BIT_H40 0x01
125+#define BIT_HILIGHT 0x8
126+#define BIT_DOUBLE_RES 0x4
127+#define BIT_INTERLACE 0x2
128+
129+//Test register
130+#define TEST_BIT_DISABLE 0x40
131+
132+typedef struct {
133+ uint16_t address;
134+ int16_t x_pos;
135+ uint8_t pal_priority;
136+ uint8_t h_flip;
137+} sprite_draw;
138+
139+typedef struct {
140+ uint8_t size;
141+ uint8_t index;
142+ int16_t y;
143+} sprite_info;
144+
145+#define FIFO_SIZE 4
146+
147+typedef struct {
148+ uint32_t cycle;
149+ uint32_t address;
150+ uint16_t value;
151+ uint8_t cd;
152+ uint8_t partial;
153+} fifo_entry;
154+
155+enum {
156+ VDP_DEBUG_PLANE,
157+ VDP_DEBUG_VRAM,
158+ VDP_DEBUG_CRAM,
159+ VDP_DEBUG_COMPOSITE,
160+ VDP_NUM_DEBUG_TYPES
161+};
162+
163+typedef struct {
164+ system_header *system;
165+ //pointer to current line in framebuffer
166+ uint32_t *output;
167+ uint32_t *done_output;
168+ //pointer to current framebuffer
169+ uint32_t *fb;
170+ uint32_t *debug_fbs[VDP_NUM_DEBUG_TYPES];
171+ uint32_t output_pitch;
172+ uint32_t debug_fb_pitch[VDP_NUM_DEBUG_TYPES];
173+ fifo_entry fifo[FIFO_SIZE];
174+ int32_t fifo_write;
175+ int32_t fifo_read;
176+ uint32_t address;
177+ uint32_t serial_address;
178+ uint32_t colors[CRAM_SIZE*4];
179+ uint32_t debugcolors[1 << (3 + 1 + 1 + 1)];//3 bits for source, 1 bit for priority, 1 bit for shadow, 1 bit for hilight
180+ uint16_t cram[CRAM_SIZE];
181+ uint32_t frame;
182+ uint8_t cd;
183+ uint8_t flags;
184+ uint8_t regs[VDP_REGS];
185+ //cycle count in MCLKs
186+ uint32_t cycles;
187+ uint32_t pending_vint_start;
188+ uint32_t pending_hint_start;
189+ uint16_t vsram[VSRAM_SIZE];
190+ uint16_t vscroll_latch[2];
191+ uint16_t vcounter;
192+ uint16_t inactive_start;
193+ uint16_t border_top;
194+ uint16_t border_bot;
195+ uint16_t hscroll_a;
196+ uint16_t hscroll_b;
197+ uint16_t h40_lines;
198+ uint16_t output_lines;
199+ sprite_draw sprite_draw_list[MAX_DRAWS];
200+ sprite_info sprite_info_list[MAX_SPRITES_LINE];
201+ uint8_t sat_cache[SAT_CACHE_SIZE];
202+ uint16_t col_1;
203+ uint16_t col_2;
204+ uint16_t hv_latch;
205+ uint16_t prefetch;
206+ uint16_t test_port;
207+ //stores 2-bit palette + 4-bit palette index + priority for current sprite line
208+ uint8_t linebuf[LINEBUF_SIZE];
209+ uint8_t layer_debug_buf[LINEBUF_SIZE];
210+ uint8_t hslot; //hcounter/2
211+ uint8_t sprite_index;
212+ uint8_t sprite_draws;
213+ int8_t slot_counter;
214+ int8_t cur_slot;
215+ uint8_t max_sprites_frame;
216+ uint8_t max_sprites_line;
217+ uint8_t fetch_tmp[2];
218+ uint8_t v_offset;
219+ uint8_t hint_counter;
220+ uint8_t flags2;
221+ uint8_t double_res;
222+ uint8_t buf_a_off;
223+ uint8_t buf_b_off;
224+ uint8_t pending_byte;
225+ uint8_t state;
226+ uint8_t cur_buffer;
227+ uint8_t tmp_buf_a[SCROLL_BUFFER_SIZE];
228+ uint8_t tmp_buf_b[SCROLL_BUFFER_SIZE];
229+ uint8_t enabled_debuggers;
230+ uint8_t debug_fb_indices[VDP_NUM_DEBUG_TYPES];
231+ uint8_t debug_modes[VDP_NUM_DEBUG_TYPES];
232+ uint8_t vdpmem[];
233+} vdp_context;
234+
235+
236+
237+vdp_context *init_vdp_context(uint8_t region_pal);
238+void vdp_free(vdp_context *context);
239+void vdp_run_context_full(vdp_context * context, uint32_t target_cycles);
240+void vdp_run_context(vdp_context * context, uint32_t target_cycles);
241+//runs from current cycle count to VBLANK for the current mode, returns ending cycle count
242+uint32_t vdp_run_to_vblank(vdp_context * context);
243+//runs until the target cycle is reached or the current DMA operation has completed, whicever comes first
244+void vdp_run_dma_done(vdp_context * context, uint32_t target_cycles);
245+uint8_t vdp_load_gst(vdp_context * context, FILE * state_file);
246+uint8_t vdp_save_gst(vdp_context * context, FILE * outfile);
247+int vdp_control_port_write(vdp_context * context, uint16_t value);
248+void vdp_control_port_write_pbc(vdp_context * context, uint8_t value);
249+int vdp_data_port_write(vdp_context * context, uint16_t value);
250+void vdp_data_port_write_pbc(vdp_context * context, uint8_t value);
251+void vdp_test_port_write(vdp_context * context, uint16_t value);
252+uint16_t vdp_control_port_read(vdp_context * context);
253+uint16_t vdp_data_port_read(vdp_context * context);
254+uint8_t vdp_data_port_read_pbc(vdp_context * context);
255+void vdp_latch_hv(vdp_context *context);
256+uint16_t vdp_hv_counter_read(vdp_context * context);
257+uint16_t vdp_test_port_read(vdp_context * context);
258+void vdp_adjust_cycles(vdp_context * context, uint32_t deduction);
259+uint32_t vdp_next_hint(vdp_context * context);
260+uint32_t vdp_next_vint(vdp_context * context);
261+uint32_t vdp_next_vint_z80(vdp_context * context);
262+uint32_t vdp_next_nmi(vdp_context *context);
263+void vdp_int_ack(vdp_context * context);
264+void vdp_print_sprite_table(vdp_context * context);
265+void vdp_print_reg_explain(vdp_context * context);
266+void latch_mode(vdp_context * context);
267+uint32_t vdp_cycles_to_frame_end(vdp_context * context);
268+void write_cram_internal(vdp_context * context, uint16_t addr, uint16_t value);
269+void vdp_check_update_sat_byte(vdp_context *context, uint32_t address, uint8_t value);
270+void vdp_pbc_pause(vdp_context *context);
271+void vdp_release_framebuffer(vdp_context *context);
272+void vdp_reacquire_framebuffer(vdp_context *context);
273+void vdp_serialize(vdp_context *context, serialize_buffer *buf);
274+void vdp_deserialize(deserialize_buffer *buf, void *vcontext);
275+void vdp_force_update_framebuffer(vdp_context *context);
276+void vdp_toggle_debug_view(vdp_context *context, uint8_t debug_type);
277+void vdp_inc_debug_mode(vdp_context *context);
278+//to be implemented by the host system
279+uint16_t read_dma_value(uint32_t address);
280+
281+#endif //VDP_H_
A
vgm.h
+74,
-0
1@@ -0,0 +1,74 @@
2+#ifndef VGM_H_
3+#define VGM_H_
4+
5+#pragma pack(push, 1)
6+typedef struct {
7+ char ident[4];
8+ uint32_t eof_offset;
9+ uint32_t version;
10+ uint32_t sn76489_clk;
11+ uint32_t ym2413_clk;
12+ uint32_t gd3_offset;
13+ uint32_t num_samples;
14+ uint32_t loop_offset;
15+ uint32_t loop_samples;
16+ uint32_t rate;
17+ uint16_t sn76489_fb;
18+ uint8_t sn76489_shift;
19+ uint8_t sn76489_flags;
20+ uint32_t ym2612_clk;
21+ uint32_t ym2151_clk;
22+ uint32_t data_offset;
23+ uint32_t sega_pcm_clk;
24+ uint32_t sega_pcm_reg;
25+} vgm_header;
26+
27+enum {
28+ CMD_PSG_STEREO = 0x4F,
29+ CMD_PSG,
30+ CMD_YM2413,
31+ CMD_YM2612_0,
32+ CMD_YM2612_1,
33+ CMD_YM2151,
34+ CMD_YM2203,
35+ CMD_YM2608_0,
36+ CMD_YM2608_1,
37+ CMD_YM2610_0,
38+ CMD_YM2610_1,
39+ CMD_YM3812,
40+ CMD_YM3526,
41+ CMD_Y8950,
42+ CMD_YMZ280B,
43+ CMD_YMF262_0,
44+ CMD_YMF262_1,
45+ CMD_WAIT = 0x61,
46+ CMD_WAIT_60,
47+ CMD_WAIT_50,
48+ CMD_END = 0x66,
49+ CMD_DATA,
50+ CMD_PCM_WRITE,
51+ CMD_WAIT_SHORT = 0x70,
52+ CMD_YM2612_DAC = 0x80,
53+ CMD_DAC_STREAM_SETUP = 0x90,
54+ CMD_DAC_STREAM_DATA,
55+ CMD_DAC_STREAM_FREQ,
56+ CMD_DAC_STREAM_START,
57+ CMD_DAC_STREAM_STOP,
58+ CMD_DAC_STREAM_STARTFAST,
59+ CMD_DATA_SEEK = 0xE0
60+};
61+
62+enum {
63+ DATA_YM2612_PCM = 0
64+};
65+
66+#pragma pack(pop)
67+
68+typedef struct {
69+ struct data_block *next;
70+ uint8_t *data;
71+ uint32_t size;
72+ uint8_t type;
73+} data_block;
74+
75+#endif //VGM_H_
+248,
-0
1@@ -0,0 +1,248 @@
2+/*
3+ Copyright 2013 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#include "render.h"
8+#include "ym2612.h"
9+#include "psg.h"
10+#include "config.h"
11+#include "util.h"
12+#include <stdint.h>
13+#include <stdio.h>
14+#include <stdlib.h>
15+#include <string.h>
16+#include "vgm.h"
17+
18+#define MCLKS_NTSC 53693175
19+#define MCLKS_PAL 53203395
20+
21+#define MCLKS_PER_68K 7
22+#define MCLKS_PER_YM MCLKS_PER_68K
23+#define MCLKS_PER_Z80 15
24+#define MCLKS_PER_PSG (MCLKS_PER_Z80*16)
25+
26+void handle_keydown(int keycode)
27+{
28+}
29+
30+void handle_keyup(int keycode)
31+{
32+}
33+
34+void handle_joydown(int joystick, int button)
35+{
36+}
37+
38+void handle_joyup(int joystick, int button)
39+{
40+}
41+
42+void handle_joy_dpad(int joystick, int dpadnum, uint8_t value)
43+{
44+}
45+
46+void handle_joy_axis(int joystick, int axis, int16_t value)
47+{
48+}
49+
50+void handle_joy_added(int joystick)
51+{
52+}
53+
54+void handle_mouse_moved(int mouse, uint16_t x, uint16_t y, int16_t deltax, int16_t deltay)
55+{
56+}
57+
58+void handle_mousedown(int mouse, int button)
59+{
60+}
61+
62+void handle_mouseup(int mouse, int button)
63+{
64+}
65+
66+int headless = 0;
67+
68+#define CYCLE_LIMIT MCLKS_NTSC/60
69+#define MAX_SOUND_CYCLES 100000
70+tern_node * config;
71+
72+void vgm_wait(ym2612_context * y_context, psg_context * p_context, uint32_t * current_cycle, uint32_t cycles)
73+{
74+ while (cycles > MAX_SOUND_CYCLES)
75+ {
76+ vgm_wait(y_context, p_context, current_cycle, MAX_SOUND_CYCLES);
77+ cycles -= MAX_SOUND_CYCLES;
78+ }
79+ *current_cycle += cycles;
80+ psg_run(p_context, *current_cycle);
81+ ym_run(y_context, *current_cycle);
82+
83+ if (*current_cycle > CYCLE_LIMIT) {
84+ *current_cycle -= CYCLE_LIMIT;
85+ p_context->cycles -= CYCLE_LIMIT;
86+ y_context->current_cycle -= CYCLE_LIMIT;
87+ process_events();
88+ }
89+}
90+
91+int main(int argc, char ** argv)
92+{
93+ set_exe_str(argv[0]);
94+ data_block *blocks = NULL;
95+ data_block *seek_block = NULL;
96+ uint32_t seek_offset;
97+ uint32_t block_offset;
98+
99+ uint32_t fps = 60;
100+ config = load_config(argv[0]);
101+ render_init(320, 240, "vgm play", 0);
102+
103+ uint32_t opts = 0;
104+ if (argc >= 3 && !strcmp(argv[2], "-y")) {
105+ opts |= YM_OPT_WAVE_LOG;
106+ }
107+
108+ char * lowpass_cutoff_str = tern_find_path(config, "audio\0lowpass_cutoff\0", TVAL_PTR).ptrval;
109+ uint32_t lowpass_cutoff = lowpass_cutoff_str ? atoi(lowpass_cutoff_str) : 3390;
110+
111+ ym2612_context y_context;
112+ ym_init(&y_context, MCLKS_NTSC, MCLKS_PER_YM, opts);
113+
114+ psg_context p_context;
115+ psg_init(&p_context, MCLKS_NTSC, MCLKS_PER_PSG);
116+
117+ FILE * f = fopen(argv[1], "rb");
118+ vgm_header header;
119+ fread(&header, sizeof(header), 1, f);
120+ if (header.version < 0x150 || !header.data_offset) {
121+ header.data_offset = 0xC;
122+ }
123+ fseek(f, header.data_offset + 0x34, SEEK_SET);
124+ uint32_t data_size = header.eof_offset + 4 - (header.data_offset + 0x34);
125+ uint8_t * data = malloc(data_size);
126+ fread(data, 1, data_size, f);
127+ fclose(f);
128+
129+ uint32_t mclks_sample = MCLKS_NTSC / 44100;
130+ uint32_t loop_count = 2;
131+
132+ uint8_t * end = data + data_size;
133+ uint8_t * cur = data;
134+ uint32_t current_cycle = 0;
135+ while (cur < end) {
136+ uint8_t cmd = *(cur++);
137+ switch(cmd)
138+ {
139+ case CMD_PSG_STEREO:
140+ //ignore for now
141+ cur++;
142+ break;
143+ case CMD_PSG:
144+ psg_write(&p_context, *(cur++));
145+ break;
146+ case CMD_YM2612_0:
147+ ym_address_write_part1(&y_context, *(cur++));
148+ ym_data_write(&y_context, *(cur++));
149+ break;
150+ case CMD_YM2612_1:
151+ ym_address_write_part2(&y_context, *(cur++));
152+ ym_data_write(&y_context, *(cur++));
153+ break;
154+ case CMD_WAIT: {
155+ uint32_t wait_time = *(cur++);
156+ wait_time |= *(cur++) << 8;
157+ wait_time *= mclks_sample;
158+ vgm_wait(&y_context, &p_context, ¤t_cycle, wait_time);
159+ break;
160+ }
161+ case CMD_WAIT_60:
162+ vgm_wait(&y_context, &p_context, ¤t_cycle, 735 * mclks_sample);
163+ break;
164+ case CMD_WAIT_50:
165+ vgm_wait(&y_context, &p_context, ¤t_cycle, 882 * mclks_sample);
166+ break;
167+ case CMD_END:
168+ if (header.loop_offset && --loop_count) {
169+ cur = data + header.loop_offset + 0x1C - (header.data_offset + 0x34);
170+ } else {
171+ //TODO: fade out
172+ return 0;
173+ }
174+ break;
175+ case CMD_DATA: {
176+ cur++; //skip compat command
177+ uint8_t data_type = *(cur++);
178+ uint32_t data_size = *(cur++);
179+ data_size |= *(cur++) << 8;
180+ data_size |= *(cur++) << 16;
181+ data_size |= *(cur++) << 24;
182+ if (data_type == DATA_YM2612_PCM) {
183+ data_block ** curblock = &blocks;
184+ while(*curblock)
185+ {
186+ curblock = &((*curblock)->next);
187+ }
188+ *curblock = malloc(sizeof(data_block));
189+ (*curblock)->size = data_size;
190+ (*curblock)->type = data_type;
191+ (*curblock)->data = cur;
192+ (*curblock)->next = NULL;
193+ } else {
194+ fprintf(stderr, "Skipping data block with unrecognized type %X\n", data_type);
195+ }
196+ cur += data_size;
197+ break;
198+ }
199+ case CMD_DATA_SEEK: {
200+ uint32_t new_offset = *(cur++);
201+ new_offset |= *(cur++) << 8;
202+ new_offset |= *(cur++) << 16;
203+ new_offset |= *(cur++) << 24;
204+ if (!seek_block || new_offset < seek_offset) {
205+ seek_block = blocks;
206+ seek_offset = 0;
207+ block_offset = 0;
208+ }
209+ while (seek_block && (seek_offset - block_offset + seek_block->size) < new_offset)
210+ {
211+ seek_offset += seek_block->size - block_offset;
212+ seek_block = seek_block->next;
213+ block_offset = 0;
214+ }
215+ block_offset += new_offset-seek_offset;
216+ seek_offset = new_offset;
217+ break;
218+ }
219+
220+ default:
221+ if (cmd >= CMD_WAIT_SHORT && cmd < (CMD_WAIT_SHORT + 0x10)) {
222+ uint32_t wait_time = (cmd & 0xF) + 1;
223+ wait_time *= mclks_sample;
224+ vgm_wait(&y_context, &p_context, ¤t_cycle, wait_time);
225+ } else if (cmd >= CMD_YM2612_DAC && cmd < CMD_DAC_STREAM_SETUP) {
226+ if (seek_block) {
227+ ym_address_write_part1(&y_context, 0x2A);
228+ ym_data_write(&y_context, seek_block->data[block_offset++]);
229+ seek_offset++;
230+ if (block_offset > seek_block->size) {
231+ seek_block = seek_block->next;
232+ block_offset = 0;
233+ }
234+ } else {
235+ fputs("Encountered DAC write command but data seek pointer is invalid!\n", stderr);
236+ }
237+ uint32_t wait_time = (cmd & 0xF);
238+ if (wait_time)
239+ {
240+ wait_time *= mclks_sample;
241+ vgm_wait(&y_context, &p_context, ¤t_cycle, wait_time);
242+ }
243+ } else {
244+ fatal_error("unimplemented command: %X at offset %X\n", cmd, (unsigned int)(cur - data - 1));
245+ }
246+ }
247+ }
248+ return 0;
249+}
+274,
-0
1@@ -0,0 +1,274 @@
2+/*
3+ Copyright 2015 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#include "ym2612.h"
8+#include "vgm.h"
9+#include <stdint.h>
10+#include <stdio.h>
11+#include <stdlib.h>
12+#include <string.h>
13+
14+#define OUT_CHANNELS 10
15+#define DAC_CHANNEL 5
16+#define PSG_BASE 6
17+#define SAMPLE_THRESHOLD 100
18+
19+uint32_t total_delay;
20+void accum_wait(uint32_t *delays, uint32_t samples)
21+{
22+ total_delay += samples;
23+ for (int i = 0; i < OUT_CHANNELS; i++)
24+ {
25+ delays[i] += samples;
26+ }
27+}
28+
29+void write_wait(uint8_t **out_buffer, uint32_t *delay)
30+{
31+ while (*delay >= 65535)
32+ {
33+ *((*out_buffer)++) = CMD_WAIT;
34+ *((*out_buffer)++) = 0xFF;
35+ *((*out_buffer)++) = 0xFF;
36+ *delay -= 65535;
37+ }
38+ if (*delay) {
39+ if (*delay == 735) {
40+ *((*out_buffer)++) = CMD_WAIT_60;
41+ } else if (*delay > 735 && *delay <= 751) {
42+ *((*out_buffer)++) = CMD_WAIT_60;
43+ *((*out_buffer)++) = CMD_WAIT_SHORT + *delay - 736;
44+ } else if (*delay == 882) {
45+ *((*out_buffer)++) = CMD_WAIT_50;
46+ } else if (*delay > 882 && *delay <= 898) {
47+ *((*out_buffer)++) = CMD_WAIT_50;
48+ *((*out_buffer)++) = CMD_WAIT_SHORT + *delay - 882;
49+ } else if (*delay <= 16) {
50+ *((*out_buffer)++) = CMD_WAIT_SHORT + *delay - 1;
51+ } else {
52+ *((*out_buffer)++) = CMD_WAIT;
53+ *((*out_buffer)++) = *delay;
54+ *((*out_buffer)++) = *delay >> 8;
55+ }
56+ *delay = 0;
57+ }
58+}
59+
60+int main(int argc, char ** argv)
61+{
62+ data_block *blocks = NULL;
63+ data_block *seek_block = NULL;
64+ uint32_t seek_offset;
65+ uint32_t block_offset;
66+
67+
68+ FILE * f = fopen(argv[1], "rb");
69+ vgm_header header;
70+ size_t bytes = fread(&header, 1, sizeof(header), f);
71+ if (bytes != sizeof(header)) {
72+ fputs("Error reading file\n", stderr);
73+ exit(1);
74+ }
75+ if (header.version < 0x150 || !header.data_offset) {
76+ header.data_offset = 0xC;
77+ }
78+ fseek(f, header.data_offset + 0x34, SEEK_SET);
79+ uint32_t data_size = header.eof_offset + 4 - (header.data_offset + 0x34);
80+ uint8_t * data = malloc(data_size);
81+ data_size = fread(data, 1, data_size, f);
82+ fclose(f);
83+ uint8_t *buffers[OUT_CHANNELS];
84+ uint8_t *out_pos[OUT_CHANNELS];
85+ uint8_t has_real_data[OUT_CHANNELS];
86+ uint32_t delay[OUT_CHANNELS];
87+
88+ buffers[0] = malloc(data_size * OUT_CHANNELS);
89+ out_pos[0] = buffers[0];
90+ has_real_data[0] = 0;
91+ delay[0] = 0;
92+ for (int i = 1; i < OUT_CHANNELS; i++)
93+ {
94+ buffers[i] = buffers[i-1] + data_size;
95+ out_pos[i] = buffers[i];
96+ has_real_data[i] = 0;
97+ delay[i] = 0;
98+ }
99+
100+ uint8_t * end = data + data_size;
101+ uint8_t * cur = data;
102+ uint32_t current_cycle = 0;
103+ uint8_t psg_latch = 0;
104+ uint8_t param,reg;
105+ uint8_t channel;
106+ uint32_t sample_count = 0;
107+ uint8_t last_cmd;
108+ while (cur < end) {
109+ uint8_t cmd = *(cur++);
110+ switch(cmd)
111+ {
112+ case CMD_PSG_STEREO:
113+ //ignore for now
114+ cur++;
115+ break;
116+ case CMD_PSG:
117+ param = *(cur++);
118+ if (param & 0x80) {
119+ psg_latch = param;
120+ channel = param >> 5 & 3;
121+ } else {
122+ channel = psg_latch >> 5 & 3;
123+ }
124+ write_wait(out_pos + PSG_BASE+channel, delay + PSG_BASE+channel);
125+ *(out_pos[PSG_BASE+channel]++) = cmd;
126+ *(out_pos[PSG_BASE+channel]++) = param;
127+ has_real_data[PSG_BASE+channel] = 1;
128+ break;
129+ case CMD_YM2612_0:
130+ reg = *(cur++);
131+ param = *(cur++);
132+ if (reg < REG_KEY_ONOFF) {
133+ for (int i = 0; i < 6; i++)
134+ {
135+ write_wait(out_pos + i, delay + i);
136+ *(out_pos[i]++) = cmd;
137+ *(out_pos[i]++) = reg;
138+ *(out_pos[i]++) = param;
139+ }
140+ break;
141+ } else if(reg == REG_DAC || reg == REG_DAC_ENABLE) {
142+ if (reg == REG_DAC) {
143+ sample_count++;
144+ }
145+ channel = DAC_CHANNEL;
146+ } else if(reg == REG_KEY_ONOFF) {
147+ channel = param & 7;
148+ if (channel > 2) {
149+ channel--;
150+ }
151+ if (param & 0xF0) {
152+ has_real_data[channel] = 1;
153+ }
154+ } else if (reg >= REG_FNUM_LOW_CH3 && reg < REG_ALG_FEEDBACK) {
155+ channel = 2;
156+ } else {
157+ channel = 255;
158+ }
159+ case CMD_YM2612_1:
160+ if (cmd == CMD_YM2612_1) {
161+ reg = *(cur++);
162+ param = *(cur++);
163+ channel = 255;
164+ }
165+ if (channel >= PSG_BASE) {
166+ if (reg >= REG_DETUNE_MULT && reg < REG_FNUM_LOW) {
167+ channel = (cmd == CMD_YM2612_0 ? 0 : 3) + (reg & 0xC >> 2);
168+ } else if ((reg >= REG_FNUM_LOW && reg < REG_FNUM_LOW_CH3) || (reg >= REG_ALG_FEEDBACK && reg < 0xC0)) {
169+ channel = (cmd == CMD_YM2612_0 ? 0 : 3) + (reg & 0x3);
170+ } else {
171+ fprintf(stderr, "WARNING: Skipping nrecognized write to register %X on part %d\n", reg, (cmd == CMD_YM2612_0 ? 1 : 2));
172+ }
173+ }
174+ if (channel < PSG_BASE) {
175+ write_wait(out_pos + channel, delay + channel);
176+ *(out_pos[channel]++) = cmd;
177+ *(out_pos[channel]++) = reg;
178+ *(out_pos[channel]++) = param;
179+ }
180+ break;
181+ case CMD_WAIT: {
182+ uint32_t wait_time = *(cur++);
183+ wait_time |= *(cur++) << 8;
184+ accum_wait(delay, wait_time);
185+ break;
186+ }
187+ case CMD_WAIT_60:
188+ accum_wait(delay, 735);
189+ break;
190+ case CMD_WAIT_50:
191+ accum_wait(delay, 882);
192+ break;
193+ case CMD_END:
194+ for (int i = 0; i < OUT_CHANNELS; i++)
195+ {
196+ write_wait(out_pos + i, delay + i);
197+ *(out_pos[i]++) = cmd;
198+ }
199+ cur = end;
200+ break;
201+ case CMD_DATA: {
202+ uint8_t * start = cur - 1;
203+ cur++; //skip compat command
204+ uint8_t data_type = *(cur++);
205+ uint32_t data_size = *(cur++);
206+ data_size |= *(cur++) << 8;
207+ data_size |= *(cur++) << 16;
208+ data_size |= *(cur++) << 24;
209+ if (cur + data_size > end) {
210+ data_size = end - cur;
211+ }
212+ cur += data_size;
213+ if (data_type == DATA_YM2612_PCM) {
214+ write_wait(out_pos + DAC_CHANNEL, delay + DAC_CHANNEL);
215+ memcpy(out_pos[DAC_CHANNEL], start, cur-start);
216+ out_pos[DAC_CHANNEL] += cur-start;
217+ } else {
218+ fprintf(stderr, "WARNING: Skipping data block with unrecognized type %X\n", data_type);
219+ }
220+ break;
221+ }
222+ case CMD_DATA_SEEK: {
223+ write_wait(out_pos + DAC_CHANNEL, delay + DAC_CHANNEL);
224+ memcpy(out_pos[DAC_CHANNEL], cur-1, 5);
225+ out_pos[DAC_CHANNEL] += 5;
226+ cur += 4;
227+ break;
228+ }
229+
230+ default:
231+ if (cmd >= CMD_WAIT_SHORT && cmd < (CMD_WAIT_SHORT + 0x10)) {
232+ accum_wait(delay, (cmd & 0xF) + 1);
233+ } else if (cmd >= CMD_YM2612_DAC && cmd < CMD_DAC_STREAM_SETUP) {
234+ write_wait(out_pos + DAC_CHANNEL, delay + DAC_CHANNEL);
235+ *(out_pos[DAC_CHANNEL]++) = cmd;
236+ for (int i = 0; i < OUT_CHANNELS; i++)
237+ {
238+ if (i != DAC_CHANNEL)
239+ {
240+ delay[i] += cmd & 0xF;
241+ }
242+ }
243+ sample_count++;
244+ } else {
245+ fprintf(stderr, "unimplemented command: %X at offset %X, last valid command was %X\n", cmd, (unsigned int)(cur - data - 1), last_cmd);
246+ exit(1);
247+ }
248+ }
249+ last_cmd = cmd;
250+ }
251+ if (sample_count > SAMPLE_THRESHOLD) {
252+ has_real_data[DAC_CHANNEL] = 1;
253+ }
254+ for (int i = 0; i < OUT_CHANNELS; i++)
255+ {
256+ if (has_real_data[i]) {
257+ char fname[11];
258+ sprintf(fname, i < PSG_BASE ? "ym_%d.vgm" : "psg_%d.vgm", i < PSG_BASE ? i : i - PSG_BASE);
259+ f = fopen(fname, "wb");
260+ if (!f) {
261+ fprintf(stderr, "Failed to open %s for writing\n", fname);
262+ exit(1);
263+ }
264+ data_size = out_pos[i] - buffers[i];
265+ header.eof_offset = (header.data_offset + 0x34) + data_size - 4;
266+ header.gd3_offset = 0;
267+ fwrite(&header, 1, sizeof(header), f);
268+ fseek(f, header.data_offset + 0x34, SEEK_SET);
269+ fwrite(buffers[i], 1, data_size, f);
270+ fclose(f);
271+ }
272+ }
273+ printf("total_delay: %d\n", total_delay);
274+ return 0;
275+}
+100,
-0
1@@ -0,0 +1,100 @@
2+#include <stdio.h>
3+#include "vos_program_module.h"
4+
5+int main(int argc, char ** argv)
6+{
7+ vos_program_module header;
8+ FILE * f = fopen(argv[1], "rb");
9+ vos_read_header(f, &header);
10+ vos_read_alloc_module_map(f, &header);
11+ vos_read_alloc_external_vars(f, &header);
12+
13+ printf("Version: %d\n", header.version);
14+ printf("Binder Version: %s\n", header.binder_version.str);
15+ printf("Binder Options: %s\n", header.binder_options.str);
16+ printf("System name: %s\n", header.system_name.str);
17+ printf("User name: %s\n", header.user_name.str);
18+ printf("Date bound: %d\n", header.date_bound);
19+ printf("Code addresss: 0x%X, Static address: 0x%X\n",
20+ header.main_entry_link.code_address, header.main_entry_link.static_address);
21+ printf("User boundary: 0x%X\n", header.user_boundary);
22+ printf("Num modules: %d\n", header.n_modules);
23+ printf("Num extern vars: %d\n", header.n_external_vars);
24+ printf("Num link names: %d\n", header.n_link_names);
25+ printf("Num unsapped links: %d\n", header.n_unsnapped_links);
26+ printf("Num VM pages: %d\n", header.n_vm_pages);
27+ printf("Num header pages: %d\n", header.n_header_pages);
28+ for (int i = 0; i < 3; i++) {
29+ for (int j = 0; j < 4; j++) {
30+ printf("Info %d:%d\n\tAddress: 0x%X\n\tLength: 0x%X\n",
31+ i, j, header.info[i][j].address, header.info[i][j].len);
32+ }
33+ }
34+ printf("Module map address: 0x%X\n", header.module_map_address);
35+ printf("Module map length: 0x%X\n", header.module_map_len);
36+ printf("External vars map address: 0x%X\n", header.external_vars_map_address);
37+ printf("External vars map length: 0x%X\n", header.external_vars_map_len);
38+ printf("Link names map address: 0x%X\n", header.link_names_map_address);
39+ printf("Link names map length: 0x%X\n", header.link_names_map_len);
40+ printf("Header address: 0x%X\n", header.header_address);
41+ printf("Header length: 0x%X\n", header.header_len);
42+ //printf("Access Info: 0x%X\n", header.header_address);
43+ printf("Flags: 0x%X\n", header.flags);
44+ printf("Num tasks: %d\n", header.n_tasks);
45+ printf("Stack Size: 0x%X\n", header.stack_len);
46+ printf("Num entries: %d\n", header.n_entries);
47+ printf("Entry map address: 0x%X\n", header.entry_map_address);
48+ printf("Entry map length: 0x%X\n", header.entry_map_len);
49+ printf("Pop Version: %d\n", header.pop_version);
50+ printf("Processor: %d\n", header.processor);
51+ printf("Processor family: %d\n", header.processor_family);
52+ printf("Release name: %s\n", header.release_name.str);
53+ printf("Relocation info:\n\tMap Addres: 0x%X\n\tMap Length: 0x%X\n\tNum Relocations: %d\n",
54+ header.relocation_info.map_address, header.relocation_info.map_len,
55+ header.relocation_info.n_relocations);
56+ printf("High water mark: 0x%X\n", header.high_water_mark);
57+ printf("Copyright notice: %s\n", header.program_name.str);
58+ printf("String pool address: 0x%X\n", header.string_pool_address);
59+ printf("String pool length: 0x%X\n", header.string_pool_len);
60+ printf("Object dir map address: 0x%X\n", header.obj_dir_map_address);
61+ printf("Object dir map length: 0x%X\n", header.obj_dir_map_len);
62+ puts("Global offset table addresses:");
63+ for (int i = 0; i < 3; i++) {
64+ printf("\t%d: 0x%X\n", i, header.global_offset_table_address[i]);
65+ }
66+ for (int i = 0; i < 3; i++) {
67+ printf("Block map info %d\n\tAddress: 0x%X\n\tLength: 0x%X\n",
68+ i, header.block_map_info[i].address, header.block_map_info[i].len);
69+ }
70+ printf("Secton map file address: 0x%X\n", header.section_map_file_address);
71+ printf("Secton map address: 0x%X\n", header.section_map_address);
72+ printf("Secton map length: 0x%X\n", header.section_map_len);
73+ printf("Num sections: %d\n", header.n_sections);
74+ printf("Max heap size: 0x%X\n", header.max_heap_size);
75+ printf("Max program size: 0x%X\n", header.max_program_size);
76+ printf("Max stack size: 0x%X\n", header.max_stack_size);
77+ printf("Stack fence size: 0x%X\n", header.stack_fence_size);
78+
79+ puts("\nModules");
80+ for (int i = 0; i < header.n_modules; i++) {
81+ printf("\t%s:\n\t\tCode Address: 0x%X, Length: 0x%X\n",
82+ header.module_map_entries[i].name.str,
83+ header.module_map_entries[i].code_address,
84+ header.module_map_entries[i].code_length);
85+ printf("\t\tFoo Address: 0x%X, Length: 0x%X\n",
86+ header.module_map_entries[i].foo_address,
87+ header.module_map_entries[i].foo_length);
88+ printf("\t\tBar Address: 0x%X, Length: 0x%X\n",
89+ header.module_map_entries[i].bar_address,
90+ header.module_map_entries[i].bar_length);
91+ }
92+
93+ puts("\nExtrnal Vars");
94+ for (int i = 0; i < header.n_external_vars; i++) {
95+ printf("\t%s: 0x%X\n",
96+ header.external_vars[i].name.str, header.external_vars[i].address);
97+ }
98+
99+ vos_header_cleanup(&header);
100+ return 0;
101+}
+208,
-0
1@@ -0,0 +1,208 @@
2+#include <stdio.h>
3+#include <stdlib.h>
4+#include <stddef.h>
5+#include <string.h>
6+#include "vos_program_module.h"
7+
8+static uint16_t big16(uint8_t ** src)
9+{
10+ uint16_t ret = *((*src)++) << 8;
11+ ret |= *((*src)++);
12+ return ret;
13+}
14+
15+static uint32_t big32(uint8_t ** src)
16+{
17+ uint32_t ret = *((*src)++) << 24;
18+ ret |= *((*src)++) << 16;
19+ ret |= *((*src)++) << 8;
20+ ret |= *((*src)++);
21+ return ret;
22+}
23+
24+static void string_(uint8_t ** src, uint16_t *len, char * str, uint32_t storage)
25+{
26+ *len = big16(src);
27+ memcpy(str, *src, storage);
28+ *src += storage;
29+ if (*len >= storage)
30+ {
31+ *len = storage;
32+ } else {
33+ str[*len] = 0;
34+ }
35+ if (storage & 1)
36+ {
37+ (*src)++;
38+ }
39+}
40+
41+#define string(src, field) string_(src, &(field).len, (field).str, sizeof((field).str))
42+
43+
44+int vos_read_header(FILE * f, vos_program_module *out)
45+{
46+ uint8_t buffer[4096];
47+ if (fread(buffer, 1, sizeof(buffer), f) != sizeof(buffer))
48+ {
49+ return 0;
50+ }
51+ uint8_t *cur = buffer;
52+ out->version = big16(&cur);
53+ string(&cur, out->binder_version);
54+ string(&cur, out->binder_options);
55+ string(&cur, out->system_name);
56+ string(&cur, out->user_name);
57+ out->date_bound = big32(&cur);
58+ out->main_entry_link.code_address = big32(&cur);
59+ out->main_entry_link.static_address = big32(&cur);
60+ out->user_boundary = big32(&cur);
61+ out->n_modules = big16(&cur);
62+ out->n_external_vars = big16(&cur);
63+ out->n_link_names = big16(&cur);
64+ out->n_unsnapped_links = big16(&cur);
65+ out->n_vm_pages = big16(&cur);
66+ out->n_header_pages = big16(&cur);
67+ for (int i = 0; i < 3; i++)
68+ {
69+ for (int j = 0; j < 4; j++)
70+ {
71+ out->info[i][j].address = big32(&cur);
72+ out->info[i][j].len = big32(&cur);
73+ }
74+ }
75+ out->module_map_address = big32(&cur);
76+ out->module_map_len = big32(&cur);
77+ out->external_vars_map_address = big32(&cur);
78+ out->external_vars_map_len = big32(&cur);
79+ out->link_names_map_address = big32(&cur);
80+ out->link_names_map_len = big32(&cur);
81+ out->link_map_address = big32(&cur);
82+ out->link_map_len = big32(&cur);
83+ out->header_address = big32(&cur);
84+ out->header_len = big32(&cur);
85+ memcpy(out->access_info, cur, sizeof(out->access_info));
86+ cur += sizeof(out->access_info);
87+ out->flags = big32(&cur);
88+ out->n_tasks = big16(&cur);
89+ for (int i = 0; i < 3; i++)
90+ {
91+ out->task_static_len[i] = big32(&cur);
92+ }
93+ out->stack_len = big32(&cur);
94+ out->n_entries = big16(&cur);
95+ out->entry_map_address = big32(&cur);
96+ out->entry_map_len = big32(&cur);
97+ out->pop_version = big16(&cur);
98+ out->processor = big16(&cur);
99+ string(&cur, out->release_name);
100+ out->relocation_info.map_address = big32(&cur);
101+ out->relocation_info.map_len = big32(&cur);
102+ out->relocation_info.n_relocations = big32(&cur);
103+ out->high_water_mark = big32(&cur);
104+ string(&cur, out->copyright_notice);
105+ for (int i = 0; i < 14; i++)
106+ {
107+ out->module_origins[i] = big32(&cur);
108+ }
109+ out->processor_family = big16(&cur);
110+ string(&cur, out->program_name);
111+ out->string_pool_address = big32(&cur);
112+ out->string_pool_len = big32(&cur);
113+ out->obj_dir_map_address = big32(&cur);
114+ out->obj_dir_map_len = big32(&cur);
115+ for (int i = 0; i < 3; i++)
116+ {
117+ out->global_offset_table_address[i] = big32(&cur);
118+ }
119+ for (int i = 0; i < 3; i++)
120+ {
121+ out->block_map_info[i].address = big32(&cur);
122+ out->block_map_info[i].len = big32(&cur);
123+ }
124+ out->section_map_file_address = big32(&cur);
125+ out->section_map_address = big32(&cur);
126+ out->section_map_len = big32(&cur);
127+ out->n_sections = big16(&cur);
128+ out->max_heap_size = big32(&cur);
129+ out->max_program_size = big32(&cur);
130+ out->max_stack_size = big32(&cur);
131+ out->stack_fence_size = big32(&cur);
132+
133+ out->module_map_entries = NULL;
134+ out->external_vars = NULL;
135+ return 1;
136+}
137+
138+#define MODULE_MAP_ENTRY_SIZE 74
139+
140+int vos_read_alloc_module_map(FILE * f, vos_program_module *header)
141+{
142+ if (header->module_map_len != header->n_modules * MODULE_MAP_ENTRY_SIZE)
143+ {
144+ return 0;
145+ }
146+ uint8_t * buf = malloc(header->module_map_len);
147+ fseek(f, header->module_map_address + 0x1000 - header->user_boundary, SEEK_SET);
148+ if (fread(buf, 1, header->module_map_len, f) != header->module_map_len)
149+ {
150+ free(buf);
151+ return 0;
152+ }
153+ uint8_t * cur = buf;
154+ header->module_map_entries = malloc(sizeof(vos_module_map_entry) * header->n_modules);
155+ for (int i = 0; i < header->n_modules; i++)
156+ {
157+ string(&cur, header->module_map_entries[i].name);
158+ for (int j = 0; j < 5; j++)
159+ {
160+ header->module_map_entries[i].unknown[j] = big16(&cur);
161+ }
162+ header->module_map_entries[i].code_address = big32(&cur);
163+ header->module_map_entries[i].code_length = big32(&cur);
164+ header->module_map_entries[i].foo_address = big32(&cur);
165+ header->module_map_entries[i].foo_length = big32(&cur);
166+ header->module_map_entries[i].bar_address = big32(&cur);
167+ header->module_map_entries[i].bar_length = big32(&cur);
168+ for (int j = 0; j < 3; j++)
169+ {
170+ header->module_map_entries[i].unknown2[j] = big16(&cur);
171+ }
172+ }
173+ return 1;
174+}
175+
176+#define EXTERNAL_VAR_ENTRY_SIZE 44
177+
178+int vos_read_alloc_external_vars(FILE * f, vos_program_module *header)
179+{
180+ if (header->external_vars_map_len != header->n_external_vars * EXTERNAL_VAR_ENTRY_SIZE)
181+ {
182+ return 0;
183+ }
184+ uint8_t * buf = malloc(header->external_vars_map_len);
185+ fseek(f, header->external_vars_map_address + 0x1000 - header->user_boundary, SEEK_SET);
186+ if (fread(buf, 1, header->external_vars_map_len, f) != header->external_vars_map_len)
187+ {
188+ free(buf);
189+ return 0;
190+ }
191+ uint8_t * cur = buf;
192+ header->external_vars = malloc(sizeof(vos_external_var_entry) * header->n_external_vars);
193+ for (int i = 0; i < header->n_external_vars; i++)
194+ {
195+ string(&cur, header->external_vars[i].name);
196+ header->external_vars[i].address = big32(&cur);
197+ for (int j = 0; j < 3; j++)
198+ {
199+ header->external_vars[i].unknown[j] = big16(&cur);
200+ }
201+ }
202+ return 1;
203+}
204+
205+void vos_header_cleanup(vos_program_module *header)
206+{
207+ free(header->module_map_entries);
208+ free(header->external_vars);
209+}
+134,
-0
1@@ -0,0 +1,134 @@
2+#ifndef VOS_PROGRAM_MODULE_H_
3+#define VOS_PROGRAM_MODULE_H_
4+
5+#include <stdint.h>
6+
7+typedef struct
8+{
9+ struct {
10+ uint16_t len;
11+ char str[32];
12+ } name;
13+ uint16_t unknown[5];
14+ uint32_t code_address;
15+ uint32_t code_length;
16+ uint32_t foo_address;
17+ uint32_t foo_length;
18+ uint32_t bar_address;
19+ uint32_t bar_length;
20+ uint16_t unknown2[3];
21+} vos_module_map_entry;
22+
23+typedef struct
24+{
25+ struct {
26+ uint16_t len;
27+ char str[32];
28+ } name;
29+ uint32_t address;
30+ uint16_t unknown[3];
31+} vos_external_var_entry;
32+
33+typedef struct
34+{
35+ uint16_t version;
36+ struct {
37+ uint16_t len;
38+ char str[32];
39+ } binder_version;
40+ struct {
41+ uint16_t len;
42+ char str[32];
43+ } binder_options;
44+ struct {
45+ uint16_t len;
46+ char str[32];
47+ } system_name;
48+ struct {
49+ uint16_t len;
50+ char str[65];
51+ } user_name;
52+ uint32_t date_bound;
53+ struct {
54+ uint32_t code_address;
55+ uint32_t static_address;
56+ } main_entry_link;
57+ uint32_t user_boundary;
58+ uint16_t n_modules;
59+ uint16_t n_external_vars;
60+ uint16_t n_link_names;
61+ uint16_t n_unsnapped_links;
62+ uint16_t n_vm_pages;
63+ uint16_t n_header_pages;
64+ struct {
65+ uint32_t address;
66+ uint32_t len;
67+ } info[3][4];
68+ uint32_t module_map_address;
69+ uint32_t module_map_len;
70+ uint32_t external_vars_map_address;
71+ uint32_t external_vars_map_len;
72+ uint32_t link_names_map_address;
73+ uint32_t link_names_map_len;
74+ uint32_t link_map_address;
75+ uint32_t link_map_len;
76+ uint32_t header_address;
77+ uint32_t header_len;
78+ uint8_t access_info[2048];
79+ uint32_t flags;
80+ uint16_t n_tasks;
81+ uint32_t task_static_len[3];
82+ uint32_t stack_len;
83+ uint16_t n_entries;
84+ uint32_t entry_map_address;
85+ uint32_t entry_map_len;
86+ uint16_t pop_version;
87+ uint16_t processor;
88+ struct {
89+ uint16_t len;
90+ char str[32];
91+ } release_name;
92+ struct {
93+ uint32_t map_address;
94+ uint32_t map_len;
95+ uint32_t n_relocations;
96+ } relocation_info;
97+ uint32_t high_water_mark;
98+ struct {
99+ uint16_t len;
100+ char str[256];
101+ } copyright_notice;
102+ uint32_t module_origins[14];
103+ uint16_t processor_family;
104+ struct {
105+ uint16_t len;
106+ char str[32];
107+ } program_name;
108+ uint32_t string_pool_address;
109+ uint32_t string_pool_len;
110+ uint32_t obj_dir_map_address;
111+ uint32_t obj_dir_map_len;
112+ uint32_t global_offset_table_address[3];
113+ struct {
114+ uint32_t address;
115+ uint32_t len;
116+ } block_map_info[3];
117+ uint32_t section_map_file_address;
118+ uint32_t section_map_address;
119+ uint32_t section_map_len;
120+ uint16_t n_sections;
121+ uint32_t max_heap_size;
122+ uint32_t max_program_size;
123+ uint32_t max_stack_size;
124+ uint32_t stack_fence_size;
125+
126+ vos_module_map_entry *module_map_entries;
127+ vos_external_var_entry *external_vars;
128+} vos_program_module;
129+
130+int vos_read_header(FILE * f, vos_program_module *out);
131+int vos_read_alloc_module_map(FILE * f, vos_program_module *header);
132+int vos_read_alloc_external_vars(FILE * f, vos_program_module *header);
133+void vos_header_cleanup(vos_program_module *header);
134+
135+#endif //VOS_PROGRAM_MODULE_H_
A
wave.c
+46,
-0
1@@ -0,0 +1,46 @@
2+/*
3+ Copyright 2013 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#include "wave.h"
8+#include <stddef.h>
9+#include <string.h>
10+
11+int wave_init(FILE * f, uint32_t sample_rate, uint16_t bits_per_sample, uint16_t num_channels)
12+{
13+ wave_header header;
14+ memcpy(header.chunk.id, "RIFF", 4);
15+ memcpy(header.chunk.format, "WAVE", 4);
16+ header.chunk.size = 0; //This will be filled in later
17+ memcpy(header.format_header.id, "fmt ", 4);
18+ header.format_header.size = sizeof(wave_header) - (sizeof(header.chunk) + sizeof(header.data_header) + sizeof(header.format_header));
19+ header.audio_format = 1;
20+ header.num_channels = num_channels;
21+ header.sample_rate = sample_rate;
22+ header.byte_rate = sample_rate * num_channels * (bits_per_sample/8);
23+ header.block_align = num_channels * (bits_per_sample/8);
24+ header.bits_per_sample = bits_per_sample;
25+ memcpy(header.data_header.id, "data", 4);
26+ header.data_header.size = 0;//This will be filled in later;
27+ return fwrite(&header, 1, sizeof(header), f) == sizeof(header);
28+}
29+
30+int wave_finalize(FILE * f)
31+{
32+ uint32_t size = ftell(f);
33+ fseek(f, offsetof(wave_header, chunk.size), SEEK_SET);
34+ size -= 8;
35+ if (fwrite(&size, sizeof(size), 1, f) != 1) {
36+ fclose(f);
37+ return 0;
38+ }
39+ fseek(f, offsetof(wave_header, data_header.size), SEEK_SET);
40+ size -= 36;
41+ if (fwrite(&size, sizeof(size), 1, f) != 1) {
42+ fclose(f);
43+ return 0;
44+ }
45+ fclose(f);
46+ return 1;
47+}
A
wave.h
+43,
-0
1@@ -0,0 +1,43 @@
2+/*
3+ Copyright 2013 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#ifndef WAVE_H_
8+#define WAVE_H_
9+
10+#include <stdint.h>
11+#include <stdio.h>
12+
13+#pragma pack(push, 1)
14+
15+typedef struct {
16+ char id[4];
17+ uint32_t size;
18+ char format[4];
19+} riff_chunk;
20+
21+typedef struct {
22+ char id[4];
23+ uint32_t size;
24+} riff_sub_chunk;
25+
26+typedef struct {
27+ riff_chunk chunk;
28+ riff_sub_chunk format_header;
29+ uint16_t audio_format;
30+ uint16_t num_channels;
31+ uint32_t sample_rate;
32+ uint32_t byte_rate;
33+ uint16_t block_align;
34+ uint16_t bits_per_sample;
35+ riff_sub_chunk data_header;
36+} wave_header;
37+
38+#pragma pack(pop)
39+
40+int wave_init(FILE * f, uint32_t sample_rate, uint16_t bits_per_sample, uint16_t num_channels);
41+int wave_finalize(FILE * f);
42+
43+#endif //WAVE_H_
44+
A
xband.c
+426,
-0
1@@ -0,0 +1,426 @@
2+#include <stdlib.h>
3+#include <stddef.h>
4+#include <string.h>
5+#include "romdb.h"
6+#include "genesis.h"
7+#include "tern.h"
8+#include "xband.h"
9+#include "util.h"
10+
11+#define BIT_ROM_HI 4
12+
13+enum {
14+ PATCH0_LOW,
15+ PATCH0_MID,
16+ PATCH0_HI,
17+ PATCH1_LOW=4,
18+ PATCH1_MID,
19+ PATCH1_HI,
20+ PATCH2_LOW=8,
21+ PATCH2_MID,
22+ PATCH2_HI,
23+ PATCH3_LOW=12,
24+ PATCH3_MID,
25+ PATCH3_HI,
26+ PATCH4_LOW=16,
27+ PATCH4_MID,
28+ PATCH4_HI,
29+ PATCH5_LOW=20,
30+ PATCH5_MID,
31+ PATCH5_HI,
32+ PATCH6_LOW=24,
33+ PATCH6_MID,
34+ PATCH6_HI,
35+ PATCH7_LOW=28,
36+ PATCH7_MID,
37+ PATCH7_HI,
38+ PATCH8_LOW=32,
39+ PATCH8_MID,
40+ PATCH8_HI,
41+ PATCH9_LOW=36,
42+ PATCH9_MID,
43+ PATCH9_HI,
44+ PATCH10_LOW=40,
45+ PATCH10_MID,
46+ PATCH10_HI,
47+ RANGE0_START_LOW=44,
48+ RANGE0_START_MID,
49+ RANGE0_START_HI,
50+ RANGE1_START=48,
51+ RANGE1_START_MID,
52+ RANGE1_START_HI,
53+ MAGIC_LOW=56,
54+ MAGIC_MID,
55+ MAGIC_HI,
56+ RANGE0_END_LOW=64,
57+ RANGE0_END_MID,
58+ RANGE0_END_HI,
59+ RANGE1_END_LOW=68,
60+ RANGE1_END_MID,
61+ RANGE1_END_HI,
62+ RANGE0_DEST_LOW=80,
63+ RANGE0_DEST_HI,
64+ RANGE0_MASK,
65+ RANGE1_DEST_LOW=84,
66+ RANGE1_DEST_HI,
67+ RANGE1_MASK,
68+
69+ MORE_MYSTERY=219,
70+ UNKNOWN_REG=221,
71+ UNKNOWN_REG2,
72+ UNKNOWN_REG3,
73+
74+};
75+
76+//#define DO_DEBUG_PRINT
77+#ifdef DO_DEBUG_PRINT
78+#define dprintf printf
79+#define dputs puts
80+#else
81+#define dprintf
82+#define dputs
83+#endif
84+
85+uint8_t xband_detect(uint8_t *rom, uint32_t rom_size)
86+{
87+ if (rom_size < 0x200) {
88+ return 0;
89+ }
90+
91+ //product ID is all NULL
92+ for (int i = GAME_ID_OFF; i <= (GAME_ID_OFF + GAME_ID_LEN); i++)
93+ {
94+ if (rom[i]) {
95+ return 0;
96+ }
97+ }
98+
99+ if (!memcmp(rom+8, "DAVE", 4)) {
100+ //XBAND test roms
101+ return 1;
102+ }
103+
104+ //Internal ROM is 512KB, accept larger ones for overdumps and custom firmware
105+ if (rom_size < (512*1024)) {
106+ return 0;
107+ }
108+
109+ //ROM has no standard header, but does have a jump at $100
110+ if (rom[0x100] != 0x4E || rom[0x101] != 0xF9) {
111+ return 0;
112+ }
113+
114+
115+ return 1;
116+}
117+
118+static xband *get_xband(genesis_context *gen)
119+{
120+ if (!gen->extra) {
121+ gen->extra = gen->m68k->options->gen.memmap[0].buffer;
122+ gen->m68k->mem_pointers[2] = (uint16_t *)gen->save_storage;
123+ }
124+ return gen->extra;
125+}
126+
127+static void update_control(genesis_context *gen, uint8_t value)
128+{
129+ xband *x = gen->extra;
130+ if ((x->control ^ value) & BIT_ROM_HI) {
131+ if (value & BIT_ROM_HI) {
132+ gen->m68k->mem_pointers[0] = (uint16_t *)gen->save_storage;
133+ gen->m68k->mem_pointers[1] = NULL;
134+ gen->m68k->mem_pointers[2] = gen->cart;
135+ gen->m68k->mem_pointers[3] = x->cart_space - 0x100000;
136+ } else {
137+ gen->m68k->mem_pointers[0] = x->cart_space;
138+ gen->m68k->mem_pointers[1] = x->cart_space;
139+ gen->m68k->mem_pointers[2] = (uint16_t *)gen->save_storage;
140+ gen->m68k->mem_pointers[3] = NULL;
141+ }
142+ m68k_invalidate_code_range(gen->m68k, 0, 0x3BC000);
143+ }
144+ x->control = value;
145+}
146+
147+static void *xband_write_b(uint32_t address, void *context, uint8_t value)
148+{
149+ m68k_context *m68k = context;
150+ genesis_context *gen = m68k->system;
151+ xband *x = get_xband(gen);
152+ if (address == 0x181) {
153+ x->kill = value;
154+ dprintf("Write to \"soft\" kill register %X\n", value);
155+ } else if (address == 0x183) {
156+ update_control(gen, value);
157+ dprintf("Write to \"soft\" control register %X\n", value);
158+ } else if ((x->control & BIT_ROM_HI && address < 0x200000) || (address >= 0x200000 && !(x->control & BIT_ROM_HI))) {
159+ gen->save_storage[(address & 0xFFFF) ^ 1] = value;
160+ m68k_handle_code_write(address, m68k);
161+ //TODO: handle code at mirror addresses
162+ } else {
163+ printf("Unhandled write to cartridge area %X: %X\n", address, value);
164+ }
165+ return context;
166+}
167+
168+static void *xband_write_hi_b(uint32_t address, void *context, uint8_t value)
169+{
170+ return xband_write_b(address | 0x200000, context, value);
171+}
172+
173+static void *xband_write_w(uint32_t address, void *context, uint16_t value)
174+{
175+ m68k_context *m68k = context;
176+ genesis_context *gen = m68k->system;
177+ xband *x = get_xband(gen);
178+ if (address == 0x180 || address == 0x182) {
179+ return xband_write_b(address | 1, context, value);
180+ } else if ((x->control & BIT_ROM_HI && address < 0x200000) || (address >= 0x200000 && !(x->control & BIT_ROM_HI))) {
181+ gen->save_storage[address & 0xFFFE] = value;
182+ gen->save_storage[(address & 0xFFFE) | 1] = value >> 8;
183+ m68k_handle_code_write(address, m68k);
184+ //TODO: handle code at mirror addresses
185+ return context;
186+ }
187+ printf("Unhandled write to %X: %X\n", address, value);
188+ return context;
189+}
190+
191+static void *xband_write_hi_w(uint32_t address, void *context, uint16_t value)
192+{
193+ return xband_write_w(address | 0x200000, context, value);
194+}
195+
196+static uint16_t xband_read_w(uint32_t address, void *context)
197+{
198+ m68k_context *m68k = context;
199+ genesis_context *gen = m68k->system;
200+ xband *x = get_xband(gen);
201+ //TODO: actually do something intelligent here
202+ return x->cart_space[address >> 1];
203+}
204+
205+static uint16_t xband_read_hi_w(uint32_t address, void *context)
206+{
207+ return xband_read_w(address | 0x200000, context);
208+}
209+
210+static uint8_t xband_read_b(uint32_t address, void *context)
211+{
212+ uint16_t val = xband_read_w(address, context);
213+ return address & 1 ? val : val >> 8;
214+}
215+
216+static uint8_t xband_read_hi_b(uint32_t address, void *context)
217+{
218+ return xband_read_b(address | 0x200000, context);
219+}
220+
221+static void *xband_reg_write_b(uint32_t address, void *context, uint8_t value)
222+{
223+ m68k_context *m68k = context;
224+ genesis_context *gen = m68k->system;
225+ if (!(address & 1)) {
226+ printf("Ignoring write to even address %X: %X\n", address, value);
227+ return context;
228+ }
229+ xband *x = get_xband(gen);
230+ if (address < 0x3BFE00) {
231+ uint32_t offset = (address - 0x3BC001) / 2;
232+ if (offset < XBAND_REGS) {
233+ switch (offset)
234+ {
235+ case MORE_MYSTERY:
236+ case UNKNOWN_REG:
237+ dprintf("Write to mysterious reg: %X: %X\n", address, value);
238+ value = value & 0x7F;
239+ break;
240+ case UNKNOWN_REG3:
241+ dprintf("Write to mysterious reg: %X: %X\n", address, value);
242+ value = value & 0xFE;
243+ break;
244+ }
245+ x->regs[offset] = value;
246+ dprintf("Write to register %X(%d): %X\n", address, offset, value);
247+ } else {
248+ printf("Unhandled register write %X: %X\n", address, value);
249+ }
250+ } else {
251+ if (address == 0x3BFE01) {
252+ x->kill = value;
253+ dprintf("Write to kill register %X\n", value);
254+ } else if (address == 0x3BFE03) {
255+ update_control(gen, value);
256+ dprintf("Write to control register %X\n", value);
257+ } else {
258+ printf("Unhandled register write %X: %X\n", address, value);
259+ }
260+ }
261+ return context;
262+}
263+
264+static void *xband_reg_write_w(uint32_t address, void *context, uint16_t value)
265+{
266+ return xband_reg_write_b(address | 1, context, value);
267+}
268+
269+static uint8_t xband_reg_read_b(uint32_t address, void *context)
270+{
271+ m68k_context *m68k = context;
272+ genesis_context *gen = m68k->system;
273+ if (!(address & 1)) {
274+ printf("Read from even address %X\n", address);
275+ return gen->header.get_open_bus_value(&gen->header) >> 8;
276+ }
277+ xband *x = get_xband(gen);
278+ if (address < 0x3BFE00) {
279+ uint32_t offset = (address - 0x3BC001) / 2;
280+ if (offset < XBAND_REGS) {
281+ dprintf("Regsister read: %X\n", address);
282+ return x->regs[offset];
283+ } else {
284+ printf("Unhandled register read from address %X\n", address);
285+ return 0x5D;
286+ }
287+ } else {
288+ if (address == 0x3BFE01) {
289+ return x->kill;
290+ } else if (address == 0x3BFE03) {
291+ return x->control;
292+ } else {
293+ printf("Unhandled register read from address %X\n", address);
294+ return 0x5D;
295+ }
296+ }
297+}
298+
299+static uint16_t xband_reg_read_w(uint32_t address, void *context)
300+{
301+ m68k_context *m68k = context;
302+ genesis_context *gen = m68k->system;
303+ uint16_t value = xband_reg_read_b(address | 1, context);
304+ value |= gen->header.get_open_bus_value(&gen->header) & 0xFF00;
305+ return value;
306+}
307+
308+void xband_serialize(genesis_context *gen, serialize_buffer *buf)
309+{
310+ xband *x = get_xband(gen);
311+ save_int8(buf, x->kill);
312+ save_int8(buf, x->control);
313+ save_buffer8(buf, x->regs, XBAND_REGS);
314+}
315+
316+void xband_deserialize(deserialize_buffer *buf, genesis_context *gen)
317+{
318+ xband *x = get_xband(gen);
319+ x->kill = load_int8(buf);
320+ update_control(gen, load_int8(buf));
321+ for (int i = 0; i < XBAND_REGS; i++)
322+ {
323+ xband_write_b(0x3BC001 + i*2, gen->m68k, load_int8(buf));
324+ }
325+}
326+
327+rom_info xband_configure_rom(tern_node *rom_db, void *rom, uint32_t rom_size, void *lock_on, uint32_t lock_on_size, memmap_chunk const *base_map, uint32_t base_chunks)
328+{
329+ rom_info info;
330+ if (lock_on && lock_on_size) {
331+ rom_info lock_on_info = configure_rom(rom_db, lock_on, lock_on_size, NULL, 0, base_map, base_chunks);
332+ info.name = alloc_concat("XBAND - ", lock_on_info.name);
333+ info.regions = lock_on_info.regions;
334+ free_rom_info(&lock_on_info);
335+ } else {
336+ info.name = strdup("XBAND");
337+ info.regions = REGION_J|REGION_U|REGION_E;
338+ }
339+ info.save_size = 64*1024;
340+ info.save_buffer = malloc(info.save_size);
341+ info.save_mask = info.save_size-1;
342+ info.save_type = RAM_FLAG_BOTH;
343+ info.port1_override = info.ext_override = info.mouse_mode = NULL;
344+ info.port2_override = strdup("xband keyboard");
345+ info.eeprom_map = NULL;
346+ info.num_eeprom = 0;
347+ info.rom = rom;
348+ info.rom_size = rom_size;
349+ info.is_save_lock_on = 0;
350+ xband *x = calloc(sizeof(xband), 1);
351+ rom_size = nearest_pow2(rom_size);
352+ for (int i = 0; (i + rom_size) <= sizeof(x->cart_space) / 2; i += rom_size)
353+ {
354+ memcpy(x->cart_space + i/2, rom, rom_size);
355+ }
356+ if (lock_on && lock_on_size >= 0x200) {
357+ memcpy(x->cart_space + 0x80, ((uint16_t *)lock_on) + 0x80, 0x100);
358+ }
359+ //observed power on values
360+ memset(x->regs, 0, sizeof(x->regs));
361+ x->regs[0x7C] = 0;
362+ x->regs[0x7D] = 0x80;
363+ x->regs[0xB4] = 0x7F;
364+ x->regs[UNKNOWN_REG2] = 8;
365+
366+ byteswap_rom(0x400000, x->cart_space);
367+
368+ info.mapper_type = MAPPER_XBAND;
369+ info.map_chunks = base_chunks + 5;
370+ info.map = calloc(sizeof(memmap_chunk), info.map_chunks);
371+ info.map[0].mask = 0xFFFFFF;
372+ info.map[0].aux_mask = 0xFFFFFF;
373+ info.map[0].flags = MMAP_READ|MMAP_CODE|MMAP_PTR_IDX|MMAP_FUNC_NULL|MMAP_AUX_BUFF;
374+ info.map[0].start = 0;
375+ info.map[0].end = 0x10000;
376+ info.map[0].ptr_index = 0;
377+ info.map[0].buffer = x->cart_space;
378+ info.map[0].write_16 = xband_write_w;
379+ info.map[0].write_8 = xband_write_b;
380+ info.map[0].read_16 = xband_read_w;
381+ info.map[0].read_8 = xband_read_b;
382+ info.map[1].mask = 0xFFFFFF;
383+ info.map[1].aux_mask = 0xFFFFFF;
384+ info.map[1].flags = MMAP_READ|MMAP_CODE|MMAP_PTR_IDX|MMAP_FUNC_NULL|MMAP_AUX_BUFF;
385+ info.map[1].start = 0x10000;
386+ info.map[1].end = 0x200000;
387+ info.map[1].ptr_index = 1;
388+ info.map[1].buffer = x->cart_space;
389+ info.map[1].write_16 = xband_write_w;
390+ info.map[1].write_8 = xband_write_b;
391+ info.map[1].read_16 = xband_read_w;
392+ info.map[1].read_8 = xband_read_b;
393+ info.map[2].mask = 0xFFFF;
394+ info.map[2].aux_mask = 0xFFFF;
395+ info.map[2].flags = MMAP_READ|MMAP_CODE|MMAP_PTR_IDX|MMAP_FUNC_NULL;
396+ info.map[2].start = 0x200000;
397+ info.map[2].end = 0x210000;
398+ info.map[2].ptr_index = 2;
399+ info.map[2].buffer = NULL;
400+ info.map[2].write_16 = xband_write_hi_w;
401+ info.map[2].write_8 = xband_write_hi_b;
402+ info.map[2].read_16 = xband_read_hi_w;
403+ info.map[2].read_8 = xband_read_hi_b;
404+ info.map[3].mask = 0xFFFFFF;
405+ info.map[3].aux_mask = 0xFFFFFF;
406+ info.map[3].flags = MMAP_READ|MMAP_CODE|MMAP_PTR_IDX|MMAP_FUNC_NULL;
407+ info.map[3].start = 0x210000;
408+ info.map[3].end = 0x3BC000;
409+ info.map[3].ptr_index = 3;
410+ info.map[3].buffer = NULL;
411+ info.map[3].write_16 = xband_write_w;
412+ info.map[3].write_8 = xband_write_b;
413+ info.map[3].read_16 = xband_read_w;
414+ info.map[3].read_8 = xband_read_b;
415+ info.map[4].mask = 0xFFFFFF;
416+ info.map[4].flags = MMAP_READ|MMAP_CODE|MMAP_PTR_IDX|MMAP_FUNC_NULL;
417+ info.map[4].start = 0x3BC000;
418+ info.map[4].end = 0x3C0000;
419+ info.map[4].ptr_index = 4;
420+ info.map[4].write_16 = xband_reg_write_w;
421+ info.map[4].write_8 = xband_reg_write_b;
422+ info.map[4].read_16 = xband_reg_read_w;
423+ info.map[4].read_8 = xband_reg_read_b;
424+ memcpy(info.map + 5, base_map, base_chunks * sizeof(memmap_chunk));
425+
426+ return info;
427+}
A
xband.h
+20,
-0
1@@ -0,0 +1,20 @@
2+#ifndef XBAND_H_
3+#define XBAND_H_
4+#include <stdint.h>
5+#include "serialize.h"
6+
7+#define XBAND_REGS 0xE0
8+
9+typedef struct {
10+ uint16_t cart_space[0x200000];
11+ uint8_t regs[XBAND_REGS];
12+ uint8_t kill;
13+ uint8_t control;
14+} xband;
15+
16+uint8_t xband_detect(uint8_t *rom, uint32_t rom_size);
17+rom_info xband_configure_rom(tern_node *rom_db, void *rom, uint32_t rom_size, void *lock_on, uint32_t lock_on_size, memmap_chunk const *base_map, uint32_t base_chunks);
18+void xband_serialize(genesis_context *gen, serialize_buffer *buf);
19+void xband_deserialize(deserialize_buffer *buf, genesis_context *gen);
20+
21+#endif //XBAND_H_
A
ym2612.c
+1245,
-0
1@@ -0,0 +1,1245 @@
2+/*
3+ Copyright 2013 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#include <string.h>
8+#include <math.h>
9+#include <stdio.h>
10+#include <stdlib.h>
11+#include "ym2612.h"
12+#include "render.h"
13+#include "wave.h"
14+#include "blastem.h"
15+
16+//#define DO_DEBUG_PRINT
17+#ifdef DO_DEBUG_PRINT
18+#define dfprintf fprintf
19+#define dfopen(var, fname, mode) var=fopen(fname, mode)
20+#else
21+#define dfprintf
22+#define dfopen(var, fname, mode)
23+#endif
24+
25+#define BUSY_CYCLES_ADDRESS 17
26+#define BUSY_CYCLES_DATA_LOW 83
27+#define BUSY_CYCLES_DATA_HIGH 47
28+#define OP_UPDATE_PERIOD 144
29+
30+#define BIT_TIMERA_ENABLE 0x1
31+#define BIT_TIMERB_ENABLE 0x2
32+#define BIT_TIMERA_OVEREN 0x4
33+#define BIT_TIMERB_OVEREN 0x8
34+#define BIT_TIMERA_RESET 0x10
35+#define BIT_TIMERB_RESET 0x20
36+
37+#define BIT_TIMERA_LOAD 0x40
38+#define BIT_TIMERB_LOAD 0x80
39+
40+#define BIT_STATUS_TIMERA 0x1
41+#define BIT_STATUS_TIMERB 0x2
42+
43+static uint32_t ym_calc_phase_inc(ym2612_context * context, ym_operator * operator, uint32_t op);
44+
45+enum {
46+ PHASE_ATTACK,
47+ PHASE_DECAY,
48+ PHASE_SUSTAIN,
49+ PHASE_RELEASE
50+};
51+
52+uint8_t did_tbl_init = 0;
53+//According to Nemesis, real hardware only uses a 256 entry quarter sine table; however,
54+//memory is cheap so using a half sine table will probably save some cycles
55+//a full sine table would be nice, but negative numbers don't get along with log2
56+#define SINE_TABLE_SIZE 512
57+static uint16_t sine_table[SINE_TABLE_SIZE];
58+//Similar deal here with the power table for log -> linear conversion
59+//According to Nemesis, real hardware only uses a 256 entry table for the fractional part
60+//and uses the whole part as a shift amount.
61+#define POW_TABLE_SIZE (1 << 13)
62+static uint16_t pow_table[POW_TABLE_SIZE];
63+
64+static uint16_t rate_table_base[] = {
65+ //main portion
66+ 0,1,0,1,0,1,0,1,
67+ 0,1,0,1,1,1,0,1,
68+ 0,1,1,1,0,1,1,1,
69+ 0,1,1,1,1,1,1,1,
70+ //top end
71+ 1,1,1,1,1,1,1,1,
72+ 1,1,1,2,1,1,1,2,
73+ 1,2,1,2,1,2,1,2,
74+ 1,2,2,2,1,2,2,2,
75+};
76+
77+static uint16_t rate_table[64*8];
78+
79+static uint8_t lfo_timer_values[] = {108, 77, 71, 67, 62, 44, 8, 5};
80+static uint8_t lfo_pm_base[][8] = {
81+ {0, 0, 0, 0, 0, 0, 0, 0},
82+ {0, 0, 0, 0, 4, 4, 4, 4},
83+ {0, 0, 0, 4, 4, 4, 8, 8},
84+ {0, 0, 4, 4, 8, 8, 0xc, 0xc},
85+ {0, 0, 4, 8, 8, 8, 0xc,0x10},
86+ {0, 0, 8, 0xc,0x10,0x10,0x14,0x18},
87+ {0, 0,0x10,0x18,0x20,0x20,0x28,0x30},
88+ {0, 0,0x20,0x30,0x40,0x40,0x50,0x60}
89+};
90+static int16_t lfo_pm_table[128 * 32 * 8];
91+
92+int16_t ams_shift[] = {8, 1, -1, -2};
93+
94+#define MAX_ENVELOPE 0xFFC
95+#define YM_DIVIDER 2
96+#define CYCLE_NEVER 0xFFFFFFFF
97+
98+static uint16_t round_fixed_point(double value, int dec_bits)
99+{
100+ return value * (1 << dec_bits) + 0.5;
101+}
102+
103+static FILE * debug_file = NULL;
104+static uint32_t first_key_on=0;
105+
106+static ym2612_context * log_context = NULL;
107+
108+static void ym_finalize_log()
109+{
110+ if (!log_context) {
111+ return;
112+ }
113+ for (int i = 0; i < NUM_CHANNELS; i++) {
114+ if (log_context->channels[i].logfile) {
115+ wave_finalize(log_context->channels[i].logfile);
116+ }
117+ }
118+ log_context = NULL;
119+}
120+
121+void ym_adjust_master_clock(ym2612_context * context, uint32_t master_clock)
122+{
123+ render_audio_adjust_clock(context->audio, master_clock, context->clock_inc * NUM_OPERATORS);
124+}
125+
126+#define TIMER_A_MAX 1023
127+#define TIMER_B_MAX 255
128+
129+void ym_reset(ym2612_context *context)
130+{
131+ memset(context->part1_regs, 0, sizeof(context->part1_regs));
132+ memset(context->part2_regs, 0, sizeof(context->part2_regs));
133+ memset(context->operators, 0, sizeof(context->operators));
134+ FILE* savedlogs[NUM_CHANNELS];
135+ for (int i = 0; i < NUM_CHANNELS; i++)
136+ {
137+ savedlogs[i] = context->channels[i].logfile;
138+ }
139+ memset(context->channels, 0, sizeof(context->channels));
140+ memset(context->ch3_supp, 0, sizeof(context->ch3_supp));
141+ context->selected_reg = 0;
142+ context->csm_keyon = 0;
143+ context->ch3_mode = 0;
144+ context->dac_enable = 0;
145+ context->status = 0;
146+ context->timer_a_load = 0;
147+ context->timer_b_load = 0;
148+ //TODO: Confirm these on hardware
149+ context->timer_a = TIMER_A_MAX;
150+ context->timer_b = TIMER_B_MAX;
151+
152+ //TODO: Reset LFO state
153+
154+ //some games seem to expect that the LR flags start out as 1
155+ for (int i = 0; i < NUM_CHANNELS; i++) {
156+ context->channels[i].lr = 0xC0;
157+ context->channels[i].logfile = savedlogs[i];
158+ }
159+ context->write_cycle = CYCLE_NEVER;
160+ for (int i = 0; i < NUM_OPERATORS; i++) {
161+ context->operators[i].envelope = MAX_ENVELOPE;
162+ context->operators[i].env_phase = PHASE_RELEASE;
163+ }
164+}
165+
166+void ym_init(ym2612_context * context, uint32_t master_clock, uint32_t clock_div, uint32_t options)
167+{
168+ static uint8_t registered_finalize;
169+ dfopen(debug_file, "ym_debug.txt", "w");
170+ memset(context, 0, sizeof(*context));
171+ context->clock_inc = clock_div * 6;
172+ context->audio = render_audio_source(master_clock, context->clock_inc * NUM_OPERATORS, 2);
173+
174+ //some games seem to expect that the LR flags start out as 1
175+ for (int i = 0; i < NUM_CHANNELS; i++) {
176+ if (options & YM_OPT_WAVE_LOG) {
177+ char fname[64];
178+ sprintf(fname, "ym_channel_%d.wav", i);
179+ FILE * f = context->channels[i].logfile = fopen(fname, "wb");
180+ if (!f) {
181+ fprintf(stderr, "Failed to open WAVE log file %s for writing\n", fname);
182+ continue;
183+ }
184+ if (!wave_init(f, master_clock / (context->clock_inc * NUM_OPERATORS), 16, 1)) {
185+ fclose(f);
186+ context->channels[i].logfile = NULL;
187+ }
188+ }
189+ }
190+ if (options & YM_OPT_WAVE_LOG) {
191+ log_context = context;
192+ if (!registered_finalize) {
193+ atexit(ym_finalize_log);
194+ registered_finalize = 1;
195+ }
196+ }
197+ if (!did_tbl_init) {
198+ //populate sine table
199+ for (int32_t i = 0; i < 512; i++) {
200+ double sine = sin( ((double)(i*2+1) / SINE_TABLE_SIZE) * M_PI_2 );
201+
202+ //table stores 4.8 fixed pointed representation of the base 2 log
203+ sine_table[i] = round_fixed_point(-log2(sine), 8);
204+ }
205+ //populate power table
206+ for (int32_t i = 0; i < POW_TABLE_SIZE; i++) {
207+ double linear = pow(2, -((double)((i & 0xFF)+1) / 256.0));
208+ int32_t tmp = round_fixed_point(linear, 11);
209+ int32_t shift = (i >> 8) - 2;
210+ if (shift < 0) {
211+ tmp <<= 0-shift;
212+ } else {
213+ tmp >>= shift;
214+ }
215+ pow_table[i] = tmp;
216+ }
217+ //populate envelope generator rate table, from small base table
218+ for (int rate = 0; rate < 64; rate++) {
219+ for (int cycle = 0; cycle < 8; cycle++) {
220+ uint16_t value;
221+ if (rate < 2) {
222+ value = 0;
223+ } else if (rate >= 60) {
224+ value = 8;
225+ } else if (rate < 8) {
226+ value = rate_table_base[((rate & 6) == 6 ? 16 : 0) + cycle];
227+ } else if (rate < 48) {
228+ value = rate_table_base[(rate & 0x3) * 8 + cycle];
229+ } else {
230+ value = rate_table_base[32 + (rate & 0x3) * 8 + cycle] << ((rate - 48) >> 2);
231+ }
232+ rate_table[rate * 8 + cycle] = value;
233+ }
234+ }
235+ //populate LFO PM table from small base table
236+ //seems like there must be a better way to derive this
237+ for (int freq = 0; freq < 128; freq++) {
238+ for (int pms = 0; pms < 8; pms++) {
239+ for (int step = 0; step < 32; step++) {
240+ int16_t value = 0;
241+ for (int bit = 0x40, shift = 0; bit > 0; bit >>= 1, shift++) {
242+ if (freq & bit) {
243+ value += lfo_pm_base[pms][(step & 0x8) ? 7-step & 7 : step & 7] >> shift;
244+ }
245+ }
246+ if (step & 0x10) {
247+ value = -value;
248+ }
249+ lfo_pm_table[freq * 256 + pms * 32 + step] = value;
250+ }
251+ }
252+ }
253+ }
254+ ym_reset(context);
255+ ym_enable_zero_offset(context, 1);
256+}
257+
258+void ym_free(ym2612_context *context)
259+{
260+ render_free_source(context->audio);
261+ if (context == log_context) {
262+ ym_finalize_log();
263+ }
264+ free(context);
265+}
266+
267+void ym_enable_zero_offset(ym2612_context *context, uint8_t enabled)
268+{
269+ if (enabled) {
270+ context->zero_offset = 0x70;
271+ context->volume_mult = 79;
272+ context->volume_div = 120;
273+ } else {
274+ context->zero_offset = 0;
275+ context->volume_mult = 2;
276+ context->volume_div = 3;
277+ }
278+}
279+#define YM_MOD_SHIFT 1
280+
281+#define CSM_MODE 0x80
282+
283+#define SSG_ENABLE 8
284+#define SSG_INVERT 4
285+#define SSG_ALTERNATE 2
286+#define SSG_HOLD 1
287+
288+#define SSG_CENTER 0x800
289+
290+static void start_envelope(ym_operator *op, ym_channel *channel)
291+{
292+ //Deal with "infinite" attack rates
293+ uint8_t rate = op->rates[PHASE_ATTACK];
294+ if (rate) {
295+ uint8_t ks = channel->keycode >> op->key_scaling;;
296+ rate = rate*2 + ks;
297+ }
298+ if (rate >= 62) {
299+ op->env_phase = PHASE_DECAY;
300+ op->envelope = 0;
301+ } else {
302+ op->env_phase = PHASE_ATTACK;
303+ }
304+}
305+
306+static void keyon(ym_operator *op, ym_channel *channel)
307+{
308+ start_envelope(op, channel);
309+ op->phase_counter = 0;
310+ op->inverted = op->ssg & SSG_INVERT;
311+}
312+
313+static const uint8_t keyon_bits[] = {0x10, 0x40, 0x20, 0x80};
314+
315+static void keyoff(ym_operator *op)
316+{
317+ op->env_phase = PHASE_RELEASE;
318+ if (op->inverted) {
319+ //Nemesis says the inversion state doesn't change here, but I don't see how that is observable either way
320+ op->inverted = 0;
321+ op->envelope = (SSG_CENTER - op->envelope) & MAX_ENVELOPE;
322+ }
323+}
324+
325+static void csm_keyoff(ym2612_context *context)
326+{
327+ context->csm_keyon = 0;
328+ uint8_t changes = 0xF0 ^ context->channels[2].keyon;
329+ for (uint8_t op = 2*4, bit = 0; op < 3*4; op++, bit++)
330+ {
331+ if (changes & keyon_bits[bit]) {
332+ keyoff(context->operators + op);
333+ }
334+ }
335+}
336+
337+void ym_run(ym2612_context * context, uint32_t to_cycle)
338+{
339+ //printf("Running YM2612 from cycle %d to cycle %d\n", context->current_cycle, to_cycle);
340+ //TODO: Fix channel update order OR remap channels in register write
341+ for (; context->current_cycle < to_cycle; context->current_cycle += context->clock_inc) {
342+ //Update timers at beginning of 144 cycle period
343+ if (!context->current_op) {
344+ if (context->timer_control & BIT_TIMERA_ENABLE) {
345+ if (context->timer_a != TIMER_A_MAX) {
346+ context->timer_a++;
347+ if (context->csm_keyon) {
348+ csm_keyoff(context);
349+ }
350+ } else {
351+ if (context->timer_control & BIT_TIMERA_LOAD) {
352+ context->timer_control &= ~BIT_TIMERA_LOAD;
353+ } else if (context->timer_control & BIT_TIMERA_OVEREN) {
354+ context->status |= BIT_STATUS_TIMERA;
355+ }
356+ context->timer_a = context->timer_a_load;
357+ if (!context->csm_keyon && context->ch3_mode == CSM_MODE) {
358+ context->csm_keyon = 0xF0;
359+ uint8_t changes = 0xF0 ^ context->channels[2].keyon;;
360+ for (uint8_t op = 2*4, bit = 0; op < 3*4; op++, bit++)
361+ {
362+ if (changes & keyon_bits[bit]) {
363+ keyon(context->operators + op, context->channels + 2);
364+ }
365+ }
366+ }
367+ }
368+ }
369+ if (!context->sub_timer_b) {
370+ if (context->timer_control & BIT_TIMERB_ENABLE) {
371+ if (context->timer_b != TIMER_B_MAX) {
372+ context->timer_b++;
373+ } else {
374+ if (context->timer_control & BIT_TIMERB_LOAD) {
375+ context->timer_control &= ~BIT_TIMERB_LOAD;
376+ } else if (context->timer_control & BIT_TIMERB_OVEREN) {
377+ context->status |= BIT_STATUS_TIMERB;
378+ }
379+ context->timer_b = context->timer_b_load;
380+ }
381+ }
382+ }
383+ context->sub_timer_b += 0x10;
384+ //Update LFO
385+ if (context->lfo_enable) {
386+ if (context->lfo_counter) {
387+ context->lfo_counter--;
388+ } else {
389+ context->lfo_counter = lfo_timer_values[context->lfo_freq];
390+ context->lfo_am_step += 2;
391+ context->lfo_am_step &= 0xFE;
392+ context->lfo_pm_step = context->lfo_am_step / 8;
393+ }
394+ }
395+ }
396+ //Update Envelope Generator
397+ if (!(context->current_op % 3)) {
398+ uint32_t env_cyc = context->env_counter;
399+ uint32_t op = context->current_env_op;
400+ ym_operator * operator = context->operators + op;
401+ ym_channel * channel = context->channels + op/4;
402+ uint8_t rate;
403+ if (operator->env_phase == PHASE_DECAY && operator->envelope >= operator->sustain_level) {
404+ //operator->envelope = operator->sustain_level;
405+ operator->env_phase = PHASE_SUSTAIN;
406+ }
407+ rate = operator->rates[operator->env_phase];
408+ if (rate) {
409+ uint8_t ks = channel->keycode >> operator->key_scaling;;
410+ rate = rate*2 + ks;
411+ if (rate > 63) {
412+ rate = 63;
413+ }
414+ }
415+ uint32_t cycle_shift = rate < 0x30 ? ((0x2F - rate) >> 2) : 0;
416+ if (first_key_on) {
417+ dfprintf(debug_file, "Operator: %d, env rate: %d (2*%d+%d), env_cyc: %d, cycle_shift: %d, env_cyc & ((1 << cycle_shift) - 1): %d\n", op, rate, operator->rates[operator->env_phase], channel->keycode >> operator->key_scaling,env_cyc, cycle_shift, env_cyc & ((1 << cycle_shift) - 1));
418+ }
419+ if (!(env_cyc & ((1 << cycle_shift) - 1))) {
420+ uint32_t update_cycle = env_cyc >> cycle_shift & 0x7;
421+ uint16_t envelope_inc = rate_table[rate * 8 + update_cycle];
422+ if (operator->env_phase == PHASE_ATTACK) {
423+ //this can probably be optimized to a single shift rather than a multiply + shift
424+ if (first_key_on) {
425+ dfprintf(debug_file, "Changing op %d envelope %d by %d(%d * %d) in attack phase\n", op, operator->envelope, (~operator->envelope * envelope_inc) >> 4, ~operator->envelope, envelope_inc);
426+ }
427+ uint16_t old_env = operator->envelope;
428+ operator->envelope += ((~operator->envelope * envelope_inc) >> 4) & 0xFFFFFFFC;
429+ if (operator->envelope > old_env) {
430+ //Handle overflow
431+ operator->envelope = 0;
432+ }
433+ if (!operator->envelope) {
434+ operator->env_phase = PHASE_DECAY;
435+ }
436+ } else {
437+ if (first_key_on) {
438+ dfprintf(debug_file, "Changing op %d envelope %d by %d in %s phase\n", op, operator->envelope, envelope_inc,
439+ operator->env_phase == PHASE_SUSTAIN ? "sustain" : (operator->env_phase == PHASE_DECAY ? "decay": "release"));
440+ }
441+ if (operator->ssg) {
442+ if (operator->envelope < SSG_CENTER) {
443+ envelope_inc *= 4;
444+ } else {
445+ envelope_inc = 0;
446+ }
447+ }
448+ //envelope value is 10-bits, but it will be used as a 4.8 value
449+ operator->envelope += envelope_inc << 2;
450+ //clamp to max attenuation value
451+ if (
452+ operator->envelope > MAX_ENVELOPE
453+ || (operator->env_phase == PHASE_RELEASE && operator->envelope >= SSG_CENTER)
454+ ) {
455+ operator->envelope = MAX_ENVELOPE;
456+ }
457+ }
458+ }
459+ context->current_env_op++;
460+ if (context->current_env_op == NUM_OPERATORS) {
461+ context->current_env_op = 0;
462+ context->env_counter++;
463+ }
464+ }
465+
466+ //Update Phase Generator
467+ uint32_t channel = context->current_op / 4;
468+ if (channel != 5 || !context->dac_enable) {
469+ uint32_t op = context->current_op;
470+ //printf("updating operator %d of channel %d\n", op, channel);
471+ ym_operator * operator = context->operators + op;
472+ ym_channel * chan = context->channels + channel;
473+ uint16_t phase = operator->phase_counter >> 10 & 0x3FF;
474+ operator->phase_counter += ym_calc_phase_inc(context, operator, context->current_op);
475+ int16_t mod = 0;
476+ if (op & 3) {
477+ if (operator->mod_src[0]) {
478+ mod = *operator->mod_src[0];
479+ if (operator->mod_src[1]) {
480+ mod += *operator->mod_src[1];
481+ }
482+ mod >>= YM_MOD_SHIFT;
483+ }
484+ } else {
485+ if (chan->feedback) {
486+ mod = (chan->op1_old + operator->output) >> (10-chan->feedback);
487+ }
488+ }
489+ uint16_t env = operator->envelope;
490+ if (operator->ssg) {
491+ if (env >= SSG_CENTER) {
492+ if (operator->ssg & SSG_ALTERNATE) {
493+ if (operator->env_phase != PHASE_RELEASE && (
494+ !(operator->ssg & SSG_HOLD) || ((operator->ssg ^ operator->inverted) & SSG_INVERT) == 0
495+ )) {
496+ operator->inverted ^= SSG_INVERT;
497+ }
498+ } else if (!(operator->ssg & SSG_HOLD)) {
499+ phase = operator->phase_counter = 0;
500+ }
501+ if (
502+ (operator->env_phase == PHASE_DECAY || operator->env_phase == PHASE_SUSTAIN)
503+ && !(operator->ssg & SSG_HOLD)
504+ ) {
505+ start_envelope(operator, chan);
506+ env = operator->envelope;
507+ }
508+ }
509+ if (operator->inverted) {
510+ env = (SSG_CENTER - env) & MAX_ENVELOPE;
511+ }
512+ }
513+ env += operator->total_level;
514+ if (operator->am) {
515+ uint16_t base_am = (context->lfo_am_step & 0x80 ? context->lfo_am_step : ~context->lfo_am_step) & 0x7E;
516+ if (ams_shift[chan->ams] >= 0) {
517+ env += (base_am >> ams_shift[chan->ams]) & MAX_ENVELOPE;
518+ } else {
519+ env += base_am << (-ams_shift[chan->ams]);
520+ }
521+ }
522+ if (env > MAX_ENVELOPE) {
523+ env = MAX_ENVELOPE;
524+ }
525+ if (first_key_on) {
526+ dfprintf(debug_file, "op %d, base phase: %d, mod: %d, sine: %d, out: %d\n", op, phase, mod, sine_table[(phase+mod) & 0x1FF], pow_table[sine_table[phase & 0x1FF] + env]);
527+ }
528+ //if ((channel != 0 && channel != 4) || chan->algorithm != 5) {
529+ phase += mod;
530+ //}
531+
532+ int16_t output = pow_table[sine_table[phase & 0x1FF] + env];
533+ if (phase & 0x200) {
534+ output = -output;
535+ }
536+ if (op % 4 == 0) {
537+ chan->op1_old = operator->output;
538+ } else if (op % 4 == 2) {
539+ chan->op2_old = operator->output;
540+ }
541+ operator->output = output;
542+ //Update the channel output if we've updated all operators
543+ if (op % 4 == 3) {
544+ if (chan->algorithm < 4) {
545+ chan->output = operator->output;
546+ } else if(chan->algorithm == 4) {
547+ chan->output = operator->output + context->operators[channel * 4 + 2].output;
548+ } else {
549+ output = 0;
550+ for (uint32_t op = ((chan->algorithm == 7) ? 0 : 1) + channel*4; op < (channel+1)*4; op++) {
551+ output += context->operators[op].output;
552+ }
553+ chan->output = output;
554+ }
555+ if (first_key_on) {
556+ int16_t value = context->channels[channel].output & 0x3FE0;
557+ if (value & 0x2000) {
558+ value |= 0xC000;
559+ }
560+ dfprintf(debug_file, "channel %d output: %d\n", channel, (value * context->volume_mult) / context->volume_div);
561+ }
562+ }
563+ //puts("operator update done");
564+ }
565+ context->current_op++;
566+ if (context->current_op == NUM_OPERATORS) {
567+ context->current_op = 0;
568+
569+ int16_t left = 0, right = 0;
570+ for (int i = 0; i < NUM_CHANNELS; i++) {
571+ int16_t value = context->channels[i].output;
572+ if (value > 0x1FE0) {
573+ value = 0x1FE0;
574+ } else if (value < -0x1FF0) {
575+ value = -0x1FF0;
576+ } else {
577+ value &= 0x3FE0;
578+ if (value & 0x2000) {
579+ value |= 0xC000;
580+ }
581+ }
582+ if (value >= 0) {
583+ value += context->zero_offset;
584+ } else {
585+ value -= context->zero_offset;
586+ }
587+ if (context->channels[i].logfile) {
588+ fwrite(&value, sizeof(value), 1, context->channels[i].logfile);
589+ }
590+ if (context->channels[i].lr & 0x80) {
591+ left += (value * context->volume_mult) / context->volume_div;
592+ } else if (context->zero_offset) {
593+ if (value >= 0) {
594+ left += (context->zero_offset * context->volume_mult) / context->volume_div;
595+ } else {
596+ left -= (context->zero_offset * context->volume_mult) / context->volume_div;
597+ }
598+ }
599+ if (context->channels[i].lr & 0x40) {
600+ right += (value * context->volume_mult) / context->volume_div;
601+ } else if (context->zero_offset) {
602+ if (value >= 0) {
603+ right += (context->zero_offset * context->volume_mult) / context->volume_div;
604+ } else {
605+ right -= (context->zero_offset * context->volume_mult) / context->volume_div;
606+ }
607+ }
608+ }
609+ render_put_stereo_sample(context->audio, left, right);
610+ }
611+
612+ }
613+ if (context->current_cycle >= context->write_cycle + (context->busy_cycles * context->clock_inc / 6)) {
614+ context->status &= 0x7F;
615+ context->write_cycle = CYCLE_NEVER;
616+ }
617+ //printf("Done running YM2612 at cycle %d\n", context->current_cycle, to_cycle);
618+}
619+
620+void ym_address_write_part1(ym2612_context * context, uint8_t address)
621+{
622+ //printf("address_write_part1: %X\n", address);
623+ context->selected_reg = address;
624+ context->selected_part = 0;
625+ context->write_cycle = context->current_cycle;
626+ context->busy_cycles = BUSY_CYCLES_ADDRESS;
627+ context->status |= 0x80;
628+}
629+
630+void ym_address_write_part2(ym2612_context * context, uint8_t address)
631+{
632+ //printf("address_write_part2: %X\n", address);
633+ context->selected_reg = address;
634+ context->selected_part = 1;
635+ context->write_cycle = context->current_cycle;
636+ context->busy_cycles = BUSY_CYCLES_ADDRESS;
637+ context->status |= 0x80;
638+}
639+
640+static uint8_t fnum_to_keycode[] = {
641+ //F11 = 0
642+ 0,0,0,0,0,0,0,1,
643+ //F11 = 1
644+ 2,3,3,3,3,3,3,3
645+};
646+
647+//table courtesy of Nemesis
648+static uint32_t detune_table[][4] = {
649+ {0, 0, 1, 2}, //0 (0x00)
650+ {0, 0, 1, 2}, //1 (0x01)
651+ {0, 0, 1, 2}, //2 (0x02)
652+ {0, 0, 1, 2}, //3 (0x03)
653+ {0, 1, 2, 2}, //4 (0x04)
654+ {0, 1, 2, 3}, //5 (0x05)
655+ {0, 1, 2, 3}, //6 (0x06)
656+ {0, 1, 2, 3}, //7 (0x07)
657+ {0, 1, 2, 4}, //8 (0x08)
658+ {0, 1, 3, 4}, //9 (0x09)
659+ {0, 1, 3, 4}, //10 (0x0A)
660+ {0, 1, 3, 5}, //11 (0x0B)
661+ {0, 2, 4, 5}, //12 (0x0C)
662+ {0, 2, 4, 6}, //13 (0x0D)
663+ {0, 2, 4, 6}, //14 (0x0E)
664+ {0, 2, 5, 7}, //15 (0x0F)
665+ {0, 2, 5, 8}, //16 (0x10)
666+ {0, 3, 6, 8}, //17 (0x11)
667+ {0, 3, 6, 9}, //18 (0x12)
668+ {0, 3, 7,10}, //19 (0x13)
669+ {0, 4, 8,11}, //20 (0x14)
670+ {0, 4, 8,12}, //21 (0x15)
671+ {0, 4, 9,13}, //22 (0x16)
672+ {0, 5,10,14}, //23 (0x17)
673+ {0, 5,11,16}, //24 (0x18)
674+ {0, 6,12,17}, //25 (0x19)
675+ {0, 6,13,19}, //26 (0x1A)
676+ {0, 7,14,20}, //27 (0x1B)
677+ {0, 8,16,22}, //28 (0x1C)
678+ {0, 8,16,22}, //29 (0x1D)
679+ {0, 8,16,22}, //30 (0x1E)
680+ {0, 8,16,22}
681+}; //31 (0x1F)
682+
683+static uint32_t ym_calc_phase_inc(ym2612_context * context, ym_operator * operator, uint32_t op)
684+{
685+ uint32_t chan_num = op / 4;
686+ //printf("ym_update_phase_inc | channel: %d, op: %d\n", chan_num, op);
687+ //base frequency
688+ ym_channel * channel = context->channels + chan_num;
689+ uint32_t inc, detune;
690+ if (chan_num == 2 && context->ch3_mode && (op < (2*4 + 3))) {
691+ //supplemental fnum registers are in a different order than normal slot paramters
692+ int index = op-2*4;
693+ if (index < 2) {
694+ index ^= 1;
695+ }
696+ inc = context->ch3_supp[index].fnum;
697+ if (channel->pms) {
698+ inc = inc * 2 + lfo_pm_table[(inc & 0x7F0) * 16 + channel->pms + context->lfo_pm_step];
699+ inc &= 0xFFF;
700+ }
701+ if (!context->ch3_supp[index].block) {
702+ inc >>= 1;
703+ } else {
704+ inc <<= (context->ch3_supp[index].block-1);
705+ }
706+ //detune
707+ detune = detune_table[context->ch3_supp[index].keycode][operator->detune & 0x3];
708+ } else {
709+ inc = channel->fnum;
710+ if (channel->pms) {
711+ inc = inc * 2 + lfo_pm_table[(inc & 0x7F0) * 16 + channel->pms + context->lfo_pm_step];
712+ inc &= 0xFFF;
713+ }
714+ if (!channel->block) {
715+ inc >>= 1;
716+ } else {
717+ inc <<= (channel->block-1);
718+ }
719+ //detune
720+ detune = detune_table[channel->keycode][operator->detune & 0x3];
721+ }
722+ if (channel->pms) {
723+ inc >>= 1;
724+ }
725+ if (operator->detune & 0x4) {
726+ inc -= detune;
727+ //this can underflow, mask to 17-bit result
728+ inc &= 0x1FFFF;
729+ } else {
730+ inc += detune;
731+ }
732+ //multiple
733+ if (operator->multiple) {
734+ inc *= operator->multiple;
735+ inc &= 0xFFFFF;
736+ } else {
737+ //0.5
738+ inc >>= 1;
739+ }
740+ //printf("phase_inc for operator %d: %d, block: %d, fnum: %d, detune: %d, multiple: %d\n", op, inc, channel->block, channel->fnum, detune, operator->multiple);
741+ return inc;
742+}
743+
744+void ym_data_write(ym2612_context * context, uint8_t value)
745+{
746+ if (context->selected_reg >= YM_REG_END) {
747+ return;
748+ }
749+ if (context->selected_part) {
750+ if (context->selected_reg < YM_PART2_START) {
751+ return;
752+ }
753+ context->part2_regs[context->selected_reg - YM_PART2_START] = value;
754+ } else {
755+ if (context->selected_reg < YM_PART1_START) {
756+ return;
757+ }
758+ context->part1_regs[context->selected_reg - YM_PART1_START] = value;
759+ }
760+ dfprintf(debug_file, "write of %X to reg %X in part %d\n", value, context->selected_reg, context->selected_part+1);
761+ if (context->selected_reg < 0x30) {
762+ //Shared regs
763+ switch (context->selected_reg)
764+ {
765+ //TODO: Test reg
766+ case REG_LFO:
767+ /*if ((value & 0x8) && !context->lfo_enable) {
768+ printf("LFO Enabled, Freq: %d\n", value & 0x7);
769+ }*/
770+ context->lfo_enable = value & 0x8;
771+ if (!context->lfo_enable) {
772+ context->lfo_am_step = context->lfo_pm_step = 0;
773+ }
774+ context->lfo_freq = value & 0x7;
775+
776+ break;
777+ case REG_TIMERA_HIGH:
778+ context->timer_a_load &= 0x3;
779+ context->timer_a_load |= value << 2;
780+ break;
781+ case REG_TIMERA_LOW:
782+ context->timer_a_load &= 0xFFFC;
783+ context->timer_a_load |= value & 0x3;
784+ break;
785+ case REG_TIMERB:
786+ context->timer_b_load = value;
787+ break;
788+ case REG_TIME_CTRL: {
789+ if (value & BIT_TIMERA_ENABLE && !(context->timer_control & BIT_TIMERA_ENABLE)) {
790+ context->timer_a = TIMER_A_MAX;
791+ context->timer_control |= BIT_TIMERA_LOAD;
792+ }
793+ if (value & BIT_TIMERB_ENABLE && !(context->timer_control & BIT_TIMERB_ENABLE)) {
794+ context->timer_b = TIMER_B_MAX;
795+ context->timer_control |= BIT_TIMERB_LOAD;
796+ }
797+ context->timer_control &= (BIT_TIMERA_LOAD | BIT_TIMERB_LOAD);
798+ context->timer_control |= value & 0xF;
799+ if (value & BIT_TIMERA_RESET) {
800+ context->status &= ~BIT_STATUS_TIMERA;
801+ }
802+ if (value & BIT_TIMERB_RESET) {
803+ context->status &= ~BIT_STATUS_TIMERB;
804+ }
805+ if (context->ch3_mode == CSM_MODE && (value & 0xC0) != CSM_MODE && context->csm_keyon) {
806+ csm_keyoff(context);
807+ }
808+ context->ch3_mode = value & 0xC0;
809+ break;
810+ }
811+ case REG_KEY_ONOFF: {
812+ uint8_t channel = value & 0x7;
813+ if (channel != 3 && channel != 7) {
814+ if (channel > 2) {
815+ channel--;
816+ }
817+ uint8_t changes = channel == 2
818+ ? (value | context->csm_keyon) ^ (context->channels[channel].keyon | context->csm_keyon)
819+ : value ^ context->channels[channel].keyon;
820+ context->channels[channel].keyon = value & 0xF0;
821+ for (uint8_t op = channel * 4, bit = 0; op < (channel + 1) * 4; op++, bit++) {
822+ if (changes & keyon_bits[bit]) {
823+ if (value & keyon_bits[bit]) {
824+ first_key_on = 1;
825+ //printf("Key On for operator %d in channel %d\n", op, channel);
826+ keyon(context->operators + op, context->channels + channel);
827+ } else {
828+ //printf("Key Off for operator %d in channel %d\n", op, channel);
829+ keyoff(context->operators + op);
830+ }
831+ }
832+ }
833+ }
834+ break;
835+ }
836+ case REG_DAC:
837+ if (context->dac_enable) {
838+ context->channels[5].output = (((int16_t)value) - 0x80) << 6;
839+ //printf("DAC Write %X(%d) @ %d\n", value, context->channels[5].output, context->current_cycle);
840+ }
841+ break;
842+ case REG_DAC_ENABLE:
843+ //printf("DAC Enable: %X\n", value);
844+ context->dac_enable = value & 0x80;
845+ break;
846+ }
847+ } else if (context->selected_reg < 0xA0) {
848+ //part
849+ uint8_t op = context->selected_part ? (NUM_OPERATORS/2) : 0;
850+ //channel in part
851+ if ((context->selected_reg & 0x3) != 0x3) {
852+ op += 4 * (context->selected_reg & 0x3) + ((context->selected_reg & 0xC) / 4);
853+ //printf("write targets operator %d (%d of channel %d)\n", op, op % 4, op / 4);
854+ ym_operator * operator = context->operators + op;
855+ switch (context->selected_reg & 0xF0)
856+ {
857+ case REG_DETUNE_MULT:
858+ operator->detune = value >> 4 & 0x7;
859+ operator->multiple = value & 0xF;
860+ break;
861+ case REG_TOTAL_LEVEL:
862+ operator->total_level = (value & 0x7F) << 5;
863+ break;
864+ case REG_ATTACK_KS:
865+ operator->key_scaling = 3 - (value >> 6);
866+ operator->rates[PHASE_ATTACK] = value & 0x1F;
867+ break;
868+ case REG_DECAY_AM:
869+ operator->am = value & 0x80;
870+ operator->rates[PHASE_DECAY] = value & 0x1F;
871+ break;
872+ case REG_SUSTAIN_RATE:
873+ operator->rates[PHASE_SUSTAIN] = value & 0x1F;
874+ break;
875+ case REG_S_LVL_R_RATE:
876+ operator->rates[PHASE_RELEASE] = (value & 0xF) << 1 | 1;
877+ operator->sustain_level = (value & 0xF0) << 3;
878+ if (operator->sustain_level == 0x780) {
879+ operator->sustain_level = MAX_ENVELOPE;
880+ }
881+ break;
882+ case REG_SSG_EG:
883+ if (!(value & SSG_ENABLE)) {
884+ value = 0;
885+ }
886+ if ((value ^ operator->ssg) & SSG_INVERT) {
887+ operator->inverted ^= SSG_INVERT;
888+ }
889+ operator->ssg = value;
890+ break;
891+ }
892+ }
893+ } else {
894+ uint8_t channel = context->selected_reg & 0x3;
895+ if (channel != 3) {
896+ if (context->selected_part) {
897+ channel += 3;
898+ }
899+ //printf("write targets channel %d\n", channel);
900+ switch (context->selected_reg & 0xFC)
901+ {
902+ case REG_FNUM_LOW:
903+ context->channels[channel].block = context->channels[channel].block_fnum_latch >> 3 & 0x7;
904+ context->channels[channel].fnum = (context->channels[channel].block_fnum_latch & 0x7) << 8 | value;
905+ context->channels[channel].keycode = context->channels[channel].block << 2 | fnum_to_keycode[context->channels[channel].fnum >> 7];
906+ break;
907+ case REG_BLOCK_FNUM_H:{
908+ context->channels[channel].block_fnum_latch = value;
909+ break;
910+ }
911+ case REG_FNUM_LOW_CH3:
912+ if (channel < 3) {
913+ context->ch3_supp[channel].block = context->ch3_supp[channel].block_fnum_latch >> 3 & 0x7;
914+ context->ch3_supp[channel].fnum = (context->ch3_supp[channel].block_fnum_latch & 0x7) << 8 | value;
915+ context->ch3_supp[channel].keycode = context->ch3_supp[channel].block << 2 | fnum_to_keycode[context->ch3_supp[channel].fnum >> 7];
916+ }
917+ break;
918+ case REG_BLOCK_FN_CH3:
919+ if (channel < 3) {
920+ context->ch3_supp[channel].block_fnum_latch = value;
921+ }
922+ break;
923+ case REG_ALG_FEEDBACK:
924+ context->channels[channel].algorithm = value & 0x7;
925+ switch (context->channels[channel].algorithm)
926+ {
927+ case 0:
928+ //operator 3 modulated by operator 2
929+ //this uses a special op2 result reg on HW, but that reg will have the most recent
930+ //result from op2 when op3 starts executing
931+ context->operators[channel*4+1].mod_src[0] = &context->operators[channel*4+2].output;
932+ context->operators[channel*4+1].mod_src[1] = NULL;
933+
934+ //operator 2 modulated by operator 1
935+ context->operators[channel*4+2].mod_src[0] = &context->operators[channel*4+0].output;
936+
937+ //operator 4 modulated by operator 3
938+ context->operators[channel*4+3].mod_src[0] = &context->operators[channel*4+1].output;
939+ context->operators[channel*4+3].mod_src[1] = NULL;
940+ break;
941+ case 1:
942+ //operator 3 modulated by operator 1+2
943+ //op1 starts executing before this, but due to pipeline length the most current result is
944+ //not available and instead the previous result is used
945+ context->operators[channel*4+1].mod_src[0] = &context->channels[channel].op1_old;
946+ //this uses a special op2 result reg on HW, but that reg will have the most recent
947+ //result from op2 when op3 starts executing
948+ context->operators[channel*4+1].mod_src[1] = &context->operators[channel*4+2].output;
949+
950+ //operator 2 unmodulated
951+ context->operators[channel*4+2].mod_src[0] = NULL;
952+
953+ //operator 4 modulated by operator 3
954+ context->operators[channel*4+3].mod_src[0] = &context->operators[channel*4+1].output;
955+ context->operators[channel*4+3].mod_src[1] = NULL;
956+ break;
957+ case 2:
958+ //operator 3 modulated by operator 2
959+ //this uses a special op2 result reg on HW, but that reg will have the most recent
960+ //result from op2 when op3 starts executing
961+ context->operators[channel*4+1].mod_src[0] = &context->operators[channel*4+2].output;
962+ context->operators[channel*4+1].mod_src[1] = NULL;
963+
964+ //operator 2 unmodulated
965+ context->operators[channel*4+2].mod_src[0] = NULL;
966+
967+ //operator 4 modulated by operator 1+3
968+ //this uses a special op1 result reg on HW, but that reg will have the most recent
969+ //result from op1 when op4 starts executing
970+ context->operators[channel*4+3].mod_src[0] = &context->operators[channel*4+0].output;
971+ context->operators[channel*4+3].mod_src[1] = &context->operators[channel*4+1].output;
972+ break;
973+ case 3:
974+ //operator 3 unmodulated
975+ context->operators[channel*4+1].mod_src[0] = NULL;
976+ context->operators[channel*4+1].mod_src[1] = NULL;
977+
978+ //operator 2 modulated by operator 1
979+ context->operators[channel*4+2].mod_src[0] = &context->operators[channel*4+0].output;
980+
981+ //operator 4 modulated by operator 2+3
982+ //op2 starts executing before this, but due to pipeline length the most current result is
983+ //not available and instead the previous result is used
984+ context->operators[channel*4+3].mod_src[0] = &context->channels[channel].op2_old;
985+ context->operators[channel*4+3].mod_src[1] = &context->operators[channel*4+1].output;
986+ break;
987+ case 4:
988+ //operator 3 unmodulated
989+ context->operators[channel*4+1].mod_src[0] = NULL;
990+ context->operators[channel*4+1].mod_src[1] = NULL;
991+
992+ //operator 2 modulated by operator 1
993+ context->operators[channel*4+2].mod_src[0] = &context->operators[channel*4+0].output;
994+
995+ //operator 4 modulated by operator 3
996+ context->operators[channel*4+3].mod_src[0] = &context->operators[channel*4+1].output;
997+ context->operators[channel*4+3].mod_src[1] = NULL;
998+ break;
999+ case 5:
1000+ //operator 3 modulated by operator 1
1001+ //op1 starts executing before this, but due to pipeline length the most current result is
1002+ //not available and instead the previous result is used
1003+ context->operators[channel*4+1].mod_src[0] = &context->channels[channel].op1_old;
1004+ context->operators[channel*4+1].mod_src[1] = NULL;
1005+
1006+ //operator 2 modulated by operator 1
1007+ context->operators[channel*4+2].mod_src[0] = &context->operators[channel*4+0].output;
1008+
1009+ //operator 4 modulated by operator 1
1010+ //this uses a special op1 result reg on HW, but that reg will have the most recent
1011+ //result from op1 when op4 starts executing
1012+ context->operators[channel*4+3].mod_src[0] = &context->operators[channel*4+0].output;
1013+ context->operators[channel*4+3].mod_src[1] = NULL;
1014+ break;
1015+ case 6:
1016+ //operator 3 unmodulated
1017+ context->operators[channel*4+1].mod_src[0] = NULL;
1018+ context->operators[channel*4+1].mod_src[1] = NULL;
1019+
1020+ //operator 2 modulated by operator 1
1021+ context->operators[channel*4+2].mod_src[0] = &context->operators[channel*4+0].output;
1022+
1023+ //operator 4 unmodulated
1024+ context->operators[channel*4+3].mod_src[0] = NULL;
1025+ context->operators[channel*4+3].mod_src[1] = NULL;
1026+ break;
1027+ case 7:
1028+ //everything is an output so no modulation (except for op 1 feedback)
1029+ context->operators[channel*4+1].mod_src[0] = NULL;
1030+ context->operators[channel*4+1].mod_src[1] = NULL;
1031+
1032+ context->operators[channel*4+2].mod_src[0] = NULL;
1033+
1034+ context->operators[channel*4+3].mod_src[0] = NULL;
1035+ context->operators[channel*4+3].mod_src[1] = NULL;
1036+ break;
1037+ }
1038+ context->channels[channel].feedback = value >> 3 & 0x7;
1039+ //printf("Algorithm %d, feedback %d for channel %d\n", value & 0x7, value >> 3 & 0x7, channel);
1040+ break;
1041+ case REG_LR_AMS_PMS:
1042+ context->channels[channel].pms = (value & 0x7) * 32;
1043+ context->channels[channel].ams = value >> 4 & 0x3;
1044+ context->channels[channel].lr = value & 0xC0;
1045+ //printf("Write of %X to LR_AMS_PMS reg for channel %d\n", value, channel);
1046+ break;
1047+ }
1048+ }
1049+ }
1050+
1051+ context->write_cycle = context->current_cycle;
1052+ context->busy_cycles = context->selected_reg < 0xA0 ? BUSY_CYCLES_DATA_LOW : BUSY_CYCLES_DATA_HIGH;
1053+ context->status |= 0x80;
1054+}
1055+
1056+uint8_t ym_read_status(ym2612_context * context)
1057+{
1058+ return context->status;
1059+}
1060+
1061+void ym_print_channel_info(ym2612_context *context, int channel)
1062+{
1063+ ym_channel *chan = context->channels + channel;
1064+ printf("\n***Channel %d***\n"
1065+ "Algorithm: %d\n"
1066+ "Feedback: %d\n"
1067+ "Pan: %s\n"
1068+ "AMS: %d\n"
1069+ "PMS: %d\n",
1070+ channel+1, chan->algorithm, chan->feedback,
1071+ chan->lr == 0xC0 ? "LR" : chan->lr == 0x80 ? "L" : chan->lr == 0x40 ? "R" : "",
1072+ chan->ams, chan->pms);
1073+ if (channel == 2) {
1074+ printf(
1075+ "Mode: %X: %s\n",
1076+ context->ch3_mode, context->ch3_mode ? "special" : "normal");
1077+ }
1078+ for (int operator = channel * 4; operator < channel * 4+4; operator++)
1079+ {
1080+ int dispnum = operator - channel * 4 + 1;
1081+ if (dispnum == 2) {
1082+ dispnum = 3;
1083+ } else if (dispnum == 3) {
1084+ dispnum = 2;
1085+ }
1086+ ym_operator *op = context->operators + operator;
1087+ printf("\nOperator %d:\n"
1088+ " Multiple: %d\n"
1089+ " Detune: %d\n"
1090+ " Total Level: %d\n"
1091+ " Attack Rate: %d\n"
1092+ " Key Scaling: %d\n"
1093+ " Decay Rate: %d\n"
1094+ " Sustain Level: %d\n"
1095+ " Sustain Rate: %d\n"
1096+ " Release Rate: %d\n"
1097+ " Amplitude Modulation %s\n",
1098+ dispnum, op->multiple, op->detune, op->total_level,
1099+ op->rates[PHASE_ATTACK], op->key_scaling, op->rates[PHASE_DECAY],
1100+ op->sustain_level, op->rates[PHASE_SUSTAIN], op->rates[PHASE_RELEASE],
1101+ op->am ? "On" : "Off");
1102+ }
1103+}
1104+
1105+void ym_print_timer_info(ym2612_context *context)
1106+{
1107+ printf("***Timer A***\n"
1108+ "Current Value: %d\n"
1109+ "Load Value: %d\n"
1110+ "Triggered: %s\n"
1111+ "Enabled: %s\n\n",
1112+ context->timer_a,
1113+ context->timer_a_load,
1114+ context->status & BIT_STATUS_TIMERA ? "yes" : "no",
1115+ context->timer_control & BIT_TIMERA_ENABLE ? "yes" : "no");
1116+ printf("***Timer B***\n"
1117+ "Current Value: %d\n"
1118+ "Load Value: %d\n"
1119+ "Triggered: %s\n"
1120+ "Enabled: %s\n\n",
1121+ context->timer_b,
1122+ context->timer_b_load,
1123+ context->status & BIT_STATUS_TIMERB ? "yes" : "no",
1124+ context->timer_control & BIT_TIMERB_ENABLE ? "yes" : "no");
1125+}
1126+
1127+void ym_serialize(ym2612_context *context, serialize_buffer *buf)
1128+{
1129+ save_buffer8(buf, context->part1_regs, YM_PART1_REGS);
1130+ save_buffer8(buf, context->part2_regs, YM_PART2_REGS);
1131+ for (int i = 0; i < NUM_OPERATORS; i++)
1132+ {
1133+ save_int32(buf, context->operators[i].phase_counter);
1134+ save_int16(buf, context->operators[i].envelope);
1135+ save_int16(buf, context->operators[i].output);
1136+ save_int8(buf, context->operators[i].env_phase);
1137+ save_int8(buf, context->operators[i].inverted);
1138+ }
1139+ for (int i = 0; i < NUM_CHANNELS; i++)
1140+ {
1141+ save_int16(buf, context->channels[i].output);
1142+ save_int16(buf, context->channels[i].op1_old);
1143+ //Due to the latching behavior, these need to be saved
1144+ //even though duplicate info is probably in the regs array
1145+ save_int8(buf, context->channels[i].block);
1146+ save_int16(buf, context->channels[i].fnum);
1147+ save_int8(buf, context->channels[i].keyon);
1148+ }
1149+ for (int i = 0; i < 3; i++)
1150+ {
1151+ //Due to the latching behavior, these need to be saved
1152+ //even though duplicate info is probably in the regs array
1153+ save_int8(buf, context->ch3_supp[i].block);
1154+ save_int8(buf, context->ch3_supp[i].fnum);
1155+ }
1156+ save_int8(buf, context->timer_control);
1157+ save_int16(buf, context->timer_a);
1158+ save_int8(buf, context->timer_b);
1159+ save_int8(buf, context->sub_timer_b);
1160+ save_int16(buf, context->env_counter);
1161+ save_int8(buf, context->current_op);
1162+ save_int8(buf, context->current_env_op);
1163+ save_int8(buf, context->lfo_counter);
1164+ save_int8(buf, context->csm_keyon);
1165+ save_int8(buf, context->status);
1166+ save_int8(buf, context->selected_reg);
1167+ save_int8(buf, context->selected_part);
1168+ save_int32(buf, context->current_cycle);
1169+ save_int32(buf, context->write_cycle);
1170+ save_int32(buf, context->busy_cycles);
1171+}
1172+
1173+void ym_deserialize(deserialize_buffer *buf, void *vcontext)
1174+{
1175+ ym2612_context *context = vcontext;
1176+ uint8_t temp_regs[YM_PART1_REGS];
1177+ load_buffer8(buf, temp_regs, YM_PART1_REGS);
1178+ context->selected_part = 0;
1179+ for (int i = 0; i < YM_PART1_REGS; i++)
1180+ {
1181+ uint8_t reg = YM_PART1_START + i;
1182+ if (reg == REG_TIME_CTRL) {
1183+ context->ch3_mode = temp_regs[i] & 0xC0;
1184+ } else if (reg != REG_FNUM_LOW && reg != REG_KEY_ONOFF) {
1185+ context->selected_reg = reg;
1186+ ym_data_write(context, temp_regs[i]);
1187+ }
1188+ }
1189+ load_buffer8(buf, temp_regs, YM_PART2_REGS);
1190+ context->selected_part = 1;
1191+ for (int i = 0; i < YM_PART2_REGS; i++)
1192+ {
1193+ uint8_t reg = YM_PART2_START + i;
1194+ if (reg != REG_FNUM_LOW) {
1195+ context->selected_reg = reg;
1196+ ym_data_write(context, temp_regs[i]);
1197+ }
1198+ }
1199+ for (int i = 0; i < NUM_OPERATORS; i++)
1200+ {
1201+ context->operators[i].phase_counter = load_int32(buf);
1202+ context->operators[i].envelope = load_int16(buf);
1203+ context->operators[i].output = load_int16(buf);
1204+ context->operators[i].env_phase = load_int8(buf);
1205+ if (context->operators[i].env_phase > PHASE_RELEASE) {
1206+ context->operators[i].env_phase = PHASE_RELEASE;
1207+ }
1208+ context->operators[i].inverted = load_int8(buf) != 0 ? SSG_INVERT : 0;
1209+ }
1210+ for (int i = 0; i < NUM_CHANNELS; i++)
1211+ {
1212+ context->channels[i].output = load_int16(buf);
1213+ context->channels[i].op1_old = load_int16(buf);
1214+ context->channels[i].block = load_int8(buf);
1215+ context->channels[i].fnum = load_int16(buf);
1216+ context->channels[i].keycode = context->channels[i].block << 2 | fnum_to_keycode[context->channels[i].fnum >> 7];
1217+ context->channels[i].keyon = load_int8(buf);
1218+ }
1219+ for (int i = 0; i < 3; i++)
1220+ {
1221+ context->ch3_supp[i].block = load_int8(buf);
1222+ context->ch3_supp[i].fnum = load_int8(buf);
1223+ context->ch3_supp[i].keycode = context->ch3_supp[i].block << 2 | fnum_to_keycode[context->ch3_supp[i].fnum >> 7];
1224+ }
1225+ context->timer_control = load_int8(buf);
1226+ context->timer_a = load_int16(buf);
1227+ context->timer_b = load_int8(buf);
1228+ context->sub_timer_b = load_int8(buf);
1229+ context->env_counter = load_int16(buf);
1230+ context->current_op = load_int8(buf);
1231+ if (context->current_op >= NUM_OPERATORS) {
1232+ context->current_op = 0;
1233+ }
1234+ context->current_env_op = load_int8(buf);
1235+ if (context->current_env_op >= NUM_OPERATORS) {
1236+ context->current_env_op = 0;
1237+ }
1238+ context->lfo_counter = load_int8(buf);
1239+ context->csm_keyon = load_int8(buf);
1240+ context->status = load_int8(buf);
1241+ context->selected_reg = load_int8(buf);
1242+ context->selected_part = load_int8(buf);
1243+ context->current_cycle = load_int32(buf);
1244+ context->write_cycle = load_int32(buf);
1245+ context->busy_cycles = load_int32(buf);
1246+}
A
ym2612.h
+149,
-0
1@@ -0,0 +1,149 @@
2+/*
3+ Copyright 2013 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#ifndef YM2612_H_
8+#define YM2612_H_
9+
10+#include <stdint.h>
11+#include <stdio.h>
12+#include "serialize.h"
13+#include "render.h"
14+
15+#define NUM_PART_REGS (0xB7-0x30)
16+#define NUM_CHANNELS 6
17+#define NUM_OPERATORS (4*NUM_CHANNELS)
18+
19+#define YM_OPT_WAVE_LOG 1
20+
21+typedef struct {
22+ int16_t *mod_src[2];
23+ uint32_t phase_counter;
24+ uint16_t envelope;
25+ int16_t output;
26+ uint16_t total_level;
27+ uint16_t sustain_level;
28+ uint8_t rates[4];
29+ uint8_t key_scaling;
30+ uint8_t multiple;
31+ uint8_t detune;
32+ uint8_t am;
33+ uint8_t env_phase;
34+ uint8_t ssg;
35+ uint8_t inverted;
36+} ym_operator;
37+
38+typedef struct {
39+ FILE * logfile;
40+ uint16_t fnum;
41+ int16_t output;
42+ int16_t op1_old;
43+ int16_t op2_old;
44+ uint8_t block_fnum_latch;
45+ uint8_t block;
46+ uint8_t keycode;
47+ uint8_t algorithm;
48+ uint8_t feedback;
49+ uint8_t ams;
50+ uint8_t pms;
51+ uint8_t lr;
52+ uint8_t keyon;
53+} ym_channel;
54+
55+typedef struct {
56+ uint16_t fnum;
57+ uint8_t block;
58+ uint8_t block_fnum_latch;
59+ uint8_t keycode;
60+} ym_supp;
61+
62+#define YM_PART1_START 0x21
63+#define YM_PART2_START 0x30
64+#define YM_REG_END 0xB8
65+#define YM_PART1_REGS (YM_REG_END-YM_PART1_START)
66+#define YM_PART2_REGS (YM_REG_END-YM_PART2_START)
67+
68+typedef struct {
69+ audio_source *audio;
70+ uint32_t clock_inc;
71+ uint32_t current_cycle;
72+ //TODO: Condense the next two fields into one
73+ uint32_t write_cycle;
74+ uint32_t busy_cycles;
75+ int32_t volume_mult;
76+ int32_t volume_div;
77+ ym_operator operators[NUM_OPERATORS];
78+ ym_channel channels[NUM_CHANNELS];
79+ int16_t zero_offset;
80+ uint16_t timer_a;
81+ uint16_t timer_a_load;
82+ uint16_t env_counter;
83+ ym_supp ch3_supp[3];
84+ uint8_t timer_b;
85+ uint8_t sub_timer_b;
86+ uint8_t timer_b_load;
87+ uint8_t ch3_mode;
88+ uint8_t current_op;
89+ uint8_t current_env_op;
90+
91+ uint8_t timer_control;
92+ uint8_t dac_enable;
93+ uint8_t lfo_enable;
94+ uint8_t lfo_freq;
95+ uint8_t lfo_counter;
96+ uint8_t lfo_am_step;
97+ uint8_t lfo_pm_step;
98+ uint8_t csm_keyon;
99+ uint8_t status;
100+ uint8_t selected_reg;
101+ uint8_t selected_part;
102+ uint8_t part1_regs[YM_PART1_REGS];
103+ uint8_t part2_regs[YM_PART2_REGS];
104+} ym2612_context;
105+
106+enum {
107+ REG_LFO = 0x22,
108+ REG_TIMERA_HIGH = 0x24,
109+ REG_TIMERA_LOW,
110+ REG_TIMERB,
111+ REG_TIME_CTRL,
112+ REG_KEY_ONOFF,
113+ REG_DAC = 0x2A,
114+ REG_DAC_ENABLE,
115+
116+ REG_DETUNE_MULT = 0x30,
117+ REG_TOTAL_LEVEL = 0x40,
118+ REG_ATTACK_KS = 0x50,
119+ REG_DECAY_AM = 0x60,
120+ REG_SUSTAIN_RATE = 0x70,
121+ REG_S_LVL_R_RATE = 0x80,
122+ REG_SSG_EG = 0x90,
123+
124+ REG_FNUM_LOW = 0xA0,
125+ REG_BLOCK_FNUM_H = 0xA4,
126+ REG_FNUM_LOW_CH3 = 0xA8,
127+ REG_BLOCK_FN_CH3 = 0xAC,
128+ REG_ALG_FEEDBACK = 0xB0,
129+ REG_LR_AMS_PMS = 0xB4
130+};
131+
132+void ym_init(ym2612_context * context, uint32_t master_clock, uint32_t clock_div, uint32_t options);
133+void ym_reset(ym2612_context *context);
134+void ym_free(ym2612_context *context);
135+void ym_enable_zero_offset(ym2612_context *context, uint8_t enabled);
136+void ym_adjust_master_clock(ym2612_context * context, uint32_t master_clock);
137+void ym_run(ym2612_context * context, uint32_t to_cycle);
138+void ym_address_write_part1(ym2612_context * context, uint8_t address);
139+void ym_address_write_part2(ym2612_context * context, uint8_t address);
140+void ym_data_write(ym2612_context * context, uint8_t value);
141+uint8_t ym_read_status(ym2612_context * context);
142+uint8_t ym_load_gst(ym2612_context * context, FILE * gstfile);
143+uint8_t ym_save_gst(ym2612_context * context, FILE * gstfile);
144+void ym_print_channel_info(ym2612_context *context, int channel);
145+void ym_print_timer_info(ym2612_context *context);
146+void ym_serialize(ym2612_context *context, serialize_buffer *buf);
147+void ym_deserialize(deserialize_buffer *buf, void *vcontext);
148+
149+#endif //YM2612_H_
150+
A
z80.cpu
+2539,
-0
1@@ -0,0 +1,2539 @@
2+info
3+ prefix z80_
4+ opcode_size 8
5+ extra_tables cb ed dded fded ddcb fdcb dd fd
6+ body z80_run_op
7+ sync_cycle z80_sync_cycle
8+ interrupt z80_interrupt
9+ include z80_util.c
10+ header z80.h
11+
12+declare
13+ void init_z80_opts(z80_options * options, memmap_chunk const * chunks, uint32_t num_chunks, memmap_chunk const * io_chunks, uint32_t num_io_chunks, uint32_t clock_divider, uint32_t io_address_mask);
14+ z80_context * init_z80_context(z80_options *options);
15+ void z80_run(z80_context *context, uint32_t target_cycle);
16+ void z80_assert_reset(z80_context * context, uint32_t cycle);
17+ void z80_clear_reset(z80_context * context, uint32_t cycle);
18+ void z80_assert_busreq(z80_context * context, uint32_t cycle);
19+ void z80_clear_busreq(z80_context * context, uint32_t cycle);
20+ void z80_assert_nmi(z80_context *context, uint32_t cycle);
21+ uint8_t z80_get_busack(z80_context * context, uint32_t cycle);
22+ void z80_invalidate_code_range(z80_context *context, uint32_t start, uint32_t end);
23+ void z80_adjust_cycles(z80_context * context, uint32_t deduction);
24+ void z80_serialize(z80_context *context, serialize_buffer *buf);
25+ void z80_deserialize(deserialize_buffer *buf, void *vcontext);
26+ void zinsert_breakpoint(z80_context * context, uint16_t address, uint8_t * bp_handler);
27+ void zremove_breakpoint(z80_context * context, uint16_t address);
28+ void z80_options_free(z80_options *opts);
29+ void z80_sync_cycle(z80_context *context, uint32_t target_cycle);
30+
31+regs
32+ main 8 b c d e h l f a
33+ alt 8 b' c' d' e' h' l' f' a'
34+ i 8
35+ r 8
36+ rhigh 8
37+ iff1 8
38+ iff2 8
39+ imode 8
40+ sp 16
41+ ix 16
42+ iy 16
43+ pc 16
44+ wz 16
45+ nflag 8
46+ last_flag_result 8
47+ pvflag 8
48+ chflags 8
49+ zflag 8
50+ scratch1 16
51+ scratch2 16
52+ busreq 8
53+ busack 8
54+ reset 8
55+ io_map ptrmemmap_chunk
56+ io_chunks 32
57+ io_mask 32
58+ int_cycle 32
59+ int_end_cycle 32
60+ int_value 8
61+ nmi_cycle 32
62+ system ptrvoid
63+ fastread ptr8 64
64+ fastwrite ptr8 64
65+ mem_pointers ptr8 4
66+
67+flags
68+ register f
69+ S 7 sign last_flag_result.7
70+ Z 6 zero zflag
71+ Y 5 bit-5 last_flag_result.5
72+ H 4 half-carry chflags.3
73+ P 2 parity pvflag
74+ V 2 overflow pvflag
75+ X 3 bit-3 last_flag_result.3
76+ N 1 none nflag
77+ C 0 carry chflags.7
78+
79+
80+z80_op_fetch
81+ cycles 1
82+ add 1 r r
83+ mov pc scratch1
84+ ocall read_8
85+ add 1 pc pc
86+
87+z80_run_op
88+ #printf "Z80: %X @ %d\n" pc cycles
89+ #printf "Z80: %X - A: %X, B: %X, C: %X D: %X, E: %X, H: %X, L: %X, SP: %X, IX: %X, IY: %X @ %d\n" pc a b c d e h l sp ix iy cycles
90+ z80_op_fetch
91+ dispatch scratch1
92+
93+z80_interrupt
94+ cmp int_cycle cycles
95+ if >=U
96+
97+ mov 0 iff1
98+ mov 0 iff2
99+ cycles 6
100+ update_sync
101+
102+ switch imode
103+ case 0
104+ dispatch int_value
105+
106+ case 1
107+ dispatch 0xFF
108+
109+ case 2
110+ lsl i 8 pc
111+ or int_value pc pc
112+ #CD is call
113+ dispatch 0xCD
114+ end
115+
116+ else
117+
118+ cmp nmi_cycle cycles
119+ if >=U
120+
121+ mov 0xFFFFFFFF nmi_cycle
122+ mov 0 iff1
123+ local pch 8
124+ lsr pc 8 pch
125+ meta high pch
126+ meta low pc
127+ z80_push
128+ mov 0x66 pc
129+ update_sync
130+
131+ end
132+ end
133+
134+
135+11001011 cb_prefix
136+ z80_op_fetch
137+ dispatch scratch1 cb
138+
139+11011101 dd_prefix
140+ z80_op_fetch
141+ dispatch scratch1 dd
142+
143+11101101 ed_prefix
144+ z80_op_fetch
145+ dispatch scratch1 ed
146+
147+11111101 fd_prefix
148+ z80_op_fetch
149+ dispatch scratch1 fd
150+
151+dd 11001011 ddcb_prefix
152+ z80_calc_index ix
153+ cycles 2
154+ mov pc scratch1
155+ ocall read_8
156+ add 1 pc pc
157+ dispatch scratch1 ddcb
158+
159+fd 11001011 fdcb_prefix
160+ z80_calc_index iy
161+ cycles 2
162+ mov pc scratch1
163+ ocall read_8
164+ add 1 pc pc
165+ dispatch scratch1 fdcb
166+
167+z80_check_cond
168+ arg cond 8
169+ local invert 8
170+ switch cond
171+ case 0
172+ meta istrue invert
173+ lnot zflag invert
174+
175+ case 1
176+ meta istrue zflag
177+
178+ case 2
179+ meta istrue invert
180+ not chflags invert
181+ and 0x80 invert invert
182+
183+ case 3
184+ meta istrue invert
185+ and 0x80 chflags invert
186+
187+ case 4
188+ meta istrue invert
189+ lnot pvflag invert
190+
191+ case 5
192+ meta istrue pvflag
193+
194+ case 6
195+ meta istrue invert
196+ not last_flag_result invert
197+ and 0x80 invert invert
198+
199+ case 7
200+ meta istrue invert
201+ and 0x80 last_flag_result invert
202+
203+ end
204+
205+z80_fetch_hl
206+ lsl h 8 scratch1
207+ or l scratch1 scratch1
208+ ocall read_8
209+
210+z80_store_hl
211+ lsl h 8 scratch2
212+ or l scratch2 scratch2
213+ ocall write_8
214+
215+z80_fetch_immed
216+ mov pc scratch1
217+ ocall read_8
218+ add 1 pc pc
219+
220+z80_fetch_immed16
221+ mov pc scratch1
222+ ocall read_8
223+ mov scratch1 wz
224+ add 1 pc pc
225+ mov pc scratch1
226+ ocall read_8
227+ add 1 pc pc
228+ lsl scratch1 8 scratch1
229+ or scratch1 wz wz
230+
231+z80_fetch_immed_reg16
232+ mov pc scratch1
233+ ocall read_8
234+ mov scratch1 low
235+ add 1 pc pc
236+ mov pc scratch1
237+ ocall read_8
238+ mov scratch1 high
239+ add 1 pc pc
240+
241+z80_fetch_immed_to_reg16
242+ mov pc scratch1
243+ ocall read_8
244+ mov scratch1 reg
245+ add 1 pc pc
246+ mov pc scratch1
247+ ocall read_8
248+ add 1 pc pc
249+ lsl scratch1 8 scratch1
250+ or scratch1 reg reg
251+
252+01RRR110 ld_from_hl
253+ z80_fetch_hl
254+ mov scratch1 main.R
255+
256+01DDDSSS ld_from_reg
257+ mov main.S main.D
258+
259+dd 01DDD100 ld_from_ixh
260+ invalid D 6
261+ lsr ix 8 main.D
262+
263+dd 01100SSS ld_to_ixh
264+ invalid S 6
265+ local tmp 16
266+ and 0xFF ix ix
267+ lsl main.S 8 tmp
268+ or tmp ix ix
269+
270+dd 0110D10S ld_ixb_to_ixb
271+
272+dd 01DDD101 ld_from_ixl
273+ invalid D 6
274+ mov ix main.D
275+
276+dd 01101SSS ld_to_ixl
277+ invalid S 6
278+ and 0xFF00 ix ix
279+ or main.S ix ix
280+
281+dd 01100101 ld_ixl_to_ixh
282+ local tmp 16
283+ lsl ix 8 tmp
284+ and 0xFF ix ix
285+ or tmp ix ix
286+
287+dd 01101100 ld_ixh_to_ixl
288+ local tmp 16
289+ lsr ix 8 tmp
290+ and 0xFF00 ix ix
291+ or tmp ix ix
292+
293+fd 01DDD100 ld_from_iyh
294+ invalid D 6
295+ lsr iy 8 main.D
296+
297+fd 01100SSS ld_to_iyh
298+ invalid S 6
299+ local tmp 16
300+ and 0xFF iy iy
301+ lsl main.S 8 tmp
302+ or tmp iy iy
303+
304+fd 0110D10S ld_iyb_to_iyb
305+
306+fd 01DDD101 ld_from_iyl
307+ invalid D 6
308+ mov iy main.D
309+
310+fd 01101SSS ld_to_iyl
311+ invalid S 6
312+ and 0xFF00 iy iy
313+ or main.S iy iy
314+
315+fd 01100101 ld_iyl_to_iyh
316+ local tmp 16
317+ lsl iy 8 tmp
318+ and 0xFF iy iy
319+ or tmp iy iy
320+
321+fd 01101100 ld_iyh_to_iyl
322+ local tmp 16
323+ lsr iy 8 tmp
324+ and 0xFF00 iy iy
325+ or tmp iy iy
326+
327+z80_calc_index
328+ arg index 16
329+ mov index wz
330+ z80_fetch_immed
331+ sext 16 scratch1 scratch1
332+ add scratch1 wz wz
333+
334+z80_fetch_index
335+ arg index 16
336+ z80_calc_index index
337+ mov wz scratch1
338+ cycles 5
339+ ocall read_8
340+
341+z80_store_index
342+ mov wz scratch2
343+ ocall write_8
344+
345+dd 01RRR110 ld_from_ix
346+ z80_fetch_index ix
347+ mov scratch1 main.R
348+
349+fd 01RRR110 ld_from_iy
350+ z80_fetch_index iy
351+ mov scratch1 main.R
352+
353+00RRR110 ld_immed
354+ z80_fetch_immed
355+ mov scratch1 main.R
356+
357+dd 00100110 ld_immed_ixh
358+ z80_fetch_immed
359+ lsl scratch1 8 scratch1
360+ and 0xFF ix ix
361+ or scratch1 ix ix
362+
363+dd 00101110 ld_immed_ixl
364+ z80_fetch_immed
365+ and 0xFF00 ix ix
366+ or scratch1 ix ix
367+
368+fd 00100110 ld_immed_iyh
369+ z80_fetch_immed
370+ lsl scratch1 8 scratch1
371+ and 0xFF iy iy
372+ or scratch1 iy iy
373+
374+fd 00101110 ld_immed_iyl
375+ z80_fetch_immed
376+ and 0xFF00 iy iy
377+ or scratch1 iy iy
378+
379+01110RRR ld_to_hl
380+ mov main.R scratch1
381+ z80_store_hl
382+
383+dd 01110RRR ld_to_ix
384+ z80_calc_index ix
385+ mov wz scratch2
386+ mov main.R scratch1
387+ cycles 5
388+ ocall write_8
389+
390+fd 01110RRR ld_to_iy
391+ z80_calc_index iy
392+ mov wz scratch2
393+ mov main.R scratch1
394+ cycles 5
395+ ocall write_8
396+
397+00110110 ld_to_hl_immed
398+ z80_fetch_immed
399+ z80_store_hl
400+
401+dd 00110110 ld_to_ixd_immed
402+ z80_calc_index ix
403+ z80_fetch_immed
404+ cycles 2
405+ mov wz scratch2
406+ ocall write_8
407+
408+fd 00110110 ld_to_iyd_immed
409+ z80_calc_index iy
410+ z80_fetch_immed
411+ cycles 2
412+ mov wz scratch2
413+ ocall write_8
414+
415+00001010 ld_a_from_bc
416+ lsl b 8 wz
417+ or c wz wz
418+ mov wz scratch1
419+ add 1 wz wz
420+ ocall read_8
421+ mov scratch1 a
422+
423+00011010 ld_a_from_de
424+ lsl d 8 wz
425+ or e wz wz
426+ mov wz scratch1
427+ add 1 wz wz
428+ ocall read_8
429+ mov scratch1 a
430+
431+00111010 ld_a_from_immed
432+ z80_fetch_immed16
433+ mov wz scratch1
434+ add 1 wz wz
435+ ocall read_8
436+ mov scratch1 a
437+
438+00000010 ld_a_to_bc
439+ local tmp 8
440+ lsl b 8 scratch2
441+ or c scratch2 scratch2
442+ mov a scratch1
443+ add c 1 tmp
444+ lsl a 8 wz
445+ or tmp wz wz
446+ ocall write_8
447+
448+00010010 ld_a_to_de
449+ local tmp 8
450+ lsl d 8 scratch2
451+ or e scratch2 scratch2
452+ mov a scratch1
453+ add e 1 tmp
454+ lsl a 8 wz
455+ or tmp wz wz
456+ ocall write_8
457+
458+00110010 ld_a_to_immed
459+ local tmp 16
460+ z80_fetch_immed16
461+ mov wz scratch2
462+ mov a scratch1
463+ add 1 wz wz
464+ ocall write_8
465+ and 0xFF wz wz
466+ lsl a 8 tmp
467+ or tmp wz wz
468+
469+ed 01000111 ld_i_a
470+ mov a i
471+ cycles 1
472+
473+ed 01001111 ld_r_a
474+ mov a r
475+ and 0x80 a rhigh
476+ cycles 1
477+
478+ed 01011111 ld_a_r
479+ cycles 1
480+ and 0x7F r a
481+ or rhigh a a
482+ update_flags SZYH0XN0
483+ mov iff2 pvflag
484+
485+ed 01010111 ld_a_i
486+ cycles 1
487+ mov i a
488+ update_flags SZYH0XN0
489+ mov iff2 pvflag
490+
491+00000001 ld_bc_immed
492+ meta high b
493+ meta low c
494+ z80_fetch_immed_reg16
495+
496+00010001 ld_de_immed
497+ meta high d
498+ meta low e
499+ z80_fetch_immed_reg16
500+
501+00100001 ld_hl_immed
502+ meta high h
503+ meta low l
504+ z80_fetch_immed_reg16
505+
506+00110001 ld_sp_immed
507+ meta reg sp
508+ z80_fetch_immed_to_reg16
509+
510+dd 00100001 ld_ix_immed
511+ meta reg ix
512+ z80_fetch_immed_to_reg16
513+
514+fd 00100001 ld_iy_immed
515+ meta reg iy
516+ z80_fetch_immed_to_reg16
517+
518+z80_fetch16_from_immed
519+ z80_fetch_immed16
520+ mov wz scratch1
521+ ocall read_8
522+ mov scratch1 low
523+ add 1 wz wz
524+ mov wz scratch1
525+ ocall read_8
526+ mov scratch1 high
527+ add 1 wz wz
528+
529+00101010 ld_hl_from_immed
530+ meta low l
531+ meta high h
532+ z80_fetch16_from_immed
533+
534+ed 01001011 ld_bc_from_immed
535+ meta low c
536+ meta high b
537+ z80_fetch16_from_immed
538+
539+ed 01011011 ld_de_from_immed
540+ meta low e
541+ meta high d
542+ z80_fetch16_from_immed
543+
544+ed 01101011 ld_hl_from_immed_slow
545+ meta low l
546+ meta high h
547+ z80_fetch16_from_immed
548+
549+z80_fetch_reg16_from_immed
550+ z80_fetch_immed16
551+ mov wz scratch1
552+ ocall read_8
553+ mov scratch1 reg
554+ add 1 wz wz
555+ mov wz scratch1
556+ ocall read_8
557+ lsl scratch1 8 scratch1
558+ or scratch1 reg reg
559+ add 1 wz wz
560+
561+ed 01111011 ld_sp_from_immed
562+ meta reg sp
563+ z80_fetch_reg16_from_immed
564+
565+dd 00101010 ld_ix_from_immed
566+ meta reg ix
567+ z80_fetch_reg16_from_immed
568+
569+fd 00101010 ld_iy_from_immed
570+ meta reg iy
571+ z80_fetch_reg16_from_immed
572+
573+00100010 ld_hl_to_immed
574+ z80_fetch_immed16
575+ mov wz scratch2
576+ mov l scratch1
577+ ocall write_8
578+ add 1 wz wz
579+ mov wz scratch2
580+ mov h scratch1
581+ ocall write_8
582+ add 1 wz wz
583+
584+dd 00100010 ld_ix_to_immed
585+ z80_fetch_immed16
586+ mov wz scratch2
587+ mov ix scratch1
588+ ocall write_8
589+ add 1 wz wz
590+ mov wz scratch2
591+ lsr ix 8 scratch1
592+ ocall write_8
593+ add 1 wz wz
594+
595+fd 00100010 ld_iy_to_immed
596+ z80_fetch_immed16
597+ mov wz scratch2
598+ mov iy scratch1
599+ ocall write_8
600+ add 1 wz wz
601+ mov wz scratch2
602+ lsr iy 8 scratch1
603+ ocall write_8
604+ add 1 wz wz
605+
606+z80_regpair_to_immed
607+ z80_fetch_immed16
608+ mov wz scratch2
609+ mov low scratch1
610+ ocall write_8
611+ add 1 wz wz
612+ mov high scratch1
613+ mov wz scratch2
614+ ocall write_8
615+ add 1 wz wz
616+
617+ed 01000011 ld_bc_to_immed
618+ meta low c
619+ meta high b
620+ z80_regpair_to_immed
621+
622+ed 01010011 ld_de_to_immed
623+ meta low e
624+ meta high d
625+ z80_regpair_to_immed
626+
627+ed 01100011 ld_hl_to_immed_slow
628+ meta low l
629+ meta high h
630+ z80_regpair_to_immed
631+
632+ed 01110011 ld_sp_to_immed
633+ meta low sp
634+ local sph 8
635+ lsr sp 8 sph
636+ meta high sph
637+ z80_regpair_to_immed
638+
639+11111001 ld_sp_hl
640+ cycles 2
641+ lsl h 8 sp
642+ or l sp sp
643+
644+dd 11111001 ld_sp_ix
645+ cycles 2
646+ mov ix sp
647+
648+fd 11111001 ld_sp_iy
649+ cycles 2
650+ mov iy sp
651+
652+z80_push
653+ cycles 1
654+ sub 1 sp sp
655+ mov sp scratch2
656+ mov high scratch1
657+ ocall write_8
658+ sub 1 sp sp
659+ mov sp scratch2
660+ mov low scratch1
661+ ocall write_8
662+
663+11000101 push_bc
664+ meta high b
665+ meta low c
666+ z80_push
667+
668+11010101 push_de
669+ meta high d
670+ meta low e
671+ z80_push
672+
673+11100101 push_hl
674+ meta high h
675+ meta low l
676+ z80_push
677+
678+11110101 push_af
679+ meta high a
680+ meta low f
681+ z80_push
682+
683+dd 11100101 push_ix
684+ local ixh 8
685+ lsr ix 8 ixh
686+ meta high ixh
687+ meta low ix
688+ z80_push
689+
690+fd 11100101 push_iy
691+ local iyh 8
692+ lsr iy 8 iyh
693+ meta high iyh
694+ meta low iy
695+ z80_push
696+
697+z80_pop
698+ mov sp scratch1
699+ ocall read_8
700+ add 1 sp sp
701+ mov scratch1 low
702+ mov sp scratch1
703+ ocall read_8
704+ add 1 sp sp
705+ mov scratch1 high
706+
707+11000001 pop_bc
708+ meta high b
709+ meta low c
710+ z80_pop
711+
712+11010001 pop_de
713+ meta high d
714+ meta low e
715+ z80_pop
716+
717+11100001 pop_hl
718+ meta high h
719+ meta low l
720+ z80_pop
721+
722+11110001 pop_af
723+ meta high a
724+ meta low f
725+ z80_pop
726+
727+dd 11100001 pop_ix
728+ local ixh 16
729+ meta high ixh
730+ meta low ix
731+ z80_pop
732+ lsl ixh 8 ixh
733+ or ixh ix ix
734+
735+fd 11100001 pop_iy
736+ local iyh 16
737+ meta high iyh
738+ meta low iy
739+ z80_pop
740+ lsl iyh 8 iyh
741+ or iyh iy iy
742+
743+11101011 ex_de_hl
744+ xchg e l
745+ xchg d h
746+
747+00001000 ex_af_af
748+ xchg a a'
749+ xchg f f'
750+
751+11011001 exx
752+ xchg b b'
753+ xchg c c'
754+ xchg d d'
755+ xchg e e'
756+ xchg h h'
757+ xchg l l'
758+
759+11100011 ex_sp_hl
760+ mov sp scratch1
761+ ocall read_8
762+ xchg l scratch1
763+ cycles 1
764+ mov sp scratch2
765+ ocall write_8
766+ add 1 sp scratch1
767+ ocall read_8
768+ xchg h scratch1
769+ cycles 2
770+ add 1 sp scratch2
771+ ocall write_8
772+ lsl h 8 wz
773+ or l wz wz
774+
775+dd 11100011 ex_sp_ix
776+ mov sp scratch1
777+ ocall read_8
778+ mov scratch1 wz
779+ mov ix scratch1
780+ cycles 1
781+ mov sp scratch2
782+ ocall write_8
783+ add 1 sp scratch1
784+ ocall read_8
785+ lsl scratch1 8 scratch1
786+ or scratch1 wz wz
787+ lsr ix 8 scratch1
788+ cycles 2
789+ add 1 sp scratch2
790+ ocall write_8
791+ mov wz ix
792+
793+fd 11100011 ex_sp_iy
794+ mov sp scratch1
795+ ocall read_8
796+ mov scratch1 wz
797+ mov iy scratch1
798+ cycles 1
799+ mov sp scratch2
800+ ocall write_8
801+ add 1 sp scratch1
802+ ocall read_8
803+ lsl scratch1 8 scratch1
804+ or scratch1 wz wz
805+ lsr iy 8 scratch1
806+ cycles 2
807+ add 1 sp scratch2
808+ ocall write_8
809+ mov wz iy
810+
811+10000RRR add_reg
812+ add a main.R a
813+ update_flags SZYHVXN0C
814+
815+dd 10000100 add_ixh
816+ lsr ix 8 scratch1
817+ add a scratch1 a
818+ update_flags SZYHVXN0C
819+
820+dd 10000101 add_ixl
821+ and ix 0xFF scratch1
822+ add a scratch1 a
823+ update_flags SZYHVXN0C
824+
825+fd 10000100 add_iyh
826+ lsr iy 8 scratch1
827+ add a scratch1 a
828+ update_flags SZYHVXN0C
829+
830+fd 10000101 add_iyl
831+ and iy 0xFF scratch1
832+ add a scratch1 a
833+ update_flags SZYHVXN0C
834+
835+10000110 add_hl
836+ z80_fetch_hl
837+ add a scratch1 a
838+ update_flags SZYHVXN0C
839+
840+dd 10000110 add_ixd
841+ z80_fetch_index ix
842+ add a scratch1 a
843+ update_flags SZYHVXN0C
844+
845+fd 10000110 add_iyd
846+ z80_fetch_index iy
847+ add a scratch1 a
848+ update_flags SZYHVXN0C
849+
850+11000110 add_immed
851+ z80_fetch_immed
852+ add a scratch1 a
853+ update_flags SZYHVXN0C
854+
855+z80_add16_hl
856+ arg src 16
857+ lsl h 8 hlt
858+ or l hlt hlt
859+ add 1 hlt wz
860+ add src hlt hlt
861+ update_flags YHXN0C
862+ mov hlt l
863+ lsr hlt 8 h
864+ cycles 7
865+
866+00001001 add_hl_bc
867+ local hlw 16
868+ local bcw 16
869+ meta hlt hlw
870+ lsl b 8 bcw
871+ or c bcw bcw
872+ z80_add16_hl bcw
873+
874+00011001 add_hl_de
875+ local hlw 16
876+ local dew 16
877+ meta hlt hlw
878+ lsl d 8 dew
879+ or e dew dew
880+ z80_add16_hl dew
881+
882+00101001 add_hl_hl
883+ local hlw 16
884+ meta hlt hlw
885+ z80_add16_hl hlw
886+
887+00111001 add_hl_sp
888+ local hlw 16
889+ meta hlt hlw
890+ z80_add16_hl sp
891+
892+dd 00001001 add_ix_bc
893+ lsl b 8 scratch1
894+ or c scratch1 scratch1
895+ add scratch1 ix ix
896+ update_flags YHXN0C
897+ cycles 7
898+
899+dd 00011001 add_ix_de
900+ lsl d 8 scratch1
901+ or e scratch1 scratch1
902+ add scratch1 ix ix
903+ update_flags YHXN0C
904+ cycles 7
905+
906+dd 00101001 add_ix_ix
907+ add ix ix ix
908+ update_flags YHXN0C
909+ cycles 7
910+
911+dd 00111001 add_ix_sp
912+ add sp ix ix
913+ update_flags YHXN0C
914+ cycles 7
915+
916+fd 00001001 add_iy_bc
917+ lsl b 8 scratch1
918+ or c scratch1 scratch1
919+ add scratch1 iy iy
920+ update_flags YHXN0C
921+ cycles 7
922+
923+fd 00011001 add_iy_de
924+ lsl d 8 scratch1
925+ or e scratch1 scratch1
926+ add scratch1 iy iy
927+ update_flags YHXN0C
928+ cycles 7
929+
930+fd 00101001 add_iy_iy
931+ add iy iy iy
932+ update_flags YHXN0C
933+ cycles 7
934+
935+fd 00111001 add_iy_sp
936+ add sp iy iy
937+ update_flags YHXN0C
938+ cycles 7
939+
940+10001RRR adc_reg
941+ adc a main.R a
942+ update_flags SZYHVXN0C
943+
944+dd 10001100 adc_ixh
945+ lsr ix 8 scratch1
946+ adc a scratch1 a
947+ update_flags SZYHVXN0C
948+
949+dd 10001101 adc_ixl
950+ and ix 0xFF scratch1
951+ adc a scratch1 a
952+ update_flags SZYHVXN0C
953+
954+fd 10001100 adc_iyh
955+ lsr iy 8 scratch1
956+ adc a scratch1 a
957+ update_flags SZYHVXN0C
958+
959+fd 10001101 adc_iyl
960+ and iy 0xFF scratch1
961+ adc a scratch1 a
962+ update_flags SZYHVXN0C
963+
964+10001110 adc_hl
965+ z80_fetch_hl
966+ adc a scratch1 a
967+ update_flags SZYHVXN0C
968+
969+dd 10001110 adc_ixd
970+ z80_fetch_index ix
971+ adc a scratch1 a
972+ update_flags SZYHVXN0C
973+
974+fd 10001110 adc_iyd
975+ z80_fetch_index iy
976+ adc a scratch1 a
977+ update_flags SZYHVXN0C
978+
979+11001110 adc_immed
980+ z80_fetch_immed
981+ adc a scratch1 a
982+ update_flags SZYHVXN0C
983+
984+z80_adc16_hl
985+ arg src 16
986+ lsl h 8 hlt
987+ or l hlt hlt
988+ add 1 hlt wz
989+ adc src hlt hlt
990+ update_flags SZYHVXN0C
991+ mov hlt l
992+ lsr hlt 8 h
993+ cycles 7
994+
995+ed 01001010 adc_hl_bc
996+ local hlw 16
997+ local bcw 16
998+ meta hlt hlw
999+ lsl b 8 bcw
1000+ or c bcw bcw
1001+ z80_adc16_hl bcw
1002+
1003+ed 01011010 adc_hl_de
1004+ local hlw 16
1005+ local dew 16
1006+ meta hlt hlw
1007+ lsl d 8 dew
1008+ or e dew dew
1009+ z80_adc16_hl dew
1010+
1011+ed 01101010 adc_hl_hl
1012+ local hlw 16
1013+ meta hlt hlw
1014+ z80_adc16_hl hlw
1015+
1016+
1017+ed 01111010 adc_hl_sp
1018+ local hlw 16
1019+ meta hlt hlw
1020+ z80_adc16_hl sp
1021+
1022+10010RRR sub_reg
1023+ sub main.R a a
1024+ update_flags SZYHVXN1C
1025+
1026+dd 10010100 sub_ixh
1027+ lsr ix 8 scratch1
1028+ sub scratch1 a a
1029+ update_flags SZYHVXN1C
1030+
1031+dd 10010101 sub_ixl
1032+ and ix 0xFF scratch1
1033+ sub scratch1 a a
1034+ update_flags SZYHVXN1C
1035+
1036+fd 10010100 sub_iyh
1037+ lsr iy 8 scratch1
1038+ sub scratch1 a a
1039+ update_flags SZYHVXN1C
1040+
1041+fd 10010101 sub_iyl
1042+ and iy 0xFF scratch1
1043+ sub scratch1 a a
1044+ update_flags SZYHVXN1C
1045+
1046+10010110 sub_hl
1047+ z80_fetch_hl
1048+ sub scratch1 a a
1049+ update_flags SZYHVXN1C
1050+
1051+dd 10010110 sub_ixd
1052+ z80_fetch_index ix
1053+ sub scratch1 a a
1054+ update_flags SZYHVXN1C
1055+
1056+fd 10010110 sub_iyd
1057+ z80_fetch_index iy
1058+ sub scratch1 a a
1059+ update_flags SZYHVXN1C
1060+
1061+11010110 sub_immed
1062+ z80_fetch_immed
1063+ sub scratch1 a a
1064+ update_flags SZYHVXN1C
1065+
1066+10011RRR sbc_reg
1067+ sbc main.R a a
1068+ update_flags SZYHVXN1C
1069+
1070+dd 10011100 sbc_ixh
1071+ lsr ix 8 scratch1
1072+ sbc scratch1 a a
1073+ update_flags SZYHVXN1C
1074+
1075+dd 10011101 sbc_ixl
1076+ and ix 0xFF scratch1
1077+ sbc scratch1 a a
1078+ update_flags SZYHVXN1C
1079+
1080+fd 10011100 sbc_iyh
1081+ lsr iy 8 scratch1
1082+ sbc scratch1 a a
1083+ update_flags SZYHVXN1C
1084+
1085+fd 10011101 sbc_iyl
1086+ and iy 0xFF scratch1
1087+ sbc scratch1 a a
1088+ update_flags SZYHVXN1C
1089+
1090+
1091+10011110 sbc_hl
1092+ z80_fetch_hl
1093+ sbc scratch1 a a
1094+ update_flags SZYHVXN1C
1095+
1096+dd 10011110 sbc_ixd
1097+ z80_fetch_index ix
1098+ sbc scratch1 a a
1099+ update_flags SZYHVXN1C
1100+
1101+fd 10011110 sbc_iyd
1102+ z80_fetch_index iy
1103+ sbc scratch1 a a
1104+ update_flags SZYHVXN1C
1105+
1106+11011110 sbc_immed
1107+ z80_fetch_immed
1108+ sbc scratch1 a a
1109+ update_flags SZYHVXN1C
1110+
1111+z80_sbc16_hl
1112+ arg src 16
1113+ lsl h 8 hlt
1114+ or l hlt hlt
1115+ add 1 hlt wz
1116+ sbc src hlt hlt
1117+ update_flags SZYHVXN1C
1118+ mov hlt l
1119+ lsr hlt 8 h
1120+ cycles 7
1121+
1122+ed 01000010 sbc_hl_bc
1123+ local hlw 16
1124+ local bcw 16
1125+ meta hlt hlw
1126+ lsl b 8 bcw
1127+ or c bcw bcw
1128+ z80_sbc16_hl bcw
1129+
1130+ed 01010010 sbc_hl_de
1131+ local hlw 16
1132+ local dew 16
1133+ meta hlt hlw
1134+ lsl d 8 dew
1135+ or e dew dew
1136+ z80_sbc16_hl dew
1137+
1138+ed 01100010 sbc_hl_hl
1139+ local hlw 16
1140+ meta hlt hlw
1141+ z80_sbc16_hl hlw
1142+
1143+
1144+ed 01110010 sbc_hl_sp
1145+ local hlw 16
1146+ meta hlt hlw
1147+ z80_sbc16_hl sp
1148+
1149+10100RRR and_reg
1150+ and a main.R a
1151+ update_flags SZYH1PXN0C0
1152+
1153+dd 10100100 and_ixh
1154+ lsr ix 8 scratch1
1155+ and scratch1 a a
1156+ update_flags SZYH1PXN0C0
1157+
1158+dd 10100101 and_ixl
1159+ and ix a a
1160+ update_flags SZYH1PXN0C0
1161+
1162+fd 10100100 and_iyh
1163+ lsr iy 8 scratch1
1164+ and scratch1 a a
1165+ update_flags SZYH1PXN0C0
1166+
1167+fd 10100101 and_iyl
1168+ and iy a a
1169+ update_flags SZYH1PXN0C0
1170+
1171+10100110 and_hl
1172+ z80_fetch_hl
1173+ and a scratch1 a
1174+ update_flags SZYH1PXN0C0
1175+
1176+dd 10100110 and_ixd
1177+ z80_fetch_index ix
1178+ and a scratch1 a
1179+ update_flags SZYH1PXN0C0
1180+
1181+fd 10100110 and_iyd
1182+ z80_fetch_index iy
1183+ and a scratch1 a
1184+ update_flags SZYH1PXN0C0
1185+
1186+11100110 and_immed
1187+ z80_fetch_immed
1188+ and a scratch1 a
1189+ update_flags SZYH1PXN0C0
1190+
1191+10110RRR or_reg
1192+ or a main.R a
1193+ update_flags SZYH0PXN0C0
1194+
1195+dd 10110100 or_ixh
1196+ lsr ix 8 scratch1
1197+ or scratch1 a a
1198+ update_flags SZYH0PXN0C0
1199+
1200+dd 10110101 or_ixl
1201+ or ix a a
1202+ update_flags SZYH0PXN0C0
1203+
1204+fd 10110100 or_iyh
1205+ lsr iy 8 scratch1
1206+ or scratch1 a a
1207+ update_flags SZYH0PXN0C0
1208+
1209+fd 10110101 or_iyl
1210+ or iy a a
1211+ update_flags SZYH0PXN0C0
1212+
1213+10110110 or_hl
1214+ z80_fetch_hl
1215+ or a scratch1 a
1216+ update_flags SZYH0PXN0C0
1217+
1218+dd 10110110 or_ixd
1219+ z80_fetch_index ix
1220+ or a scratch1 a
1221+ update_flags SZYH0PXN0C0
1222+
1223+fd 10110110 or_iyd
1224+ z80_fetch_index iy
1225+ or a scratch1 a
1226+ update_flags SZYH0PXN0C0
1227+
1228+11110110 or_immed
1229+ z80_fetch_immed
1230+ or a scratch1 a
1231+ update_flags SZYH0PXN0C0
1232+
1233+10101RRR xor_reg
1234+ xor a main.R a
1235+ update_flags SZYH0PXN0C0
1236+
1237+dd 10101100 xor_ixh
1238+ lsr ix 8 scratch1
1239+ xor scratch1 a a
1240+ update_flags SZYH0PXN0C0
1241+
1242+dd 10101101 xor_ixl
1243+ xor ix a a
1244+ update_flags SZYH0PXN0C0
1245+
1246+fd 10101100 xor_iyh
1247+ lsr iy 8 scratch1
1248+ xor scratch1 a a
1249+ update_flags SZYH0PXN0C0
1250+
1251+fd 10101101 xor_iyl
1252+ xor iy a a
1253+ update_flags SZYH0PXN0C0
1254+
1255+10101110 xor_hl
1256+ z80_fetch_hl
1257+ xor a scratch1 a
1258+ update_flags SZYH0PXN0C0
1259+
1260+dd 10101110 xor_ixd
1261+ z80_fetch_index ix
1262+ xor a scratch1 a
1263+ update_flags SZYH0PXN0C0
1264+
1265+fd 10101110 xor_iyd
1266+ z80_fetch_index iy
1267+ xor a scratch1 a
1268+ update_flags SZYH0PXN0C0
1269+
1270+11101110 xor_immed
1271+ z80_fetch_immed
1272+ xor a scratch1 a
1273+ update_flags SZYH0PXN0C0
1274+
1275+10111RRR cp_reg
1276+ mov main.R last_flag_result
1277+ cmp main.R a
1278+ update_flags SZHVN1C
1279+
1280+dd 10111100 cp_ixh
1281+ local tmp 8
1282+ lsr ix 8 tmp
1283+ mov tmp last_flag_result
1284+ cmp tmp a
1285+ update_flags SZHVN1C
1286+
1287+dd 10111101 cp_ixl
1288+ local tmp 8
1289+ mov ix tmp
1290+ mov ix last_flag_result
1291+ cmp tmp a
1292+ update_flags SZHVN1C
1293+
1294+fd 10111100 cp_iyh
1295+ local tmp 8
1296+ lsr iy 8 tmp
1297+ mov tmp last_flag_result
1298+ cmp tmp a
1299+ update_flags SZHVN1C
1300+
1301+fd 10111101 cp_iyl
1302+ local tmp 8
1303+ mov iy tmp
1304+ mov iy last_flag_result
1305+ cmp tmp a
1306+ update_flags SZHVN1C
1307+
1308+10111110 cp_hl
1309+ local tmp 8
1310+ z80_fetch_hl
1311+ mov scratch1 tmp
1312+ mov scratch1 last_flag_result
1313+ cmp tmp a
1314+ update_flags SZHVN1C
1315+
1316+dd 10111110 cp_ixd
1317+ local tmp 8
1318+ z80_fetch_index ix
1319+ mov scratch1 tmp
1320+ mov scratch1 last_flag_result
1321+ cmp tmp a
1322+ update_flags SZHVN1C
1323+
1324+fd 10111110 cp_iyd
1325+ local tmp 8
1326+ z80_fetch_index iy
1327+ mov scratch1 tmp
1328+ mov scratch1 last_flag_result
1329+ cmp tmp a
1330+ update_flags SZHVN1C
1331+
1332+11111110 cp_immed
1333+ local tmp 8
1334+ z80_fetch_immed
1335+ mov scratch1 tmp
1336+ mov scratch1 last_flag_result
1337+ cmp tmp a
1338+ update_flags SZHVN1C
1339+
1340+00RRR100 inc_reg
1341+ add 1 main.R main.R
1342+ update_flags SZYHVXN0
1343+
1344+dd 00100100 inc_ixh
1345+ add 0x100 ix ix
1346+ update_flags SZYHVXN0
1347+
1348+dd 00101100 inc_ixl
1349+ local tmp 8
1350+ mov ix tmp
1351+ add 1 tmp tmp
1352+ update_flags SZYHVXN0
1353+ and 0xFF00 ix ix
1354+ or tmp ix ix
1355+
1356+fd 00100100 inc_iyh
1357+ add 0x100 iy iy
1358+ update_flags SZYHVXN0
1359+
1360+fd 00101100 inc_iyl
1361+ local tmp 8
1362+ mov iy tmp
1363+ add 1 tmp tmp
1364+ update_flags SZYHVXN0
1365+ and 0xFF00 iy iy
1366+ or tmp iy iy
1367+
1368+00110100 inc_hl
1369+ local tmp 8
1370+ z80_fetch_hl
1371+ #TODO: Either make DSL compiler smart enough to optimize these unnecessary moves out
1372+ #or add some syntax to force a certain size on an operation so they are unnecessary
1373+ mov scratch1 tmp
1374+ add 1 tmp tmp
1375+ update_flags SZYHVXN0
1376+ mov tmp scratch1
1377+ cycles 1
1378+ z80_store_hl
1379+
1380+dd 00110100 inc_ixd
1381+ local tmp 8
1382+ z80_fetch_index ix
1383+ #TODO: Either make DSL compiler smart enough to optimize these unnecessary moves out
1384+ #or add some syntax to force a certain size on an operation so they are unnecessary
1385+ mov scratch1 tmp
1386+ add 1 tmp tmp
1387+ update_flags SZYHVXN0
1388+ mov tmp scratch1
1389+ cycles 1
1390+ z80_store_index
1391+
1392+fd 00110100 inc_iyd
1393+ local tmp 8
1394+ z80_fetch_index iy
1395+ #TODO: Either make DSL compiler smart enough to optimize these unnecessary moves out
1396+ #or add some syntax to force a certain size on an operation so they are unnecessary
1397+ mov scratch1 tmp
1398+ add 1 tmp tmp
1399+ update_flags SZYHVXN0
1400+ mov tmp scratch1
1401+ cycles 1
1402+ z80_store_index
1403+
1404+z80_inc_pair
1405+ arg high 8
1406+ arg low 8
1407+ cycles 2
1408+ local word 16
1409+ lsl high 8 word
1410+ or low word word
1411+ add 1 word word
1412+ mov word low
1413+ lsr word 8 high
1414+
1415+00000011 inc_bc
1416+ z80_inc_pair b c
1417+
1418+00010011 inc_de
1419+ z80_inc_pair d e
1420+
1421+00100011 inc16_hl
1422+ z80_inc_pair h l
1423+
1424+00110011 inc_sp
1425+ add 1 sp sp
1426+
1427+dd 00100011 inc_ix
1428+ add 1 ix ix
1429+
1430+fd 00100011 inc_iy
1431+ add 1 iy iy
1432+
1433+00RRR101 dec_reg
1434+ sub 1 main.R main.R
1435+ update_flags SZYHVXN1
1436+
1437+dd 00100101 dec_ixh
1438+ sub 0x100 ix ix
1439+ update_flags SZYHVXN1
1440+
1441+dd 00101101 dec_ixl
1442+ local tmp 8
1443+ mov ix tmp
1444+ sub 1 tmp tmp
1445+ update_flags SZYHVXN1
1446+ and 0xFF00 ix ix
1447+ or tmp ix ix
1448+
1449+fd 00100101 dec_iyh
1450+ sub 0x100 iy iy
1451+ update_flags SZYHVXN1
1452+
1453+fd 00101101 dec_iyl
1454+ local tmp 8
1455+ mov iy tmp
1456+ sub 1 tmp tmp
1457+ update_flags SZYHVXN1
1458+ and 0xFF00 iy iy
1459+ or tmp iy iy
1460+
1461+00110101 dec_hl
1462+ local tmp 8
1463+ z80_fetch_hl
1464+ #TODO: Either make DSL compiler smart enough to optimize these unnecessary moves out
1465+ #or add some syntax to force a certain size on an operation so they are unnecessary
1466+ mov scratch1 tmp
1467+ sub 1 tmp tmp
1468+ update_flags SZYHVXN1
1469+ mov tmp scratch1
1470+ cycles 1
1471+ z80_store_hl
1472+
1473+dd 00110101 dec_ixd
1474+ local tmp 8
1475+ z80_fetch_index ix
1476+ #TODO: Either make DSL compiler smart enough to optimize these unnecessary moves out
1477+ #or add some syntax to force a certain size on an operation so they are unnecessary
1478+ mov scratch1 tmp
1479+ sub 1 tmp tmp
1480+ update_flags SZYHVXN1
1481+ mov tmp scratch1
1482+ cycles 1
1483+ z80_store_index
1484+
1485+fd 00110101 dec_iyd
1486+ local tmp 8
1487+ z80_fetch_index iy
1488+ #TODO: Either make DSL compiler smart enough to optimize these unnecessary moves out
1489+ #or add some syntax to force a certain size on an operation so they are unnecessary
1490+ mov scratch1 tmp
1491+ sub 1 tmp tmp
1492+ update_flags SZYHVXN1
1493+ mov tmp scratch1
1494+ cycles 1
1495+ z80_store_index
1496+
1497+z80_dec_pair
1498+ arg high 8
1499+ arg low 8
1500+ local word 16
1501+ lsl high 8 word
1502+ or low word word
1503+ sub 1 word word
1504+ mov word low
1505+ lsr word 8 high
1506+ cycles 2
1507+
1508+00001011 dec_bc
1509+ z80_dec_pair b c
1510+
1511+00011011 dec_de
1512+ z80_dec_pair d e
1513+
1514+00101011 dec16_hl
1515+ z80_dec_pair h l
1516+
1517+00111011 dec_sp
1518+ sub 1 sp sp
1519+
1520+dd 00101011 dec_ix
1521+ sub 1 ix ix
1522+
1523+fd 00101011 dec_iy
1524+ sub 1 iy iy
1525+
1526+00101111 cpl
1527+ not a a
1528+ update_flags YH1XN1
1529+
1530+ed 01DDD100 neg
1531+ neg a a
1532+ update_flags SZYHVXN1C
1533+
1534+00111111 ccf
1535+ local tmp 8
1536+ and 0x80 last_flag_result last_flag_result
1537+ and 0x7F a tmp
1538+ or tmp last_flag_result last_flag_result
1539+ and 0x80 chflags chflags
1540+ lsr chflags 4 tmp
1541+ or tmp chflags chflags
1542+ xor 0x80 chflags chflags
1543+ update_flags N0
1544+
1545+00110111 scf
1546+ local tmp 8
1547+ and 0x80 last_flag_result last_flag_result
1548+ and 0x7F a tmp
1549+ or tmp last_flag_result last_flag_result
1550+ update_flags H0N0C1
1551+
1552+00000000 nop
1553+
1554+01110110 halt
1555+ cmp nmi_cycle cycles
1556+ if >=U
1557+
1558+ else
1559+ cmp int_cycle cycles
1560+ if >=U
1561+
1562+ if iff1
1563+ else
1564+ sub 1 pc pc
1565+ end
1566+
1567+ else
1568+ sub 1 pc pc
1569+ end
1570+ end
1571+
1572+11110011 di
1573+ mov 0 iff1
1574+ mov 0 iff2
1575+ update_sync
1576+
1577+11111011 ei
1578+ mov 1 iff1
1579+ mov 1 iff2
1580+ update_sync
1581+ cmp int_cycle cycles
1582+ if >=U
1583+
1584+ add 1 cycles int_cycle
1585+
1586+ end
1587+
1588+ed 01D00110 im0
1589+ mov 0 imode
1590+
1591+ed 01D10110 im1
1592+ mov 1 imode
1593+
1594+ed 01D11110 im2
1595+ mov 2 imode
1596+
1597+ed 01D01110 im3
1598+ #some sources call this mode 0/1, but unclear
1599+ #if the behavior is really different from im 0
1600+ mov 0 imode
1601+
1602+11000011 jp
1603+ z80_fetch_immed16
1604+ mov wz pc
1605+
1606+11101001 jp_hl
1607+ lsl h 8 pc
1608+ or l pc pc
1609+
1610+dd 11101001 jp_ix
1611+ mov ix pc
1612+
1613+fd 11101001 jp_iy
1614+ mov iy pc
1615+
1616+11CCC010 jp_cc
1617+ z80_check_cond C
1618+ z80_fetch_immed16
1619+ if istrue
1620+
1621+ mov wz pc
1622+
1623+ end
1624+
1625+00011000 jr
1626+ z80_fetch_immed
1627+ #TODO: determine if this updates wz
1628+ sext 16 scratch1 scratch1
1629+ add scratch1 pc pc
1630+ cycles 5
1631+
1632+001CC000 jr_cc
1633+ z80_check_cond C
1634+ z80_fetch_immed
1635+
1636+ if istrue
1637+
1638+ sext 16 scratch1 scratch1
1639+ add scratch1 pc pc
1640+ cycles 5
1641+
1642+ end
1643+
1644+00010000 djnz
1645+ cycles 1
1646+ z80_fetch_immed
1647+ sub 1 b b
1648+
1649+ if b
1650+
1651+ sext 16 scratch1 scratch1
1652+ add scratch1 pc pc
1653+ cycles 5
1654+
1655+ end
1656+
1657+
1658+11001101 call_uncond
1659+ z80_fetch_immed16
1660+ local pch 8
1661+ lsr pc 8 pch
1662+ meta high pch
1663+ meta low pc
1664+ z80_push
1665+ mov wz pc
1666+
1667+11CCC100 call_cond
1668+ local pch 8
1669+ z80_fetch_immed16
1670+ z80_check_cond C
1671+
1672+ if istrue
1673+
1674+ lsr pc 8 pch
1675+ meta high pch
1676+ meta low pc
1677+ z80_push
1678+ mov wz pc
1679+
1680+ end
1681+
1682+11TTT111 rst
1683+ local pch 8
1684+ lsr pc 8 pch
1685+ meta high pch
1686+ meta low pc
1687+ z80_push
1688+ lsl T 3 scratch1
1689+ mov scratch1 pc
1690+
1691+11001001 ret
1692+ local pch 16
1693+ meta high pch
1694+ meta low pc
1695+ z80_pop
1696+ lsl pch 8 pch
1697+ or pch pc pc
1698+
1699+ed 01001101 reti
1700+ local pch 16
1701+ cycles 1
1702+ meta high pch
1703+ meta low pc
1704+ z80_pop
1705+ lsl pch 8 pch
1706+ or pch pc pc
1707+
1708+ed 01NN1101 retn
1709+ mov iff2 iff1
1710+ local pch 16
1711+ cycles 1
1712+ meta high pch
1713+ meta low pc
1714+ z80_pop
1715+ lsl pch 8 pch
1716+ or pch pc pc
1717+
1718+11CCC000 ret_cond
1719+ local pch 16
1720+ cycles 1
1721+ z80_check_cond C
1722+ if istrue
1723+
1724+ meta high pch
1725+ meta low pc
1726+ z80_pop
1727+ lsl pch 8 pch
1728+ or pch pc pc
1729+
1730+ end
1731+
1732+11011011 in_abs
1733+ z80_fetch_immed
1734+ ocall io_read8
1735+ mov scratch1 a
1736+
1737+ed 01RRR000 in_bc
1738+ lsl b 8 scratch1
1739+ or c scratch1 scratch1
1740+ ocall io_read8
1741+ mov scratch1 main.R
1742+
1743+z80_ini_ind
1744+ arg change 16
1745+ local tmp 8
1746+ cycles 1
1747+
1748+ lsl 8 b wz
1749+ or c wz wz
1750+ add change wz wz
1751+
1752+ sub 1 b b
1753+ update_flags SZYX
1754+
1755+ lsl b 8 scratch1
1756+ or c scratch1 scratch1
1757+ ocall io_read8
1758+
1759+ and 0x80 scratch1 nflag
1760+
1761+ mov wz tmp
1762+ add tmp scratch1 tmp
1763+ update_flags C
1764+
1765+ z80_store_hl
1766+
1767+ lsl h 8 scratch2
1768+ or l scratch2 scratch2
1769+ add change scratch2 scratch2
1770+ mov scratch2 l
1771+ lsr scratch2 8 h
1772+
1773+ and 7 tmp tmp
1774+ xor b tmp tmp
1775+ update_flags P
1776+ lsr chflags 4 tmp
1777+ or tmp chflags chflags
1778+
1779+ed 10100010 ini
1780+ z80_ini_ind 1
1781+
1782+ed 10110010 inir
1783+ z80_ini_ind 1
1784+ if zflag
1785+ else
1786+ sub 2 pc pc
1787+ cycles 5
1788+ end
1789+
1790+ed 10101010 ind
1791+ z80_ini_ind -1
1792+
1793+ed 10111010 indr
1794+ z80_ini_ind -1
1795+ if zflag
1796+ else
1797+ sub 2 pc pc
1798+ cycles 5
1799+ end
1800+
1801+11010011 out_abs
1802+ z80_fetch_immed
1803+ mov scratch1 scratch2
1804+ mov a scratch1
1805+ ocall io_write8
1806+
1807+ed 01RRR001 out_bc
1808+ lsl b 8 scratch2
1809+ or c scratch2 scratch2
1810+ mov main.R scratch1
1811+ ocall io_write8
1812+
1813+z80_outi_outd
1814+ arg change 16
1815+ local tmp 8
1816+ cycles 1
1817+ z80_fetch_hl
1818+
1819+ and 0x80 scratch1 nflag
1820+
1821+ lsl h 8 scratch2
1822+ or l scratch2 scratch2
1823+ add change scratch2 scratch2
1824+ mov scratch2 l
1825+ lsr scratch2 8 h
1826+
1827+ add l scratch1 tmp
1828+ update_flags C
1829+ and 7 tmp tmp
1830+
1831+ lsl b 8 scratch2
1832+ or c scratch2 scratch2
1833+ ocall io_write8
1834+
1835+ sub 1 b b
1836+ update_flags SZYX
1837+
1838+ lsl 8 b wz
1839+ or c wz wz
1840+ add change wz wz
1841+
1842+ xor b tmp tmp
1843+ update_flags P
1844+ lsr chflags 4 tmp
1845+ or tmp chflags chflags
1846+
1847+ed 10100011 outi
1848+ z80_outi_outd 1
1849+
1850+ed 10110011 otir
1851+ z80_outi_outd 1
1852+ if zflag
1853+ else
1854+ sub 2 pc pc
1855+ cycles 5
1856+ end
1857+
1858+ed 10101011 outd
1859+ z80_outi_outd -1
1860+
1861+ed 10111011 otdr
1862+ z80_outi_outd -1
1863+ if zflag
1864+ else
1865+ sub 2 pc pc
1866+ cycles 5
1867+ end
1868+
1869+00000111 rlca
1870+ rol a 1 a
1871+ update_flags YH0XN0C
1872+
1873+00010111 rla
1874+ rlc a 1 a
1875+ update_flags YH0XN0C
1876+
1877+00001111 rrca
1878+ ror a 1 a
1879+ update_flags YH0XN0C
1880+
1881+00011111 rra
1882+ rrc a 1 a
1883+ update_flags YH0XN0C
1884+
1885+cb 00000RRR rlc
1886+ rol main.R 1 main.R
1887+ update_flags SZYH0PXN0C
1888+
1889+cb 00000110 rlc_hl
1890+ local tmp 8
1891+ z80_fetch_hl
1892+ mov scratch1 tmp
1893+ rol tmp 1 tmp
1894+ update_flags SZYH0PXN0C
1895+ mov tmp scratch1
1896+ z80_store_hl
1897+
1898+z80_rlc_index
1899+ arg tmp 8
1900+ mov wz scratch1
1901+ ocall read_8
1902+ cycles 1
1903+ mov scratch1 tmp
1904+ rol tmp 1 tmp
1905+ update_flags SZYH0PXN0C
1906+ mov tmp scratch1
1907+ z80_store_index
1908+
1909+ddcb 00000110 rlc_ixd
1910+ local tmp 8
1911+ z80_rlc_index tmp
1912+
1913+ddcb 00000RRR rlc_ixd_reg
1914+ z80_rlc_index main.R
1915+
1916+fdcb 00000110 rlc_iyd
1917+ local tmp 8
1918+ z80_rlc_index tmp
1919+
1920+fdcb 00000RRR rlc_iyd_reg
1921+ z80_rlc_index main.R
1922+
1923+cb 00010RRR rl
1924+ rlc main.R 1 main.R
1925+ update_flags SZYH0PXN0C
1926+
1927+cb 00010110 rl_hl
1928+ local tmp 8
1929+ z80_fetch_hl
1930+ mov scratch1 tmp
1931+ rlc tmp 1 tmp
1932+ update_flags SZYH0PXN0C
1933+ mov tmp scratch1
1934+ z80_store_hl
1935+
1936+z80_rl_index
1937+ arg tmp 8
1938+ mov wz scratch1
1939+ ocall read_8
1940+ cycles 1
1941+ mov scratch1 tmp
1942+ rlc tmp 1 tmp
1943+ update_flags SZYH0PXN0C
1944+ mov tmp scratch1
1945+ z80_store_index
1946+
1947+ddcb 00010110 rl_ixd
1948+ local tmp 8
1949+ z80_rl_index tmp
1950+
1951+fdcb 00010110 rl_iyd
1952+ local tmp 8
1953+ z80_rl_index tmp
1954+
1955+
1956+ddcb 00010RRR rl_ixd_reg
1957+ z80_rl_index main.R
1958+
1959+fdcb 00010RRR rl_iyd_reg
1960+ z80_rl_index main.R
1961+
1962+cb 00001RRR rrc
1963+ ror main.R 1 main.R
1964+ update_flags SZYH0PXN0C
1965+
1966+cb 00001110 rrc_hl
1967+ local tmp 8
1968+ z80_fetch_hl
1969+ mov scratch1 tmp
1970+ ror tmp 1 tmp
1971+ update_flags SZYH0PXN0C
1972+ mov tmp scratch1
1973+ z80_store_hl
1974+
1975+z80_rrc_index
1976+ arg tmp 8
1977+ mov wz scratch1
1978+ ocall read_8
1979+ cycles 1
1980+ mov scratch1 tmp
1981+ ror tmp 1 tmp
1982+ update_flags SZYH0PXN0C
1983+ mov tmp scratch1
1984+ z80_store_index
1985+
1986+ddcb 00001110 rrc_ixd
1987+ local tmp 8
1988+ z80_rrc_index tmp
1989+
1990+ddcb 00001RRR rrc_ixd_reg
1991+ z80_rrc_index main.R
1992+
1993+fdcb 00001110 rrc_iyd
1994+ local tmp 8
1995+ z80_rrc_index tmp
1996+
1997+fdcb 00001RRR rrc_iyd_reg
1998+ z80_rrc_index main.R
1999+
2000+cb 00011RRR rr
2001+ rrc main.R 1 main.R
2002+ update_flags SZYH0PXN0C
2003+
2004+cb 00011110 rr_hl
2005+ local tmp 8
2006+ z80_fetch_hl
2007+ mov scratch1 tmp
2008+ rrc tmp 1 tmp
2009+ update_flags SZYH0PXN0C
2010+ mov tmp scratch1
2011+ z80_store_hl
2012+
2013+z80_rr_index
2014+ arg tmp 8
2015+ mov wz scratch1
2016+ ocall read_8
2017+ cycles 1
2018+ mov scratch1 tmp
2019+ rrc tmp 1 tmp
2020+ update_flags SZYH0PXN0C
2021+ mov tmp scratch1
2022+ z80_store_index
2023+
2024+ddcb 00011110 rr_ixd
2025+ local tmp 8
2026+ z80_rr_index tmp
2027+
2028+ddcb 00011RRR rr_ixd_reg
2029+ z80_rr_index main.R
2030+
2031+fdcb 00011110 rr_iyd
2032+ local tmp 8
2033+ z80_rr_index tmp
2034+
2035+fdcb 00011RRR rr_iyd_reg
2036+ z80_rr_index main.R
2037+
2038+cb 00100RRR sla
2039+ lsl main.R 1 main.R
2040+ update_flags SZYH0PXN0C
2041+
2042+cb 00100110 sla_hl
2043+ local tmp 8
2044+ z80_fetch_hl
2045+ mov scratch1 tmp
2046+ lsl tmp 1 tmp
2047+ update_flags SZYH0PXN0C
2048+ mov tmp scratch1
2049+ z80_store_hl
2050+
2051+z80_sla_index
2052+ arg tmp 8
2053+ mov wz scratch1
2054+ ocall read_8
2055+ cycles 1
2056+ mov scratch1 tmp
2057+ lsl tmp 1 tmp
2058+ update_flags SZYH0PXN0C
2059+ mov tmp scratch1
2060+ z80_store_index
2061+
2062+ddcb 00100110 sla_ixd
2063+ local tmp 8
2064+ z80_sla_index tmp
2065+
2066+ddcb 00100RRR sla_ixd_reg
2067+ z80_sla_index main.R
2068+
2069+fdcb 00100110 sla_iyd
2070+ local tmp 8
2071+ z80_sla_index tmp
2072+
2073+fdcb 00100RRR sla_iyd_reg
2074+ z80_sla_index main.R
2075+
2076+cb 00101RRR sra
2077+ asr main.R 1 main.R
2078+ update_flags SZYH0PXN0C
2079+
2080+cb 00101110 sra_hl
2081+ local tmp 8
2082+ z80_fetch_hl
2083+ mov scratch1 tmp
2084+ asr tmp 1 tmp
2085+ update_flags SZYH0PXN0C
2086+ mov tmp scratch1
2087+ z80_store_hl
2088+
2089+z80_sra_index
2090+ arg tmp 8
2091+ mov wz scratch1
2092+ ocall read_8
2093+ cycles 1
2094+ mov scratch1 tmp
2095+ asr tmp 1 tmp
2096+ update_flags SZYH0PXN0C
2097+ mov tmp scratch1
2098+ z80_store_index
2099+
2100+ddcb 00101110 sra_ixd
2101+ local tmp 8
2102+ z80_sra_index tmp
2103+
2104+ddcb 00101RRR sra_ixd_reg
2105+ z80_sra_index main.R
2106+
2107+fdcb 00101110 sra_iyd
2108+ local tmp 8
2109+ z80_sra_index tmp
2110+
2111+fdcb 00101RRR sra_iyd_reg
2112+ z80_sra_index main.R
2113+
2114+cb 00110RRR sll
2115+ lsl main.R 1 main.R
2116+ update_flags SZ0YH0XN0C
2117+ or 1 main.R main.R
2118+ update_flags P
2119+
2120+cb 00110110 sll_hl
2121+ local tmp 8
2122+ z80_fetch_hl
2123+ mov scratch1 tmp
2124+ lsl tmp 1 tmp
2125+ update_flags SZ0YH0XN0C
2126+ or 1 tmp tmp
2127+ update_flags P
2128+ mov tmp scratch1
2129+ z80_store_hl
2130+
2131+z80_sll_index
2132+ arg tmp 8
2133+ mov wz scratch1
2134+ ocall read_8
2135+ cycles 1
2136+ mov scratch1 tmp
2137+ lsl tmp 1 tmp
2138+ update_flags SZ0YH0XN0C
2139+ or 1 tmp tmp
2140+ update_flags P
2141+ mov tmp scratch1
2142+ z80_store_index
2143+
2144+ddcb 00110110 sll_ixd
2145+ local tmp 8
2146+ z80_sll_index tmp
2147+
2148+ddcb 00110RRR sll_ixd_reg
2149+ z80_sll_index main.R
2150+
2151+fdcb 00110110 sll_iyd
2152+ local tmp 8
2153+ z80_sll_index tmp
2154+
2155+fdcb 00110RRR sll_iyd_reg
2156+ z80_sll_index main.R
2157+
2158+cb 00111RRR srl
2159+ lsr main.R 1 main.R
2160+ update_flags SZYH0PXN0C
2161+
2162+cb 00111110 srl_hl
2163+ local tmp 8
2164+ z80_fetch_hl
2165+ mov scratch1 tmp
2166+ lsr tmp 1 tmp
2167+ update_flags SZYH0PXN0C
2168+ mov tmp scratch1
2169+ z80_store_hl
2170+
2171+z80_srl_index
2172+ arg tmp 8
2173+ mov wz scratch1
2174+ ocall read_8
2175+ cycles 1
2176+ mov scratch1 tmp
2177+ lsr tmp 1 tmp
2178+ update_flags SZYH0PXN0C
2179+ mov tmp scratch1
2180+ z80_store_index
2181+
2182+ddcb 00111110 srl_ixd
2183+ local tmp 8
2184+ z80_srl_index tmp
2185+
2186+ddcb 00111RRR srl_ixd_reg
2187+ z80_srl_index main.R
2188+
2189+fdcb 00111110 srl_iyd
2190+ local tmp 8
2191+ z80_srl_index tmp
2192+
2193+fdcb 00111RRR srl_iyd_reg
2194+ z80_srl_index main.R
2195+
2196+cb 01BBBRRR bit_reg
2197+ local tmp 8
2198+ lsl 1 B tmp
2199+ mov main.R last_flag_result
2200+ and main.R tmp tmp
2201+ update_flags SZH1PN0
2202+
2203+cb 01BBB110 bit_hl
2204+ local tmp 8
2205+ z80_fetch_hl
2206+ cycles 1
2207+ lsl 1 B tmp
2208+ lsr wz 8 last_flag_result
2209+ and scratch1 tmp tmp
2210+ update_flags SZH1PN0
2211+
2212+
2213+ddcb 01BBBRRR bit_ixd
2214+ local tmp 8
2215+ mov wz scratch1
2216+ ocall read_8
2217+ cycles 1
2218+ lsl 1 B tmp
2219+ lsr wz 8 last_flag_result
2220+ and scratch1 tmp tmp
2221+ update_flags SZH1PN0
2222+
2223+fdcb 01BBBRRR bit_iyd
2224+ local tmp 8
2225+ mov wz scratch1
2226+ ocall read_8
2227+ cycles 1
2228+ lsl 1 B tmp
2229+ lsr wz 8 last_flag_result
2230+ and scratch1 tmp tmp
2231+ update_flags SZH1PN0
2232+
2233+cb 10BBBRRR res_reg
2234+ local tmp 8
2235+ lsl 1 B tmp
2236+ not tmp tmp
2237+ and main.R tmp main.R
2238+
2239+cb 10BBB110 res_hl
2240+ z80_fetch_hl
2241+ cycles 1
2242+ local tmp 8
2243+ lsl 1 B tmp
2244+ not tmp tmp
2245+ and scratch1 tmp scratch1
2246+ z80_store_hl
2247+
2248+z80_res_index
2249+ arg bit 8
2250+ arg tmp 8
2251+ lsl 1 bit tmp
2252+ not tmp tmp
2253+ mov wz scratch1
2254+ ocall read_8
2255+ cycles 1
2256+ and scratch1 tmp tmp
2257+ mov tmp scratch1
2258+ z80_store_index
2259+
2260+ddcb 10BBB110 res_ixd
2261+ local tmp 8
2262+ z80_res_index B tmp
2263+
2264+ddcb 10BBBRRR res_ixd_reg
2265+ z80_res_index B main.R
2266+
2267+fdcb 10BBB110 res_iyd
2268+ local tmp 8
2269+ z80_res_index B tmp
2270+
2271+fdcb 10BBBRRR res_iyd_reg
2272+ z80_res_index B main.R
2273+
2274+cb 11BBBRRR set_reg
2275+ local tmp 8
2276+ lsl 1 B tmp
2277+ or main.R tmp main.R
2278+
2279+cb 11BBB110 set_hl
2280+ z80_fetch_hl
2281+ cycles 1
2282+ local tmp 8
2283+ lsl 1 B tmp
2284+ or scratch1 tmp scratch1
2285+ z80_store_hl
2286+
2287+z80_set_index
2288+ arg bit 8
2289+ arg tmp 8
2290+ lsl 1 bit tmp
2291+ mov wz scratch1
2292+ ocall read_8
2293+ cycles 1
2294+ or scratch1 tmp tmp
2295+ mov tmp scratch1
2296+ z80_store_index
2297+
2298+ddcb 11BBB110 set_ixd
2299+ local tmp 8
2300+ z80_set_index B tmp
2301+
2302+ddcb 11BBBRRR set_ixd_reg
2303+ z80_set_index B main.R
2304+
2305+fdcb 11BBB110 set_iyd
2306+ local tmp 8
2307+ z80_set_index B tmp
2308+
2309+fdcb 11BBBRRR set_iyd_reg
2310+ z80_set_index B main.R
2311+
2312+z80_fetch_mod_hl
2313+ local tmp 16
2314+ arg change 16
2315+ lsl h 8 tmp
2316+ or l tmp tmp
2317+ mov tmp scratch1
2318+ add change tmp tmp
2319+ mov tmp l
2320+ lsr tmp 8 h
2321+ ocall read_8
2322+ cycles 2
2323+
2324+z80_ldd_ldi
2325+ arg change 16
2326+ local tmp 16
2327+ local tmp8 8
2328+ z80_fetch_mod_hl change
2329+
2330+ add a scratch1 tmp8
2331+ update_flags H0XN0
2332+
2333+ and 0x2 tmp8 tmp8
2334+ lsl tmp8 4 tmp8
2335+ and 0x88 last_flag_result last_flag_result
2336+ or tmp8 last_flag_result last_flag_result
2337+
2338+ lsl d 8 tmp
2339+ or e tmp tmp
2340+ mov tmp scratch2
2341+ add change tmp tmp
2342+ mov tmp e
2343+ lsr tmp 8 d
2344+ ocall write_8
2345+
2346+ lsl b 8 tmp
2347+ or c tmp tmp
2348+ sub 1 tmp tmp
2349+
2350+ mov tmp c
2351+ lsr tmp 8 b
2352+ mov c pvflag
2353+ or b pvflag pvflag
2354+
2355+
2356+ed 10100000 ldi
2357+ z80_ldd_ldi 1
2358+
2359+ed 10101000 ldd
2360+ z80_ldd_ldi -1
2361+
2362+ed 10110000 ldir
2363+ z80_ldd_ldi 1
2364+ if pvflag
2365+
2366+ add 1 pc wz
2367+ sub 2 pc pc
2368+ cycles 5
2369+
2370+ end
2371+
2372+ed 10111000 lddr
2373+ z80_ldd_ldi -1
2374+ if pvflag
2375+
2376+ add 1 pc wz
2377+ sub 2 pc pc
2378+ cycles 5
2379+
2380+ end
2381+
2382+z80_cpd_cpi
2383+ local tmp 16
2384+ local tmp8 8
2385+ local hf 8
2386+ arg change 16
2387+
2388+ z80_fetch_mod_hl change
2389+ sub scratch1 a tmp8
2390+ update_flags SZHN1
2391+
2392+ lsr chflags 3 hf
2393+ and 1 hf hf
2394+
2395+ sub hf tmp8 tmp8
2396+ update_flags X
2397+
2398+ and 0x2 tmp8 tmp8
2399+ lsl tmp8 4 tmp8
2400+ and 0x88 last_flag_result last_flag_result
2401+ or tmp8 last_flag_result last_flag_result
2402+
2403+ lsl b 8 tmp
2404+ or c tmp tmp
2405+ sub 1 tmp tmp
2406+
2407+ mov tmp c
2408+ lsr tmp 8 b
2409+ mov c pvflag
2410+ or b pvflag pvflag
2411+
2412+ cycles 5
2413+
2414+ed 10100001 cpi
2415+ z80_cpd_cpi 1
2416+
2417+ed 10101001 cpd
2418+ z80_cpd_cpi -1
2419+
2420+ed 10110001 cpir
2421+ z80_cpd_cpi 1
2422+ if pvflag
2423+
2424+ if zflag
2425+
2426+ else
2427+
2428+ add 1 pc wz
2429+ sub 2 pc pc
2430+ cycles 5
2431+
2432+ end
2433+ end
2434+
2435+ed 10111001 cpdr
2436+ z80_cpd_cpi -1
2437+ if pvflag
2438+
2439+ if zflag
2440+
2441+ else
2442+
2443+ add 1 pc wz
2444+ sub 2 pc pc
2445+ cycles 5
2446+
2447+ end
2448+ end
2449+
2450+00100111 daa
2451+ local diff 8
2452+ local tmp 8
2453+ local low 8
2454+ and 0xF a low
2455+ and 0x8 chflags tmp
2456+ if tmp
2457+
2458+ mov 6 diff
2459+
2460+ else
2461+
2462+ cmp 0xA low
2463+ if >=U
2464+ mov 6 diff
2465+ else
2466+ mov 0 diff
2467+ end
2468+
2469+ end
2470+
2471+ and 0x80 chflags tmp
2472+ if tmp
2473+
2474+ or 0x60 diff diff
2475+ update_flags C1
2476+
2477+ else
2478+
2479+ cmp 0x9A a
2480+ if >=U
2481+ or 0x60 diff diff
2482+ update_flags C1
2483+ else
2484+ update_flags C0
2485+ end
2486+ end
2487+
2488+ if nflag
2489+
2490+ sub diff a a
2491+ update_flags SZYHPX
2492+
2493+ else
2494+
2495+ add diff a a
2496+ update_flags SZYHPX
2497+
2498+ end
2499+
2500+dd OOOOOOOO dd_normal
2501+ dispatch O
2502+
2503+fd OOOOOOOO fd_normal
2504+ dispatch O
2505+
2506+ed 01101111 rld
2507+ local tmp 8
2508+ local tmp2 8
2509+ z80_fetch_hl
2510+ cycles 4
2511+
2512+ lsr scratch1 4 tmp
2513+
2514+ lsl scratch1 4 scratch1
2515+
2516+ and 0xF a tmp2
2517+ or tmp2 scratch1 scratch1
2518+
2519+ and 0xF0 a a
2520+ or tmp a a
2521+ update_flags SZYH0XPN0
2522+ z80_store_hl
2523+
2524+ed 01100111 rrd
2525+ local tmp 8
2526+ local tmp2 8
2527+ z80_fetch_hl
2528+ cycles 4
2529+
2530+ and 0xF scratch1 tmp
2531+ lsr scratch1 4 scratch1
2532+
2533+ lsl a 4 tmp2
2534+ or tmp2 scratch1 scratch1
2535+
2536+ and 0xF0 a a
2537+ or tmp a a
2538+ update_flags SZYH0XPN0
2539+ z80_store_hl
2540+
+3982,
-0
1@@ -0,0 +1,3982 @@
2+/*
3+ Copyright 2013 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#include "z80inst.h"
8+#include "z80_to_x86.h"
9+#include "gen_x86.h"
10+#include "mem.h"
11+#include "util.h"
12+#include <stdio.h>
13+#include <stdlib.h>
14+#include <stddef.h>
15+#include <string.h>
16+
17+#define MODE_UNUSED (MODE_IMMED-1)
18+#define MAX_MCYCLE_LENGTH 6
19+#define NATIVE_CHUNK_SIZE 1024
20+#define NATIVE_MAP_CHUNKS (0x10000 / NATIVE_CHUNK_SIZE)
21+
22+//#define DO_DEBUG_PRINT
23+
24+#ifdef DO_DEBUG_PRINT
25+#define dprintf printf
26+#else
27+#define dprintf
28+#endif
29+
30+uint32_t zbreakpoint_patch(z80_context * context, uint16_t address, code_ptr dst);
31+void z80_handle_deferred(z80_context * context);
32+
33+uint8_t z80_size(z80inst * inst)
34+{
35+ uint8_t reg = (inst->reg & 0x1F);
36+ if (reg != Z80_UNUSED && reg != Z80_USE_IMMED) {
37+ return reg < Z80_BC ? SZ_B : SZ_W;
38+ }
39+ //TODO: Handle any necessary special cases
40+ return SZ_B;
41+}
42+
43+uint8_t zf_off(uint8_t flag)
44+{
45+ return offsetof(z80_context, flags) + flag;
46+}
47+
48+uint8_t zaf_off(uint8_t flag)
49+{
50+ return offsetof(z80_context, alt_flags) + flag;
51+}
52+
53+uint8_t zr_off(uint8_t reg)
54+{
55+ if (reg > Z80_A) {
56+ reg = z80_low_reg(reg);
57+ }
58+ return offsetof(z80_context, regs) + reg;
59+}
60+
61+uint8_t zar_off(uint8_t reg)
62+{
63+ if (reg > Z80_A) {
64+ reg = z80_low_reg(reg);
65+ }
66+ return offsetof(z80_context, alt_regs) + reg;
67+}
68+
69+void zreg_to_native(z80_options *opts, uint8_t reg, uint8_t native_reg)
70+{
71+ if (opts->regs[reg] >= 0) {
72+ mov_rr(&opts->gen.code, opts->regs[reg], native_reg, reg > Z80_A ? SZ_W : SZ_B);
73+ } else {
74+ mov_rdispr(&opts->gen.code, opts->gen.context_reg, zr_off(reg), native_reg, reg > Z80_A ? SZ_W : SZ_B);
75+ }
76+}
77+
78+void native_to_zreg(z80_options *opts, uint8_t native_reg, uint8_t reg)
79+{
80+ if (opts->regs[reg] >= 0) {
81+ mov_rr(&opts->gen.code, native_reg, opts->regs[reg], reg > Z80_A ? SZ_W : SZ_B);
82+ } else {
83+ mov_rrdisp(&opts->gen.code, native_reg, opts->gen.context_reg, zr_off(reg), reg > Z80_A ? SZ_W : SZ_B);
84+ }
85+}
86+
87+void translate_z80_reg(z80inst * inst, host_ea * ea, z80_options * opts)
88+{
89+ code_info *code = &opts->gen.code;
90+ if (inst->reg == Z80_USE_IMMED) {
91+ ea->mode = MODE_IMMED;
92+ ea->disp = inst->immed;
93+ } else if ((inst->reg & 0x1F) == Z80_UNUSED) {
94+ ea->mode = MODE_UNUSED;
95+ } else {
96+ ea->mode = MODE_REG_DIRECT;
97+ if (inst->reg == Z80_IYH && opts->regs[Z80_IYL] >= 0) {
98+ if ((inst->addr_mode & 0x1F) == Z80_REG && inst->ea_reg == Z80_IYL) {
99+ mov_rr(code, opts->regs[Z80_IY], opts->gen.scratch1, SZ_W);
100+ ror_ir(code, 8, opts->gen.scratch1, SZ_W);
101+ ea->base = opts->gen.scratch1;
102+ } else {
103+ ea->base = opts->regs[Z80_IYL];
104+ ror_ir(code, 8, opts->regs[Z80_IY], SZ_W);
105+ }
106+ } else if(opts->regs[inst->reg] >= 0) {
107+ ea->base = opts->regs[inst->reg];
108+ if (ea->base >= AH && ea->base <= BH) {
109+ if ((inst->addr_mode & 0x1F) == Z80_REG) {
110+ uint8_t other_reg = opts->regs[inst->ea_reg];
111+ if (other_reg >= R8 || (other_reg >= RSP && other_reg <= RDI)) {
112+ //we can't mix an *H reg with a register that requires the REX prefix
113+ ea->base = opts->regs[z80_low_reg(inst->reg)];
114+ ror_ir(code, 8, ea->base, SZ_W);
115+ }
116+ } else if((inst->addr_mode & 0x1F) != Z80_UNUSED && (inst->addr_mode & 0x1F) != Z80_IMMED) {
117+ //temp regs require REX prefix too
118+ ea->base = opts->regs[z80_low_reg(inst->reg)];
119+ ror_ir(code, 8, ea->base, SZ_W);
120+ }
121+ }
122+ } else {
123+ ea->mode = MODE_REG_DISPLACE8;
124+ ea->base = opts->gen.context_reg;
125+ ea->disp = zr_off(inst->reg);
126+ }
127+ }
128+}
129+
130+void z80_save_reg(z80inst * inst, z80_options * opts)
131+{
132+ code_info *code = &opts->gen.code;
133+ if (inst->reg == Z80_USE_IMMED || inst->reg == Z80_UNUSED) {
134+ return;
135+ }
136+ if (inst->reg == Z80_IYH && opts->regs[Z80_IYL] >= 0) {
137+ if ((inst->addr_mode & 0x1F) == Z80_REG && inst->ea_reg == Z80_IYL) {
138+ ror_ir(code, 8, opts->regs[Z80_IY], SZ_W);
139+ mov_rr(code, opts->gen.scratch1, opts->regs[Z80_IYL], SZ_B);
140+ ror_ir(code, 8, opts->regs[Z80_IY], SZ_W);
141+ } else {
142+ ror_ir(code, 8, opts->regs[Z80_IY], SZ_W);
143+ }
144+ } else if (opts->regs[inst->reg] >= AH && opts->regs[inst->reg] <= BH) {
145+ if ((inst->addr_mode & 0x1F) == Z80_REG) {
146+ uint8_t other_reg = opts->regs[inst->ea_reg];
147+ if (other_reg >= R8 || (other_reg >= RSP && other_reg <= RDI)) {
148+ //we can't mix an *H reg with a register that requires the REX prefix
149+ ror_ir(code, 8, opts->regs[z80_low_reg(inst->reg)], SZ_W);
150+ }
151+ } else if((inst->addr_mode & 0x1F) != Z80_UNUSED && (inst->addr_mode & 0x1F) != Z80_IMMED) {
152+ //temp regs require REX prefix too
153+ ror_ir(code, 8, opts->regs[z80_low_reg(inst->reg)], SZ_W);
154+ }
155+ }
156+}
157+
158+void translate_z80_ea(z80inst * inst, host_ea * ea, z80_options * opts, uint8_t read, uint8_t modify)
159+{
160+ code_info *code = &opts->gen.code;
161+ uint8_t size, areg;
162+ int8_t reg;
163+ ea->mode = MODE_REG_DIRECT;
164+ areg = read ? opts->gen.scratch1 : opts->gen.scratch2;
165+ switch(inst->addr_mode & 0x1F)
166+ {
167+ case Z80_REG:
168+ if (inst->ea_reg == Z80_IYH && opts->regs[Z80_IYL] >= 0) {
169+ if (inst->reg == Z80_IYL) {
170+ mov_rr(code, opts->regs[Z80_IY], opts->gen.scratch1, SZ_W);
171+ ror_ir(code, 8, opts->gen.scratch1, SZ_W);
172+ ea->base = opts->gen.scratch1;
173+ } else {
174+ ea->base = opts->regs[Z80_IYL];
175+ ror_ir(code, 8, opts->regs[Z80_IY], SZ_W);
176+ }
177+ } else if(opts->regs[inst->ea_reg] >= 0) {
178+ ea->base = opts->regs[inst->ea_reg];
179+ if (ea->base >= AH && ea->base <= BH && inst->reg != Z80_UNUSED && inst->reg != Z80_USE_IMMED) {
180+ uint8_t other_reg = opts->regs[inst->reg];
181+#ifdef X86_64
182+ if (other_reg >= R8 || (other_reg >= RSP && other_reg <= RDI)) {
183+ //we can't mix an *H reg with a register that requires the REX prefix
184+ ea->base = opts->regs[z80_low_reg(inst->ea_reg)];
185+ ror_ir(code, 8, ea->base, SZ_W);
186+ }
187+#endif
188+ }
189+ } else {
190+ ea->mode = MODE_REG_DISPLACE8;
191+ ea->base = opts->gen.context_reg;
192+ ea->disp = zr_off(inst->ea_reg);
193+ }
194+ break;
195+ case Z80_REG_INDIRECT:
196+ zreg_to_native(opts, inst->ea_reg, areg);
197+ size = z80_size(inst);
198+ if (read) {
199+ if (modify) {
200+ //push_r(code, opts->gen.scratch1);
201+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(z80_context, scratch1), SZ_W);
202+ }
203+ if (size == SZ_B) {
204+ call(code, opts->read_8);
205+ } else {
206+ call(code, opts->read_16);
207+ }
208+ }
209+ ea->base = opts->gen.scratch1;
210+ break;
211+ case Z80_IMMED:
212+ ea->mode = MODE_IMMED;
213+ ea->disp = inst->immed;
214+ break;
215+ case Z80_IMMED_INDIRECT:
216+ mov_ir(code, inst->immed, areg, SZ_W);
217+ size = z80_size(inst);
218+ if (read) {
219+ /*if (modify) {
220+ push_r(code, opts->gen.scratch1);
221+ }*/
222+ if (size == SZ_B) {
223+ call(code, opts->read_8);
224+ } else {
225+ call(code, opts->read_16);
226+ }
227+ }
228+ ea->base = opts->gen.scratch1;
229+ break;
230+ case Z80_IX_DISPLACE:
231+ case Z80_IY_DISPLACE:
232+ zreg_to_native(opts, (inst->addr_mode & 0x1F) == Z80_IX_DISPLACE ? Z80_IX : Z80_IY, areg);
233+ add_ir(code, inst->ea_reg & 0x80 ? inst->ea_reg - 256 : inst->ea_reg, areg, SZ_W);
234+ size = z80_size(inst);
235+ if (read) {
236+ if (modify) {
237+ //push_r(code, opts->gen.scratch1);
238+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(z80_context, scratch1), SZ_W);
239+ }
240+ if (size == SZ_B) {
241+ call(code, opts->read_8);
242+ } else {
243+ call(code, opts->read_16);
244+ }
245+ }
246+ ea->base = opts->gen.scratch1;
247+ break;
248+ case Z80_UNUSED:
249+ ea->mode = MODE_UNUSED;
250+ break;
251+ default:
252+ fatal_error("Unrecognized Z80 addressing mode %d\n", inst->addr_mode & 0x1F);
253+ }
254+}
255+
256+void z80_save_ea(code_info *code, z80inst * inst, z80_options * opts)
257+{
258+ if ((inst->addr_mode & 0x1F) == Z80_REG) {
259+ if (inst->ea_reg == Z80_IYH && opts->regs[Z80_IYL] >= 0) {
260+ if (inst->reg == Z80_IYL) {
261+ ror_ir(code, 8, opts->regs[Z80_IY], SZ_W);
262+ mov_rr(code, opts->gen.scratch1, opts->regs[Z80_IYL], SZ_B);
263+ ror_ir(code, 8, opts->regs[Z80_IY], SZ_W);
264+ } else {
265+ ror_ir(code, 8, opts->regs[Z80_IY], SZ_W);
266+ }
267+ } else if (inst->reg != Z80_UNUSED && inst->reg != Z80_USE_IMMED && opts->regs[inst->ea_reg] >= AH && opts->regs[inst->ea_reg] <= BH) {
268+ uint8_t other_reg = opts->regs[inst->reg];
269+#ifdef X86_64
270+ if (other_reg >= R8 || (other_reg >= RSP && other_reg <= RDI)) {
271+ //we can't mix an *H reg with a register that requires the REX prefix
272+ ror_ir(code, 8, opts->regs[z80_low_reg(inst->ea_reg)], SZ_W);
273+ }
274+#endif
275+ }
276+ }
277+}
278+
279+void z80_save_result(z80_options *opts, z80inst * inst)
280+{
281+ switch(inst->addr_mode & 0x1f)
282+ {
283+ case Z80_REG_INDIRECT:
284+ case Z80_IMMED_INDIRECT:
285+ case Z80_IX_DISPLACE:
286+ case Z80_IY_DISPLACE:
287+ if (inst->op != Z80_LD) {
288+ mov_rdispr(&opts->gen.code, opts->gen.context_reg, offsetof(z80_context, scratch1), opts->gen.scratch2, SZ_W);
289+ }
290+ if (z80_size(inst) == SZ_B) {
291+ call(&opts->gen.code, opts->write_8);
292+ } else {
293+ call(&opts->gen.code, opts->write_16_lowfirst);
294+ }
295+ }
296+}
297+
298+enum {
299+ DONT_READ=0,
300+ READ
301+};
302+
303+enum {
304+ DONT_MODIFY=0,
305+ MODIFY
306+};
307+
308+void z80_print_regs_exit(z80_context * context)
309+{
310+ printf("A: %X\nB: %X\nC: %X\nD: %X\nE: %X\nHL: %X\nIX: %X\nIY: %X\nSP: %X\n\nIM: %d, IFF1: %d, IFF2: %d\n",
311+ context->regs[Z80_A], context->regs[Z80_B], context->regs[Z80_C],
312+ context->regs[Z80_D], context->regs[Z80_E],
313+ (context->regs[Z80_H] << 8) | context->regs[Z80_L],
314+ (context->regs[Z80_IXH] << 8) | context->regs[Z80_IXL],
315+ (context->regs[Z80_IYH] << 8) | context->regs[Z80_IYL],
316+ context->sp, context->im, context->iff1, context->iff2);
317+ puts("--Alternate Regs--");
318+ printf("A: %X\nB: %X\nC: %X\nD: %X\nE: %X\nHL: %X\nIX: %X\nIY: %X\n",
319+ context->alt_regs[Z80_A], context->alt_regs[Z80_B], context->alt_regs[Z80_C],
320+ context->alt_regs[Z80_D], context->alt_regs[Z80_E],
321+ (context->alt_regs[Z80_H] << 8) | context->alt_regs[Z80_L],
322+ (context->alt_regs[Z80_IXH] << 8) | context->alt_regs[Z80_IXL],
323+ (context->alt_regs[Z80_IYH] << 8) | context->alt_regs[Z80_IYL]);
324+ exit(0);
325+}
326+
327+void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, uint8_t interp)
328+{
329+ uint32_t num_cycles;
330+ host_ea src_op, dst_op;
331+ uint8_t size;
332+ z80_options *opts = context->options;
333+ uint8_t * start = opts->gen.code.cur;
334+ code_info *code = &opts->gen.code;
335+ if (!interp) {
336+ check_cycles_int(&opts->gen, address);
337+ if (context->breakpoint_flags[address / 8] & (1 << (address % 8))) {
338+ zbreakpoint_patch(context, address, start);
339+ }
340+ num_cycles = 4 * inst->opcode_bytes;
341+ add_ir(code, inst->opcode_bytes > 1 ? 2 : 1, opts->regs[Z80_R], SZ_B);
342+#ifdef Z80_LOG_ADDRESS
343+ log_address(&opts->gen, address, "Z80: %X @ %d\n");
344+#endif
345+ }
346+ switch(inst->op)
347+ {
348+ case Z80_LD:
349+ size = z80_size(inst);
350+ switch (inst->addr_mode & 0x1F)
351+ {
352+ case Z80_REG:
353+ case Z80_REG_INDIRECT:
354+ if (size != SZ_B) {
355+ num_cycles += 2;
356+ }
357+ if (inst->reg == Z80_I || inst->ea_reg == Z80_I || inst->reg == Z80_R || inst->ea_reg == Z80_R) {
358+ num_cycles += 1;
359+ } else if (inst->reg == Z80_USE_IMMED) {
360+ num_cycles += 3;
361+ }
362+ break;
363+ case Z80_IMMED:
364+ num_cycles += size == SZ_B ? 3 : 6;
365+ break;
366+ case Z80_IMMED_INDIRECT:
367+ num_cycles += 6;
368+ break;
369+ case Z80_IX_DISPLACE:
370+ case Z80_IY_DISPLACE:
371+ num_cycles += 8; //3 for displacement, 5 for address addition
372+ break;
373+ }
374+ cycles(&opts->gen, num_cycles);
375+ if (inst->addr_mode & Z80_DIR) {
376+ translate_z80_ea(inst, &dst_op, opts, DONT_READ, MODIFY);
377+ translate_z80_reg(inst, &src_op, opts);
378+ } else {
379+ translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY);
380+ translate_z80_reg(inst, &dst_op, opts);
381+ }
382+ if (inst->reg == Z80_R) {
383+ mov_rr(code, opts->regs[Z80_A], opts->gen.scratch1, SZ_B);
384+ mov_rr(code, opts->regs[Z80_A], opts->regs[Z80_R], SZ_B);
385+ and_ir(code, 0x80, opts->gen.scratch1, SZ_B);
386+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zr_off(Z80_R), SZ_B);
387+ } else if (inst->ea_reg == Z80_R && inst->addr_mode == Z80_REG) {
388+ mov_rr(code, opts->regs[Z80_R], opts->regs[Z80_A], SZ_B);
389+ and_ir(code, 0x7F, opts->regs[Z80_A], SZ_B);
390+ or_rdispr(code, opts->gen.context_reg, zr_off(Z80_R), opts->regs[Z80_A], SZ_B);
391+ } else if (src_op.mode == MODE_REG_DIRECT) {
392+ if(dst_op.mode == MODE_REG_DISPLACE8) {
393+ mov_rrdisp(code, src_op.base, dst_op.base, dst_op.disp, size);
394+ } else {
395+ mov_rr(code, src_op.base, dst_op.base, size);
396+ }
397+ } else if(src_op.mode == MODE_IMMED) {
398+ if(dst_op.mode == MODE_REG_DISPLACE8) {
399+ mov_irdisp(code, src_op.disp, dst_op.base, dst_op.disp, size);
400+ } else {
401+ mov_ir(code, src_op.disp, dst_op.base, size);
402+ }
403+ } else {
404+ if(dst_op.mode == MODE_REG_DISPLACE8) {
405+ mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, size);
406+ mov_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, size);
407+ } else {
408+ mov_rdispr(code, src_op.base, src_op.disp, dst_op.base, size);
409+ }
410+ }
411+ if ((inst->ea_reg == Z80_I || inst->ea_reg == Z80_R) && inst->addr_mode == Z80_REG) {
412+ //ld a, i and ld a, r sets some flags
413+ cmp_ir(code, 0, dst_op.base, SZ_B);
414+ setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
415+ setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
416+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_H), SZ_B);;
417+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);;
418+ mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, iff2), opts->gen.scratch1, SZ_B);
419+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_PV), SZ_B);
420+ }
421+ z80_save_reg(inst, opts);
422+ z80_save_ea(code, inst, opts);
423+ if (inst->addr_mode & Z80_DIR) {
424+ z80_save_result(opts, inst);
425+ }
426+ break;
427+ case Z80_PUSH:
428+ cycles(&opts->gen, num_cycles + 1);
429+ sub_ir(code, 2, opts->regs[Z80_SP], SZ_W);
430+ if (inst->reg == Z80_AF) {
431+ zreg_to_native(opts, Z80_A, opts->gen.scratch1);
432+ shl_ir(code, 8, opts->gen.scratch1, SZ_W);
433+ mov_rdispr(code, opts->gen.context_reg, zf_off(ZF_XY), opts->gen.scratch1, SZ_B);
434+ and_ir(code, 0x28, opts->gen.scratch1, SZ_B);
435+ or_rdispr(code, opts->gen.context_reg, zf_off(ZF_C), opts->gen.scratch1, SZ_B);
436+ ror_ir(code, 1, opts->gen.scratch1, SZ_B);
437+ or_rdispr(code, opts->gen.context_reg, zf_off(ZF_N), opts->gen.scratch1, SZ_B);
438+ ror_ir(code, 1, opts->gen.scratch1, SZ_B);
439+ or_rdispr(code, opts->gen.context_reg, zf_off(ZF_PV), opts->gen.scratch1, SZ_B);
440+ ror_ir(code, 2, opts->gen.scratch1, SZ_B);
441+ or_rdispr(code, opts->gen.context_reg, zf_off(ZF_H), opts->gen.scratch1, SZ_B);
442+ ror_ir(code, 2, opts->gen.scratch1, SZ_B);
443+ or_rdispr(code, opts->gen.context_reg, zf_off(ZF_Z), opts->gen.scratch1, SZ_B);
444+ ror_ir(code, 1, opts->gen.scratch1, SZ_B);
445+ or_rdispr(code, opts->gen.context_reg, zf_off(ZF_S), opts->gen.scratch1, SZ_B);
446+ ror_ir(code, 1, opts->gen.scratch1, SZ_B);
447+ } else {
448+ zreg_to_native(opts, inst->reg, opts->gen.scratch1);
449+ }
450+ mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W);
451+ call(code, opts->write_16_highfirst);
452+ //no call to save_z80_reg needed since there's no chance we'll use the only
453+ //the upper half of a register pair
454+ break;
455+ case Z80_POP:
456+ cycles(&opts->gen, num_cycles);
457+ mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W);
458+ call(code, opts->read_16);
459+ add_ir(code, 2, opts->regs[Z80_SP], SZ_W);
460+ if (inst->reg == Z80_AF) {
461+
462+ bt_ir(code, 0, opts->gen.scratch1, SZ_W);
463+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
464+ bt_ir(code, 1, opts->gen.scratch1, SZ_W);
465+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_N));
466+ bt_ir(code, 2, opts->gen.scratch1, SZ_W);
467+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_PV));
468+ bt_ir(code, 4, opts->gen.scratch1, SZ_W);
469+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
470+ bt_ir(code, 6, opts->gen.scratch1, SZ_W);
471+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_Z));
472+ bt_ir(code, 7, opts->gen.scratch1, SZ_W);
473+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_S));
474+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
475+ shr_ir(code, 8, opts->gen.scratch1, SZ_W);
476+ native_to_zreg(opts, opts->gen.scratch1, Z80_A);
477+ } else {
478+ native_to_zreg(opts, opts->gen.scratch1, inst->reg);
479+ }
480+ //no call to save_z80_reg needed since there's no chance we'll use the only
481+ //the upper half of a register pair
482+ break;
483+ case Z80_EX:
484+ cycles(&opts->gen, num_cycles);
485+ if (inst->addr_mode == Z80_REG) {
486+ if(inst->reg == Z80_AF) {
487+ zreg_to_native(opts, Z80_A, opts->gen.scratch1);
488+ mov_rdispr(code, opts->gen.context_reg, zar_off(Z80_A), opts->gen.scratch2, SZ_B);
489+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zar_off(Z80_A), SZ_B);
490+ native_to_zreg(opts, opts->gen.scratch2, Z80_A);
491+
492+ //Flags are currently word aligned, so we can move
493+ //them efficiently a word at a time
494+ for (int f = ZF_C; f < ZF_NUM; f+=2) {
495+ mov_rdispr(code, opts->gen.context_reg, zf_off(f), opts->gen.scratch1, SZ_W);
496+ mov_rdispr(code, opts->gen.context_reg, zaf_off(f), opts->gen.scratch2, SZ_W);
497+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zaf_off(f), SZ_W);
498+ mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, zf_off(f), SZ_W);
499+ }
500+ } else {
501+ if (opts->regs[Z80_DE] >= 0 && opts->regs[Z80_HL] >= 0) {
502+ xchg_rr(code, opts->regs[Z80_DE], opts->regs[Z80_HL], SZ_W);
503+ } else {
504+ zreg_to_native(opts, Z80_DE, opts->gen.scratch1);
505+ zreg_to_native(opts, Z80_HL, opts->gen.scratch2);
506+ native_to_zreg(opts, opts->gen.scratch1, Z80_HL);
507+ native_to_zreg(opts, opts->gen.scratch2, Z80_DE);
508+ }
509+ }
510+ } else {
511+ mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W);
512+ call(code, opts->read_8);
513+ if (opts->regs[inst->reg] >= 0) {
514+ xchg_rr(code, opts->regs[inst->reg], opts->gen.scratch1, SZ_B);
515+ } else {
516+ zreg_to_native(opts, inst->reg, opts->gen.scratch2);
517+ xchg_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
518+ native_to_zreg(opts, opts->gen.scratch2, inst->reg);
519+ }
520+ mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W);
521+ call(code, opts->write_8);
522+ cycles(&opts->gen, 1);
523+ uint8_t high_reg = z80_high_reg(inst->reg);
524+ mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W);
525+ add_ir(code, 1, opts->gen.scratch1, SZ_W);
526+ call(code, opts->read_8);
527+ if (opts->regs[inst->reg] >= 0) {
528+ //even though some of the upper halves can be used directly
529+ //the limitations on mixing *H regs with the REX prefix
530+ //prevent us from taking advantage of it
531+ uint8_t use_reg = opts->regs[inst->reg];
532+ ror_ir(code, 8, use_reg, SZ_W);
533+ xchg_rr(code, use_reg, opts->gen.scratch1, SZ_B);
534+ //restore reg to normal rotation
535+ ror_ir(code, 8, use_reg, SZ_W);
536+ } else {
537+ zreg_to_native(opts, high_reg, opts->gen.scratch2);
538+ xchg_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
539+ native_to_zreg(opts, opts->gen.scratch2, high_reg);
540+ }
541+ mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W);
542+ add_ir(code, 1, opts->gen.scratch2, SZ_W);
543+ call(code, opts->write_8);
544+ cycles(&opts->gen, 2);
545+ }
546+ break;
547+ case Z80_EXX:
548+ cycles(&opts->gen, num_cycles);
549+ zreg_to_native(opts, Z80_BC, opts->gen.scratch1);
550+ mov_rdispr(code, opts->gen.context_reg, zar_off(Z80_BC), opts->gen.scratch2, SZ_W);
551+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zar_off(Z80_BC), SZ_W);
552+ native_to_zreg(opts, opts->gen.scratch2, Z80_BC);
553+
554+ zreg_to_native(opts, Z80_HL, opts->gen.scratch1);
555+ mov_rdispr(code, opts->gen.context_reg, zar_off(Z80_HL), opts->gen.scratch2, SZ_W);
556+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zar_off(Z80_HL), SZ_W);
557+ native_to_zreg(opts, opts->gen.scratch2, Z80_HL);
558+
559+ zreg_to_native(opts, Z80_DE, opts->gen.scratch1);
560+ mov_rdispr(code, opts->gen.context_reg, zar_off(Z80_DE), opts->gen.scratch2, SZ_W);
561+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zar_off(Z80_DE), SZ_W);
562+ native_to_zreg(opts, opts->gen.scratch2, Z80_DE);
563+ break;
564+ case Z80_LDI: {
565+ cycles(&opts->gen, num_cycles);
566+ zreg_to_native(opts, Z80_HL, opts->gen.scratch1);
567+ call(code, opts->read_8);
568+ zreg_to_native(opts, Z80_DE, opts->gen.scratch2);
569+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
570+ call(code, opts->write_8);
571+ mov_rdispr(code, opts->gen.context_reg, zf_off(ZF_XY), opts->gen.scratch1, SZ_B);
572+ add_rr(code, opts->regs[Z80_A], opts->gen.scratch1, SZ_B);
573+ mov_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
574+ and_ir(code, 0x8, opts->gen.scratch1, SZ_B);
575+ shl_ir(code, 4, opts->gen.scratch2, SZ_B);
576+ or_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
577+ mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
578+ cycles(&opts->gen, 2);
579+ if (opts->regs[Z80_DE] >= 0) {
580+ add_ir(code, 1, opts->regs[Z80_DE], SZ_W);
581+ } else {
582+ add_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_DE), SZ_W);
583+ }
584+ if (opts->regs[Z80_HL] >= 0) {
585+ add_ir(code, 1, opts->regs[Z80_HL], SZ_W);
586+ } else {
587+ add_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_HL), SZ_W);
588+ }
589+ if (opts->regs[Z80_BC] >= 0) {
590+ sub_ir(code, 1, opts->regs[Z80_BC], SZ_W);
591+ } else {
592+ sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_BC), SZ_W);
593+ }
594+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
595+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
596+ setcc_rdisp(code, CC_NZ, opts->gen.context_reg, zf_off(ZF_PV));
597+ break;
598+ }
599+ case Z80_LDIR: {
600+ cycles(&opts->gen, num_cycles);
601+ zreg_to_native(opts, Z80_HL, opts->gen.scratch1);
602+ call(code, opts->read_8);
603+ zreg_to_native(opts, Z80_DE, opts->gen.scratch2);
604+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
605+ call(code, opts->write_8);
606+ mov_rdispr(code, opts->gen.context_reg, zf_off(ZF_XY), opts->gen.scratch1, SZ_B);
607+ add_rr(code, opts->regs[Z80_A], opts->gen.scratch1, SZ_B);
608+ mov_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
609+ and_ir(code, 0x8, opts->gen.scratch1, SZ_B);
610+ shl_ir(code, 4, opts->gen.scratch2, SZ_B);
611+ or_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
612+ mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
613+ if (opts->regs[Z80_DE] >= 0) {
614+ add_ir(code, 1, opts->regs[Z80_DE], SZ_W);
615+ } else {
616+ add_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_DE), SZ_W);
617+ }
618+ if (opts->regs[Z80_HL] >= 0) {
619+ add_ir(code, 1, opts->regs[Z80_HL], SZ_W);
620+ } else {
621+ add_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_HL), SZ_W);
622+ }
623+ if (opts->regs[Z80_BC] >= 0) {
624+ sub_ir(code, 1, opts->regs[Z80_BC], SZ_W);
625+ } else {
626+ sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_BC), SZ_W);
627+ }
628+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
629+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
630+ uint8_t * cont = code->cur+1;
631+ jcc(code, CC_Z, code->cur+2);
632+ cycles(&opts->gen, 7);
633+ mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_PV), SZ_B);
634+ jmp(code, start);
635+ *cont = code->cur - (cont + 1);
636+ cycles(&opts->gen, 2);
637+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_PV), SZ_B);
638+ break;
639+ }
640+ case Z80_LDD: {
641+ cycles(&opts->gen, num_cycles);
642+ zreg_to_native(opts, Z80_HL, opts->gen.scratch1);
643+ call(code, opts->read_8);
644+ zreg_to_native(opts, Z80_DE, opts->gen.scratch2);
645+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
646+ call(code, opts->write_8);
647+ mov_rdispr(code, opts->gen.context_reg, zf_off(ZF_XY), opts->gen.scratch1, SZ_B);
648+ add_rr(code, opts->regs[Z80_A], opts->gen.scratch1, SZ_B);
649+ mov_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
650+ and_ir(code, 0x8, opts->gen.scratch1, SZ_B);
651+ shl_ir(code, 4, opts->gen.scratch2, SZ_B);
652+ or_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
653+ mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
654+ cycles(&opts->gen, 2);
655+ if (opts->regs[Z80_DE] >= 0) {
656+ sub_ir(code, 1, opts->regs[Z80_DE], SZ_W);
657+ } else {
658+ sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_DE), SZ_W);
659+ }
660+ if (opts->regs[Z80_HL] >= 0) {
661+ sub_ir(code, 1, opts->regs[Z80_HL], SZ_W);
662+ } else {
663+ sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_HL), SZ_W);
664+ }
665+ if (opts->regs[Z80_BC] >= 0) {
666+ sub_ir(code, 1, opts->regs[Z80_BC], SZ_W);
667+ } else {
668+ sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_BC), SZ_W);
669+ }
670+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
671+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
672+ setcc_rdisp(code, CC_NZ, opts->gen.context_reg, zf_off(ZF_PV));
673+ break;
674+ }
675+ case Z80_LDDR: {
676+ cycles(&opts->gen, num_cycles);
677+ zreg_to_native(opts, Z80_HL, opts->gen.scratch1);
678+ call(code, opts->read_8);
679+ zreg_to_native(opts, Z80_DE, opts->gen.scratch2);
680+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
681+ call(code, opts->write_8);
682+ mov_rdispr(code, opts->gen.context_reg, zf_off(ZF_XY), opts->gen.scratch1, SZ_B);
683+ add_rr(code, opts->regs[Z80_A], opts->gen.scratch1, SZ_B);
684+ mov_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
685+ and_ir(code, 0x8, opts->gen.scratch1, SZ_B);
686+ shl_ir(code, 4, opts->gen.scratch2, SZ_B);
687+ or_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
688+ mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
689+ if (opts->regs[Z80_DE] >= 0) {
690+ sub_ir(code, 1, opts->regs[Z80_DE], SZ_W);
691+ } else {
692+ sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_DE), SZ_W);
693+ }
694+ if (opts->regs[Z80_HL] >= 0) {
695+ sub_ir(code, 1, opts->regs[Z80_HL], SZ_W);
696+ } else {
697+ sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_HL), SZ_W);
698+ }
699+ if (opts->regs[Z80_BC] >= 0) {
700+ sub_ir(code, 1, opts->regs[Z80_BC], SZ_W);
701+ } else {
702+ sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_BC), SZ_W);
703+ }
704+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
705+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
706+ uint8_t * cont = code->cur+1;
707+ jcc(code, CC_Z, code->cur+2);
708+ cycles(&opts->gen, 7);
709+ mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_PV), SZ_B);
710+ jmp(code, start);
711+ *cont = code->cur - (cont + 1);
712+ cycles(&opts->gen, 2);
713+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_PV), SZ_B);
714+ break;
715+ }
716+ case Z80_CPI:
717+ cycles(&opts->gen, num_cycles);//T-States 4,4
718+ zreg_to_native(opts, Z80_HL, opts->gen.scratch1);
719+ call(code, opts->read_8);//T-States 3
720+ mov_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B);
721+ sub_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
722+ mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
723+ setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
724+ setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
725+ xor_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B);
726+ xor_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
727+ bt_ir(code, 4, opts->gen.scratch2, SZ_B);
728+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
729+ cycles(&opts->gen, 5);//T-States 5
730+ if (opts->regs[Z80_HL] >= 0) {
731+ add_ir(code, 1, opts->regs[Z80_HL], SZ_W);
732+ } else {
733+ add_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_HL), SZ_W);
734+ }
735+ if (opts->regs[Z80_BC] >= 0) {
736+ sub_ir(code, 1, opts->regs[Z80_BC], SZ_W);
737+ } else {
738+ sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_BC), SZ_W);
739+ }
740+ setcc_rdisp(code, CC_NZ, opts->gen.context_reg, zf_off(ZF_PV));
741+ mov_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B);
742+ sub_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
743+ sub_rdispr(code, opts->gen.context_reg, zf_off(ZF_H), opts->gen.scratch2, SZ_B);
744+ mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
745+ shl_ir(code, 4, opts->gen.scratch2, SZ_B);
746+ and_irdisp(code, 0x8, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
747+ and_ir(code, 0x20, opts->gen.scratch2, SZ_B);
748+ or_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
749+ break;
750+ case Z80_CPIR: {
751+ cycles(&opts->gen, num_cycles);//T-States 4,4
752+ zreg_to_native(opts, Z80_HL, opts->gen.scratch1);
753+ call(code, opts->read_8);//T-States 3
754+ mov_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B);
755+ sub_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
756+ mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
757+ setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
758+ setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
759+ xor_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B);
760+ xor_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
761+ bt_ir(code, 4, opts->gen.scratch2, SZ_B);
762+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
763+ cycles(&opts->gen, 5);//T-States 5
764+ if (opts->regs[Z80_HL] >= 0) {
765+ add_ir(code, 1, opts->regs[Z80_HL], SZ_W);
766+ } else {
767+ add_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_HL), SZ_W);
768+ }
769+ mov_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B);
770+ sub_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
771+ sub_rdispr(code, opts->gen.context_reg, zf_off(ZF_H), opts->gen.scratch2, SZ_B);
772+ mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
773+ shl_ir(code, 4, opts->gen.scratch2, SZ_B);
774+ and_irdisp(code, 0x8, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
775+ and_ir(code, 0x20, opts->gen.scratch2, SZ_B);
776+ or_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
777+ if (opts->regs[Z80_BC] >= 0) {
778+ sub_ir(code, 1, opts->regs[Z80_BC], SZ_W);
779+ } else {
780+ sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_BC), SZ_W);
781+ }
782+ setcc_rdisp(code, CC_NZ, opts->gen.context_reg, zf_off(ZF_PV));
783+ uint8_t * cont = code->cur+1;
784+ jcc(code, CC_Z, code->cur+2);
785+ cmp_rr(code, opts->gen.scratch1, opts->regs[Z80_A], SZ_B);
786+ uint8_t * cont2 = code->cur+1;
787+ jcc(code, CC_Z, code->cur+2);
788+ //repeat case
789+ cycles(&opts->gen, 5);//T-States 5
790+ jmp(code, start);
791+ *cont = code->cur - (cont + 1);
792+ *cont2 = code->cur - (cont2 + 1);
793+ break;
794+ }
795+ case Z80_CPD:
796+ cycles(&opts->gen, num_cycles);//T-States 4,4
797+ zreg_to_native(opts, Z80_HL, opts->gen.scratch1);
798+ call(code, opts->read_8);//T-States 3
799+ mov_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B);
800+ sub_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
801+ mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
802+ setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
803+ setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
804+ xor_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B);
805+ xor_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
806+ bt_ir(code, 4, opts->gen.scratch2, SZ_B);
807+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
808+ cycles(&opts->gen, 5);//T-States 5
809+ if (opts->regs[Z80_HL] >= 0) {
810+ sub_ir(code, 1, opts->regs[Z80_HL], SZ_W);
811+ } else {
812+ sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_HL), SZ_W);
813+ }
814+ if (opts->regs[Z80_BC] >= 0) {
815+ sub_ir(code, 1, opts->regs[Z80_BC], SZ_W);
816+ } else {
817+ sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_BC), SZ_W);
818+ }
819+ setcc_rdisp(code, CC_NZ, opts->gen.context_reg, zf_off(ZF_PV));
820+ mov_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B);
821+ sub_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
822+ sub_rdispr(code, opts->gen.context_reg, zf_off(ZF_H), opts->gen.scratch2, SZ_B);
823+ mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
824+ shl_ir(code, 4, opts->gen.scratch2, SZ_B);
825+ and_irdisp(code, 0x8, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
826+ and_ir(code, 0x20, opts->gen.scratch2, SZ_B);
827+ or_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
828+ break;
829+ case Z80_CPDR: {
830+ cycles(&opts->gen, num_cycles);//T-States 4,4
831+ zreg_to_native(opts, Z80_HL, opts->gen.scratch1);
832+ call(code, opts->read_8);//T-States 3
833+ mov_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B);
834+ sub_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
835+ mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
836+ setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
837+ setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
838+ xor_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B);
839+ xor_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
840+ bt_ir(code, 4, opts->gen.scratch2, SZ_B);
841+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
842+ cycles(&opts->gen, 5);//T-States 5
843+ if (opts->regs[Z80_HL] >= 0) {
844+ sub_ir(code, 1, opts->regs[Z80_HL], SZ_W);
845+ } else {
846+ sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_HL), SZ_W);
847+ }
848+ mov_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B);
849+ sub_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B);
850+ sub_rdispr(code, opts->gen.context_reg, zf_off(ZF_H), opts->gen.scratch2, SZ_B);
851+ mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
852+ shl_ir(code, 4, opts->gen.scratch2, SZ_B);
853+ and_irdisp(code, 0x8, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
854+ and_ir(code, 0x20, opts->gen.scratch2, SZ_B);
855+ or_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
856+ if (opts->regs[Z80_BC] >= 0) {
857+ sub_ir(code, 1, opts->regs[Z80_BC], SZ_W);
858+ } else {
859+ sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_BC), SZ_W);
860+ }
861+ setcc_rdisp(code, CC_NZ, opts->gen.context_reg, zf_off(ZF_PV));
862+ uint8_t * cont = code->cur+1;
863+ jcc(code, CC_Z, code->cur+2);
864+ cmp_rr(code, opts->gen.scratch1, opts->regs[Z80_A], SZ_B);
865+ uint8_t * cont2 = code->cur+1;
866+ jcc(code, CC_Z, code->cur+2);
867+ //repeat case
868+ cycles(&opts->gen, 5);//T-States 5
869+ jmp(code, start);
870+ *cont = code->cur - (cont + 1);
871+ *cont2 = code->cur - (cont2 + 1);
872+ break;
873+ }
874+ case Z80_ADD:
875+ if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
876+ num_cycles += 8;
877+ } else if(inst->addr_mode == Z80_IMMED) {
878+ num_cycles += 3;
879+ } else if(z80_size(inst) == SZ_W) {
880+ num_cycles += 7;
881+ }
882+ cycles(&opts->gen, num_cycles);
883+ translate_z80_reg(inst, &dst_op, opts);
884+ translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY);
885+ if (dst_op.mode == MODE_REG_DIRECT) {
886+ mov_rr(code, dst_op.base, opts->gen.scratch2, z80_size(inst));
887+ } else {
888+ mov_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch2, z80_size(inst));
889+ }
890+ if (src_op.mode == MODE_REG_DIRECT) {
891+ xor_rr(code, src_op.base, opts->gen.scratch2, z80_size(inst));
892+ } else if (src_op.mode == MODE_IMMED) {
893+ xor_ir(code, src_op.disp, opts->gen.scratch2, z80_size(inst));
894+ } else {
895+ xor_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch2, z80_size(inst));
896+ }
897+ if (dst_op.mode == MODE_REG_DIRECT) {
898+ if (src_op.mode == MODE_REG_DIRECT) {
899+ add_rr(code, src_op.base, dst_op.base, z80_size(inst));
900+ } else if (src_op.mode == MODE_IMMED) {
901+ add_ir(code, src_op.disp, dst_op.base, z80_size(inst));
902+ } else {
903+ add_rdispr(code, src_op.base, src_op.disp, dst_op.base, z80_size(inst));
904+ }
905+ if (z80_size(inst) == SZ_B) {
906+ mov_rrdisp(code, dst_op.base, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
907+ }
908+ } else {
909+ if (src_op.mode == MODE_REG_DIRECT) {
910+ add_rrdisp(code, src_op.base, dst_op.base, dst_op.disp, z80_size(inst));
911+ } else if (src_op.mode == MODE_IMMED) {
912+ add_irdisp(code, src_op.disp, dst_op.base, dst_op.disp, z80_size(inst));
913+ } else {
914+ mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, z80_size(inst));
915+ add_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, z80_size(inst));
916+ }
917+ mov_rdispr(code, dst_op.base, dst_op.disp + (z80_size(inst) == SZ_B ? 0 : 1), opts->gen.scratch1, SZ_B);
918+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
919+ }
920+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
921+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
922+ if (z80_size(inst) == SZ_B) {
923+ setcc_rdisp(code, CC_O, opts->gen.context_reg, zf_off(ZF_PV));
924+ setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
925+ setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
926+ }
927+ if (dst_op.mode == MODE_REG_DIRECT) {
928+ xor_rr(code, dst_op.base, opts->gen.scratch2, z80_size(inst));
929+ } else {
930+ xor_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch2, z80_size(inst));
931+ }
932+ bt_ir(code, z80_size(inst) == SZ_B ? 4 : 12, opts->gen.scratch2, z80_size(inst));
933+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
934+ if (z80_size(inst) == SZ_W & dst_op.mode == MODE_REG_DIRECT) {
935+ mov_rr(code, dst_op.base, opts->gen.scratch2, SZ_W);
936+ shr_ir(code, 8, opts->gen.scratch2, SZ_W);
937+ mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
938+ }
939+ z80_save_reg(inst, opts);
940+ z80_save_ea(code, inst, opts);
941+ break;
942+ case Z80_ADC:
943+ if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
944+ num_cycles += 8;
945+ } else if(inst->addr_mode == Z80_IMMED) {
946+ num_cycles += 3;
947+ } else if(z80_size(inst) == SZ_W) {
948+ num_cycles += 7;
949+ }
950+ cycles(&opts->gen, num_cycles);
951+ translate_z80_reg(inst, &dst_op, opts);
952+ translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY);
953+ if (dst_op.mode == MODE_REG_DIRECT) {
954+ mov_rr(code, dst_op.base, opts->gen.scratch2, z80_size(inst));
955+ } else {
956+ mov_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch2, z80_size(inst));
957+ }
958+ if (src_op.mode == MODE_REG_DIRECT) {
959+ xor_rr(code, src_op.base, opts->gen.scratch2, z80_size(inst));
960+ } else if (src_op.mode == MODE_IMMED) {
961+ xor_ir(code, src_op.disp, opts->gen.scratch2, z80_size(inst));
962+ } else {
963+ xor_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch2, z80_size(inst));
964+ }
965+ bt_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
966+ if (dst_op.mode == MODE_REG_DIRECT) {
967+ if (src_op.mode == MODE_REG_DIRECT) {
968+ adc_rr(code, src_op.base, dst_op.base, z80_size(inst));
969+ } else if (src_op.mode == MODE_IMMED) {
970+ adc_ir(code, src_op.disp, dst_op.base, z80_size(inst));
971+ } else {
972+ adc_rdispr(code, src_op.base, src_op.disp, dst_op.base, z80_size(inst));
973+ }
974+ if (z80_size(inst) == SZ_B) {
975+ mov_rrdisp(code, dst_op.base, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
976+ }
977+ } else {
978+ if (src_op.mode == MODE_REG_DIRECT) {
979+ adc_rrdisp(code, src_op.base, dst_op.base, dst_op.disp, z80_size(inst));
980+ } else if (src_op.mode == MODE_IMMED) {
981+ adc_irdisp(code, src_op.disp, dst_op.base, dst_op.disp, z80_size(inst));
982+ } else {
983+ mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, z80_size(inst));
984+ adc_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, z80_size(inst));
985+ }
986+ mov_rdispr(code, dst_op.base, dst_op.disp + z80_size(inst) == SZ_B ? 0 : 8, opts->gen.scratch1, SZ_B);
987+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
988+ }
989+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
990+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
991+ setcc_rdisp(code, CC_O, opts->gen.context_reg, zf_off(ZF_PV));
992+ setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
993+ setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
994+ if (dst_op.mode == MODE_REG_DIRECT) {
995+ xor_rr(code, dst_op.base, opts->gen.scratch2, z80_size(inst));
996+ } else {
997+ xor_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch2, z80_size(inst));
998+ }
999+ bt_ir(code, z80_size(inst) == SZ_B ? 4 : 12, opts->gen.scratch2, z80_size(inst));
1000+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
1001+ if (z80_size(inst) == SZ_W & dst_op.mode == MODE_REG_DIRECT) {
1002+ mov_rr(code, dst_op.base, opts->gen.scratch2, SZ_W);
1003+ shr_ir(code, 8, opts->gen.scratch2, SZ_W);
1004+ mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1005+ }
1006+ z80_save_reg(inst, opts);
1007+ z80_save_ea(code, inst, opts);
1008+ break;
1009+ case Z80_SUB:
1010+ if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
1011+ num_cycles += 8;
1012+ } else if(inst->addr_mode == Z80_IMMED) {
1013+ num_cycles += 3;
1014+ }
1015+ cycles(&opts->gen, num_cycles);
1016+ translate_z80_reg(inst, &dst_op, opts);
1017+ translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY);
1018+ if (dst_op.mode == MODE_REG_DIRECT) {
1019+ mov_rr(code, dst_op.base, opts->gen.scratch2, z80_size(inst));
1020+ } else {
1021+ mov_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch2, z80_size(inst));
1022+ }
1023+ if (src_op.mode == MODE_REG_DIRECT) {
1024+ xor_rr(code, src_op.base, opts->gen.scratch2, z80_size(inst));
1025+ } else if (src_op.mode == MODE_IMMED) {
1026+ xor_ir(code, src_op.disp, opts->gen.scratch2, z80_size(inst));
1027+ } else {
1028+ xor_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch2, z80_size(inst));
1029+ }
1030+ if (dst_op.mode == MODE_REG_DIRECT) {
1031+ if (src_op.mode == MODE_REG_DIRECT) {
1032+ sub_rr(code, src_op.base, dst_op.base, z80_size(inst));
1033+ } else if (src_op.mode == MODE_IMMED) {
1034+ sub_ir(code, src_op.disp, dst_op.base, z80_size(inst));
1035+ } else {
1036+ sub_rdispr(code, src_op.base, src_op.disp, dst_op.base, z80_size(inst));
1037+ }
1038+ if (z80_size(inst) == SZ_B) {
1039+ mov_rrdisp(code, dst_op.base, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1040+ }
1041+ } else {
1042+ if (src_op.mode == MODE_REG_DIRECT) {
1043+ sub_rrdisp(code, src_op.base, dst_op.base, dst_op.disp, z80_size(inst));
1044+ } else if (src_op.mode == MODE_IMMED) {
1045+ sub_irdisp(code, src_op.disp, dst_op.base, dst_op.disp, z80_size(inst));
1046+ } else {
1047+ mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, z80_size(inst));
1048+ sub_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, z80_size(inst));
1049+ }
1050+ mov_rdispr(code, dst_op.base, dst_op.disp + z80_size(inst) == SZ_B ? 0 : 8, opts->gen.scratch1, SZ_B);
1051+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1052+ }
1053+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
1054+ mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
1055+ setcc_rdisp(code, CC_O, opts->gen.context_reg, zf_off(ZF_PV));
1056+ setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
1057+ setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
1058+ if (dst_op.mode == MODE_REG_DIRECT) {
1059+ xor_rr(code, dst_op.base, opts->gen.scratch2, z80_size(inst));
1060+ } else {
1061+ xor_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch2, z80_size(inst));
1062+ }
1063+ bt_ir(code, z80_size(inst) == SZ_B ? 4 : 12, opts->gen.scratch2, z80_size(inst));
1064+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
1065+ if (z80_size(inst) == SZ_W & dst_op.mode == MODE_REG_DIRECT) {
1066+ mov_rr(code, dst_op.base, opts->gen.scratch2, SZ_W);
1067+ shr_ir(code, 8, opts->gen.scratch2, SZ_W);
1068+ mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1069+ }
1070+ z80_save_reg(inst, opts);
1071+ z80_save_ea(code, inst, opts);
1072+ break;
1073+ case Z80_SBC:
1074+ if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
1075+ num_cycles += 8;
1076+ } else if(inst->addr_mode == Z80_IMMED) {
1077+ num_cycles += 3;
1078+ } else if(z80_size(inst) == SZ_W) {
1079+ num_cycles += 7;
1080+ }
1081+ cycles(&opts->gen, num_cycles);
1082+ translate_z80_reg(inst, &dst_op, opts);
1083+ translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY);
1084+ if (dst_op.mode == MODE_REG_DIRECT) {
1085+ mov_rr(code, dst_op.base, opts->gen.scratch2, z80_size(inst));
1086+ } else {
1087+ mov_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch2, z80_size(inst));
1088+ }
1089+ if (src_op.mode == MODE_REG_DIRECT) {
1090+ xor_rr(code, src_op.base, opts->gen.scratch2, z80_size(inst));
1091+ } else if (src_op.mode == MODE_IMMED) {
1092+ xor_ir(code, src_op.disp, opts->gen.scratch2, z80_size(inst));
1093+ } else {
1094+ xor_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch2, z80_size(inst));
1095+ }
1096+ bt_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
1097+ if (dst_op.mode == MODE_REG_DIRECT) {
1098+ if (src_op.mode == MODE_REG_DIRECT) {
1099+ sbb_rr(code, src_op.base, dst_op.base, z80_size(inst));
1100+ } else if (src_op.mode == MODE_IMMED) {
1101+ sbb_ir(code, src_op.disp, dst_op.base, z80_size(inst));
1102+ } else {
1103+ sbb_rdispr(code, src_op.base, src_op.disp, dst_op.base, z80_size(inst));
1104+ }
1105+ if (z80_size(inst) == SZ_B) {
1106+ mov_rrdisp(code, dst_op.base, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1107+ }
1108+ } else {
1109+ if (src_op.mode == MODE_REG_DIRECT) {
1110+ sbb_rrdisp(code, src_op.base, dst_op.base, dst_op.disp, z80_size(inst));
1111+ } else if (src_op.mode == MODE_IMMED) {
1112+ sbb_irdisp(code, src_op.disp, dst_op.base, dst_op.disp, z80_size(inst));
1113+ } else {
1114+ mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, z80_size(inst));
1115+ sbb_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, z80_size(inst));
1116+ }
1117+ mov_rdispr(code, dst_op.base, dst_op.disp + z80_size(inst) == SZ_B ? 0 : 8, opts->gen.scratch1, SZ_B);
1118+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1119+ }
1120+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
1121+ mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
1122+ setcc_rdisp(code, CC_O, opts->gen.context_reg, zf_off(ZF_PV));
1123+ setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
1124+ setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
1125+ if (dst_op.mode == MODE_REG_DIRECT) {
1126+ xor_rr(code, dst_op.base, opts->gen.scratch2, z80_size(inst));
1127+ } else {
1128+ xor_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch2, z80_size(inst));
1129+ }
1130+ bt_ir(code, z80_size(inst) == SZ_B ? 4 : 12, opts->gen.scratch2, z80_size(inst));
1131+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
1132+ if (z80_size(inst) == SZ_W & dst_op.mode == MODE_REG_DIRECT) {
1133+ mov_rr(code, dst_op.base, opts->gen.scratch2, SZ_W);
1134+ shr_ir(code, 8, opts->gen.scratch2, SZ_W);
1135+ mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1136+ }
1137+ z80_save_reg(inst, opts);
1138+ z80_save_ea(code, inst, opts);
1139+ break;
1140+ case Z80_AND:
1141+ if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
1142+ num_cycles += 8;
1143+ } else if(inst->addr_mode == Z80_IMMED) {
1144+ num_cycles += 3;
1145+ } else if(z80_size(inst) == SZ_W) {
1146+ num_cycles += 4;
1147+ }
1148+ cycles(&opts->gen, num_cycles);
1149+ translate_z80_reg(inst, &dst_op, opts);
1150+ translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY);
1151+ if (src_op.mode == MODE_REG_DIRECT) {
1152+ and_rr(code, src_op.base, dst_op.base, z80_size(inst));
1153+ } else if (src_op.mode == MODE_IMMED) {
1154+ and_ir(code, src_op.disp, dst_op.base, z80_size(inst));
1155+ } else {
1156+ and_rdispr(code, src_op.base, src_op.disp, dst_op.base, z80_size(inst));
1157+ }
1158+ mov_rrdisp(code, dst_op.base, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1159+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
1160+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
1161+ mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
1162+ setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
1163+ setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
1164+ setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
1165+ z80_save_reg(inst, opts);
1166+ z80_save_ea(code, inst, opts);
1167+ break;
1168+ case Z80_OR:
1169+ if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
1170+ num_cycles += 8;
1171+ } else if(inst->addr_mode == Z80_IMMED) {
1172+ num_cycles += 3;
1173+ } else if(z80_size(inst) == SZ_W) {
1174+ num_cycles += 4;
1175+ }
1176+ cycles(&opts->gen, num_cycles);
1177+ translate_z80_reg(inst, &dst_op, opts);
1178+ translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY);
1179+ if (src_op.mode == MODE_REG_DIRECT) {
1180+ or_rr(code, src_op.base, dst_op.base, z80_size(inst));
1181+ } else if (src_op.mode == MODE_IMMED) {
1182+ or_ir(code, src_op.disp, dst_op.base, z80_size(inst));
1183+ } else {
1184+ or_rdispr(code, src_op.base, src_op.disp, dst_op.base, z80_size(inst));
1185+ }
1186+ mov_rrdisp(code, dst_op.base, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1187+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
1188+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
1189+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
1190+ setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
1191+ setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
1192+ setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
1193+ z80_save_reg(inst, opts);
1194+ z80_save_ea(code, inst, opts);
1195+ break;
1196+ case Z80_XOR:
1197+ if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
1198+ num_cycles += 8;
1199+ } else if(inst->addr_mode == Z80_IMMED) {
1200+ num_cycles += 3;
1201+ } else if(z80_size(inst) == SZ_W) {
1202+ num_cycles += 4;
1203+ }
1204+ cycles(&opts->gen, num_cycles);
1205+ translate_z80_reg(inst, &dst_op, opts);
1206+ translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY);
1207+ if (src_op.mode == MODE_REG_DIRECT) {
1208+ xor_rr(code, src_op.base, dst_op.base, z80_size(inst));
1209+ } else if (src_op.mode == MODE_IMMED) {
1210+ xor_ir(code, src_op.disp, dst_op.base, z80_size(inst));
1211+ } else {
1212+ xor_rdispr(code, src_op.base, src_op.disp, dst_op.base, z80_size(inst));
1213+ }
1214+ mov_rrdisp(code, dst_op.base, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1215+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
1216+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
1217+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
1218+ setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
1219+ setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
1220+ setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
1221+ z80_save_reg(inst, opts);
1222+ z80_save_ea(code, inst, opts);
1223+ break;
1224+ case Z80_CP:
1225+ if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
1226+ num_cycles += 8;
1227+ } else if(inst->addr_mode == Z80_IMMED) {
1228+ num_cycles += 3;
1229+ }
1230+ cycles(&opts->gen, num_cycles);
1231+ translate_z80_reg(inst, &dst_op, opts);
1232+ translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY);
1233+ mov_rr(code, dst_op.base, opts->gen.scratch2, z80_size(inst));
1234+ if (src_op.mode == MODE_REG_DIRECT) {
1235+ sub_rr(code, src_op.base, opts->gen.scratch2, z80_size(inst));
1236+ mov_rrdisp(code, src_op.base, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1237+ } else if (src_op.mode == MODE_IMMED) {
1238+ sub_ir(code, src_op.disp, opts->gen.scratch2, z80_size(inst));
1239+ mov_irdisp(code, src_op.disp, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1240+ } else {
1241+ sub_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch2, z80_size(inst));
1242+ mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, SZ_B);
1243+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1244+ }
1245+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
1246+ mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
1247+ setcc_rdisp(code, CC_O, opts->gen.context_reg, zf_off(ZF_PV));
1248+ setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
1249+ setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
1250+ xor_rr(code, dst_op.base, opts->gen.scratch2, z80_size(inst));
1251+ if (src_op.mode == MODE_REG_DIRECT) {
1252+ xor_rr(code, src_op.base, opts->gen.scratch2, z80_size(inst));
1253+ } else if (src_op.mode == MODE_IMMED) {
1254+ xor_ir(code, src_op.disp, opts->gen.scratch2, z80_size(inst));
1255+ } else {
1256+ xor_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch2, z80_size(inst));
1257+ }
1258+ bt_ir(code, 4, opts->gen.scratch2, SZ_B);
1259+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
1260+ z80_save_reg(inst, opts);
1261+ z80_save_ea(code, inst, opts);
1262+ break;
1263+ case Z80_INC:
1264+ case Z80_DEC:
1265+ if(z80_size(inst) == SZ_W) {
1266+ num_cycles += 2;
1267+ } else if (inst->addr_mode == Z80_REG_INDIRECT) {
1268+ num_cycles += 1;
1269+ } else if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
1270+ num_cycles += 9;
1271+ }
1272+ cycles(&opts->gen, num_cycles);
1273+ translate_z80_reg(inst, &dst_op, opts);
1274+ if (dst_op.mode == MODE_UNUSED) {
1275+ translate_z80_ea(inst, &dst_op, opts, READ, MODIFY);
1276+ }
1277+ if (z80_size(inst) == SZ_B) {
1278+ if (dst_op.mode == MODE_REG_DIRECT) {
1279+ if (dst_op.base >= AH && dst_op.base <= BH) {
1280+ mov_rr(code, dst_op.base - AH, opts->gen.scratch2, SZ_W);
1281+ } else {
1282+ mov_rr(code, dst_op.base, opts->gen.scratch2, SZ_B);
1283+ }
1284+ } else {
1285+ mov_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch2, SZ_B);
1286+ }
1287+ }
1288+ if (inst->op == Z80_INC) {
1289+ if (dst_op.mode == MODE_REG_DIRECT) {
1290+ add_ir(code, 1, dst_op.base, z80_size(inst));
1291+ } else {
1292+ add_irdisp(code, 1, dst_op.base, dst_op.disp, z80_size(inst));
1293+ }
1294+ } else {
1295+ if (dst_op.mode == MODE_REG_DIRECT) {
1296+ sub_ir(code, 1, dst_op.base, z80_size(inst));
1297+ } else {
1298+ sub_irdisp(code, 1, dst_op.base, dst_op.disp, z80_size(inst));
1299+ }
1300+ }
1301+ if (z80_size(inst) == SZ_B) {
1302+ mov_irdisp(code, inst->op == Z80_DEC, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
1303+ setcc_rdisp(code, CC_O, opts->gen.context_reg, zf_off(ZF_PV));
1304+ setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
1305+ setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
1306+ int bit = 4;
1307+ if (dst_op.mode == MODE_REG_DIRECT) {
1308+ mov_rrdisp(code, dst_op.base, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1309+ if (dst_op.base >= AH && dst_op.base <= BH) {
1310+ bit = 12;
1311+ xor_rr(code, dst_op.base - AH, opts->gen.scratch2, SZ_W);
1312+ } else {
1313+ xor_rr(code, dst_op.base, opts->gen.scratch2, SZ_B);
1314+ }
1315+ } else {
1316+ mov_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch1, SZ_B);
1317+ xor_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch2, SZ_B);
1318+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1319+ }
1320+ bt_ir(code, bit, opts->gen.scratch2, SZ_W);
1321+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
1322+ }
1323+ z80_save_reg(inst, opts);
1324+ z80_save_ea(code, inst, opts);
1325+ z80_save_result(opts, inst);
1326+ break;
1327+ case Z80_DAA: {
1328+ cycles(&opts->gen, num_cycles);
1329+ xor_rr(code, opts->gen.scratch2, opts->gen.scratch2, SZ_B);
1330+ zreg_to_native(opts, Z80_A, opts->gen.scratch1);
1331+ and_ir(code, 0xF, opts->gen.scratch1, SZ_B);
1332+ cmp_ir(code, 0xA, opts->gen.scratch1, SZ_B);
1333+ mov_ir(code, 0xA0, opts->gen.scratch1, SZ_B);
1334+ code_ptr corf_low_range = code->cur + 1;
1335+ jcc(code, CC_NC, code->cur+2);
1336+ cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
1337+ code_ptr corf_low = code->cur + 1;
1338+ jcc(code, CC_NZ, code->cur+2);
1339+ code_ptr no_corf_low = code->cur + 1;
1340+ jmp(code, code->cur + 2);
1341+
1342+ *corf_low_range = code->cur - (corf_low_range + 1);
1343+ mov_ir(code, 0x90, opts->gen.scratch1, SZ_B);
1344+ *corf_low = code->cur - (corf_low + 1);
1345+ mov_ir(code, 0x06, opts->gen.scratch2, SZ_B);
1346+
1347+ *no_corf_low = code->cur - (no_corf_low + 1);
1348+ cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
1349+ code_ptr corf_high = code->cur+1;
1350+ jcc(code, CC_NZ, code->cur+2);
1351+ cmp_rr(code, opts->gen.scratch1, opts->regs[Z80_A], SZ_B);
1352+ code_ptr no_corf_high = code->cur+1;
1353+ jcc(code, CC_C, code->cur+2);
1354+ *corf_high = code->cur - (corf_high + 1);
1355+ or_ir(code, 0x60, opts->gen.scratch2, SZ_B);
1356+ mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
1357+ *no_corf_high = code->cur - (no_corf_high + 1);
1358+
1359+ mov_rr(code, opts->regs[Z80_A], opts->gen.scratch1, SZ_B);
1360+ xor_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_B);
1361+
1362+ cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
1363+ code_ptr not_sub = code->cur+1;
1364+ jcc(code, CC_Z, code->cur+2);
1365+ neg_r(code, opts->gen.scratch2, SZ_B);
1366+ *not_sub = code->cur - (not_sub + 1);
1367+
1368+ add_rr(code, opts->gen.scratch2, opts->regs[Z80_A], SZ_B);
1369+ setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
1370+ setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
1371+ setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
1372+ xor_rr(code, opts->regs[Z80_A], opts->gen.scratch1, SZ_B);
1373+ bt_ir(code, 4, opts->gen.scratch1, SZ_B);
1374+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
1375+ mov_rrdisp(code, opts->regs[Z80_A], opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1376+ break;
1377+ }
1378+ case Z80_CPL:
1379+ cycles(&opts->gen, num_cycles);
1380+ not_r(code, opts->regs[Z80_A], SZ_B);
1381+ mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
1382+ mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
1383+ mov_rrdisp(code, opts->regs[Z80_A], opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1384+ break;
1385+ case Z80_NEG:
1386+ cycles(&opts->gen, num_cycles);
1387+ mov_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B);
1388+ neg_r(code, opts->regs[Z80_A], SZ_B);
1389+ mov_rrdisp(code, opts->regs[Z80_A], opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1390+ setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
1391+ setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
1392+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
1393+ setcc_rdisp(code, CC_O, opts->gen.context_reg, zf_off(ZF_PV));
1394+ mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
1395+ xor_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B);
1396+ bt_ir(code, 4, opts->gen.scratch2, SZ_B);
1397+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
1398+ break;
1399+ case Z80_CCF:
1400+ cycles(&opts->gen, num_cycles);
1401+ mov_rdispr(code, opts->gen.context_reg, zf_off(ZF_C), opts->gen.scratch1, SZ_B);
1402+ xor_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
1403+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
1404+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
1405+ mov_rrdisp(code, opts->regs[Z80_A], opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1406+ break;
1407+ case Z80_SCF:
1408+ cycles(&opts->gen, num_cycles);
1409+ mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
1410+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
1411+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
1412+ mov_rrdisp(code, opts->regs[Z80_A], opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1413+ break;
1414+ case Z80_NOP:
1415+ cycles(&opts->gen, num_cycles);
1416+ break;
1417+ case Z80_HALT: {
1418+ code_ptr loop_top = code->cur;
1419+ //this isn't terribly efficient, but it's good enough for now
1420+ cycles(&opts->gen, num_cycles);
1421+ check_cycles_int(&opts->gen, address+1);
1422+ jmp(code, loop_top);
1423+ break;
1424+ }
1425+ case Z80_DI:
1426+ cycles(&opts->gen, num_cycles);
1427+ mov_irdisp(code, 0, opts->gen.context_reg, offsetof(z80_context, iff1), SZ_B);
1428+ mov_irdisp(code, 0, opts->gen.context_reg, offsetof(z80_context, iff2), SZ_B);
1429+ //turn cycles remaining into current cycle
1430+ neg_r(code, opts->gen.cycles, SZ_D);
1431+ add_rdispr(code, opts->gen.context_reg, offsetof(z80_context, target_cycle), opts->gen.cycles, SZ_D);
1432+ //set interrupt cycle to never and fetch the new target cycle from sync_cycle
1433+ mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, sync_cycle), opts->gen.scratch1, SZ_D);
1434+ mov_irdisp(code, 0xFFFFFFFF, opts->gen.context_reg, offsetof(z80_context, int_cycle), SZ_D);
1435+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(z80_context, target_cycle), SZ_D);
1436+ //turn current cycle back into cycles remaining
1437+ neg_r(code, opts->gen.cycles, SZ_D);
1438+ add_rr(code, opts->gen.scratch1, opts->gen.cycles, SZ_D);
1439+ break;
1440+ case Z80_EI:
1441+ cycles(&opts->gen, num_cycles);
1442+ neg_r(code, opts->gen.cycles, SZ_D);
1443+ add_rdispr(code, opts->gen.context_reg, offsetof(z80_context, target_cycle), opts->gen.cycles, SZ_D);
1444+ mov_rrdisp(code, opts->gen.cycles, opts->gen.context_reg, offsetof(z80_context, int_enable_cycle), SZ_D);
1445+ neg_r(code, opts->gen.cycles, SZ_D);
1446+ add_rdispr(code, opts->gen.context_reg, offsetof(z80_context, target_cycle), opts->gen.cycles, SZ_D);
1447+ mov_irdisp(code, 1, opts->gen.context_reg, offsetof(z80_context, iff1), SZ_B);
1448+ mov_irdisp(code, 1, opts->gen.context_reg, offsetof(z80_context, iff2), SZ_B);
1449+ //interrupt enable has a one-instruction latency, minimum instruction duration is 4 cycles
1450+ add_irdisp(code, 4*opts->gen.clock_divider, opts->gen.context_reg, offsetof(z80_context, int_enable_cycle), SZ_D);
1451+ call(code, opts->do_sync);
1452+ break;
1453+ case Z80_IM:
1454+ cycles(&opts->gen, num_cycles);
1455+ mov_irdisp(code, inst->immed, opts->gen.context_reg, offsetof(z80_context, im), SZ_B);
1456+ break;
1457+ case Z80_RLC:
1458+ if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
1459+ num_cycles += 8;
1460+ }
1461+ cycles(&opts->gen, num_cycles);
1462+ if (inst->addr_mode != Z80_UNUSED) {
1463+ translate_z80_ea(inst, &dst_op, opts, READ, MODIFY);
1464+ translate_z80_reg(inst, &src_op, opts); //For IX/IY variants that also write to a register
1465+ cycles(&opts->gen, 1);
1466+ } else {
1467+ src_op.mode = MODE_UNUSED;
1468+ translate_z80_reg(inst, &dst_op, opts);
1469+ }
1470+ if (dst_op.mode == MODE_REG_DIRECT) {
1471+ rol_ir(code, 1, dst_op.base, SZ_B);
1472+ mov_rrdisp(code, dst_op.base, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1473+ } else {
1474+ rol_irdisp(code, 1, dst_op.base, dst_op.disp, SZ_B);
1475+ mov_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch1, SZ_B);
1476+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1477+ }
1478+ if (src_op.mode == MODE_REG_DIRECT) {
1479+ mov_rr(code, dst_op.base, src_op.base, SZ_B);
1480+ } else if(src_op.mode == MODE_REG_DISPLACE8) {
1481+ mov_rrdisp(code, dst_op.base, src_op.base, src_op.disp, SZ_B);
1482+ }
1483+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
1484+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
1485+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
1486+ if (inst->immed) {
1487+ //rlca does not set these flags
1488+ if (dst_op.mode == MODE_REG_DIRECT) {
1489+ cmp_ir(code, 0, dst_op.base, SZ_B);
1490+ } else {
1491+ cmp_irdisp(code, 0, dst_op.base, dst_op.disp, SZ_B);
1492+ }
1493+ setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
1494+ setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
1495+ setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
1496+ }
1497+ if (inst->addr_mode != Z80_UNUSED) {
1498+ z80_save_result(opts, inst);
1499+ if (src_op.mode != MODE_UNUSED) {
1500+ z80_save_reg(inst, opts);
1501+ }
1502+ } else {
1503+ z80_save_reg(inst, opts);
1504+ }
1505+ break;
1506+ case Z80_RL:
1507+ if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
1508+ num_cycles += 8;
1509+ }
1510+ cycles(&opts->gen, num_cycles);
1511+ if (inst->addr_mode != Z80_UNUSED) {
1512+ translate_z80_ea(inst, &dst_op, opts, READ, MODIFY);
1513+ translate_z80_reg(inst, &src_op, opts); //For IX/IY variants that also write to a register
1514+ cycles(&opts->gen, 1);
1515+ } else {
1516+ src_op.mode = MODE_UNUSED;
1517+ translate_z80_reg(inst, &dst_op, opts);
1518+ }
1519+ bt_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
1520+ if (dst_op.mode == MODE_REG_DIRECT) {
1521+ rcl_ir(code, 1, dst_op.base, SZ_B);
1522+ mov_rrdisp(code, dst_op.base, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1523+ } else {
1524+ rcl_irdisp(code, 1, dst_op.base, dst_op.disp, SZ_B);
1525+ mov_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch1, SZ_B);
1526+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1527+ }
1528+ if (src_op.mode == MODE_REG_DIRECT) {
1529+ mov_rr(code, dst_op.base, src_op.base, SZ_B);
1530+ } else if(src_op.mode == MODE_REG_DISPLACE8) {
1531+ mov_rrdisp(code, dst_op.base, src_op.base, src_op.disp, SZ_B);
1532+ }
1533+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
1534+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
1535+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
1536+ if (inst->immed) {
1537+ //rla does not set these flags
1538+ if (dst_op.mode == MODE_REG_DIRECT) {
1539+ cmp_ir(code, 0, dst_op.base, SZ_B);
1540+ } else {
1541+ cmp_irdisp(code, 0, dst_op.base, dst_op.disp, SZ_B);
1542+ }
1543+ setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
1544+ setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
1545+ setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
1546+ }
1547+ if (inst->addr_mode != Z80_UNUSED) {
1548+ z80_save_result(opts, inst);
1549+ if (src_op.mode != MODE_UNUSED) {
1550+ z80_save_reg(inst, opts);
1551+ }
1552+ } else {
1553+ z80_save_reg(inst, opts);
1554+ }
1555+ break;
1556+ case Z80_RRC:
1557+ if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
1558+ num_cycles += 8;
1559+ }
1560+ cycles(&opts->gen, num_cycles);
1561+ if (inst->addr_mode != Z80_UNUSED) {
1562+ translate_z80_ea(inst, &dst_op, opts, READ, MODIFY);
1563+ translate_z80_reg(inst, &src_op, opts); //For IX/IY variants that also write to a register
1564+ cycles(&opts->gen, 1);
1565+ } else {
1566+ src_op.mode = MODE_UNUSED;
1567+ translate_z80_reg(inst, &dst_op, opts);
1568+ }
1569+ if (dst_op.mode == MODE_REG_DIRECT) {
1570+ ror_ir(code, 1, dst_op.base, SZ_B);
1571+ mov_rrdisp(code, dst_op.base, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1572+ } else {
1573+ ror_irdisp(code, 1, dst_op.base, dst_op.disp, SZ_B);
1574+ mov_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch1, SZ_B);
1575+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1576+ }
1577+ if (src_op.mode == MODE_REG_DIRECT) {
1578+ mov_rr(code, dst_op.base, src_op.base, SZ_B);
1579+ } else if(src_op.mode == MODE_REG_DISPLACE8) {
1580+ mov_rrdisp(code, dst_op.base, src_op.base, src_op.disp, SZ_B);
1581+ }
1582+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
1583+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
1584+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
1585+ if (inst->immed) {
1586+ //rrca does not set these flags
1587+ if (dst_op.mode == MODE_REG_DIRECT) {
1588+ cmp_ir(code, 0, dst_op.base, SZ_B);
1589+ } else {
1590+ cmp_irdisp(code, 0, dst_op.base, dst_op.disp, SZ_B);
1591+ }
1592+ setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
1593+ setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
1594+ setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
1595+ }
1596+ if (inst->addr_mode != Z80_UNUSED) {
1597+ z80_save_result(opts, inst);
1598+ if (src_op.mode != MODE_UNUSED) {
1599+ z80_save_reg(inst, opts);
1600+ }
1601+ } else {
1602+ z80_save_reg(inst, opts);
1603+ }
1604+ break;
1605+ case Z80_RR:
1606+ if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
1607+ num_cycles += 8;
1608+ }
1609+ cycles(&opts->gen, num_cycles);
1610+ if (inst->addr_mode != Z80_UNUSED) {
1611+ translate_z80_ea(inst, &dst_op, opts, READ, MODIFY);
1612+ translate_z80_reg(inst, &src_op, opts); //For IX/IY variants that also write to a register
1613+ cycles(&opts->gen, 1);
1614+ } else {
1615+ src_op.mode = MODE_UNUSED;
1616+ translate_z80_reg(inst, &dst_op, opts);
1617+ }
1618+ bt_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
1619+ if (dst_op.mode == MODE_REG_DIRECT) {
1620+ rcr_ir(code, 1, dst_op.base, SZ_B);
1621+ mov_rrdisp(code, dst_op.base, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1622+ } else {
1623+ rcr_irdisp(code, 1, dst_op.base, dst_op.disp, SZ_B);
1624+ mov_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch1, SZ_B);
1625+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1626+ }
1627+ if (src_op.mode == MODE_REG_DIRECT) {
1628+ mov_rr(code, dst_op.base, src_op.base, SZ_B);
1629+ } else if(src_op.mode == MODE_REG_DISPLACE8) {
1630+ mov_rrdisp(code, dst_op.base, src_op.base, src_op.disp, SZ_B);
1631+ }
1632+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
1633+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
1634+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
1635+ if (inst->immed) {
1636+ //rra does not set these flags
1637+ if (dst_op.mode == MODE_REG_DIRECT) {
1638+ cmp_ir(code, 0, dst_op.base, SZ_B);
1639+ } else {
1640+ cmp_irdisp(code, 0, dst_op.base, dst_op.disp, SZ_B);
1641+ }
1642+ setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
1643+ setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
1644+ setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
1645+ }
1646+ if (inst->addr_mode != Z80_UNUSED) {
1647+ z80_save_result(opts, inst);
1648+ if (src_op.mode != MODE_UNUSED) {
1649+ z80_save_reg(inst, opts);
1650+ }
1651+ } else {
1652+ z80_save_reg(inst, opts);
1653+ }
1654+ break;
1655+ case Z80_SLA:
1656+ case Z80_SLL:
1657+ if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
1658+ num_cycles += 8;
1659+ }
1660+ cycles(&opts->gen, num_cycles);
1661+ if (inst->addr_mode != Z80_UNUSED) {
1662+ translate_z80_ea(inst, &dst_op, opts, READ, MODIFY);
1663+ translate_z80_reg(inst, &src_op, opts); //For IX/IY variants that also write to a register
1664+ cycles(&opts->gen, 1);
1665+ } else {
1666+ src_op.mode = MODE_UNUSED;
1667+ translate_z80_reg(inst, &dst_op, opts);
1668+ }
1669+ if (dst_op.mode == MODE_REG_DIRECT) {
1670+ shl_ir(code, 1, dst_op.base, SZ_B);
1671+ } else {
1672+ shl_irdisp(code, 1, dst_op.base, dst_op.disp, SZ_B);
1673+ }
1674+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
1675+ if (inst->op == Z80_SLL) {
1676+ if (dst_op.mode == MODE_REG_DIRECT) {
1677+ or_ir(code, 1, dst_op.base, SZ_B);
1678+ } else {
1679+ or_irdisp(code, 1, dst_op.base, dst_op.disp, SZ_B);
1680+ }
1681+ }
1682+ if (src_op.mode == MODE_REG_DIRECT) {
1683+ mov_rr(code, dst_op.base, src_op.base, SZ_B);
1684+ } else if(src_op.mode == MODE_REG_DISPLACE8) {
1685+ mov_rrdisp(code, dst_op.base, src_op.base, src_op.disp, SZ_B);
1686+ }
1687+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
1688+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
1689+ if (dst_op.mode == MODE_REG_DIRECT) {
1690+ mov_rrdisp(code, dst_op.base, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1691+ cmp_ir(code, 0, dst_op.base, SZ_B);
1692+ } else {
1693+ mov_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch1, SZ_B);
1694+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1695+ cmp_irdisp(code, 0, dst_op.base, dst_op.disp, SZ_B);
1696+ }
1697+ setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
1698+ setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
1699+ setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
1700+ if (inst->addr_mode != Z80_UNUSED) {
1701+ z80_save_result(opts, inst);
1702+ if (src_op.mode != MODE_UNUSED) {
1703+ z80_save_reg(inst, opts);
1704+ }
1705+ } else {
1706+ z80_save_reg(inst, opts);
1707+ }
1708+ break;
1709+ case Z80_SRA:
1710+ if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
1711+ num_cycles += 8;
1712+ }
1713+ cycles(&opts->gen, num_cycles);
1714+ if (inst->addr_mode != Z80_UNUSED) {
1715+ translate_z80_ea(inst, &dst_op, opts, READ, MODIFY);
1716+ translate_z80_reg(inst, &src_op, opts); //For IX/IY variants that also write to a register
1717+ cycles(&opts->gen, 1);
1718+ } else {
1719+ src_op.mode = MODE_UNUSED;
1720+ translate_z80_reg(inst, &dst_op, opts);
1721+ }
1722+ if (dst_op.mode == MODE_REG_DIRECT) {
1723+ sar_ir(code, 1, dst_op.base, SZ_B);
1724+ } else {
1725+ sar_irdisp(code, 1, dst_op.base, dst_op.disp, SZ_B);
1726+ }
1727+ if (src_op.mode == MODE_REG_DIRECT) {
1728+ mov_rr(code, dst_op.base, src_op.base, SZ_B);
1729+ } else if(src_op.mode == MODE_REG_DISPLACE8) {
1730+ mov_rrdisp(code, dst_op.base, src_op.base, src_op.disp, SZ_B);
1731+ }
1732+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
1733+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
1734+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
1735+ if (dst_op.mode == MODE_REG_DIRECT) {
1736+ mov_rrdisp(code, dst_op.base, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1737+ cmp_ir(code, 0, dst_op.base, SZ_B);
1738+ } else {
1739+ mov_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch1, SZ_B);
1740+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1741+ cmp_irdisp(code, 0, dst_op.base, dst_op.disp, SZ_B);
1742+ }
1743+ setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
1744+ setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
1745+ setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
1746+ if (inst->addr_mode != Z80_UNUSED) {
1747+ z80_save_result(opts, inst);
1748+ if (src_op.mode != MODE_UNUSED) {
1749+ z80_save_reg(inst, opts);
1750+ }
1751+ } else {
1752+ z80_save_reg(inst, opts);
1753+ }
1754+ break;
1755+ case Z80_SRL:
1756+ if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
1757+ num_cycles += 8;
1758+ }
1759+ cycles(&opts->gen, num_cycles);
1760+ if (inst->addr_mode != Z80_UNUSED) {
1761+ translate_z80_ea(inst, &dst_op, opts, READ, MODIFY);
1762+ translate_z80_reg(inst, &src_op, opts); //For IX/IY variants that also write to a register
1763+ cycles(&opts->gen, 1);
1764+ } else {
1765+ src_op.mode = MODE_UNUSED;
1766+ translate_z80_reg(inst, &dst_op, opts);
1767+ }
1768+ if (dst_op.mode == MODE_REG_DIRECT) {
1769+ shr_ir(code, 1, dst_op.base, SZ_B);
1770+ } else {
1771+ shr_irdisp(code, 1, dst_op.base, dst_op.disp, SZ_B);
1772+ }
1773+ if (src_op.mode == MODE_REG_DIRECT) {
1774+ mov_rr(code, dst_op.base, src_op.base, SZ_B);
1775+ } else if(src_op.mode == MODE_REG_DISPLACE8) {
1776+ mov_rrdisp(code, dst_op.base, src_op.base, src_op.disp, SZ_B);
1777+ }
1778+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
1779+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
1780+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
1781+ if (dst_op.mode == MODE_REG_DIRECT) {
1782+ mov_rrdisp(code, dst_op.base, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1783+ cmp_ir(code, 0, dst_op.base, SZ_B);
1784+ } else {
1785+ mov_rdispr(code, dst_op.base, dst_op.disp, opts->gen.scratch1, SZ_B);
1786+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1787+ cmp_irdisp(code, 0, dst_op.base, dst_op.disp, SZ_B);
1788+ }
1789+ setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
1790+ setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
1791+ setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
1792+ if (inst->addr_mode != Z80_UNUSED) {
1793+ z80_save_result(opts, inst);
1794+ if (src_op.mode != MODE_UNUSED) {
1795+ z80_save_reg(inst, opts);
1796+ }
1797+ } else {
1798+ z80_save_reg(inst, opts);
1799+ }
1800+ break;
1801+ case Z80_RLD:
1802+ cycles(&opts->gen, num_cycles);
1803+ zreg_to_native(opts, Z80_HL, opts->gen.scratch1);
1804+ call(code, opts->read_8);
1805+ //Before: (HL) = 0x12, A = 0x34
1806+ //After: (HL) = 0x24, A = 0x31
1807+ zreg_to_native(opts, Z80_A, opts->gen.scratch2);
1808+ shl_ir(code, 4, opts->gen.scratch1, SZ_W);
1809+ and_ir(code, 0xF, opts->gen.scratch2, SZ_W);
1810+ and_ir(code, 0xFFF, opts->gen.scratch1, SZ_W);
1811+ and_ir(code, 0xF0, opts->regs[Z80_A], SZ_B);
1812+ or_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_W);
1813+ //opts->gen.scratch1 = 0x0124
1814+ ror_ir(code, 8, opts->gen.scratch1, SZ_W);
1815+ cycles(&opts->gen, 4);
1816+ or_rr(code, opts->gen.scratch1, opts->regs[Z80_A], SZ_B);
1817+ //set flags
1818+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
1819+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
1820+ setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
1821+ setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
1822+ setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
1823+ mov_rrdisp(code, opts->regs[Z80_A], opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1824+
1825+ zreg_to_native(opts, Z80_HL, opts->gen.scratch2);
1826+ ror_ir(code, 8, opts->gen.scratch1, SZ_W);
1827+ call(code, opts->write_8);
1828+ break;
1829+ case Z80_RRD:
1830+ cycles(&opts->gen, num_cycles);
1831+ zreg_to_native(opts, Z80_HL, opts->gen.scratch1);
1832+ call(code, opts->read_8);
1833+ //Before: (HL) = 0x12, A = 0x34
1834+ //After: (HL) = 0x41, A = 0x32
1835+ zreg_to_native(opts, Z80_A, opts->gen.scratch2);
1836+ ror_ir(code, 4, opts->gen.scratch1, SZ_W);
1837+ shl_ir(code, 4, opts->gen.scratch2, SZ_W);
1838+ and_ir(code, 0xF00F, opts->gen.scratch1, SZ_W);
1839+ and_ir(code, 0xF0, opts->regs[Z80_A], SZ_B);
1840+ and_ir(code, 0xF0, opts->gen.scratch2, SZ_W);
1841+ //opts->gen.scratch1 = 0x2001
1842+ //opts->gen.scratch2 = 0x0040
1843+ or_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_W);
1844+ //opts->gen.scratch1 = 0x2041
1845+ ror_ir(code, 8, opts->gen.scratch1, SZ_W);
1846+ cycles(&opts->gen, 4);
1847+ shr_ir(code, 4, opts->gen.scratch1, SZ_B);
1848+ or_rr(code, opts->gen.scratch1, opts->regs[Z80_A], SZ_B);
1849+ //set flags
1850+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
1851+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
1852+ setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
1853+ setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
1854+ setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
1855+ mov_rrdisp(code, opts->regs[Z80_A], opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1856+
1857+ zreg_to_native(opts, Z80_HL, opts->gen.scratch2);
1858+ ror_ir(code, 8, opts->gen.scratch1, SZ_W);
1859+ call(code, opts->write_8);
1860+ break;
1861+ case Z80_BIT: {
1862+ if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
1863+ num_cycles += 4;
1864+ }
1865+ cycles(&opts->gen, num_cycles);
1866+ uint8_t bit;
1867+ if ((inst->addr_mode & 0x1F) == Z80_REG && opts->regs[inst->ea_reg] >= AH && opts->regs[inst->ea_reg] <= BH) {
1868+ src_op.base = opts->regs[z80_word_reg(inst->ea_reg)];
1869+ src_op.mode = MODE_REG_DIRECT;
1870+ size = SZ_W;
1871+ bit = inst->immed + 8;
1872+ } else {
1873+ size = SZ_B;
1874+ bit = inst->immed;
1875+ translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY);
1876+ }
1877+ if (inst->addr_mode != Z80_REG) {
1878+ //Reads normally take 3 cycles, but the read at the end of a bit instruction takes 4
1879+ cycles(&opts->gen, 1);
1880+ }
1881+ if (src_op.mode == MODE_REG_DIRECT) {
1882+ bt_ir(code, bit, src_op.base, size);
1883+ } else {
1884+ bt_irdisp(code, bit, src_op.base, src_op.disp, size);
1885+ }
1886+ setcc_rdisp(code, CC_NC, opts->gen.context_reg, zf_off(ZF_Z));
1887+ setcc_rdisp(code, CC_NC, opts->gen.context_reg, zf_off(ZF_PV));
1888+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
1889+ mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
1890+ if (inst->immed == 7) {
1891+ if (src_op.mode == MODE_REG_DIRECT) {
1892+ cmp_ir(code, 0, src_op.base, size);
1893+ } else {
1894+ cmp_irdisp(code, 0, src_op.base, src_op.disp, size);
1895+ }
1896+ setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
1897+ } else {
1898+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_S), SZ_B);
1899+ }
1900+
1901+ if ((inst->addr_mode & 0x1F) == Z80_REG) {
1902+ if (src_op.mode == MODE_REG_DIRECT) {
1903+ if (size == SZ_W) {
1904+ mov_rr(code, src_op.base, opts->gen.scratch1, SZ_W);
1905+ shr_ir(code, 8, opts->gen.scratch1, SZ_W);
1906+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1907+ } else {
1908+ mov_rrdisp(code, src_op.base, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1909+ }
1910+ } else {
1911+ mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, SZ_B);
1912+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1913+ }
1914+ } else if((inst->addr_mode & 0x1F) != Z80_REG_INDIRECT) {
1915+ zreg_to_native(opts, (inst->addr_mode & 0x1F) == Z80_IX_DISPLACE ? Z80_IX : Z80_IY, opts->gen.scratch2);
1916+ add_ir(code, inst->ea_reg & 0x80 ? inst->ea_reg - 256 : inst->ea_reg, opts->gen.scratch2, SZ_W);
1917+ shr_ir(code, 8, opts->gen.scratch2, SZ_W);
1918+ mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
1919+ }
1920+ break;
1921+ }
1922+ case Z80_SET: {
1923+ if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
1924+ num_cycles += 4;
1925+ }
1926+ cycles(&opts->gen, num_cycles);
1927+ uint8_t bit;
1928+ if ((inst->addr_mode & 0x1F) == Z80_REG && opts->regs[inst->ea_reg] >= AH && opts->regs[inst->ea_reg] <= BH) {
1929+ src_op.base = opts->regs[z80_word_reg(inst->ea_reg)];
1930+ src_op.mode = MODE_REG_DIRECT;
1931+ size = SZ_W;
1932+ bit = inst->immed + 8;
1933+ } else {
1934+ size = SZ_B;
1935+ bit = inst->immed;
1936+ translate_z80_ea(inst, &src_op, opts, READ, MODIFY);
1937+ }
1938+ if (inst->reg != Z80_USE_IMMED) {
1939+ translate_z80_reg(inst, &dst_op, opts);
1940+ }
1941+ if (inst->addr_mode != Z80_REG) {
1942+ //Reads normally take 3 cycles, but the read in the middle of a set instruction takes 4
1943+ cycles(&opts->gen, 1);
1944+ }
1945+ if (src_op.mode == MODE_REG_DIRECT) {
1946+ bts_ir(code, bit, src_op.base, size);
1947+ } else {
1948+ bts_irdisp(code, bit, src_op.base, src_op.disp, size);
1949+ }
1950+ if (inst->reg != Z80_USE_IMMED) {
1951+ if (size == SZ_W) {
1952+#ifdef X86_64
1953+ if (dst_op.base >= R8) {
1954+ ror_ir(code, 8, src_op.base, SZ_W);
1955+ mov_rr(code, opts->regs[z80_low_reg(inst->ea_reg)], dst_op.base, SZ_B);
1956+ ror_ir(code, 8, src_op.base, SZ_W);
1957+ } else {
1958+#endif
1959+ if (dst_op.mode == MODE_REG_DIRECT) {
1960+ zreg_to_native(opts, inst->ea_reg, dst_op.base);
1961+ } else {
1962+ zreg_to_native(opts, inst->ea_reg, opts->gen.scratch1);
1963+ mov_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, SZ_B);
1964+ }
1965+#ifdef X86_64
1966+ }
1967+#endif
1968+ } else {
1969+ if (dst_op.mode == MODE_REG_DIRECT) {
1970+ if (src_op.mode == MODE_REG_DIRECT) {
1971+ mov_rr(code, src_op.base, dst_op.base, SZ_B);
1972+ } else {
1973+ mov_rdispr(code, src_op.base, src_op.disp, dst_op.base, SZ_B);
1974+ }
1975+ } else if (src_op.mode == MODE_REG_DIRECT) {
1976+ mov_rrdisp(code, src_op.base, dst_op.base, dst_op.disp, SZ_B);
1977+ } else {
1978+ mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, SZ_B);
1979+ mov_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, SZ_B);
1980+ }
1981+ }
1982+ }
1983+ if ((inst->addr_mode & 0x1F) != Z80_REG) {
1984+ z80_save_result(opts, inst);
1985+ if (inst->reg != Z80_USE_IMMED) {
1986+ z80_save_reg(inst, opts);
1987+ }
1988+ }
1989+ break;
1990+ }
1991+ case Z80_RES: {
1992+ if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
1993+ num_cycles += 4;
1994+ }
1995+ cycles(&opts->gen, num_cycles);
1996+ uint8_t bit;
1997+ if ((inst->addr_mode & 0x1F) == Z80_REG && opts->regs[inst->ea_reg] >= AH && opts->regs[inst->ea_reg] <= BH) {
1998+ src_op.base = opts->regs[z80_word_reg(inst->ea_reg)];
1999+ src_op.mode = MODE_REG_DIRECT;
2000+ size = SZ_W;
2001+ bit = inst->immed + 8;
2002+ } else {
2003+ size = SZ_B;
2004+ bit = inst->immed;
2005+ translate_z80_ea(inst, &src_op, opts, READ, MODIFY);
2006+ }
2007+ if (inst->reg != Z80_USE_IMMED) {
2008+ translate_z80_reg(inst, &dst_op, opts);
2009+ }
2010+ if (inst->addr_mode != Z80_REG) {
2011+ //Reads normally take 3 cycles, but the read in the middle of a set instruction takes 4
2012+ cycles(&opts->gen, 1);
2013+ }
2014+ if (src_op.mode == MODE_REG_DIRECT) {
2015+ btr_ir(code, bit, src_op.base, size);
2016+ } else {
2017+ btr_irdisp(code, bit, src_op.base, src_op.disp, size);
2018+ }
2019+ if (inst->reg != Z80_USE_IMMED) {
2020+ if (size == SZ_W) {
2021+#ifdef X86_64
2022+ if (dst_op.base >= R8) {
2023+ ror_ir(code, 8, src_op.base, SZ_W);
2024+ mov_rr(code, opts->regs[z80_low_reg(inst->ea_reg)], dst_op.base, SZ_B);
2025+ ror_ir(code, 8, src_op.base, SZ_W);
2026+ } else {
2027+#endif
2028+ if (dst_op.mode == MODE_REG_DIRECT) {
2029+ zreg_to_native(opts, inst->ea_reg, dst_op.base);
2030+ } else {
2031+ zreg_to_native(opts, inst->ea_reg, opts->gen.scratch1);
2032+ mov_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, SZ_B);
2033+ }
2034+#ifdef X86_64
2035+ }
2036+#endif
2037+ } else {
2038+ if (dst_op.mode == MODE_REG_DIRECT) {
2039+ if (src_op.mode == MODE_REG_DIRECT) {
2040+ mov_rr(code, src_op.base, dst_op.base, SZ_B);
2041+ } else {
2042+ mov_rdispr(code, src_op.base, src_op.disp, dst_op.base, SZ_B);
2043+ }
2044+ } else if (src_op.mode == MODE_REG_DIRECT) {
2045+ mov_rrdisp(code, src_op.base, dst_op.base, dst_op.disp, SZ_B);
2046+ } else {
2047+ mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, SZ_B);
2048+ mov_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, SZ_B);
2049+ }
2050+ }
2051+ }
2052+ if (inst->addr_mode != Z80_REG) {
2053+ z80_save_result(opts, inst);
2054+ if (inst->reg != Z80_USE_IMMED) {
2055+ z80_save_reg(inst, opts);
2056+ }
2057+ }
2058+ break;
2059+ }
2060+ case Z80_JP: {
2061+ if (inst->addr_mode != Z80_REG_INDIRECT) {
2062+ num_cycles += 6;
2063+ }
2064+ cycles(&opts->gen, num_cycles);
2065+ if (inst->addr_mode != Z80_REG_INDIRECT) {
2066+ code_ptr call_dst = z80_get_native_address(context, inst->immed);
2067+ if (!call_dst) {
2068+ opts->gen.deferred = defer_address(opts->gen.deferred, inst->immed, code->cur + 1);
2069+ //fake address to force large displacement
2070+ call_dst = code->cur + 256;
2071+ }
2072+ jmp(code, call_dst);
2073+ } else {
2074+ if (inst->addr_mode == Z80_REG_INDIRECT) {
2075+ zreg_to_native(opts, inst->ea_reg, opts->gen.scratch1);
2076+ } else {
2077+ mov_ir(code, inst->immed, opts->gen.scratch1, SZ_W);
2078+ }
2079+ call(code, opts->native_addr);
2080+ jmp_r(code, opts->gen.scratch1);
2081+ }
2082+ break;
2083+ }
2084+ case Z80_JPCC: {
2085+ cycles(&opts->gen, num_cycles + 6);//T States: 4,3,3
2086+ uint8_t cond = CC_Z;
2087+ switch (inst->reg)
2088+ {
2089+ case Z80_CC_NZ:
2090+ cond = CC_NZ;
2091+ case Z80_CC_Z:
2092+ cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_Z), SZ_B);
2093+ break;
2094+ case Z80_CC_NC:
2095+ cond = CC_NZ;
2096+ case Z80_CC_C:
2097+ cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
2098+ break;
2099+ case Z80_CC_PO:
2100+ cond = CC_NZ;
2101+ case Z80_CC_PE:
2102+ cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_PV), SZ_B);
2103+ break;
2104+ case Z80_CC_P:
2105+ cond = CC_NZ;
2106+ case Z80_CC_M:
2107+ cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_S), SZ_B);
2108+ break;
2109+ }
2110+ uint8_t *no_jump_off = code->cur+1;
2111+ jcc(code, cond, code->cur+2);
2112+ uint16_t dest_addr = inst->immed;
2113+ code_ptr call_dst = z80_get_native_address(context, dest_addr);
2114+ if (!call_dst) {
2115+ opts->gen.deferred = defer_address(opts->gen.deferred, dest_addr, code->cur + 1);
2116+ //fake address to force large displacement
2117+ call_dst = code->cur + 256;
2118+ }
2119+ jmp(code, call_dst);
2120+ *no_jump_off = code->cur - (no_jump_off+1);
2121+ break;
2122+ }
2123+ case Z80_JR: {
2124+ cycles(&opts->gen, num_cycles + 8);//T States: 4,3,5
2125+ uint16_t dest_addr = address + inst->immed + 2;
2126+ code_ptr call_dst = z80_get_native_address(context, dest_addr);
2127+ if (!call_dst) {
2128+ opts->gen.deferred = defer_address(opts->gen.deferred, dest_addr, code->cur + 1);
2129+ //fake address to force large displacement
2130+ call_dst = code->cur + 256;
2131+ }
2132+ jmp(code, call_dst);
2133+ break;
2134+ }
2135+ case Z80_JRCC: {
2136+ cycles(&opts->gen, num_cycles + 3);//T States: 4,3
2137+ uint8_t cond = CC_Z;
2138+ switch (inst->reg)
2139+ {
2140+ case Z80_CC_NZ:
2141+ cond = CC_NZ;
2142+ case Z80_CC_Z:
2143+ cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_Z), SZ_B);
2144+ break;
2145+ case Z80_CC_NC:
2146+ cond = CC_NZ;
2147+ case Z80_CC_C:
2148+ cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
2149+ break;
2150+ }
2151+ uint8_t *no_jump_off = code->cur+1;
2152+ jcc(code, cond, code->cur+2);
2153+ cycles(&opts->gen, 5);//T States: 5
2154+ uint16_t dest_addr = address + inst->immed + 2;
2155+ code_ptr call_dst = z80_get_native_address(context, dest_addr);
2156+ if (!call_dst) {
2157+ opts->gen.deferred = defer_address(opts->gen.deferred, dest_addr, code->cur + 1);
2158+ //fake address to force large displacement
2159+ call_dst = code->cur + 256;
2160+ }
2161+ jmp(code, call_dst);
2162+ *no_jump_off = code->cur - (no_jump_off+1);
2163+ break;
2164+ }
2165+ case Z80_DJNZ: {
2166+ cycles(&opts->gen, num_cycles + 4);//T States: 5,3
2167+ if (opts->regs[Z80_B] >= 0) {
2168+ sub_ir(code, 1, opts->regs[Z80_B], SZ_B);
2169+ } else {
2170+ sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_B), SZ_B);
2171+ }
2172+ uint8_t *no_jump_off = code->cur+1;
2173+ jcc(code, CC_Z, code->cur+2);
2174+ cycles(&opts->gen, 5);//T States: 5
2175+ uint16_t dest_addr = address + inst->immed + 2;
2176+ code_ptr call_dst = z80_get_native_address(context, dest_addr);
2177+ if (!call_dst) {
2178+ opts->gen.deferred = defer_address(opts->gen.deferred, dest_addr, code->cur + 1);
2179+ //fake address to force large displacement
2180+ call_dst = code->cur + 256;
2181+ }
2182+ jmp(code, call_dst);
2183+ *no_jump_off = code->cur - (no_jump_off+1);
2184+ break;
2185+ }
2186+ case Z80_CALL: {
2187+ cycles(&opts->gen, num_cycles + 7);//T States: 4,3,4
2188+ sub_ir(code, 2, opts->regs[Z80_SP], SZ_W);
2189+ mov_ir(code, address + 3, opts->gen.scratch1, SZ_W);
2190+ mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W);
2191+ call(code, opts->write_16_highfirst);//T States: 3, 3
2192+ code_ptr call_dst = z80_get_native_address(context, inst->immed);
2193+ if (!call_dst) {
2194+ opts->gen.deferred = defer_address(opts->gen.deferred, inst->immed, code->cur + 1);
2195+ //fake address to force large displacement
2196+ call_dst = code->cur + 256;
2197+ }
2198+ jmp(code, call_dst);
2199+ break;
2200+ }
2201+ case Z80_CALLCC: {
2202+ cycles(&opts->gen, num_cycles + 6);//T States: 4,3,3 (false case)
2203+ uint8_t cond = CC_Z;
2204+ switch (inst->reg)
2205+ {
2206+ case Z80_CC_NZ:
2207+ cond = CC_NZ;
2208+ case Z80_CC_Z:
2209+ cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_Z), SZ_B);
2210+ break;
2211+ case Z80_CC_NC:
2212+ cond = CC_NZ;
2213+ case Z80_CC_C:
2214+ cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
2215+ break;
2216+ case Z80_CC_PO:
2217+ cond = CC_NZ;
2218+ case Z80_CC_PE:
2219+ cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_PV), SZ_B);
2220+ break;
2221+ case Z80_CC_P:
2222+ cond = CC_NZ;
2223+ case Z80_CC_M:
2224+ cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_S), SZ_B);
2225+ break;
2226+ }
2227+ uint8_t *no_call_off = code->cur+1;
2228+ jcc(code, cond, code->cur+2);
2229+ cycles(&opts->gen, 1);//Last of the above T states takes an extra cycle in the true case
2230+ sub_ir(code, 2, opts->regs[Z80_SP], SZ_W);
2231+ mov_ir(code, address + 3, opts->gen.scratch1, SZ_W);
2232+ mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W);
2233+ call(code, opts->write_16_highfirst);//T States: 3, 3
2234+ code_ptr call_dst = z80_get_native_address(context, inst->immed);
2235+ if (!call_dst) {
2236+ opts->gen.deferred = defer_address(opts->gen.deferred, inst->immed, code->cur + 1);
2237+ //fake address to force large displacement
2238+ call_dst = code->cur + 256;
2239+ }
2240+ jmp(code, call_dst);
2241+ *no_call_off = code->cur - (no_call_off+1);
2242+ break;
2243+ }
2244+ case Z80_RET:
2245+ cycles(&opts->gen, num_cycles);//T States: 4
2246+ mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W);
2247+ call(code, opts->read_16);//T STates: 3, 3
2248+ add_ir(code, 2, opts->regs[Z80_SP], SZ_W);
2249+ call(code, opts->native_addr);
2250+ jmp_r(code, opts->gen.scratch1);
2251+ break;
2252+ case Z80_RETCC: {
2253+ cycles(&opts->gen, num_cycles + 1);//T States: 5
2254+ uint8_t cond = CC_Z;
2255+ switch (inst->reg)
2256+ {
2257+ case Z80_CC_NZ:
2258+ cond = CC_NZ;
2259+ case Z80_CC_Z:
2260+ cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_Z), SZ_B);
2261+ break;
2262+ case Z80_CC_NC:
2263+ cond = CC_NZ;
2264+ case Z80_CC_C:
2265+ cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B);
2266+ break;
2267+ case Z80_CC_PO:
2268+ cond = CC_NZ;
2269+ case Z80_CC_PE:
2270+ cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_PV), SZ_B);
2271+ break;
2272+ case Z80_CC_P:
2273+ cond = CC_NZ;
2274+ case Z80_CC_M:
2275+ cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_S), SZ_B);
2276+ break;
2277+ }
2278+ uint8_t *no_call_off = code->cur+1;
2279+ jcc(code, cond, code->cur+2);
2280+ mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W);
2281+ call(code, opts->read_16);//T STates: 3, 3
2282+ add_ir(code, 2, opts->regs[Z80_SP], SZ_W);
2283+ call(code, opts->native_addr);
2284+ jmp_r(code, opts->gen.scratch1);
2285+ *no_call_off = code->cur - (no_call_off+1);
2286+ break;
2287+ }
2288+ case Z80_RETI:
2289+ //For some systems, this may need a callback for signalling interrupt routine completion
2290+ cycles(&opts->gen, num_cycles);//T States: 4, 4
2291+ mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W);
2292+ call(code, opts->read_16);//T STates: 3, 3
2293+ add_ir(code, 2, opts->regs[Z80_SP], SZ_W);
2294+ call(code, opts->native_addr);
2295+ jmp_r(code, opts->gen.scratch1);
2296+ break;
2297+ case Z80_RETN:
2298+ cycles(&opts->gen, num_cycles);//T States: 4, 4
2299+ mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, iff2), opts->gen.scratch2, SZ_B);
2300+ mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W);
2301+ mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, offsetof(z80_context, iff1), SZ_B);
2302+ call(code, opts->read_16);//T STates: 3, 3
2303+ add_ir(code, 2, opts->regs[Z80_SP], SZ_W);
2304+ call(code, opts->native_addr);
2305+ jmp_r(code, opts->gen.scratch1);
2306+ break;
2307+ case Z80_RST: {
2308+ //RST is basically CALL to an address in page 0
2309+ cycles(&opts->gen, num_cycles + 1);//T States: 5
2310+ sub_ir(code, 2, opts->regs[Z80_SP], SZ_W);
2311+ mov_ir(code, address + 1, opts->gen.scratch1, SZ_W);
2312+ mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W);
2313+ call(code, opts->write_16_highfirst);//T States: 3, 3
2314+ code_ptr call_dst = z80_get_native_address(context, inst->immed);
2315+ if (!call_dst) {
2316+ opts->gen.deferred = defer_address(opts->gen.deferred, inst->immed, code->cur + 1);
2317+ //fake address to force large displacement
2318+ call_dst = code->cur + 256;
2319+ }
2320+ jmp(code, call_dst);
2321+ break;
2322+ }
2323+ case Z80_IN:
2324+ if (inst->addr_mode == Z80_IMMED_INDIRECT) {
2325+ num_cycles += 3;
2326+ }
2327+ cycles(&opts->gen, num_cycles);//T States: 4 3/4
2328+ if (inst->addr_mode == Z80_IMMED_INDIRECT) {
2329+ mov_ir(code, inst->immed, opts->gen.scratch1, SZ_B);
2330+ } else {
2331+ zreg_to_native(opts, Z80_C, opts->gen.scratch2);
2332+ }
2333+ call(code, opts->read_io);
2334+ if (inst->addr_mode != Z80_IMMED_INDIRECT) {
2335+ or_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_B);
2336+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_H), SZ_B);
2337+ mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);
2338+ setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
2339+ setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
2340+ setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
2341+ }
2342+ if (inst->reg != Z80_UNUSED) {
2343+ translate_z80_reg(inst, &dst_op, opts);
2344+ if (dst_op.mode == MODE_REG_DIRECT) {
2345+ mov_rr(code, opts->gen.scratch1, dst_op.base, SZ_B);
2346+ } else {
2347+ mov_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, SZ_B);
2348+ }
2349+ }
2350+ z80_save_reg(inst, opts);
2351+ break;
2352+ case Z80_INI:
2353+ cycles(&opts->gen, num_cycles + 1);//T States: 4, 5
2354+ //read from IO (C)
2355+ zreg_to_native(opts, Z80_BC, opts->gen.scratch1);
2356+ call(code, opts->read_io);//T states 3
2357+
2358+ //undocumented N flag behavior
2359+ //flag set on bit 7 of value written
2360+ bt_ir(code, 7, opts->gen.scratch1, SZ_B);
2361+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_N));
2362+ //save value to be written for flag calculation, as the write func does not
2363+ //guarantee that it's preserved across the call
2364+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(z80_context, scratch1), SZ_B);
2365+
2366+ //write to (HL)
2367+ zreg_to_native(opts, Z80_HL, opts->gen.scratch2);
2368+ call(code, opts->write_8);//T states 4
2369+ cycles(&opts->gen, 1);
2370+
2371+ //increment HL
2372+ if (opts->regs[Z80_HL] >= 0) {
2373+ add_ir(code, 1, opts->regs[Z80_HL], SZ_W);
2374+ } else {
2375+ add_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_HL), SZ_B);
2376+ }
2377+ mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, scratch1), opts->gen.scratch1, SZ_B);
2378+ if (opts->regs[Z80_C] >= 0) {
2379+ add_rr(code, opts->regs[Z80_C], opts->gen.scratch1, SZ_B);
2380+ } else {
2381+ add_rdispr(code, opts->gen.context_reg, zr_off(Z80_C), opts->gen.scratch1, SZ_B);
2382+ }
2383+ add_ir(code, 1, opts->gen.scratch1, SZ_B);
2384+ //undocumented C and H flag behavior
2385+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
2386+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
2387+ //decrement B
2388+ if (opts->regs[Z80_B] >= 0) {
2389+ sub_ir(code, 1, opts->regs[Z80_B], SZ_B);
2390+ mov_rrdisp(code, opts->regs[Z80_B], opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
2391+ } else {
2392+ sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_B), SZ_B);
2393+ }
2394+ //undocumented Z and S flag behavior, set based on decrement of B
2395+ setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
2396+ setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
2397+ //crazy undocumented P/V flag behavior
2398+ and_ir(code, 7, opts->gen.scratch1, SZ_B);
2399+ if (opts->regs[Z80_B] >= 0) {
2400+ //deal with silly x86-64 restrictions on *H registers
2401+ ror_ir(code, 8, opts->regs[Z80_BC], SZ_W);
2402+ xor_rr(code, opts->regs[Z80_C], opts->gen.scratch1, SZ_B);
2403+ ror_ir(code, 8, opts->regs[Z80_BC], SZ_W);
2404+ } else {
2405+ xor_rdispr(code, opts->gen.context_reg, zr_off(Z80_B), opts->gen.scratch1, SZ_B);
2406+ }
2407+ setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
2408+ break;
2409+ case Z80_INIR: {
2410+ cycles(&opts->gen, num_cycles + 1);//T States: 4, 5
2411+ //read from IO (C)
2412+ zreg_to_native(opts, Z80_BC, opts->gen.scratch1);
2413+ call(code, opts->read_io);//T states 3
2414+
2415+ //undocumented N flag behavior
2416+ //flag set on bit 7 of value written
2417+ bt_ir(code, 7, opts->gen.scratch1, SZ_B);
2418+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_N));
2419+ //save value to be written for flag calculation, as the write func does not
2420+ //guarantee that it's preserved across the call
2421+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(z80_context, scratch1), SZ_B);
2422+
2423+ //write to (HL)
2424+ zreg_to_native(opts, Z80_HL, opts->gen.scratch2);
2425+ call(code, opts->write_8);//T states 4
2426+ cycles(&opts->gen, 1);
2427+
2428+ //increment HL
2429+ if (opts->regs[Z80_HL] >= 0) {
2430+ add_ir(code, 1, opts->regs[Z80_HL], SZ_W);
2431+ } else {
2432+ add_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_HL), SZ_B);
2433+ }
2434+ mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, scratch1), opts->gen.scratch1, SZ_B);
2435+ if (opts->regs[Z80_C] >= 0) {
2436+ add_rr(code, opts->regs[Z80_C], opts->gen.scratch1, SZ_B);
2437+ } else {
2438+ add_rdispr(code, opts->gen.context_reg, zr_off(Z80_C), opts->gen.scratch1, SZ_B);
2439+ }
2440+ add_ir(code, 1, opts->gen.scratch1, SZ_B);
2441+ //undocumented C and H flag behavior
2442+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
2443+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
2444+ //decrement B
2445+ if (opts->regs[Z80_B] >= 0) {
2446+ sub_ir(code, 1, opts->regs[Z80_B], SZ_B);
2447+ mov_rrdisp(code, opts->regs[Z80_B], opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
2448+ } else {
2449+ sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_B), SZ_B);
2450+ }
2451+ //undocumented Z and S flag behavior, set based on decrement of B
2452+ setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
2453+ setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
2454+ //crazy undocumented P/V flag behavior
2455+ and_ir(code, 7, opts->gen.scratch1, SZ_B);
2456+ if (opts->regs[Z80_B] >= 0) {
2457+ //deal with silly x86-64 restrictions on *H registers
2458+ ror_ir(code, 8, opts->regs[Z80_BC], SZ_W);
2459+ xor_rr(code, opts->regs[Z80_C], opts->gen.scratch1, SZ_B);
2460+ ror_ir(code, 8, opts->regs[Z80_BC], SZ_W);
2461+ } else {
2462+ xor_rdispr(code, opts->gen.context_reg, zr_off(Z80_B), opts->gen.scratch1, SZ_B);
2463+ }
2464+ setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
2465+ if (opts->regs[Z80_B] >= 0) {
2466+ cmp_ir(code, 0, opts->regs[Z80_B], SZ_B);
2467+ } else {
2468+ cmp_irdisp(code, 0, opts->gen.context_reg, zr_off(Z80_B), SZ_B);
2469+ }
2470+ code_ptr done = code->cur+1;
2471+ jcc(code, CC_Z, code->cur+2);
2472+ cycles(&opts->gen, 5);
2473+ jmp(code, start);
2474+ *done = code->cur - (done + 1);
2475+ break;
2476+ }
2477+ case Z80_IND:
2478+ cycles(&opts->gen, num_cycles + 1);//T States: 4, 5
2479+ //read from IO (C)
2480+ zreg_to_native(opts, Z80_BC, opts->gen.scratch1);
2481+ call(code, opts->read_io);//T states 3
2482+
2483+ //undocumented N flag behavior
2484+ //flag set on bit 7 of value written
2485+ bt_ir(code, 7, opts->gen.scratch1, SZ_B);
2486+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_N));
2487+ //save value to be written for flag calculation, as the write func does not
2488+ //guarantee that it's preserved across the call
2489+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(z80_context, scratch1), SZ_B);
2490+
2491+ //write to (HL)
2492+ zreg_to_native(opts, Z80_HL, opts->gen.scratch2);
2493+ call(code, opts->write_8);//T states 4
2494+ cycles(&opts->gen, 1);
2495+
2496+ //decrement HL
2497+ if (opts->regs[Z80_HL] >= 0) {
2498+ sub_ir(code, 1, opts->regs[Z80_HL], SZ_W);
2499+ } else {
2500+ sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_HL), SZ_B);
2501+ }
2502+ mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, scratch1), opts->gen.scratch1, SZ_B);
2503+ if (opts->regs[Z80_C] >= 0) {
2504+ add_rr(code, opts->regs[Z80_C], opts->gen.scratch1, SZ_B);
2505+ } else {
2506+ add_rdispr(code, opts->gen.context_reg, zr_off(Z80_C), opts->gen.scratch1, SZ_B);
2507+ }
2508+ add_ir(code, 1, opts->gen.scratch1, SZ_B);
2509+ //undocumented C and H flag behavior
2510+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
2511+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
2512+ //decrement B
2513+ if (opts->regs[Z80_B] >= 0) {
2514+ sub_ir(code, 1, opts->regs[Z80_B], SZ_B);
2515+ mov_rrdisp(code, opts->regs[Z80_B], opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
2516+ } else {
2517+ sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_B), SZ_B);
2518+ }
2519+ //undocumented Z and S flag behavior, set based on decrement of B
2520+ setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
2521+ setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
2522+ //crazy undocumented P/V flag behavior
2523+ and_ir(code, 7, opts->gen.scratch1, SZ_B);
2524+ if (opts->regs[Z80_B] >= 0) {
2525+ //deal with silly x86-64 restrictions on *H registers
2526+ ror_ir(code, 8, opts->regs[Z80_BC], SZ_W);
2527+ xor_rr(code, opts->regs[Z80_C], opts->gen.scratch1, SZ_B);
2528+ ror_ir(code, 8, opts->regs[Z80_BC], SZ_W);
2529+ } else {
2530+ xor_rdispr(code, opts->gen.context_reg, zr_off(Z80_B), opts->gen.scratch1, SZ_B);
2531+ }
2532+ setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
2533+ break;
2534+ case Z80_INDR: {
2535+ cycles(&opts->gen, num_cycles + 1);//T States: 4, 5
2536+ //read from IO (C)
2537+ zreg_to_native(opts, Z80_BC, opts->gen.scratch1);
2538+ call(code, opts->read_io);//T states 3
2539+
2540+ //undocumented N flag behavior
2541+ //flag set on bit 7 of value written
2542+ bt_ir(code, 7, opts->gen.scratch1, SZ_B);
2543+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_N));
2544+ //save value to be written for flag calculation, as the write func does not
2545+ //guarantee that it's preserved across the call
2546+ mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(z80_context, scratch1), SZ_B);
2547+
2548+ //write to (HL)
2549+ zreg_to_native(opts, Z80_HL, opts->gen.scratch2);
2550+ call(code, opts->write_8);//T states 4
2551+ cycles(&opts->gen, 1);
2552+
2553+ //decrement HL
2554+ if (opts->regs[Z80_HL] >= 0) {
2555+ sub_ir(code, 1, opts->regs[Z80_HL], SZ_W);
2556+ } else {
2557+ sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_HL), SZ_B);
2558+ }
2559+ mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, scratch1), opts->gen.scratch1, SZ_B);
2560+ if (opts->regs[Z80_C] >= 0) {
2561+ add_rr(code, opts->regs[Z80_C], opts->gen.scratch1, SZ_B);
2562+ } else {
2563+ add_rdispr(code, opts->gen.context_reg, zr_off(Z80_C), opts->gen.scratch1, SZ_B);
2564+ }
2565+ add_ir(code, 1, opts->gen.scratch1, SZ_B);
2566+ //undocumented C and H flag behavior
2567+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
2568+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
2569+ //decrement B
2570+ if (opts->regs[Z80_B] >= 0) {
2571+ sub_ir(code, 1, opts->regs[Z80_B], SZ_B);
2572+ mov_rrdisp(code, opts->regs[Z80_B], opts->gen.context_reg, zf_off(ZF_XY), SZ_B);
2573+ } else {
2574+ sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_B), SZ_B);
2575+ }
2576+ //undocumented Z and S flag behavior, set based on decrement of B
2577+ setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
2578+ setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
2579+ //crazy undocumented P/V flag behavior
2580+ and_ir(code, 7, opts->gen.scratch1, SZ_B);
2581+ if (opts->regs[Z80_B] >= 0) {
2582+ //deal with silly x86-64 restrictions on *H registers
2583+ ror_ir(code, 8, opts->regs[Z80_BC], SZ_W);
2584+ xor_rr(code, opts->regs[Z80_C], opts->gen.scratch1, SZ_B);
2585+ ror_ir(code, 8, opts->regs[Z80_BC], SZ_W);
2586+ } else {
2587+ xor_rdispr(code, opts->gen.context_reg, zr_off(Z80_B), opts->gen.scratch1, SZ_B);
2588+ }
2589+ setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
2590+ if (opts->regs[Z80_B] >= 0) {
2591+ cmp_ir(code, 0, opts->regs[Z80_B], SZ_B);
2592+ } else {
2593+ cmp_irdisp(code, 0, opts->gen.context_reg, zr_off(Z80_B), SZ_B);
2594+ }
2595+ code_ptr done = code->cur+1;
2596+ jcc(code, CC_Z, code->cur+2);
2597+ cycles(&opts->gen, 5);
2598+ jmp(code, start);
2599+ *done = code->cur - (done + 1);
2600+ break;
2601+ }
2602+ case Z80_OUT:
2603+ if (inst->addr_mode == Z80_IMMED_INDIRECT) {
2604+ num_cycles += 3;
2605+ }
2606+ cycles(&opts->gen, num_cycles);//T States: 4 3/4
2607+ if ((inst->addr_mode & 0x1F) == Z80_IMMED_INDIRECT) {
2608+ mov_ir(code, inst->immed, opts->gen.scratch2, SZ_B);
2609+ } else {
2610+ zreg_to_native(opts, Z80_C, opts->gen.scratch2);
2611+ }
2612+ translate_z80_reg(inst, &src_op, opts);
2613+ if (src_op.mode == MODE_REG_DIRECT) {
2614+ mov_rr(code, src_op.base, opts->gen.scratch1, SZ_B);
2615+ } else if (src_op.mode == MODE_IMMED) {
2616+ mov_ir(code, src_op.disp, opts->gen.scratch1, SZ_B);
2617+ } else {
2618+ mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, SZ_B);
2619+ }
2620+ call(code, opts->write_io);
2621+ z80_save_reg(inst, opts);
2622+ break;
2623+ case Z80_OUTI:
2624+ cycles(&opts->gen, num_cycles + 1);//T States: 4, 5
2625+ //read from (HL)
2626+ zreg_to_native(opts, Z80_HL, opts->gen.scratch1);
2627+ call(code, opts->read_8);//T states 3
2628+ //undocumented N flag behavior
2629+ //flag set on bit 7 of value written
2630+ bt_ir(code, 7, opts->gen.scratch1, SZ_B);
2631+ setcc_rdisp(code, CC_NC, opts->gen.context_reg, zf_off(ZF_N));
2632+ //write to IO (C)
2633+ zreg_to_native(opts, Z80_C, opts->gen.scratch2);
2634+ call(code, opts->write_io);//T states 4
2635+ //increment HL
2636+ if (opts->regs[Z80_HL] >= 0) {
2637+ add_ir(code, 1, opts->regs[Z80_HL], SZ_W);
2638+ add_rr(code, opts->regs[Z80_L], opts->gen.scratch1, SZ_B);
2639+ } else {
2640+ add_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_HL), SZ_B);
2641+ add_rdispr(code, opts->gen.context_reg, zr_off(Z80_L), opts->gen.scratch1, SZ_B);
2642+ }
2643+ //undocumented C and H flag behavior
2644+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
2645+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
2646+ //decrement B
2647+ if (opts->regs[Z80_B] >= 0) {
2648+ sub_ir(code, 1, opts->regs[Z80_B], SZ_B);
2649+ } else {
2650+ sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_B), SZ_B);
2651+ }
2652+ //undocumented Z and S flag behavior, set based on decrement of B
2653+ setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
2654+ setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
2655+ //crazy undocumented P/V flag behavior
2656+ and_ir(code, 7, opts->gen.scratch1, SZ_B);
2657+ if (opts->regs[Z80_B] >= 0) {
2658+ //deal with silly x86-64 restrictions on *H registers
2659+ ror_ir(code, 8, opts->regs[Z80_BC], SZ_W);
2660+ xor_rr(code, opts->regs[Z80_C], opts->gen.scratch1, SZ_B);
2661+ ror_ir(code, 8, opts->regs[Z80_BC], SZ_W);
2662+ } else {
2663+ xor_rdispr(code, opts->gen.context_reg, zr_off(Z80_B), opts->gen.scratch1, SZ_B);
2664+ }
2665+ setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
2666+ break;
2667+ case Z80_OTIR: {
2668+ cycles(&opts->gen, num_cycles + 1);//T States: 4, 5
2669+ //read from (HL)
2670+ zreg_to_native(opts, Z80_HL, opts->gen.scratch1);
2671+ call(code, opts->read_8);//T states 3
2672+ //undocumented N flag behavior
2673+ //flag set on bit 7 of value written
2674+ bt_ir(code, 7, opts->gen.scratch1, SZ_B);
2675+ setcc_rdisp(code, CC_NC, opts->gen.context_reg, zf_off(ZF_N));
2676+ //write to IO (C)
2677+ zreg_to_native(opts, Z80_C, opts->gen.scratch2);
2678+ call(code, opts->write_io);//T states 4
2679+ //increment HL
2680+ if (opts->regs[Z80_HL] >= 0) {
2681+ add_ir(code, 1, opts->regs[Z80_HL], SZ_W);
2682+ add_rr(code, opts->regs[Z80_L], opts->gen.scratch1, SZ_B);
2683+ } else {
2684+ add_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_HL), SZ_B);
2685+ add_rdispr(code, opts->gen.context_reg, zr_off(Z80_L), opts->gen.scratch1, SZ_B);
2686+ }
2687+ //undocumented C and H flag behavior
2688+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
2689+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
2690+ //decrement B
2691+ if (opts->regs[Z80_B] >= 0) {
2692+ sub_ir(code, 1, opts->regs[Z80_B], SZ_B);
2693+ } else {
2694+ sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_B), SZ_B);
2695+ }
2696+ //undocumented Z and S flag behavior, set based on decrement of B
2697+ setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
2698+ setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
2699+ //crazy undocumented P/V flag behavior
2700+ and_ir(code, 7, opts->gen.scratch1, SZ_B);
2701+ if (opts->regs[Z80_B] >= 0) {
2702+ //deal with silly x86-64 restrictions on *H registers
2703+ ror_ir(code, 8, opts->regs[Z80_BC], SZ_W);
2704+ xor_rr(code, opts->regs[Z80_C], opts->gen.scratch1, SZ_B);
2705+ ror_ir(code, 8, opts->regs[Z80_BC], SZ_W);
2706+ } else {
2707+ xor_rdispr(code, opts->gen.context_reg, zr_off(Z80_B), opts->gen.scratch1, SZ_B);
2708+ }
2709+ setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
2710+ if (opts->regs[Z80_B] >= 0) {
2711+ cmp_ir(code, 0, opts->regs[Z80_B], SZ_B);
2712+ } else {
2713+ cmp_irdisp(code, 0, opts->gen.context_reg, zr_off(Z80_B), SZ_B);
2714+ }
2715+ code_ptr done = code->cur+1;
2716+ jcc(code, CC_Z, code->cur+2);
2717+ cycles(&opts->gen, 5);
2718+ jmp(code, start);
2719+ *done = code->cur - (done + 1);
2720+ break;
2721+ }
2722+ case Z80_OUTD:
2723+ cycles(&opts->gen, num_cycles + 1);//T States: 4, 5
2724+ //read from (HL)
2725+ zreg_to_native(opts, Z80_HL, opts->gen.scratch1);
2726+ call(code, opts->read_8);//T states 3
2727+ //undocumented N flag behavior
2728+ //flag set on bit 7 of value written
2729+ bt_ir(code, 7, opts->gen.scratch1, SZ_B);
2730+ setcc_rdisp(code, CC_NC, opts->gen.context_reg, zf_off(ZF_N));
2731+ //write to IO (C)
2732+ zreg_to_native(opts, Z80_C, opts->gen.scratch2);
2733+ call(code, opts->write_io);//T states 4
2734+ //decrement HL
2735+ if (opts->regs[Z80_HL] >= 0) {
2736+ sub_ir(code, 1, opts->regs[Z80_HL], SZ_W);
2737+ add_rr(code, opts->regs[Z80_L], opts->gen.scratch1, SZ_B);
2738+ } else {
2739+ sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_HL), SZ_B);
2740+ add_rdispr(code, opts->gen.context_reg, zr_off(Z80_L), opts->gen.scratch1, SZ_B);
2741+ }
2742+ //undocumented C and H flag behavior
2743+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
2744+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
2745+ //decrement B
2746+ if (opts->regs[Z80_B] >= 0) {
2747+ sub_ir(code, 1, opts->regs[Z80_B], SZ_B);
2748+ } else {
2749+ sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_B), SZ_B);
2750+ }
2751+ //undocumented Z and S flag behavior, set based on decrement of B
2752+ setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
2753+ setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
2754+ //crazy undocumented P/V flag behavior
2755+ and_ir(code, 7, opts->gen.scratch1, SZ_B);
2756+ if (opts->regs[Z80_B] >= 0) {
2757+ //deal with silly x86-64 restrictions on *H registers
2758+ ror_ir(code, 8, opts->regs[Z80_BC], SZ_W);
2759+ xor_rr(code, opts->regs[Z80_C], opts->gen.scratch1, SZ_B);
2760+ ror_ir(code, 8, opts->regs[Z80_BC], SZ_W);
2761+ } else {
2762+ xor_rdispr(code, opts->gen.context_reg, zr_off(Z80_B), opts->gen.scratch1, SZ_B);
2763+ }
2764+ setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
2765+ break;
2766+ case Z80_OTDR: {
2767+ cycles(&opts->gen, num_cycles + 1);//T States: 4, 5
2768+ //read from (HL)
2769+ zreg_to_native(opts, Z80_HL, opts->gen.scratch1);
2770+ call(code, opts->read_8);//T states 3
2771+ //undocumented N flag behavior
2772+ //flag set on bit 7 of value written
2773+ bt_ir(code, 7, opts->gen.scratch1, SZ_B);
2774+ setcc_rdisp(code, CC_NC, opts->gen.context_reg, zf_off(ZF_N));
2775+ //write to IO (C)
2776+ zreg_to_native(opts, Z80_C, opts->gen.scratch2);
2777+ call(code, opts->write_io);//T states 4
2778+ //increment HL
2779+ if (opts->regs[Z80_HL] >= 0) {
2780+ sub_ir(code, 1, opts->regs[Z80_HL], SZ_W);
2781+ add_rr(code, opts->regs[Z80_L], opts->gen.scratch1, SZ_B);
2782+ } else {
2783+ sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_HL), SZ_B);
2784+ add_rdispr(code, opts->gen.context_reg, zr_off(Z80_L), opts->gen.scratch1, SZ_B);
2785+ }
2786+ //undocumented C and H flag behavior
2787+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C));
2788+ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H));
2789+ //decrement B
2790+ if (opts->regs[Z80_B] >= 0) {
2791+ sub_ir(code, 1, opts->regs[Z80_B], SZ_B);
2792+ } else {
2793+ sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_B), SZ_B);
2794+ }
2795+ //undocumented Z and S flag behavior, set based on decrement of B
2796+ setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
2797+ setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
2798+ //crazy undocumented P/V flag behavior
2799+ and_ir(code, 7, opts->gen.scratch1, SZ_B);
2800+ if (opts->regs[Z80_B] >= 0) {
2801+ //deal with silly x86-64 restrictions on *H registers
2802+ ror_ir(code, 8, opts->regs[Z80_BC], SZ_W);
2803+ xor_rr(code, opts->regs[Z80_C], opts->gen.scratch1, SZ_B);
2804+ ror_ir(code, 8, opts->regs[Z80_BC], SZ_W);
2805+ } else {
2806+ xor_rdispr(code, opts->gen.context_reg, zr_off(Z80_B), opts->gen.scratch1, SZ_B);
2807+ }
2808+ setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV));
2809+ if (opts->regs[Z80_B] >= 0) {
2810+ cmp_ir(code, 0, opts->regs[Z80_B], SZ_B);
2811+ } else {
2812+ cmp_irdisp(code, 0, opts->gen.context_reg, zr_off(Z80_B), SZ_B);
2813+ }
2814+ code_ptr done = code->cur+1;
2815+ jcc(code, CC_Z, code->cur+2);
2816+ cycles(&opts->gen, 5);
2817+ jmp(code, start);
2818+ *done = code->cur - (done + 1);
2819+ break;
2820+ }
2821+ default: {
2822+ char disbuf[80];
2823+ z80_disasm(inst, disbuf, address);
2824+ FILE * f = fopen("zram.bin", "wb");
2825+ fwrite(context->mem_pointers[0], 1, 8 * 1024, f);
2826+ fclose(f);
2827+ fatal_error("unimplemented Z80 instruction: %s at %X\nZ80 RAM has been saved to zram.bin for debugging", disbuf, address);
2828+ }
2829+ }
2830+}
2831+
2832+uint8_t * z80_interp_handler(uint8_t opcode, z80_context * context)
2833+{
2834+ if (!context->interp_code[opcode]) {
2835+ if (opcode == 0xCB || (opcode >= 0xDD && (opcode & 0xF) == 0xD)) {
2836+ fatal_error("Encountered prefix byte %X at address %X. Z80 interpeter doesn't support those yet.", opcode, context->pc);
2837+ }
2838+ uint8_t codebuf[8];
2839+ memset(codebuf, 0, sizeof(codebuf));
2840+ codebuf[0] = opcode;
2841+ z80inst inst;
2842+ uint8_t * after = z80_decode(codebuf, &inst);
2843+ if (after - codebuf > 1) {
2844+ fatal_error("Encountered multi-byte Z80 instruction at %X. Z80 interpeter doesn't support those yet.", context->pc);
2845+ }
2846+
2847+ z80_options * opts = context->options;
2848+ code_info *code = &opts->gen.code;
2849+ check_alloc_code(code, ZMAX_NATIVE_SIZE);
2850+ context->interp_code[opcode] = code->cur;
2851+ translate_z80inst(&inst, context, 0, 1);
2852+ mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, pc), opts->gen.scratch1, SZ_W);
2853+ add_ir(code, after - codebuf, opts->gen.scratch1, SZ_W);
2854+ call(code, opts->native_addr);
2855+ jmp_r(code, opts->gen.scratch1);
2856+ z80_handle_deferred(context);
2857+ }
2858+ return context->interp_code[opcode];
2859+}
2860+
2861+code_info z80_make_interp_stub(z80_context * context, uint16_t address)
2862+{
2863+ z80_options *opts = context->options;
2864+ code_info * code = &opts->gen.code;
2865+ check_alloc_code(code, 32);
2866+ code_info stub = {code->cur, NULL};
2867+ //TODO: make this play well with the breakpoint code
2868+ mov_ir(code, address, opts->gen.scratch1, SZ_W);
2869+ call(code, opts->read_8);
2870+ //opcode fetch M-cycles have one extra T-state
2871+ cycles(&opts->gen, 1);
2872+ //TODO: increment R
2873+ check_cycles_int(&opts->gen, address);
2874+ call(code, opts->gen.save_context);
2875+ mov_irdisp(code, address, opts->gen.context_reg, offsetof(z80_context, pc), SZ_W);
2876+ push_r(code, opts->gen.context_reg);
2877+ call_args(code, (code_ptr)z80_interp_handler, 2, opts->gen.scratch1, opts->gen.context_reg);
2878+ mov_rr(code, RAX, opts->gen.scratch1, SZ_PTR);
2879+ pop_r(code, opts->gen.context_reg);
2880+ call(code, opts->gen.load_context);
2881+ jmp_r(code, opts->gen.scratch1);
2882+ stub.last = code->cur;
2883+ return stub;
2884+}
2885+
2886+
2887+uint8_t * z80_get_native_address(z80_context * context, uint32_t address)
2888+{
2889+ z80_options *opts = context->options;
2890+ native_map_slot * native_code_map = opts->gen.native_code_map;
2891+
2892+ memmap_chunk const *mem_chunk = find_map_chunk(address, &opts->gen, 0, NULL);
2893+ if (mem_chunk) {
2894+ //calculate the lowest alias for this address
2895+ address = mem_chunk->start + ((address - mem_chunk->start) & mem_chunk->mask);
2896+ }
2897+ uint32_t chunk = address / NATIVE_CHUNK_SIZE;
2898+ if (!native_code_map[chunk].base) {
2899+ return NULL;
2900+ }
2901+ uint32_t offset = address % NATIVE_CHUNK_SIZE;
2902+ if (native_code_map[chunk].offsets[offset] == INVALID_OFFSET || native_code_map[chunk].offsets[offset] == EXTENSION_WORD) {
2903+ return NULL;
2904+ }
2905+ return native_code_map[chunk].base + native_code_map[chunk].offsets[offset];
2906+}
2907+
2908+uint8_t z80_get_native_inst_size(z80_options * opts, uint32_t address)
2909+{
2910+ uint32_t meta_off;
2911+ memmap_chunk const *chunk = find_map_chunk(address, &opts->gen, MMAP_CODE, &meta_off);
2912+ if (chunk) {
2913+ meta_off += (address - chunk->start) & chunk->mask;
2914+ }
2915+ uint32_t slot = meta_off/1024;
2916+ return opts->gen.ram_inst_sizes[slot][meta_off%1024];
2917+}
2918+
2919+void z80_map_native_address(z80_context * context, uint32_t address, uint8_t * native_address, uint8_t size, uint8_t native_size)
2920+{
2921+ z80_options * opts = context->options;
2922+ uint32_t meta_off;
2923+ memmap_chunk const *mem_chunk = find_map_chunk(address, &opts->gen, MMAP_CODE, &meta_off);
2924+ if (mem_chunk) {
2925+ if (mem_chunk->flags & MMAP_CODE) {
2926+ uint32_t masked = (address & mem_chunk->mask);
2927+ uint32_t final_off = masked + meta_off;
2928+ uint32_t ram_flags_off = final_off >> (opts->gen.ram_flags_shift + 3);
2929+ context->ram_code_flags[ram_flags_off] |= 1 << ((final_off >> opts->gen.ram_flags_shift) & 7);
2930+
2931+ uint32_t slot = final_off / 1024;
2932+ if (!opts->gen.ram_inst_sizes[slot]) {
2933+ opts->gen.ram_inst_sizes[slot] = malloc(sizeof(uint8_t) * 1024);
2934+ }
2935+ opts->gen.ram_inst_sizes[slot][final_off % 1024] = native_size;
2936+
2937+ //TODO: Deal with case in which end of instruction is in a different memory chunk
2938+ masked = (address + size - 1) & mem_chunk->mask;
2939+ final_off = masked + meta_off;
2940+ ram_flags_off = final_off >> (opts->gen.ram_flags_shift + 3);
2941+ context->ram_code_flags[ram_flags_off] |= 1 << ((final_off >> opts->gen.ram_flags_shift) & 7);
2942+ }
2943+ //calculate the lowest alias for this address
2944+ address = mem_chunk->start + ((address - mem_chunk->start) & mem_chunk->mask);
2945+ } else {
2946+ address &= opts->gen.address_mask;
2947+ }
2948+
2949+ native_map_slot *map = opts->gen.native_code_map + address / NATIVE_CHUNK_SIZE;
2950+ if (!map->base) {
2951+ map->base = native_address;
2952+ map->offsets = malloc(sizeof(int32_t) * NATIVE_CHUNK_SIZE);
2953+ memset(map->offsets, 0xFF, sizeof(int32_t) * NATIVE_CHUNK_SIZE);
2954+ }
2955+ map->offsets[address % NATIVE_CHUNK_SIZE] = native_address - map->base;
2956+ for(--size, address++; size; --size, address++) {
2957+ address &= opts->gen.address_mask;
2958+ map = opts->gen.native_code_map + address / NATIVE_CHUNK_SIZE;
2959+ if (!map->base) {
2960+ map->base = native_address;
2961+ map->offsets = malloc(sizeof(int32_t) * NATIVE_CHUNK_SIZE);
2962+ memset(map->offsets, 0xFF, sizeof(int32_t) * NATIVE_CHUNK_SIZE);
2963+ }
2964+
2965+ if (map->offsets[address % NATIVE_CHUNK_SIZE] == INVALID_OFFSET) {
2966+ //TODO: better handling of potentially overlapping instructions
2967+ map->offsets[address % NATIVE_CHUNK_SIZE] = EXTENSION_WORD;
2968+ }
2969+ }
2970+}
2971+
2972+#define INVALID_INSTRUCTION_START 0xFEEDFEED
2973+
2974+uint32_t z80_get_instruction_start(z80_context *context, uint32_t address)
2975+{
2976+ z80_options *opts = context->options;
2977+ native_map_slot * native_code_map = opts->gen.native_code_map;
2978+ memmap_chunk const *mem_chunk = find_map_chunk(address, &opts->gen, 0, NULL);
2979+ if (mem_chunk) {
2980+ //calculate the lowest alias for this address
2981+ address = mem_chunk->start + ((address - mem_chunk->start) & mem_chunk->mask);
2982+ }
2983+
2984+ uint32_t chunk = address / NATIVE_CHUNK_SIZE;
2985+ if (!native_code_map[chunk].base) {
2986+ return INVALID_INSTRUCTION_START;
2987+ }
2988+ uint32_t offset = address % NATIVE_CHUNK_SIZE;
2989+ if (native_code_map[chunk].offsets[offset] == INVALID_OFFSET) {
2990+ return INVALID_INSTRUCTION_START;
2991+ }
2992+ while (native_code_map[chunk].offsets[offset] == EXTENSION_WORD)
2993+ {
2994+ --address;
2995+ chunk = address / NATIVE_CHUNK_SIZE;
2996+ offset = address % NATIVE_CHUNK_SIZE;
2997+ }
2998+ return address;
2999+}
3000+
3001+//Technically unbounded due to redundant prefixes, but this is the max useful size
3002+#define Z80_MAX_INST_SIZE 4
3003+
3004+z80_context * z80_handle_code_write(uint32_t address, z80_context * context)
3005+{
3006+ uint32_t inst_start = z80_get_instruction_start(context, address);
3007+ while (inst_start != INVALID_INSTRUCTION_START && (address - inst_start) < Z80_MAX_INST_SIZE) {
3008+ code_ptr dst = z80_get_native_address(context, inst_start);
3009+ code_info code = {dst, dst+32, 0};
3010+ z80_options * opts = context->options;
3011+ dprintf("patching code at %p for Z80 instruction at %X due to write to %X\n", code.cur, inst_start, address);
3012+ mov_ir(&code, inst_start, opts->gen.scratch1, SZ_D);
3013+ call(&code, opts->retrans_stub);
3014+ inst_start = z80_get_instruction_start(context, inst_start - 1);
3015+ }
3016+ return context;
3017+}
3018+
3019+void z80_invalidate_code_range(z80_context *context, uint32_t start, uint32_t end)
3020+{
3021+ z80_options *opts = context->options;
3022+ native_map_slot * native_code_map = opts->gen.native_code_map;
3023+ memmap_chunk const *mem_chunk = find_map_chunk(start, &opts->gen, 0, NULL);
3024+ if (mem_chunk) {
3025+ //calculate the lowest alias for this address
3026+ start = mem_chunk->start + ((start - mem_chunk->start) & mem_chunk->mask);
3027+ }
3028+ mem_chunk = find_map_chunk(end, &opts->gen, 0, NULL);
3029+ if (mem_chunk) {
3030+ //calculate the lowest alias for this address
3031+ end = mem_chunk->start + ((end - mem_chunk->start) & mem_chunk->mask);
3032+ }
3033+ uint32_t start_chunk = start / NATIVE_CHUNK_SIZE, end_chunk = end / NATIVE_CHUNK_SIZE;
3034+ for (uint32_t chunk = start_chunk; chunk <= end_chunk; chunk++)
3035+ {
3036+ if (native_code_map[chunk].base) {
3037+ uint32_t start_offset = chunk == start_chunk ? start % NATIVE_CHUNK_SIZE : 0;
3038+ uint32_t end_offset = chunk == end_chunk ? end % NATIVE_CHUNK_SIZE : NATIVE_CHUNK_SIZE;
3039+ for (uint32_t offset = start_offset; offset < end_offset; offset++)
3040+ {
3041+ if (native_code_map[chunk].offsets[offset] != INVALID_OFFSET && native_code_map[chunk].offsets[offset] != EXTENSION_WORD) {
3042+ code_info code;
3043+ code.cur = native_code_map[chunk].base + native_code_map[chunk].offsets[offset];
3044+ code.last = code.cur + 32;
3045+ code.stack_off = 0;
3046+ mov_ir(&code, chunk * NATIVE_CHUNK_SIZE + offset, opts->gen.scratch1, SZ_D);
3047+ call(&code, opts->retrans_stub);
3048+ }
3049+ }
3050+ }
3051+ }
3052+}
3053+
3054+uint8_t * z80_get_native_address_trans(z80_context * context, uint32_t address)
3055+{
3056+ uint8_t * addr = z80_get_native_address(context, address);
3057+ if (!addr) {
3058+ translate_z80_stream(context, address);
3059+ addr = z80_get_native_address(context, address);
3060+ if (!addr) {
3061+ printf("Failed to translate %X to native code\n", address);
3062+ }
3063+ }
3064+ return addr;
3065+}
3066+
3067+void z80_handle_deferred(z80_context * context)
3068+{
3069+ z80_options * opts = context->options;
3070+ process_deferred(&opts->gen.deferred, context, (native_addr_func)z80_get_native_address);
3071+ if (opts->gen.deferred) {
3072+ translate_z80_stream(context, opts->gen.deferred->address);
3073+ }
3074+}
3075+
3076+extern void * z80_retranslate_inst(uint32_t address, z80_context * context, uint8_t * orig_start) asm("z80_retranslate_inst");
3077+void * z80_retranslate_inst(uint32_t address, z80_context * context, uint8_t * orig_start)
3078+{
3079+ char disbuf[80];
3080+ z80_options * opts = context->options;
3081+ uint8_t orig_size = z80_get_native_inst_size(opts, address);
3082+ code_info *code = &opts->gen.code;
3083+ uint8_t *after, *inst = get_native_pointer(address, (void **)context->mem_pointers, &opts->gen);
3084+ z80inst instbuf;
3085+ dprintf("Retranslating code at Z80 address %X, native address %p\n", address, orig_start);
3086+ after = z80_decode(inst, &instbuf);
3087+ #ifdef DO_DEBUG_PRINT
3088+ z80_disasm(&instbuf, disbuf, address);
3089+ if (instbuf.op == Z80_NOP) {
3090+ printf("%X\t%s(%d)\n", address, disbuf, instbuf.immed);
3091+ } else {
3092+ printf("%X\t%s\n", address, disbuf);
3093+ }
3094+ #endif
3095+ if (orig_size != ZMAX_NATIVE_SIZE) {
3096+ check_alloc_code(code, ZMAX_NATIVE_SIZE);
3097+ code_ptr start = code->cur;
3098+ deferred_addr * orig_deferred = opts->gen.deferred;
3099+ translate_z80inst(&instbuf, context, address, 0);
3100+ /*
3101+ if ((native_end - dst) <= orig_size) {
3102+ uint8_t * native_next = z80_get_native_address(context, address + after-inst);
3103+ if (native_next && ((native_next == orig_start + orig_size) || (orig_size - (native_end - dst)) > 5)) {
3104+ remove_deferred_until(&opts->gen.deferred, orig_deferred);
3105+ native_end = translate_z80inst(&instbuf, orig_start, context, address, 0);
3106+ if (native_next == orig_start + orig_size && (native_next-native_end) < 2) {
3107+ while (native_end < orig_start + orig_size) {
3108+ *(native_end++) = 0x90; //NOP
3109+ }
3110+ } else {
3111+ jmp(native_end, native_next);
3112+ }
3113+ z80_handle_deferred(context);
3114+ return orig_start;
3115+ }
3116+ }*/
3117+ z80_map_native_address(context, address, start, after-inst, ZMAX_NATIVE_SIZE);
3118+ code_info tmp_code = {orig_start, orig_start + 16};
3119+ jmp(&tmp_code, start);
3120+ tmp_code = *code;
3121+ code->cur = start + ZMAX_NATIVE_SIZE;
3122+ if (!z80_is_terminal(&instbuf)) {
3123+ jmp(&tmp_code, z80_get_native_address_trans(context, address + after-inst));
3124+ }
3125+ z80_handle_deferred(context);
3126+ return start;
3127+ } else {
3128+ code_info tmp_code = *code;
3129+ code->cur = orig_start;
3130+ code->last = orig_start + ZMAX_NATIVE_SIZE;
3131+ translate_z80inst(&instbuf, context, address, 0);
3132+ code_info tmp2 = *code;
3133+ *code = tmp_code;
3134+ if (!z80_is_terminal(&instbuf)) {
3135+
3136+ jmp(&tmp2, z80_get_native_address_trans(context, address + after-inst));
3137+ }
3138+ z80_handle_deferred(context);
3139+ return orig_start;
3140+ }
3141+}
3142+
3143+void translate_z80_stream(z80_context * context, uint32_t address)
3144+{
3145+ char disbuf[80];
3146+ if (z80_get_native_address(context, address)) {
3147+ return;
3148+ }
3149+ z80_options * opts = context->options;
3150+ uint32_t start_address = address;
3151+
3152+ do
3153+ {
3154+ z80inst inst;
3155+ dprintf("translating Z80 code at address %X\n", address);
3156+ do {
3157+ uint8_t * existing = z80_get_native_address(context, address);
3158+ if (existing) {
3159+ jmp(&opts->gen.code, existing);
3160+ break;
3161+ }
3162+ uint8_t * encoded, *next;
3163+ encoded = get_native_pointer(address, (void **)context->mem_pointers, &opts->gen);
3164+ if (!encoded) {
3165+ code_info stub = z80_make_interp_stub(context, address);
3166+ z80_map_native_address(context, address, stub.cur, 1, stub.last - stub.cur);
3167+ break;
3168+ }
3169+ //make sure prologue is in a contiguous chunk of code
3170+ check_code_prologue(&opts->gen.code);
3171+ next = z80_decode(encoded, &inst);
3172+ #ifdef DO_DEBUG_PRINT
3173+ z80_disasm(&inst, disbuf, address);
3174+ if (inst.op == Z80_NOP) {
3175+ printf("%X\t%s(%d)\n", address, disbuf, inst.immed);
3176+ } else {
3177+ printf("%X\t%s\n", address, disbuf);
3178+ }
3179+ #endif
3180+ code_ptr start = opts->gen.code.cur;
3181+ translate_z80inst(&inst, context, address, 0);
3182+ z80_map_native_address(context, address, start, next-encoded, opts->gen.code.cur - start);
3183+ address += next-encoded;
3184+ address &= 0xFFFF;
3185+ } while (!z80_is_terminal(&inst));
3186+ process_deferred(&opts->gen.deferred, context, (native_addr_func)z80_get_native_address);
3187+ if (opts->gen.deferred) {
3188+ address = opts->gen.deferred->address;
3189+ dprintf("defferred address: %X\n", address);
3190+ }
3191+ } while (opts->gen.deferred);
3192+}
3193+
3194+void init_z80_opts(z80_options * options, memmap_chunk const * chunks, uint32_t num_chunks, memmap_chunk const * io_chunks, uint32_t num_io_chunks, uint32_t clock_divider, uint32_t io_address_mask)
3195+{
3196+ memset(options, 0, sizeof(*options));
3197+
3198+ options->gen.memmap = chunks;
3199+ options->gen.memmap_chunks = num_chunks;
3200+ options->gen.address_size = SZ_W;
3201+ options->gen.address_mask = 0xFFFF;
3202+ options->gen.max_address = 0x10000;
3203+ options->gen.bus_cycles = 3;
3204+ options->gen.clock_divider = clock_divider;
3205+ options->gen.mem_ptr_off = offsetof(z80_context, mem_pointers);
3206+ options->gen.ram_flags_off = offsetof(z80_context, ram_code_flags);
3207+ options->gen.ram_flags_shift = 7;
3208+
3209+ options->flags = 0;
3210+#ifdef X86_64
3211+ options->regs[Z80_B] = BH;
3212+ options->regs[Z80_C] = RBX;
3213+ options->regs[Z80_D] = CH;
3214+ options->regs[Z80_E] = RCX;
3215+ options->regs[Z80_H] = AH;
3216+ options->regs[Z80_L] = RAX;
3217+ options->regs[Z80_IXH] = DH;
3218+ options->regs[Z80_IXL] = RDX;
3219+ options->regs[Z80_IYH] = -1;
3220+ options->regs[Z80_IYL] = R8;
3221+ options->regs[Z80_I] = -1;
3222+ options->regs[Z80_R] = RDI;
3223+ options->regs[Z80_A] = R10;
3224+ options->regs[Z80_BC] = RBX;
3225+ options->regs[Z80_DE] = RCX;
3226+ options->regs[Z80_HL] = RAX;
3227+ options->regs[Z80_SP] = R9;
3228+ options->regs[Z80_AF] = -1;
3229+ options->regs[Z80_IX] = RDX;
3230+ options->regs[Z80_IY] = R8;
3231+
3232+ options->gen.scratch1 = R13;
3233+ options->gen.scratch2 = R14;
3234+#else
3235+ memset(options->regs, -1, sizeof(options->regs));
3236+ options->regs[Z80_A] = RAX;
3237+ options->regs[Z80_R] = AH;
3238+ options->regs[Z80_H] = BH;
3239+ options->regs[Z80_L] = RBX;
3240+ options->regs[Z80_HL] = RBX;
3241+
3242+ options->regs[Z80_SP] = RDI;
3243+
3244+ options->gen.scratch1 = RCX;
3245+ options->gen.scratch2 = RDX;
3246+#endif
3247+
3248+ options->gen.context_reg = RSI;
3249+ options->gen.cycles = RBP;
3250+ options->gen.limit = -1;
3251+
3252+ options->gen.native_code_map = malloc(sizeof(native_map_slot) * NATIVE_MAP_CHUNKS);
3253+ memset(options->gen.native_code_map, 0, sizeof(native_map_slot) * NATIVE_MAP_CHUNKS);
3254+ options->gen.deferred = NULL;
3255+ uint32_t inst_size_size = sizeof(uint8_t *) * ram_size(&options->gen) / 1024;
3256+ options->gen.ram_inst_sizes = malloc(inst_size_size);
3257+ memset(options->gen.ram_inst_sizes, 0, inst_size_size);
3258+
3259+ code_info *code = &options->gen.code;
3260+ init_code_info(code);
3261+
3262+ options->save_context_scratch = code->cur;
3263+ mov_rrdisp(code, options->gen.scratch1, options->gen.context_reg, offsetof(z80_context, scratch1), SZ_W);
3264+ mov_rrdisp(code, options->gen.scratch2, options->gen.context_reg, offsetof(z80_context, scratch2), SZ_W);
3265+
3266+ options->gen.save_context = code->cur;
3267+ for (int i = 0; i <= Z80_A; i++)
3268+ {
3269+ int reg;
3270+ uint8_t size;
3271+ if (i < Z80_I) {
3272+ reg = i /2 + Z80_BC + (i > Z80_H ? 2 : 0);
3273+ size = SZ_W;
3274+ } else {
3275+ reg = i;
3276+ size = SZ_B;
3277+ }
3278+ if (reg == Z80_R) {
3279+ and_ir(code, 0x7F, options->regs[Z80_R], SZ_B);
3280+ or_rrdisp(code, options->regs[Z80_R], options->gen.context_reg, zr_off(Z80_R), SZ_B);
3281+ } else if (options->regs[reg] >= 0) {
3282+ mov_rrdisp(code, options->regs[reg], options->gen.context_reg, zr_off(reg), size);
3283+ }
3284+ if (size == SZ_W) {
3285+ i++;
3286+ }
3287+ }
3288+ if (options->regs[Z80_SP] >= 0) {
3289+ mov_rrdisp(code, options->regs[Z80_SP], options->gen.context_reg, offsetof(z80_context, sp), SZ_W);
3290+ }
3291+ neg_r(code, options->gen.cycles, SZ_D);
3292+ add_rdispr(code, options->gen.context_reg, offsetof(z80_context, target_cycle), options->gen.cycles, SZ_D);
3293+ mov_rrdisp(code, options->gen.cycles, options->gen.context_reg, offsetof(z80_context, current_cycle), SZ_D);
3294+ retn(code);
3295+
3296+ options->load_context_scratch = code->cur;
3297+ mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, scratch1), options->gen.scratch1, SZ_W);
3298+ mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, scratch2), options->gen.scratch2, SZ_W);
3299+ options->gen.load_context = code->cur;
3300+ for (int i = 0; i <= Z80_A; i++)
3301+ {
3302+ int reg;
3303+ uint8_t size;
3304+ if (i < Z80_I) {
3305+ reg = i /2 + Z80_BC + (i > Z80_H ? 2 : 0);
3306+ size = SZ_W;
3307+ } else {
3308+ reg = i;
3309+ size = SZ_B;
3310+ }
3311+ if (options->regs[reg] >= 0) {
3312+ mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, regs) + i, options->regs[reg], size);
3313+ if (reg == Z80_R) {
3314+ and_irdisp(code, 0x80, options->gen.context_reg, zr_off(reg), SZ_B);
3315+ }
3316+ }
3317+ if (size == SZ_W) {
3318+ i++;
3319+ }
3320+ }
3321+ if (options->regs[Z80_SP] >= 0) {
3322+ mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, sp), options->regs[Z80_SP], SZ_W);
3323+ }
3324+ mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, target_cycle), options->gen.cycles, SZ_D);
3325+ sub_rdispr(code, options->gen.context_reg, offsetof(z80_context, current_cycle), options->gen.cycles, SZ_D);
3326+ retn(code);
3327+
3328+ options->native_addr = code->cur;
3329+ call(code, options->gen.save_context);
3330+ push_r(code, options->gen.context_reg);
3331+ movzx_rr(code, options->gen.scratch1, options->gen.scratch1, SZ_W, SZ_D);
3332+ call_args(code, (code_ptr)z80_get_native_address_trans, 2, options->gen.context_reg, options->gen.scratch1);
3333+ mov_rr(code, RAX, options->gen.scratch1, SZ_PTR);
3334+ pop_r(code, options->gen.context_reg);
3335+ call(code, options->gen.load_context);
3336+ retn(code);
3337+
3338+ uint32_t tmp_stack_off;
3339+
3340+ options->gen.handle_cycle_limit = code->cur;
3341+ //calculate call/stack adjust size
3342+ sub_ir(code, 16-sizeof(void *), RSP, SZ_PTR);
3343+ call_noalign(code, options->gen.handle_cycle_limit);
3344+ uint32_t call_adjust_size = code->cur - options->gen.handle_cycle_limit;
3345+ code->cur = options->gen.handle_cycle_limit;
3346+
3347+ neg_r(code, options->gen.cycles, SZ_D);
3348+ add_rdispr(code, options->gen.context_reg, offsetof(z80_context, target_cycle), options->gen.cycles, SZ_D);
3349+ cmp_rdispr(code, options->gen.context_reg, offsetof(z80_context, sync_cycle), options->gen.cycles, SZ_D);
3350+ code_ptr no_sync = code->cur+1;
3351+ jcc(code, CC_B, no_sync);
3352+ neg_r(code, options->gen.cycles, SZ_D);
3353+ add_rdispr(code, options->gen.context_reg, offsetof(z80_context, target_cycle), options->gen.cycles, SZ_D);
3354+ mov_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, pc), SZ_W);
3355+ call(code, options->save_context_scratch);
3356+ tmp_stack_off = code->stack_off;
3357+ pop_r(code, RAX); //return address in read/write func
3358+ add_ir(code, 16-sizeof(void *), RSP, SZ_PTR);
3359+ pop_r(code, RBX); //return address in translated code
3360+ add_ir(code, 16-sizeof(void *), RSP, SZ_PTR);
3361+ sub_ir(code, call_adjust_size, RAX, SZ_PTR); //adjust return address to point to the call + stack adjust that got us here
3362+ mov_rrdisp(code, RBX, options->gen.context_reg, offsetof(z80_context, extra_pc), SZ_PTR);
3363+ mov_rrind(code, RAX, options->gen.context_reg, SZ_PTR);
3364+ restore_callee_save_regs(code);
3365+ //return to caller of z80_run
3366+ retn(code);
3367+
3368+ *no_sync = code->cur - (no_sync + 1);
3369+ neg_r(code, options->gen.cycles, SZ_D);
3370+ add_rdispr(code, options->gen.context_reg, offsetof(z80_context, target_cycle), options->gen.cycles, SZ_D);
3371+ retn(code);
3372+ code->stack_off = tmp_stack_off;
3373+
3374+ options->gen.handle_code_write = (code_ptr)z80_handle_code_write;
3375+
3376+ options->read_8 = gen_mem_fun(&options->gen, chunks, num_chunks, READ_8, &options->read_8_noinc);
3377+ options->write_8 = gen_mem_fun(&options->gen, chunks, num_chunks, WRITE_8, &options->write_8_noinc);
3378+
3379+ code_ptr skip_int = code->cur;
3380+ //calculate adjust size
3381+ add_ir(code, 16-sizeof(void *), RSP, SZ_PTR);
3382+ uint32_t adjust_size = code->cur - skip_int;
3383+ code->cur = skip_int;
3384+
3385+ cmp_rdispr(code, options->gen.context_reg, offsetof(z80_context, sync_cycle), options->gen.cycles, SZ_D);
3386+ code_ptr skip_sync = code->cur + 1;
3387+ jcc(code, CC_B, skip_sync);
3388+ neg_r(code, options->gen.cycles, SZ_D);
3389+ add_rdispr(code, options->gen.context_reg, offsetof(z80_context, target_cycle), options->gen.cycles, SZ_D);
3390+ //save PC
3391+ mov_rrdisp(code, options->gen.scratch1, options->gen.context_reg, offsetof(z80_context, pc), SZ_D);
3392+ options->do_sync = code->cur;
3393+ call(code, options->gen.save_context);
3394+ tmp_stack_off = code->stack_off;
3395+ //pop return address off the stack and save for resume later
3396+ //pop_rind(code, options->gen.context_reg);
3397+ pop_r(code, RAX);
3398+ add_ir(code, adjust_size, RAX, SZ_PTR);
3399+ add_ir(code, 16-sizeof(void *), RSP, SZ_PTR);
3400+ mov_rrind(code, RAX, options->gen.context_reg, SZ_PTR);
3401+
3402+ //restore callee saved registers
3403+ restore_callee_save_regs(code);
3404+ //return to caller of z80_run
3405+ retn(code);
3406+ *skip_sync = code->cur - (skip_sync+1);
3407+ neg_r(code, options->gen.cycles, SZ_D);
3408+ add_rdispr(code, options->gen.context_reg, offsetof(z80_context, target_cycle), options->gen.cycles, SZ_D);
3409+ retn(code);
3410+ code->stack_off = tmp_stack_off;
3411+
3412+ options->gen.handle_cycle_limit_int = code->cur;
3413+ neg_r(code, options->gen.cycles, SZ_D);
3414+ add_rdispr(code, options->gen.context_reg, offsetof(z80_context, target_cycle), options->gen.cycles, SZ_D);
3415+ cmp_rdispr(code, options->gen.context_reg, offsetof(z80_context, int_cycle), options->gen.cycles, SZ_D);
3416+ jcc(code, CC_B, skip_int);
3417+ //set limit to the cycle limit
3418+ mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, sync_cycle), options->gen.scratch2, SZ_D);
3419+ mov_rrdisp(code, options->gen.scratch2, options->gen.context_reg, offsetof(z80_context, target_cycle), SZ_D);
3420+ neg_r(code, options->gen.cycles, SZ_D);
3421+ add_rr(code, options->gen.scratch2, options->gen.cycles, SZ_D);
3422+ //disable interrupts
3423+ cmp_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, int_is_nmi), SZ_B);
3424+ code_ptr is_nmi = code->cur + 1;
3425+ jcc(code, CC_NZ, is_nmi);
3426+ mov_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, iff1), SZ_B);
3427+ mov_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, iff2), SZ_B);
3428+ cycles(&options->gen, 6); //interupt ack cycle
3429+ code_ptr after_int_disable = code->cur + 1;
3430+ jmp(code, after_int_disable);
3431+ *is_nmi = code->cur - (is_nmi + 1);
3432+ mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, iff1), options->gen.scratch2, SZ_B);
3433+ mov_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, iff1), SZ_B);
3434+ mov_rrdisp(code, options->gen.scratch2, options->gen.context_reg, offsetof(z80_context, iff2), SZ_B);
3435+ cycles(&options->gen, 5); //NMI processing cycles
3436+ *after_int_disable = code->cur - (after_int_disable + 1);
3437+ //save return address (in scratch1) to Z80 stack
3438+ sub_ir(code, 2, options->regs[Z80_SP], SZ_W);
3439+ mov_rr(code, options->regs[Z80_SP], options->gen.scratch2, SZ_W);
3440+ //we need to do check_cycles and cycles outside of the write_8 call
3441+ //so that the stack has the correct depth if we need to return to C
3442+ //for a synchronization
3443+ check_cycles(&options->gen);
3444+ cycles(&options->gen, 3);
3445+ //save word to write before call to write_8_noinc
3446+ push_r(code, options->gen.scratch1);
3447+ call(code, options->write_8_noinc);
3448+ //restore word to write
3449+ pop_r(code, options->gen.scratch1);
3450+ //write high byte to SP+1
3451+ mov_rr(code, options->regs[Z80_SP], options->gen.scratch2, SZ_W);
3452+ add_ir(code, 1, options->gen.scratch2, SZ_W);
3453+ shr_ir(code, 8, options->gen.scratch1, SZ_W);
3454+ check_cycles(&options->gen);
3455+ cycles(&options->gen, 3);
3456+ call(code, options->write_8_noinc);
3457+ //dispose of return address as we'll be jumping somewhere else
3458+ add_ir(code, 16, RSP, SZ_PTR);
3459+ cmp_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, int_is_nmi), SZ_B);
3460+ is_nmi = code->cur + 1;
3461+ jcc(code, CC_NZ, is_nmi);
3462+ //TODO: Support interrupt mode 0, not needed for Genesis sit it seems to read $FF during intack
3463+ //which is conveniently rst $38, i.e. the same thing that im 1 does
3464+ //check interrupt mode
3465+ cmp_irdisp(code, 2, options->gen.context_reg, offsetof(z80_context, im), SZ_B);
3466+ code_ptr im2 = code->cur + 1;
3467+ jcc(code, CC_Z, im2);
3468+ mov_ir(code, 0x38, options->gen.scratch1, SZ_W);
3469+ cycles(&options->gen, 1); //total time for mode 0/1 is 13 t-states
3470+ code_ptr after_int_dest = code->cur + 1;
3471+ jmp(code, after_int_dest);
3472+ *im2 = code->cur - (im2 + 1);
3473+ //read vector address from I << 8 | vector
3474+ mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, regs) + Z80_I, options->gen.scratch1, SZ_B);
3475+ shl_ir(code, 8, options->gen.scratch1, SZ_W);
3476+ movzx_rdispr(code, options->gen.context_reg, offsetof(z80_context, im2_vector), options->gen.scratch2, SZ_B, SZ_W);
3477+ or_rr(code, options->gen.scratch2, options->gen.scratch1, SZ_W);
3478+ push_r(code, options->gen.scratch1);
3479+ cycles(&options->gen, 3);
3480+ call(code, options->read_8_noinc);
3481+ pop_r(code, options->gen.scratch2);
3482+ push_r(code, options->gen.scratch1);
3483+ mov_rr(code, options->gen.scratch2, options->gen.scratch1, SZ_W);
3484+ add_ir(code, 1, options->gen.scratch1, SZ_W);
3485+ cycles(&options->gen, 3);
3486+ call(code, options->read_8_noinc);
3487+ pop_r(code, options->gen.scratch2);
3488+ shl_ir(code, 8, options->gen.scratch1, SZ_W);
3489+ movzx_rr(code, options->gen.scratch2, options->gen.scratch2, SZ_B, SZ_W);
3490+ or_rr(code, options->gen.scratch2, options->gen.scratch1, SZ_W);
3491+ code_ptr after_int_dest2 = code->cur + 1;
3492+ jmp(code, after_int_dest2);
3493+ *is_nmi = code->cur - (is_nmi + 1);
3494+ mov_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, int_is_nmi), SZ_B);
3495+ mov_irdisp(code, CYCLE_NEVER, options->gen.context_reg, offsetof(z80_context, nmi_start), SZ_D);
3496+ mov_ir(code, 0x66, options->gen.scratch1, SZ_W);
3497+ *after_int_dest = code->cur - (after_int_dest + 1);
3498+ *after_int_dest2 = code->cur - (after_int_dest2 + 1);
3499+ call(code, options->native_addr);
3500+ mov_rrind(code, options->gen.scratch1, options->gen.context_reg, SZ_PTR);
3501+ tmp_stack_off = code->stack_off;
3502+ restore_callee_save_regs(code);
3503+ //return to caller of z80_run to sync
3504+ retn(code);
3505+ code->stack_off = tmp_stack_off;
3506+
3507+ //HACK
3508+ options->gen.address_size = SZ_D;
3509+ options->gen.address_mask = io_address_mask;
3510+ options->gen.bus_cycles = 4;
3511+ options->read_io = gen_mem_fun(&options->gen, io_chunks, num_io_chunks, READ_8, NULL);
3512+ options->write_io = gen_mem_fun(&options->gen, io_chunks, num_io_chunks, WRITE_8, NULL);
3513+ options->gen.address_size = SZ_W;
3514+ options->gen.address_mask = 0xFFFF;
3515+ options->gen.bus_cycles = 3;
3516+
3517+ options->read_16 = code->cur;
3518+ cycles(&options->gen, 3);
3519+ check_cycles(&options->gen);
3520+ //TODO: figure out how to handle the extra wait state for word reads to bank area
3521+ //may also need special handling to avoid too much stack depth when access is blocked
3522+ push_r(code, options->gen.scratch1);
3523+ call(code, options->read_8_noinc);
3524+ mov_rr(code, options->gen.scratch1, options->gen.scratch2, SZ_B);
3525+#ifndef X86_64
3526+ //scratch 2 is a caller save register in 32-bit builds and may be clobbered by something called from the read8 fun
3527+ mov_rrdisp(code, options->gen.scratch1, options->gen.context_reg, offsetof(z80_context, scratch2), SZ_B);
3528+#endif
3529+ pop_r(code, options->gen.scratch1);
3530+ add_ir(code, 1, options->gen.scratch1, SZ_W);
3531+ cycles(&options->gen, 3);
3532+ check_cycles(&options->gen);
3533+ call(code, options->read_8_noinc);
3534+ shl_ir(code, 8, options->gen.scratch1, SZ_W);
3535+#ifdef X86_64
3536+ mov_rr(code, options->gen.scratch2, options->gen.scratch1, SZ_B);
3537+#else
3538+ mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, scratch2), options->gen.scratch1, SZ_B);
3539+#endif
3540+ retn(code);
3541+
3542+ options->write_16_highfirst = code->cur;
3543+ cycles(&options->gen, 3);
3544+ check_cycles(&options->gen);
3545+ push_r(code, options->gen.scratch2);
3546+ push_r(code, options->gen.scratch1);
3547+ add_ir(code, 1, options->gen.scratch2, SZ_W);
3548+ shr_ir(code, 8, options->gen.scratch1, SZ_W);
3549+ call(code, options->write_8_noinc);
3550+ pop_r(code, options->gen.scratch1);
3551+ pop_r(code, options->gen.scratch2);
3552+ cycles(&options->gen, 3);
3553+ check_cycles(&options->gen);
3554+ //TODO: Check if we can get away with TCO here
3555+ call(code, options->write_8_noinc);
3556+ retn(code);
3557+
3558+ options->write_16_lowfirst = code->cur;
3559+ cycles(&options->gen, 3);
3560+ check_cycles(&options->gen);
3561+ push_r(code, options->gen.scratch2);
3562+ push_r(code, options->gen.scratch1);
3563+ call(code, options->write_8_noinc);
3564+ pop_r(code, options->gen.scratch1);
3565+ pop_r(code, options->gen.scratch2);
3566+ add_ir(code, 1, options->gen.scratch2, SZ_W);
3567+ shr_ir(code, 8, options->gen.scratch1, SZ_W);
3568+ cycles(&options->gen, 3);
3569+ check_cycles(&options->gen);
3570+ //TODO: Check if we can get away with TCO here
3571+ call(code, options->write_8_noinc);
3572+ retn(code);
3573+
3574+ options->retrans_stub = code->cur;
3575+ tmp_stack_off = code->stack_off;
3576+ //calculate size of patch
3577+ mov_ir(code, 0x7FFF, options->gen.scratch1, SZ_D);
3578+ code->stack_off += sizeof(void *);
3579+ if (code->stack_off & 0xF) {
3580+ sub_ir(code, 16 - (code->stack_off & 0xF), RSP, SZ_PTR);
3581+ }
3582+ call_noalign(code, options->retrans_stub);
3583+ uint32_t patch_size = code->cur - options->retrans_stub;
3584+ code->cur = options->retrans_stub;
3585+ code->stack_off = tmp_stack_off;
3586+
3587+ //pop return address
3588+ pop_r(code, options->gen.scratch2);
3589+ add_ir(code, 16-sizeof(void*), RSP, SZ_PTR);
3590+ code->stack_off = tmp_stack_off;
3591+ call(code, options->gen.save_context);
3592+ //adjust pointer before move and call instructions that got us here
3593+ sub_ir(code, patch_size, options->gen.scratch2, SZ_PTR);
3594+ push_r(code, options->gen.context_reg);
3595+ call_args(code, (code_ptr)z80_retranslate_inst, 3, options->gen.scratch1, options->gen.context_reg, options->gen.scratch2);
3596+ pop_r(code, options->gen.context_reg);
3597+ mov_rr(code, RAX, options->gen.scratch1, SZ_PTR);
3598+ call(code, options->gen.load_context);
3599+ jmp_r(code, options->gen.scratch1);
3600+
3601+ options->run = (z80_ctx_fun)code->cur;
3602+ tmp_stack_off = code->stack_off;
3603+ save_callee_save_regs(code);
3604+#ifdef X86_64
3605+ mov_rr(code, RDI, options->gen.context_reg, SZ_PTR);
3606+#else
3607+ mov_rdispr(code, RSP, 5 * sizeof(int32_t), options->gen.context_reg, SZ_PTR);
3608+#endif
3609+ call(code, options->load_context_scratch);
3610+ cmp_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, extra_pc), SZ_PTR);
3611+ code_ptr no_extra = code->cur+1;
3612+ jcc(code, CC_Z, no_extra);
3613+ sub_ir(code, 16-sizeof(void *), RSP, SZ_PTR);
3614+ push_rdisp(code, options->gen.context_reg, offsetof(z80_context, extra_pc));
3615+ mov_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, extra_pc), SZ_PTR);
3616+ *no_extra = code->cur - (no_extra + 1);
3617+ jmp_rind(code, options->gen.context_reg);
3618+ code->stack_off = tmp_stack_off;
3619+}
3620+
3621+z80_context *init_z80_context(z80_options * options)
3622+{
3623+ size_t ctx_size = sizeof(z80_context) + ram_size(&options->gen) / (1 << options->gen.ram_flags_shift) / 8;
3624+ z80_context *context = calloc(1, ctx_size);
3625+ context->options = options;
3626+ context->int_cycle = CYCLE_NEVER;
3627+ context->int_pulse_start = CYCLE_NEVER;
3628+ context->int_pulse_end = CYCLE_NEVER;
3629+ context->nmi_start = CYCLE_NEVER;
3630+
3631+ return context;
3632+}
3633+
3634+static void check_nmi(z80_context *context)
3635+{
3636+ if (context->nmi_start < context->int_cycle) {
3637+ context->int_cycle = context->nmi_start;
3638+ context->int_is_nmi = 1;
3639+ }
3640+}
3641+
3642+void z80_run(z80_context * context, uint32_t target_cycle)
3643+{
3644+ if (context->reset || context->busack) {
3645+ context->current_cycle = target_cycle;
3646+ } else {
3647+ if (context->current_cycle < target_cycle) {
3648+ //busreq is sampled at the end of an m-cycle
3649+ //we can approximate that by running for a single m-cycle after a bus request
3650+ context->sync_cycle = context->busreq ? context->current_cycle + 3*context->options->gen.clock_divider : target_cycle;
3651+ if (!context->native_pc) {
3652+ context->native_pc = z80_get_native_address_trans(context, context->pc);
3653+ }
3654+ while (context->current_cycle < context->sync_cycle)
3655+ {
3656+ if (context->next_int_pulse && (context->int_pulse_end < context->current_cycle || context->int_pulse_end == CYCLE_NEVER)) {
3657+ context->next_int_pulse(context);
3658+ }
3659+ if (context->iff1) {
3660+ context->int_cycle = context->int_pulse_start < context->int_enable_cycle ? context->int_enable_cycle : context->int_pulse_start;
3661+ context->int_is_nmi = 0;
3662+ } else {
3663+ context->int_cycle = CYCLE_NEVER;
3664+ }
3665+ check_nmi(context);
3666+
3667+ context->target_cycle = context->sync_cycle < context->int_cycle ? context->sync_cycle : context->int_cycle;
3668+ dprintf("Running Z80 from cycle %d to cycle %d. Int cycle: %d (%d - %d)\n", context->current_cycle, context->sync_cycle, context->int_cycle, context->int_pulse_start, context->int_pulse_end);
3669+ context->options->run(context);
3670+ dprintf("Z80 ran to cycle %d\n", context->current_cycle);
3671+ }
3672+ if (context->busreq) {
3673+ context->busack = 1;
3674+ context->current_cycle = target_cycle;
3675+ }
3676+ }
3677+ }
3678+}
3679+
3680+void z80_options_free(z80_options *opts)
3681+{
3682+ for (uint32_t address = 0; address < opts->gen.address_mask; address += NATIVE_CHUNK_SIZE)
3683+ {
3684+ uint32_t chunk = address / NATIVE_CHUNK_SIZE;
3685+ if (opts->gen.native_code_map[chunk].base) {
3686+ free(opts->gen.native_code_map[chunk].offsets);
3687+ }
3688+ }
3689+ free(opts->gen.native_code_map);
3690+ uint32_t ram_inst_slots = ram_size(&opts->gen) / 1024;
3691+ for (uint32_t i = 0; i < ram_inst_slots; i++)
3692+ {
3693+ free(opts->gen.ram_inst_sizes[i]);
3694+ }
3695+ free(opts->gen.ram_inst_sizes);
3696+ free(opts);
3697+}
3698+
3699+void z80_assert_reset(z80_context * context, uint32_t cycle)
3700+{
3701+ z80_run(context, cycle);
3702+ context->reset = 1;
3703+}
3704+
3705+void z80_clear_reset(z80_context * context, uint32_t cycle)
3706+{
3707+ z80_run(context, cycle);
3708+ if (context->reset) {
3709+ //TODO: Handle case where reset is not asserted long enough
3710+ context->im = 0;
3711+ context->iff1 = context->iff2 = 0;
3712+ context->native_pc = NULL;
3713+ context->extra_pc = NULL;
3714+ context->pc = 0;
3715+ context->reset = 0;
3716+ if (context->busreq) {
3717+ //TODO: Figure out appropriate delay
3718+ context->busack = 1;
3719+ }
3720+ }
3721+}
3722+
3723+void z80_assert_busreq(z80_context * context, uint32_t cycle)
3724+{
3725+ z80_run(context, cycle);
3726+ context->busreq = 1;
3727+ //this is an imperfect aproximation since most M-cycles take less tstates than the max
3728+ //and a short 3-tstate m-cycle can take an unbounded number due to wait states
3729+ if (context->current_cycle - cycle > MAX_MCYCLE_LENGTH * context->options->gen.clock_divider) {
3730+ context->busack = 1;
3731+ }
3732+}
3733+
3734+void z80_clear_busreq(z80_context * context, uint32_t cycle)
3735+{
3736+ z80_run(context, cycle);
3737+ context->busreq = 0;
3738+ context->busack = 0;
3739+ //there appears to be at least a 1 Z80 cycle delay between busreq
3740+ //being released and resumption of execution
3741+ context->current_cycle += context->options->gen.clock_divider;
3742+}
3743+
3744+uint8_t z80_get_busack(z80_context * context, uint32_t cycle)
3745+{
3746+ z80_run(context, cycle);
3747+ return context->busack;
3748+}
3749+
3750+void z80_assert_nmi(z80_context *context, uint32_t cycle)
3751+{
3752+ context->nmi_start = cycle;
3753+ check_nmi(context);
3754+}
3755+
3756+void z80_adjust_cycles(z80_context * context, uint32_t deduction)
3757+{
3758+ if (context->current_cycle < deduction) {
3759+ fprintf(stderr, "WARNING: Deduction of %u cycles when Z80 cycle counter is only %u\n", deduction, context->current_cycle);
3760+ context->current_cycle = 0;
3761+ } else {
3762+ context->current_cycle -= deduction;
3763+ }
3764+ if (context->int_enable_cycle != CYCLE_NEVER) {
3765+ if (context->int_enable_cycle < deduction) {
3766+ context->int_enable_cycle = 0;
3767+ } else {
3768+ context->int_enable_cycle -= deduction;
3769+ }
3770+ }
3771+ if (context->int_pulse_start != CYCLE_NEVER) {
3772+ if (context->int_pulse_end < deduction) {
3773+ context->int_pulse_start = context->int_pulse_end = CYCLE_NEVER;
3774+ } else {
3775+ if (context->int_pulse_end != CYCLE_NEVER) {
3776+ context->int_pulse_end -= deduction;
3777+ }
3778+ if (context->int_pulse_start < deduction) {
3779+ context->int_pulse_start = 0;
3780+ } else {
3781+ context->int_pulse_start -= deduction;
3782+ }
3783+ }
3784+ }
3785+}
3786+
3787+uint32_t zbreakpoint_patch(z80_context * context, uint16_t address, code_ptr dst)
3788+{
3789+ code_info code = {
3790+ dst,
3791+ dst+32,
3792+#ifdef X86_64
3793+ 8
3794+#else
3795+ 0
3796+#endif
3797+ };
3798+ mov_ir(&code, address, context->options->gen.scratch1, SZ_W);
3799+ call(&code, context->bp_stub);
3800+ return code.cur-dst;
3801+}
3802+
3803+void zcreate_stub(z80_context * context)
3804+{
3805+ //FIXME: Stack offset stuff is probably broken on 32-bit
3806+ z80_options * opts = context->options;
3807+ code_info *code = &opts->gen.code;
3808+ uint32_t start_stack_off = code->stack_off;
3809+ check_code_prologue(code);
3810+ context->bp_stub = code->cur;
3811+
3812+ //Calculate length of prologue
3813+ check_cycles_int(&opts->gen, 0);
3814+ int check_int_size = code->cur-context->bp_stub;
3815+ code->cur = context->bp_stub;
3816+
3817+ //Calculate length of patch
3818+ int patch_size = zbreakpoint_patch(context, 0, code->cur);
3819+
3820+#ifdef X86_64
3821+ code->stack_off = 8;
3822+#endif
3823+ //Save context and call breakpoint handler
3824+ call(code, opts->gen.save_context);
3825+ push_r(code, opts->gen.scratch1);
3826+ call_args_abi(code, context->bp_handler, 2, opts->gen.context_reg, opts->gen.scratch1);
3827+ mov_rr(code, RAX, opts->gen.context_reg, SZ_PTR);
3828+ //Restore context
3829+ call(code, opts->gen.load_context);
3830+ pop_r(code, opts->gen.scratch1);
3831+ //do prologue stuff
3832+ cmp_ir(code, 1, opts->gen.cycles, SZ_D);
3833+ uint8_t * jmp_off = code->cur+1;
3834+ jcc(code, CC_NS, code->cur + 7);
3835+ pop_r(code, opts->gen.scratch1);
3836+ add_ir(code, check_int_size - patch_size, opts->gen.scratch1, SZ_PTR);
3837+#ifdef X86_64
3838+ sub_ir(code, 8, RSP, SZ_PTR);
3839+#endif
3840+ push_r(code, opts->gen.scratch1);
3841+ jmp(code, opts->gen.handle_cycle_limit_int);
3842+ *jmp_off = code->cur - (jmp_off+1);
3843+ //jump back to body of translated instruction
3844+ pop_r(code, opts->gen.scratch1);
3845+ add_ir(code, check_int_size - patch_size, opts->gen.scratch1, SZ_PTR);
3846+ jmp_r(code, opts->gen.scratch1);
3847+ code->stack_off = start_stack_off;
3848+}
3849+
3850+void zinsert_breakpoint(z80_context * context, uint16_t address, uint8_t * bp_handler)
3851+{
3852+ context->bp_handler = bp_handler;
3853+ uint8_t bit = 1 << (address % 8);
3854+ if (!(bit & context->breakpoint_flags[address / 8])) {
3855+ context->breakpoint_flags[address / 8] |= bit;
3856+ if (!context->bp_stub) {
3857+ zcreate_stub(context);
3858+ }
3859+ uint8_t * native = z80_get_native_address(context, address);
3860+ if (native) {
3861+ zbreakpoint_patch(context, address, native);
3862+ }
3863+ }
3864+}
3865+
3866+void zremove_breakpoint(z80_context * context, uint16_t address)
3867+{
3868+ context->breakpoint_flags[address / 8] &= ~(1 << (address % 8));
3869+ uint8_t * native = z80_get_native_address(context, address);
3870+ if (native) {
3871+ z80_options * opts = context->options;
3872+ code_info tmp_code = opts->gen.code;
3873+ opts->gen.code.cur = native;
3874+ opts->gen.code.last = native + 128;
3875+ check_cycles_int(&opts->gen, address);
3876+ opts->gen.code = tmp_code;
3877+ }
3878+}
3879+
3880+void z80_serialize(z80_context *context, serialize_buffer *buf)
3881+{
3882+ for (int i = 0; i <= Z80_A; i++)
3883+ {
3884+ save_int8(buf, context->regs[i]);
3885+ }
3886+ uint8_t f = context->flags[ZF_S];
3887+ f <<= 1;
3888+ f |= context->flags[ZF_Z] ;
3889+ f <<= 2;
3890+ f |= context->flags[ZF_H];
3891+ f <<= 2;
3892+ f |= context->flags[ZF_PV];
3893+ f <<= 1;
3894+ f |= context->flags[ZF_N];
3895+ f <<= 1;
3896+ f |= context->flags[ZF_C];
3897+ f |= context->flags[ZF_XY] & 0x28;
3898+ save_int8(buf, f);
3899+ for (int i = 0; i <= Z80_A; i++)
3900+ {
3901+ save_int8(buf, context->alt_regs[i]);
3902+ }
3903+ f = context->alt_flags[ZF_S];
3904+ f <<= 1;
3905+ f |= context->alt_flags[ZF_Z] ;
3906+ f <<= 2;
3907+ f |= context->alt_flags[ZF_H];
3908+ f <<= 2;
3909+ f |= context->alt_flags[ZF_PV];
3910+ f <<= 1;
3911+ f |= context->alt_flags[ZF_N];
3912+ f <<= 1;
3913+ f |= context->alt_flags[ZF_C];
3914+ f |= context->flags[ZF_XY] & 0x28;
3915+ save_int8(buf, f);
3916+ save_int16(buf, context->pc);
3917+ save_int16(buf, context->sp);
3918+ save_int8(buf, context->im);
3919+ save_int8(buf, context->iff1);
3920+ save_int8(buf, context->iff2);
3921+ save_int8(buf, context->int_is_nmi);
3922+ save_int8(buf, context->busack);
3923+ save_int32(buf, context->current_cycle);
3924+ save_int32(buf, context->int_cycle);
3925+ save_int32(buf, context->int_enable_cycle);
3926+ save_int32(buf, context->int_pulse_start);
3927+ save_int32(buf, context->int_pulse_end);
3928+ save_int32(buf, context->nmi_start);
3929+}
3930+
3931+void z80_deserialize(deserialize_buffer *buf, void *vcontext)
3932+{
3933+ z80_context *context = vcontext;
3934+ for (int i = 0; i <= Z80_A; i++)
3935+ {
3936+ context->regs[i] = load_int8(buf);
3937+ }
3938+ uint8_t f = load_int8(buf);
3939+ context->flags[ZF_XY] = f & 0x28;
3940+ context->flags[ZF_C] = f & 1;
3941+ f >>= 1;
3942+ context->flags[ZF_N] = f & 1;
3943+ f >>= 1;
3944+ context->flags[ZF_PV] = f & 1;
3945+ f >>= 2;
3946+ context->flags[ZF_H] = f & 1;
3947+ f >>= 2;
3948+ context->flags[ZF_Z] = f & 1;
3949+ f >>= 1;
3950+ context->flags[ZF_S] = f;
3951+ for (int i = 0; i <= Z80_A; i++)
3952+ {
3953+ context->alt_regs[i] = load_int8(buf);
3954+ }
3955+ f = load_int8(buf);
3956+ context->alt_flags[ZF_XY] = f & 0x28;
3957+ context->alt_flags[ZF_C] = f & 1;
3958+ f >>= 1;
3959+ context->alt_flags[ZF_N] = f & 1;
3960+ f >>= 1;
3961+ context->alt_flags[ZF_PV] = f & 1;
3962+ f >>= 2;
3963+ context->alt_flags[ZF_H] = f & 1;
3964+ f >>= 2;
3965+ context->alt_flags[ZF_Z] = f & 1;
3966+ f >>= 1;
3967+ context->alt_flags[ZF_S] = f;
3968+ context->pc = load_int16(buf);
3969+ context->sp = load_int16(buf);
3970+ context->im = load_int8(buf);
3971+ context->iff1 = load_int8(buf);
3972+ context->iff2 = load_int8(buf);
3973+ context->int_is_nmi = load_int8(buf);
3974+ context->busack = load_int8(buf);
3975+ context->current_cycle = load_int32(buf);
3976+ context->int_cycle = load_int32(buf);
3977+ context->int_enable_cycle = load_int32(buf);
3978+ context->int_pulse_start = load_int32(buf);
3979+ context->int_pulse_end = load_int32(buf);
3980+ context->nmi_start = load_int32(buf);
3981+ context->native_pc = context->extra_pc = NULL;
3982+}
3983+
+117,
-0
1@@ -0,0 +1,117 @@
2+/*
3+ Copyright 2013 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#ifndef Z80_TO_X86_H_
8+#define Z80_TO_X86_H_
9+#include "z80inst.h"
10+#include "backend.h"
11+#include "serialize.h"
12+
13+#define ZNUM_MEM_AREAS 4
14+#ifdef Z80_LOG_ADDRESS
15+#define ZMAX_NATIVE_SIZE 255
16+#else
17+#define ZMAX_NATIVE_SIZE 160
18+#endif
19+
20+enum {
21+ ZF_C = 0,
22+ ZF_N,
23+ ZF_PV,
24+ ZF_H,
25+ ZF_Z,
26+ ZF_S,
27+ ZF_XY,
28+ ZF_NUM
29+};
30+
31+typedef struct z80_context z80_context;
32+typedef void (*z80_ctx_fun)(z80_context * context);
33+
34+typedef struct {
35+ cpu_options gen;
36+ code_ptr save_context_scratch;
37+ code_ptr load_context_scratch;
38+ code_ptr native_addr;
39+ code_ptr retrans_stub;
40+ code_ptr do_sync;
41+ code_ptr read_8;
42+ code_ptr write_8;
43+ code_ptr read_8_noinc;
44+ code_ptr write_8_noinc;
45+ code_ptr read_16;
46+ code_ptr write_16_highfirst;
47+ code_ptr write_16_lowfirst;
48+ code_ptr read_io;
49+ code_ptr write_io;
50+
51+ uint32_t flags;
52+ int8_t regs[Z80_UNUSED];
53+ z80_ctx_fun run;
54+} z80_options;
55+
56+struct z80_context {
57+ void * native_pc;
58+ uint16_t sp;
59+ uint8_t flags[ZF_NUM];
60+ uint16_t bank_reg;
61+ uint8_t regs[Z80_A+1];
62+ uint8_t im;
63+ uint8_t alt_regs[Z80_A+1];
64+ uint32_t target_cycle;
65+ uint32_t current_cycle;
66+ uint8_t alt_flags[ZF_NUM];
67+ uint8_t * mem_pointers[ZNUM_MEM_AREAS];
68+ uint8_t iff1;
69+ uint8_t iff2;
70+ uint16_t scratch1;
71+ uint16_t scratch2;
72+ void * extra_pc;
73+ uint32_t sync_cycle;
74+ uint32_t int_cycle;
75+ z80_options * options;
76+ void * system;
77+ uint32_t int_enable_cycle;
78+ uint16_t pc;
79+ uint32_t int_pulse_start;
80+ uint32_t int_pulse_end;
81+ uint32_t nmi_start;
82+ uint8_t breakpoint_flags[(16 * 1024)/sizeof(uint8_t)];
83+ uint8_t * bp_handler;
84+ uint8_t * bp_stub;
85+ uint8_t * interp_code[256];
86+ z80_ctx_fun next_int_pulse;
87+ uint8_t reset;
88+ uint8_t busreq;
89+ uint8_t busack;
90+ uint8_t int_is_nmi;
91+ uint8_t im2_vector;
92+ uint8_t ram_code_flags[];
93+};
94+
95+void translate_z80_stream(z80_context * context, uint32_t address);
96+void init_z80_opts(z80_options * options, memmap_chunk const * chunks, uint32_t num_chunks, memmap_chunk const * io_chunks, uint32_t num_io_chunks, uint32_t clock_divider, uint32_t io_address_mask);
97+void z80_options_free(z80_options *opts);
98+z80_context * init_z80_context(z80_options * options);
99+code_ptr z80_get_native_address(z80_context * context, uint32_t address);
100+code_ptr z80_get_native_address_trans(z80_context * context, uint32_t address);
101+z80_context * z80_handle_code_write(uint32_t address, z80_context * context);
102+void z80_invalidate_code_range(z80_context *context, uint32_t start, uint32_t end);
103+void z80_reset(z80_context * context);
104+void zinsert_breakpoint(z80_context * context, uint16_t address, uint8_t * bp_handler);
105+void zremove_breakpoint(z80_context * context, uint16_t address);
106+void z80_run(z80_context * context, uint32_t target_cycle);
107+void z80_assert_reset(z80_context * context, uint32_t cycle);
108+void z80_clear_reset(z80_context * context, uint32_t cycle);
109+void z80_assert_busreq(z80_context * context, uint32_t cycle);
110+void z80_clear_busreq(z80_context * context, uint32_t cycle);
111+void z80_assert_nmi(z80_context *context, uint32_t cycle);
112+uint8_t z80_get_busack(z80_context * context, uint32_t cycle);
113+void z80_adjust_cycles(z80_context * context, uint32_t deduction);
114+void z80_serialize(z80_context *context, serialize_buffer *buf);
115+void z80_deserialize(deserialize_buffer *buf, void *vcontext);
116+
117+#endif //Z80_TO_X86_H_
118+
+341,
-0
1@@ -0,0 +1,341 @@
2+#include <string.h>
3+
4+void z80_read_8(z80_context *context)
5+{
6+ context->cycles += 3 * context->opts->gen.clock_divider;
7+ uint8_t *fast = context->fastread[context->scratch1 >> 10];
8+ if (fast) {
9+ context->scratch1 = fast[context->scratch1 & 0x3FF];
10+ } else {
11+ context->scratch1 = read_byte(context->scratch1, (void **)context->mem_pointers, &context->opts->gen, context);
12+ }
13+}
14+
15+void z80_write_8(z80_context *context)
16+{
17+ context->cycles += 3 * context->opts->gen.clock_divider;
18+ uint8_t *fast = context->fastwrite[context->scratch2 >> 10];
19+ if (fast) {
20+ fast[context->scratch2 & 0x3FF] = context->scratch1;
21+ } else {
22+ write_byte(context->scratch2, context->scratch1, (void **)context->mem_pointers, &context->opts->gen, context);
23+ }
24+}
25+
26+void z80_io_read8(z80_context *context)
27+{
28+ uint32_t tmp_mask = context->opts->gen.address_mask;
29+ memmap_chunk const *tmp_map = context->opts->gen.memmap;
30+ uint32_t tmp_chunks = context->opts->gen.memmap_chunks;
31+
32+ context->opts->gen.address_mask = context->io_mask;
33+ context->opts->gen.memmap = context->io_map;
34+ context->opts->gen.memmap_chunks = context->io_chunks;
35+
36+ context->cycles += 4 * context->opts->gen.clock_divider;
37+ context->scratch1 = read_byte(context->scratch1, (void **)context->mem_pointers, &context->opts->gen, context);
38+
39+ context->opts->gen.address_mask = tmp_mask;
40+ context->opts->gen.memmap = tmp_map;
41+ context->opts->gen.memmap_chunks = tmp_chunks;
42+}
43+
44+void z80_io_write8(z80_context *context)
45+{
46+ uint32_t tmp_mask = context->opts->gen.address_mask;
47+ memmap_chunk const *tmp_map = context->opts->gen.memmap;
48+ uint32_t tmp_chunks = context->opts->gen.memmap_chunks;
49+
50+ context->opts->gen.address_mask = context->io_mask;
51+ context->opts->gen.memmap = context->io_map;
52+ context->opts->gen.memmap_chunks = context->io_chunks;
53+
54+ context->cycles += 4 * context->opts->gen.clock_divider;
55+ write_byte(context->scratch2, context->scratch1, (void **)context->mem_pointers, &context->opts->gen, context);
56+
57+ context->opts->gen.address_mask = tmp_mask;
58+ context->opts->gen.memmap = tmp_map;
59+ context->opts->gen.memmap_chunks = tmp_chunks;
60+}
61+
62+//quick hack until I get a chance to change which init method these get passed to
63+static memmap_chunk const * tmp_io_chunks;
64+static uint32_t tmp_num_io_chunks, tmp_io_mask;
65+void init_z80_opts(z80_options * options, memmap_chunk const * chunks, uint32_t num_chunks, memmap_chunk const * io_chunks, uint32_t num_io_chunks, uint32_t clock_divider, uint32_t io_address_mask)
66+{
67+ memset(options, 0, sizeof(*options));
68+ options->gen.memmap = chunks;
69+ options->gen.memmap_chunks = num_chunks;
70+ options->gen.address_mask = 0xFFFF;
71+ options->gen.max_address = 0xFFFF;
72+ options->gen.clock_divider = clock_divider;
73+ tmp_io_chunks = io_chunks;
74+ tmp_num_io_chunks = num_io_chunks;
75+ tmp_io_mask = io_address_mask;
76+}
77+
78+void z80_options_free(z80_options *opts)
79+{
80+ free(opts);
81+}
82+
83+z80_context * init_z80_context(z80_options *options)
84+{
85+ z80_context *context = calloc(1, sizeof(z80_context));
86+ context->opts = options;
87+ context->io_map = (memmap_chunk *)tmp_io_chunks;
88+ context->io_chunks = tmp_num_io_chunks;
89+ context->io_mask = tmp_io_mask;
90+ context->int_cycle = context->int_end_cycle = context->nmi_cycle = 0xFFFFFFFFU;
91+ z80_invalidate_code_range(context, 0, 0xFFFF);
92+ return context;
93+}
94+
95+void z80_sync_cycle(z80_context *context, uint32_t target_cycle)
96+{
97+ if (context->iff1 && context->int_cycle < target_cycle) {
98+ if (context->cycles > context->int_end_cycle) {
99+ context->int_cycle = 0xFFFFFFFFU;
100+ } else {
101+ target_cycle = context->int_cycle;
102+ }
103+ };
104+ if (context->nmi_cycle < target_cycle) {
105+ target_cycle = context->nmi_cycle;
106+ }
107+ context->sync_cycle = target_cycle;
108+}
109+
110+void z80_run(z80_context *context, uint32_t target_cycle)
111+{
112+ if (context->reset || context->busack) {
113+ context->cycles = target_cycle;
114+ } else if (target_cycle > context->cycles) {
115+ if (context->busreq) {
116+ //busreq is sampled at the end of an m-cycle
117+ //we can approximate that by running for a single m-cycle after a bus request
118+ target_cycle = context->cycles + 4 * context->opts->gen.clock_divider;
119+ }
120+ z80_execute(context, target_cycle);
121+ if (context->busreq) {
122+ context->busack = 1;
123+ }
124+ }
125+}
126+
127+void z80_assert_reset(z80_context * context, uint32_t cycle)
128+{
129+ z80_run(context, cycle);
130+ context->reset = 1;
131+}
132+
133+void z80_clear_reset(z80_context * context, uint32_t cycle)
134+{
135+ z80_run(context, cycle);
136+ if (context->reset) {
137+ context->imode = 0;
138+ context->iff1 = context->iff2 = 0;
139+ context->pc = 0;
140+ context->reset = 0;
141+ if (context->busreq) {
142+ //TODO: Figure out appropriate delay
143+ context->busack = 1;
144+ }
145+ }
146+}
147+
148+#define MAX_MCYCLE_LENGTH 6
149+void z80_assert_busreq(z80_context * context, uint32_t cycle)
150+{
151+ z80_run(context, cycle);
152+ context->busreq = 1;
153+ //this is an imperfect aproximation since most M-cycles take less tstates than the max
154+ //and a short 3-tstate m-cycle can take an unbounded number due to wait states
155+ if (context->cycles - cycle > MAX_MCYCLE_LENGTH * context->opts->gen.clock_divider) {
156+ context->busack = 1;
157+ }
158+}
159+
160+void z80_clear_busreq(z80_context * context, uint32_t cycle)
161+{
162+ z80_run(context, cycle);
163+ context->busreq = 0;
164+ context->busack = 0;
165+ //there appears to be at least a 1 Z80 cycle delay between busreq
166+ //being released and resumption of execution
167+ context->cycles += context->opts->gen.clock_divider;
168+}
169+
170+void z80_assert_nmi(z80_context *context, uint32_t cycle)
171+{
172+ context->nmi_cycle = cycle;
173+}
174+
175+uint8_t z80_get_busack(z80_context * context, uint32_t cycle)
176+{
177+ z80_run(context, cycle);
178+ return context->busack;
179+}
180+
181+void z80_invalidate_code_range(z80_context *context, uint32_t startA, uint32_t endA)
182+{
183+ for(startA &= ~0x3FF; startA < endA; startA += 1024)
184+ {
185+ uint8_t *start = get_native_pointer(startA, (void**)context->mem_pointers, &context->opts->gen);
186+ if (start) {
187+ uint8_t *end = get_native_pointer(startA + 1023, (void**)context->mem_pointers, &context->opts->gen);
188+ if (!end || end - start != 1023) {
189+ start = NULL;
190+ }
191+ }
192+ context->fastread[startA >> 10] = start;
193+ start = get_native_write_pointer(startA, (void**)context->mem_pointers, &context->opts->gen);
194+ if (start) {
195+ uint8_t *end = get_native_write_pointer(startA + 1023, (void**)context->mem_pointers, &context->opts->gen);
196+ if (!end || end - start != 1023) {
197+ start = NULL;
198+ }
199+ }
200+ context->fastwrite[startA >> 10] = start;
201+ }
202+}
203+
204+void z80_adjust_cycles(z80_context * context, uint32_t deduction)
205+{
206+ context->cycles -= deduction;
207+ if (context->int_cycle != 0xFFFFFFFFU) {
208+ if (context->int_cycle > deduction) {
209+ context->int_cycle -= deduction;
210+ } else {
211+ context->int_cycle = 0;
212+ }
213+ }
214+ if (context->int_end_cycle != 0xFFFFFFFFU) {
215+ if (context->int_end_cycle > deduction) {
216+ context->int_end_cycle -= deduction;
217+ } else {
218+ context->int_end_cycle = 0;
219+ }
220+ }
221+ if (context->nmi_cycle != 0xFFFFFFFFU) {
222+ if (context->nmi_cycle > deduction) {
223+ context->nmi_cycle -= deduction;
224+ } else {
225+ context->nmi_cycle = 0;
226+ }
227+ }
228+}
229+
230+void z80_serialize(z80_context *context, serialize_buffer *buf)
231+{
232+ save_int8(buf, context->main[1]);//C
233+ save_int8(buf, context->main[0]);//B
234+ save_int8(buf, context->main[3]);//E
235+ save_int8(buf, context->main[2]);//D
236+ save_int8(buf, context->main[5]);//L
237+ save_int8(buf, context->main[4]);//H
238+ save_int8(buf, context->ix);//IXL
239+ save_int8(buf, context->ix >> 8);//IXH
240+ save_int8(buf, context->iy);//IYL
241+ save_int8(buf, context->iy >> 8);//IYH
242+ save_int8(buf, context->i);
243+ save_int8(buf, (context->rhigh & 0x80) | (context->r & 0x7F));
244+ save_int8(buf, context->main[7]);//A
245+ uint8_t f = context->last_flag_result & 0xA8
246+ | (context->zflag ? 0x40 : 0)
247+ | (context->chflags & 8 ? 0x10 : 0)
248+ | (context->pvflag ? 4 : 0)
249+ | (context->nflag ? 2 : 0)
250+ | (context->chflags & 0x80 ? 1 : 0);
251+ save_int8(buf, f);
252+ save_int8(buf, context->alt[1]);//C
253+ save_int8(buf, context->alt[0]);//B
254+ save_int8(buf, context->alt[3]);//E
255+ save_int8(buf, context->alt[2]);//D
256+ save_int8(buf, context->alt[5]);//L
257+ save_int8(buf, context->alt[4]);//H
258+ save_int8(buf, 0);//non-existant alt ixl
259+ save_int8(buf, 0);//non-existant alt ixh
260+ save_int8(buf, 0);//non-existant alt iyl
261+ save_int8(buf, 0);//non-existant alt iyh
262+ save_int8(buf, 0);//non-existant alt i
263+ save_int8(buf, 0);//non-existant alt r
264+ save_int8(buf, context->alt[7]);//A
265+ save_int8(buf, context->alt[6]);//F
266+
267+ save_int16(buf, context->pc);
268+ save_int16(buf, context->sp);
269+ save_int8(buf, context->imode);
270+ save_int8(buf, context->iff1);
271+ save_int8(buf, context->iff2);
272+ uint8_t is_nmi = context->nmi_cycle != 0xFFFFFFFF && (context->nmi_cycle < context->int_cycle || !context->iff1);
273+ save_int8(buf, is_nmi);//int_is_nmi
274+ save_int8(buf, context->busack);
275+ save_int32(buf, context->cycles);
276+ save_int32(buf, is_nmi ? context->nmi_cycle : context->int_cycle);//int_cycle
277+ save_int32(buf, 0);//int_enable_cycle
278+ save_int32(buf, context->int_cycle);
279+ save_int32(buf, context->int_end_cycle);
280+ save_int32(buf, context->nmi_cycle);
281+}
282+
283+void z80_deserialize(deserialize_buffer *buf, void *vcontext)
284+{
285+ z80_context *context = vcontext;
286+ context->main[1] = load_int8(buf);//C
287+ context->main[0] = load_int8(buf);//B
288+ context->main[3] = load_int8(buf);//E
289+ context->main[2] = load_int8(buf);//D
290+ context->main[5] = load_int8(buf);//L
291+ context->main[4] = load_int8(buf);//H
292+ context->ix = load_int8(buf);//IXL
293+ context->ix |= load_int8(buf) << 8;//IXH
294+ context->iy = load_int8(buf);//IYL
295+ context->iy |= load_int8(buf) << 8;//IYH
296+ context->i = load_int8(buf);
297+ context->r = load_int8(buf);
298+ context->rhigh = context->r & 0x80;
299+ context->main[7] = load_int8(buf);//A
300+ context->last_flag_result = load_int8(buf);
301+ context->zflag = context->last_flag_result & 0x40;
302+ context->chflags = context->last_flag_result & 0x10 ? 8 : 0;
303+ context->pvflag = context->last_flag_result & 4;
304+ context->nflag = context->last_flag_result & 2;
305+ context->chflags |= context->last_flag_result & 1 ? 0x80 : 0;
306+ context->alt[1] = load_int8(buf);//C
307+ context->alt[0] = load_int8(buf);//B
308+ context->alt[3] = load_int8(buf);//E
309+ context->alt[2] = load_int8(buf);//D
310+ context->alt[5] = load_int8(buf);//L
311+ context->alt[4] = load_int8(buf);//H
312+ load_int8(buf);//non-existant alt ixl
313+ load_int8(buf);//non-existant alt ixh
314+ load_int8(buf);//non-existant alt iyl
315+ load_int8(buf);//non-existant alt iyh
316+ load_int8(buf);//non-existant alt i
317+ load_int8(buf);//non-existant alt r
318+ context->alt[7] = load_int8(buf);//A
319+ context->alt[6] = load_int8(buf);//F
320+
321+ context->pc = load_int16(buf);
322+ context->sp = load_int16(buf);
323+ context->imode = load_int8(buf);
324+ context->iff1 = load_int8(buf);
325+ context->iff2 = load_int8(buf);
326+ load_int8(buf);//int_is_nmi
327+ context->busack = load_int8(buf);
328+ context->cycles = load_int32(buf);
329+ load_int32(buf);//int_cycle
330+ load_int32(buf);//int_enable_cycle
331+ context->int_cycle = load_int32(buf);
332+ context->int_end_cycle = load_int32(buf);
333+ context->nmi_cycle = load_int32(buf);
334+}
335+
336+void zinsert_breakpoint(z80_context * context, uint16_t address, uint8_t * bp_handler)
337+{
338+}
339+
340+void zremove_breakpoint(z80_context * context, uint16_t address)
341+{
342+}
+1577,
-0
1@@ -0,0 +1,1577 @@
2+/*
3+ Copyright 2013 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#include "z80inst.h"
8+#include <string.h>
9+#include <stdio.h>
10+#include <stddef.h>
11+
12+#define NOP {Z80_NOP, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0}
13+#define USE_MAIN {Z80_USE_MAIN, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0}
14+
15+z80inst z80_tbl_a[256] = {
16+ //0
17+ NOP,
18+ {Z80_LD, Z80_BC, Z80_IMMED, Z80_UNUSED, 0},
19+ {Z80_LD, Z80_A, Z80_REG_INDIRECT | Z80_DIR, Z80_BC, 0},
20+ {Z80_INC, Z80_BC, Z80_UNUSED, Z80_UNUSED, 0},
21+ {Z80_INC, Z80_B, Z80_UNUSED, Z80_UNUSED, 0},
22+ {Z80_DEC, Z80_B, Z80_UNUSED, Z80_UNUSED, 0},
23+ {Z80_LD, Z80_B, Z80_IMMED, Z80_UNUSED, 0},
24+ {Z80_RLC, Z80_A, Z80_UNUSED, Z80_UNUSED, 0},
25+ {Z80_EX, Z80_AF, Z80_REG, Z80_AF, 0},
26+ {Z80_ADD, Z80_HL, Z80_REG, Z80_BC, 0},
27+ {Z80_LD, Z80_A, Z80_REG_INDIRECT, Z80_BC, 0},
28+ {Z80_DEC, Z80_BC, Z80_UNUSED, Z80_UNUSED, 0},
29+ {Z80_INC, Z80_C, Z80_UNUSED, Z80_UNUSED, 0},
30+ {Z80_DEC, Z80_C, Z80_UNUSED, Z80_UNUSED, 0},
31+ {Z80_LD, Z80_C, Z80_IMMED, Z80_UNUSED, 0},
32+ {Z80_RRC, Z80_A, Z80_UNUSED, Z80_UNUSED, 0},
33+ //1
34+ {Z80_DJNZ, Z80_UNUSED, Z80_IMMED, Z80_UNUSED, 0},
35+ {Z80_LD, Z80_DE, Z80_IMMED, Z80_UNUSED, 0},
36+ {Z80_LD, Z80_A, Z80_REG_INDIRECT | Z80_DIR, Z80_DE, 0},
37+ {Z80_INC, Z80_DE, Z80_UNUSED, Z80_UNUSED, 0},
38+ {Z80_INC, Z80_D, Z80_UNUSED, Z80_UNUSED, 0},
39+ {Z80_DEC, Z80_D, Z80_UNUSED, Z80_UNUSED, 0},
40+ {Z80_LD, Z80_D, Z80_IMMED, Z80_UNUSED, 0},
41+ {Z80_RL, Z80_A, Z80_UNUSED, Z80_UNUSED, 0},
42+ {Z80_JR, Z80_UNUSED, Z80_IMMED, Z80_UNUSED, 0},
43+ {Z80_ADD, Z80_HL, Z80_REG, Z80_DE, 0},
44+ {Z80_LD, Z80_A, Z80_REG_INDIRECT, Z80_DE, 0},
45+ {Z80_DEC, Z80_DE, Z80_UNUSED, Z80_UNUSED, 0},
46+ {Z80_INC, Z80_E, Z80_UNUSED, Z80_UNUSED, 0},
47+ {Z80_DEC, Z80_E, Z80_UNUSED, Z80_UNUSED, 0},
48+ {Z80_LD, Z80_E, Z80_IMMED, Z80_UNUSED, 0},
49+ {Z80_RR, Z80_A, Z80_UNUSED, Z80_UNUSED, 0},
50+ //2
51+ {Z80_JRCC, Z80_CC_NZ, Z80_IMMED, Z80_UNUSED, 0},
52+ {Z80_LD, Z80_HL, Z80_IMMED, Z80_UNUSED, 0},
53+ {Z80_LD, Z80_HL, Z80_IMMED_INDIRECT | Z80_DIR, Z80_UNUSED, 0},
54+ {Z80_INC, Z80_HL, Z80_UNUSED, Z80_UNUSED, 0},
55+ {Z80_INC, Z80_H, Z80_UNUSED, Z80_UNUSED, 0},
56+ {Z80_DEC, Z80_H, Z80_UNUSED, Z80_UNUSED, 0},
57+ {Z80_LD, Z80_H, Z80_IMMED, Z80_UNUSED, 0},
58+ {Z80_DAA, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
59+ {Z80_JRCC, Z80_CC_Z, Z80_IMMED, Z80_UNUSED, 0},
60+ {Z80_ADD, Z80_HL, Z80_REG, Z80_HL, 0},
61+ {Z80_LD, Z80_HL, Z80_IMMED_INDIRECT, Z80_IMMED, 0},
62+ {Z80_DEC, Z80_HL, Z80_UNUSED, Z80_UNUSED, 0},
63+ {Z80_INC, Z80_L, Z80_UNUSED, Z80_UNUSED, 0},
64+ {Z80_DEC, Z80_L, Z80_UNUSED, Z80_UNUSED, 0},
65+ {Z80_LD, Z80_L, Z80_IMMED, Z80_UNUSED, 0},
66+ {Z80_CPL, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
67+ //3
68+ {Z80_JRCC, Z80_CC_NC, Z80_IMMED, Z80_UNUSED, 0},
69+ {Z80_LD, Z80_SP, Z80_IMMED, Z80_UNUSED, 0},
70+ {Z80_LD, Z80_A, Z80_IMMED_INDIRECT | Z80_DIR, Z80_UNUSED, 0},
71+ {Z80_INC, Z80_SP, Z80_UNUSED, Z80_UNUSED, 0},
72+ {Z80_INC, Z80_UNUSED, Z80_REG_INDIRECT, Z80_HL, 0},
73+ {Z80_DEC, Z80_UNUSED, Z80_REG_INDIRECT, Z80_HL, 0},
74+ {Z80_LD, Z80_USE_IMMED, Z80_REG_INDIRECT | Z80_DIR, Z80_HL, 0},
75+ {Z80_SCF, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
76+ {Z80_JRCC, Z80_CC_C, Z80_IMMED, Z80_UNUSED, 0},
77+ {Z80_ADD, Z80_HL, Z80_REG, Z80_SP, 0},
78+ {Z80_LD, Z80_A, Z80_IMMED_INDIRECT, Z80_IMMED, 0},
79+ {Z80_DEC, Z80_SP, Z80_UNUSED, Z80_UNUSED, 0},
80+ {Z80_INC, Z80_A, Z80_UNUSED, Z80_UNUSED, 0},
81+ {Z80_DEC, Z80_A, Z80_UNUSED, Z80_UNUSED, 0},
82+ {Z80_LD, Z80_A, Z80_IMMED, Z80_UNUSED, 0},
83+ {Z80_CCF, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
84+ //4
85+ {Z80_LD, Z80_B, Z80_REG, Z80_B, 0},
86+ {Z80_LD, Z80_B, Z80_REG, Z80_C, 0},
87+ {Z80_LD, Z80_B, Z80_REG, Z80_D, 0},
88+ {Z80_LD, Z80_B, Z80_REG, Z80_E, 0},
89+ {Z80_LD, Z80_B, Z80_REG, Z80_H, 0},
90+ {Z80_LD, Z80_B, Z80_REG, Z80_L, 0},
91+ {Z80_LD, Z80_B, Z80_REG_INDIRECT, Z80_HL, 0},
92+ {Z80_LD, Z80_B, Z80_REG, Z80_A, 0},
93+ {Z80_LD, Z80_C, Z80_REG, Z80_B, 0},
94+ {Z80_LD, Z80_C, Z80_REG, Z80_C, 0},
95+ {Z80_LD, Z80_C, Z80_REG, Z80_D, 0},
96+ {Z80_LD, Z80_C, Z80_REG, Z80_E, 0},
97+ {Z80_LD, Z80_C, Z80_REG, Z80_H, 0},
98+ {Z80_LD, Z80_C, Z80_REG, Z80_L, 0},
99+ {Z80_LD, Z80_C, Z80_REG_INDIRECT, Z80_HL, 0},
100+ {Z80_LD, Z80_C, Z80_REG, Z80_A, 0},
101+ //5
102+ {Z80_LD, Z80_D, Z80_REG, Z80_B, 0},
103+ {Z80_LD, Z80_D, Z80_REG, Z80_C, 0},
104+ {Z80_LD, Z80_D, Z80_REG, Z80_D, 0},
105+ {Z80_LD, Z80_D, Z80_REG, Z80_E, 0},
106+ {Z80_LD, Z80_D, Z80_REG, Z80_H, 0},
107+ {Z80_LD, Z80_D, Z80_REG, Z80_L, 0},
108+ {Z80_LD, Z80_D, Z80_REG_INDIRECT, Z80_HL, 0},
109+ {Z80_LD, Z80_D, Z80_REG, Z80_A, 0},
110+ {Z80_LD, Z80_E, Z80_REG, Z80_B, 0},
111+ {Z80_LD, Z80_E, Z80_REG, Z80_C, 0},
112+ {Z80_LD, Z80_E, Z80_REG, Z80_D, 0},
113+ {Z80_LD, Z80_E, Z80_REG, Z80_E, 0},
114+ {Z80_LD, Z80_E, Z80_REG, Z80_H, 0},
115+ {Z80_LD, Z80_E, Z80_REG, Z80_L, 0},
116+ {Z80_LD, Z80_E, Z80_REG_INDIRECT, Z80_HL, 0},
117+ {Z80_LD, Z80_E, Z80_REG, Z80_A, 0},
118+ //6
119+ {Z80_LD, Z80_H, Z80_REG, Z80_B, 0},
120+ {Z80_LD, Z80_H, Z80_REG, Z80_C, 0},
121+ {Z80_LD, Z80_H, Z80_REG, Z80_D, 0},
122+ {Z80_LD, Z80_H, Z80_REG, Z80_E, 0},
123+ {Z80_LD, Z80_H, Z80_REG, Z80_H, 0},
124+ {Z80_LD, Z80_H, Z80_REG, Z80_L, 0},
125+ {Z80_LD, Z80_H, Z80_REG_INDIRECT, Z80_HL, 0},
126+ {Z80_LD, Z80_H, Z80_REG, Z80_A, 0},
127+ {Z80_LD, Z80_L, Z80_REG, Z80_B, 0},
128+ {Z80_LD, Z80_L, Z80_REG, Z80_C, 0},
129+ {Z80_LD, Z80_L, Z80_REG, Z80_D, 0},
130+ {Z80_LD, Z80_L, Z80_REG, Z80_E, 0},
131+ {Z80_LD, Z80_L, Z80_REG, Z80_H, 0},
132+ {Z80_LD, Z80_L, Z80_REG, Z80_L, 0},
133+ {Z80_LD, Z80_L, Z80_REG_INDIRECT, Z80_HL, 0},
134+ {Z80_LD, Z80_L, Z80_REG, Z80_A, 0},
135+ //7
136+ {Z80_LD, Z80_B, Z80_REG_INDIRECT | Z80_DIR, Z80_HL, 0},
137+ {Z80_LD, Z80_C, Z80_REG_INDIRECT | Z80_DIR, Z80_HL, 0},
138+ {Z80_LD, Z80_D, Z80_REG_INDIRECT | Z80_DIR, Z80_HL, 0},
139+ {Z80_LD, Z80_E, Z80_REG_INDIRECT | Z80_DIR, Z80_HL, 0},
140+ {Z80_LD, Z80_H, Z80_REG_INDIRECT | Z80_DIR, Z80_HL, 0},
141+ {Z80_LD, Z80_L, Z80_REG_INDIRECT | Z80_DIR, Z80_HL, 0},
142+ {Z80_HALT, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
143+ {Z80_LD, Z80_A, Z80_REG_INDIRECT | Z80_DIR, Z80_HL, 0},
144+ {Z80_LD, Z80_A, Z80_REG, Z80_B, 0},
145+ {Z80_LD, Z80_A, Z80_REG, Z80_C, 0},
146+ {Z80_LD, Z80_A, Z80_REG, Z80_D, 0},
147+ {Z80_LD, Z80_A, Z80_REG, Z80_E, 0},
148+ {Z80_LD, Z80_A, Z80_REG, Z80_H, 0},
149+ {Z80_LD, Z80_A, Z80_REG, Z80_L, 0},
150+ {Z80_LD, Z80_A, Z80_REG_INDIRECT, Z80_HL, 0},
151+ {Z80_LD, Z80_A, Z80_REG, Z80_A, 0},
152+ //8
153+ {Z80_ADD, Z80_A, Z80_REG, Z80_B, 0},
154+ {Z80_ADD, Z80_A, Z80_REG, Z80_C, 0},
155+ {Z80_ADD, Z80_A, Z80_REG, Z80_D, 0},
156+ {Z80_ADD, Z80_A, Z80_REG, Z80_E, 0},
157+ {Z80_ADD, Z80_A, Z80_REG, Z80_H, 0},
158+ {Z80_ADD, Z80_A, Z80_REG, Z80_L, 0},
159+ {Z80_ADD, Z80_A, Z80_REG_INDIRECT, Z80_HL, 0},
160+ {Z80_ADD, Z80_A, Z80_REG, Z80_A, 0},
161+ {Z80_ADC, Z80_A, Z80_REG, Z80_B, 0},
162+ {Z80_ADC, Z80_A, Z80_REG, Z80_C, 0},
163+ {Z80_ADC, Z80_A, Z80_REG, Z80_D, 0},
164+ {Z80_ADC, Z80_A, Z80_REG, Z80_E, 0},
165+ {Z80_ADC, Z80_A, Z80_REG, Z80_H, 0},
166+ {Z80_ADC, Z80_A, Z80_REG, Z80_L, 0},
167+ {Z80_ADC, Z80_A, Z80_REG_INDIRECT, Z80_HL, 0},
168+ {Z80_ADC, Z80_A, Z80_REG, Z80_A, 0},
169+ //9
170+ {Z80_SUB, Z80_A, Z80_REG, Z80_B, 0},
171+ {Z80_SUB, Z80_A, Z80_REG, Z80_C, 0},
172+ {Z80_SUB, Z80_A, Z80_REG, Z80_D, 0},
173+ {Z80_SUB, Z80_A, Z80_REG, Z80_E, 0},
174+ {Z80_SUB, Z80_A, Z80_REG, Z80_H, 0},
175+ {Z80_SUB, Z80_A, Z80_REG, Z80_L, 0},
176+ {Z80_SUB, Z80_A, Z80_REG_INDIRECT, Z80_HL, 0},
177+ {Z80_SUB, Z80_A, Z80_REG, Z80_A, 0},
178+ {Z80_SBC, Z80_A, Z80_REG, Z80_B, 0},
179+ {Z80_SBC, Z80_A, Z80_REG, Z80_C, 0},
180+ {Z80_SBC, Z80_A, Z80_REG, Z80_D, 0},
181+ {Z80_SBC, Z80_A, Z80_REG, Z80_E, 0},
182+ {Z80_SBC, Z80_A, Z80_REG, Z80_H, 0},
183+ {Z80_SBC, Z80_A, Z80_REG, Z80_L, 0},
184+ {Z80_SBC, Z80_A, Z80_REG_INDIRECT, Z80_HL, 0},
185+ {Z80_SBC, Z80_A, Z80_REG, Z80_A, 0},
186+ //A
187+ {Z80_AND, Z80_A, Z80_REG, Z80_B, 0},
188+ {Z80_AND, Z80_A, Z80_REG, Z80_C, 0},
189+ {Z80_AND, Z80_A, Z80_REG, Z80_D, 0},
190+ {Z80_AND, Z80_A, Z80_REG, Z80_E, 0},
191+ {Z80_AND, Z80_A, Z80_REG, Z80_H, 0},
192+ {Z80_AND, Z80_A, Z80_REG, Z80_L, 0},
193+ {Z80_AND, Z80_A, Z80_REG_INDIRECT, Z80_HL, 0},
194+ {Z80_AND, Z80_A, Z80_REG, Z80_A, 0},
195+ {Z80_XOR, Z80_A, Z80_REG, Z80_B, 0},
196+ {Z80_XOR, Z80_A, Z80_REG, Z80_C, 0},
197+ {Z80_XOR, Z80_A, Z80_REG, Z80_D, 0},
198+ {Z80_XOR, Z80_A, Z80_REG, Z80_E, 0},
199+ {Z80_XOR, Z80_A, Z80_REG, Z80_H, 0},
200+ {Z80_XOR, Z80_A, Z80_REG, Z80_L, 0},
201+ {Z80_XOR, Z80_A, Z80_REG_INDIRECT, Z80_HL, 0},
202+ {Z80_XOR, Z80_A, Z80_REG, Z80_A, 0},
203+ //B
204+ {Z80_OR, Z80_A, Z80_REG, Z80_B, 0},
205+ {Z80_OR, Z80_A, Z80_REG, Z80_C, 0},
206+ {Z80_OR, Z80_A, Z80_REG, Z80_D, 0},
207+ {Z80_OR, Z80_A, Z80_REG, Z80_E, 0},
208+ {Z80_OR, Z80_A, Z80_REG, Z80_H, 0},
209+ {Z80_OR, Z80_A, Z80_REG, Z80_L, 0},
210+ {Z80_OR, Z80_A, Z80_REG_INDIRECT, Z80_HL, 0},
211+ {Z80_OR, Z80_A, Z80_REG, Z80_A, 0},
212+ {Z80_CP, Z80_A, Z80_REG, Z80_B, 0},
213+ {Z80_CP, Z80_A, Z80_REG, Z80_C, 0},
214+ {Z80_CP, Z80_A, Z80_REG, Z80_D, 0},
215+ {Z80_CP, Z80_A, Z80_REG, Z80_E, 0},
216+ {Z80_CP, Z80_A, Z80_REG, Z80_H, 0},
217+ {Z80_CP, Z80_A, Z80_REG, Z80_L, 0},
218+ {Z80_CP, Z80_A, Z80_REG_INDIRECT, Z80_HL, 0},
219+ {Z80_CP, Z80_A, Z80_REG, Z80_A, 0},
220+ //C
221+ {Z80_RETCC, Z80_CC_NZ, Z80_UNUSED, Z80_UNUSED, 0},
222+ {Z80_POP, Z80_BC, Z80_UNUSED, Z80_UNUSED, 0},
223+ {Z80_JPCC, Z80_CC_NZ, Z80_IMMED, Z80_UNUSED, 0},
224+ {Z80_JP, Z80_UNUSED, Z80_IMMED, Z80_UNUSED, 0},
225+ {Z80_CALLCC, Z80_CC_NZ, Z80_IMMED, Z80_UNUSED, 0},
226+ {Z80_PUSH, Z80_BC, Z80_UNUSED, Z80_UNUSED, 0},
227+ {Z80_ADD, Z80_A, Z80_IMMED, Z80_UNUSED, 0},
228+ {Z80_RST, Z80_UNUSED, Z80_IMMED, Z80_UNUSED, 0x0},
229+ {Z80_RETCC, Z80_CC_Z, Z80_UNUSED, Z80_UNUSED, 0},
230+ {Z80_RET, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
231+ {Z80_JPCC, Z80_CC_Z, Z80_IMMED, Z80_UNUSED, 0},
232+ {0, 0, 0, 0, 0},//BITS Prefix
233+ {Z80_CALLCC, Z80_CC_Z, Z80_IMMED, Z80_UNUSED, 0},
234+ {Z80_CALL, Z80_UNUSED, Z80_IMMED, Z80_UNUSED, 0},
235+ {Z80_ADC, Z80_A, Z80_IMMED, Z80_UNUSED, 0},
236+ {Z80_RST, Z80_UNUSED, Z80_IMMED, Z80_UNUSED, 0x8},
237+ //D
238+ {Z80_RETCC, Z80_CC_NC, Z80_UNUSED, Z80_UNUSED, 0},
239+ {Z80_POP, Z80_DE, Z80_UNUSED, Z80_UNUSED, 0},
240+ {Z80_JPCC, Z80_CC_NC, Z80_IMMED, Z80_UNUSED, 0},
241+ {Z80_OUT, Z80_A, Z80_IMMED_INDIRECT, Z80_UNUSED, 0},
242+ {Z80_CALLCC, Z80_CC_NC, Z80_IMMED, Z80_UNUSED, 0},
243+ {Z80_PUSH, Z80_DE, Z80_UNUSED, Z80_UNUSED, 0},
244+ {Z80_SUB, Z80_A, Z80_IMMED, Z80_UNUSED, 0},
245+ {Z80_RST, Z80_UNUSED, Z80_IMMED, Z80_UNUSED, 0x10},
246+ {Z80_RETCC, Z80_CC_C, Z80_UNUSED, Z80_UNUSED, 0},
247+ {Z80_EXX, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
248+ {Z80_JPCC, Z80_CC_C, Z80_IMMED, Z80_UNUSED, 0},
249+ {Z80_IN, Z80_A, Z80_IMMED_INDIRECT, Z80_UNUSED, 0},
250+ {Z80_CALLCC, Z80_CC_C, Z80_IMMED, Z80_UNUSED, 0},
251+ {0, 0, 0, 0, 0},//IX Prefix
252+ {Z80_SBC, Z80_A, Z80_IMMED, Z80_UNUSED, 0},
253+ {Z80_RST, Z80_UNUSED, Z80_IMMED, Z80_UNUSED, 0x18},
254+ //E
255+ {Z80_RETCC, Z80_CC_PO, Z80_UNUSED, Z80_UNUSED, 0},
256+ {Z80_POP, Z80_HL, Z80_UNUSED, Z80_UNUSED, 0},
257+ {Z80_JPCC, Z80_CC_PO, Z80_IMMED, Z80_UNUSED, 0},
258+ {Z80_EX, Z80_HL, Z80_REG_INDIRECT | Z80_DIR, Z80_SP, 0},
259+ {Z80_CALLCC, Z80_CC_PO, Z80_IMMED, Z80_UNUSED, 0},
260+ {Z80_PUSH, Z80_HL, Z80_UNUSED, Z80_UNUSED, 0},
261+ {Z80_AND, Z80_A, Z80_IMMED, Z80_UNUSED, 0},
262+ {Z80_RST, Z80_UNUSED, Z80_IMMED, Z80_UNUSED, 0x20},
263+ {Z80_RETCC, Z80_CC_PE, Z80_UNUSED, Z80_UNUSED, 0},
264+ {Z80_JP, Z80_UNUSED, Z80_REG_INDIRECT, Z80_HL, 0},
265+ {Z80_JPCC, Z80_CC_PE, Z80_IMMED, Z80_UNUSED, 0},
266+ {Z80_EX, Z80_DE, Z80_REG, Z80_HL, 0},
267+ {Z80_CALLCC, Z80_CC_PE, Z80_IMMED, Z80_UNUSED, 0},
268+ {0, 0, 0, 0, 0},//EXTD Prefix
269+ {Z80_XOR, Z80_A, Z80_IMMED, Z80_UNUSED, 0},
270+ {Z80_RST, Z80_UNUSED, Z80_IMMED, Z80_UNUSED, 0x28},
271+ //F
272+ {Z80_RETCC, Z80_CC_P, Z80_UNUSED, Z80_UNUSED, 0},
273+ {Z80_POP, Z80_AF, Z80_UNUSED, Z80_UNUSED, 0},
274+ {Z80_JPCC, Z80_CC_P, Z80_IMMED, Z80_UNUSED, 0},
275+ {Z80_DI, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
276+ {Z80_CALLCC, Z80_CC_P, Z80_IMMED, Z80_UNUSED, 0},
277+ {Z80_PUSH, Z80_AF, Z80_UNUSED, Z80_UNUSED, 0},
278+ {Z80_OR, Z80_A, Z80_IMMED, Z80_UNUSED, 0},
279+ {Z80_RST, Z80_UNUSED, Z80_IMMED, Z80_UNUSED, 0x30},
280+ {Z80_RETCC, Z80_CC_M, Z80_UNUSED, Z80_UNUSED, 0},
281+ {Z80_LD, Z80_SP, Z80_REG, Z80_HL, 0},
282+ {Z80_JPCC, Z80_CC_M, Z80_IMMED, Z80_UNUSED, 0},
283+ {Z80_EI, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
284+ {Z80_CALLCC, Z80_CC_M, Z80_IMMED, Z80_UNUSED, 0},
285+ {0, 0, 0, 0, 0},//IY Prefix
286+ {Z80_CP, Z80_A, Z80_IMMED, Z80_UNUSED, 0},
287+ {Z80_RST, Z80_UNUSED, Z80_IMMED, Z80_UNUSED, 0x38}
288+};
289+
290+z80inst z80_tbl_extd[0xC0-0x40] = {
291+ //4
292+ {Z80_IN, Z80_B, Z80_REG_INDIRECT, Z80_C, 0},
293+ {Z80_OUT, Z80_B, Z80_REG_INDIRECT | Z80_DIR, Z80_C, 0},
294+ {Z80_SBC, Z80_HL, Z80_REG, Z80_BC, 0},
295+ {Z80_LD, Z80_BC, Z80_IMMED_INDIRECT | Z80_DIR, Z80_UNUSED, 0},
296+ {Z80_NEG, Z80_A, Z80_UNUSED, Z80_UNUSED, 0},
297+ {Z80_RETN, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
298+ {Z80_IM, Z80_UNUSED, Z80_IMMED, Z80_UNUSED, 0},
299+ {Z80_LD, Z80_I, Z80_REG, Z80_A, 0},
300+ {Z80_IN, Z80_C, Z80_REG_INDIRECT, Z80_C, 0},
301+ {Z80_OUT, Z80_C, Z80_REG_INDIRECT | Z80_DIR, Z80_C, 0},
302+ {Z80_ADC, Z80_HL, Z80_REG, Z80_BC, 0},
303+ {Z80_LD, Z80_BC, Z80_IMMED_INDIRECT, Z80_UNUSED, 0},
304+ {Z80_NEG, Z80_A, Z80_UNUSED, Z80_UNUSED, 0},
305+ {Z80_RETI, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
306+ {Z80_IM, Z80_UNUSED, Z80_IMMED, Z80_UNUSED, 3},//Set undocumented mode 0/1
307+ {Z80_LD, Z80_R, Z80_REG, Z80_A, 0},
308+ //5
309+ {Z80_IN, Z80_D, Z80_REG_INDIRECT, Z80_C, 0},
310+ {Z80_OUT, Z80_D, Z80_REG_INDIRECT | Z80_DIR, Z80_C, 0},
311+ {Z80_SBC, Z80_HL, Z80_REG, Z80_DE, 0},
312+ {Z80_LD, Z80_DE, Z80_IMMED_INDIRECT | Z80_DIR, Z80_UNUSED, 0},
313+ {Z80_NEG, Z80_A, Z80_UNUSED, Z80_UNUSED, 0},
314+ {Z80_RETN, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
315+ {Z80_IM, Z80_UNUSED, Z80_IMMED, Z80_UNUSED, 1},
316+ {Z80_LD, Z80_A, Z80_REG, Z80_I, 0},
317+ {Z80_IN, Z80_E, Z80_REG_INDIRECT, Z80_C, 0},
318+ {Z80_OUT, Z80_E, Z80_REG_INDIRECT | Z80_DIR, Z80_C, 0},
319+ {Z80_ADC, Z80_HL, Z80_REG, Z80_DE, 0},
320+ {Z80_LD, Z80_DE, Z80_IMMED_INDIRECT, Z80_UNUSED, 0},
321+ {Z80_NEG, Z80_A, Z80_UNUSED, Z80_UNUSED, 0},
322+ {Z80_RETN, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
323+ {Z80_IM, Z80_UNUSED, Z80_IMMED, Z80_UNUSED, 2},
324+ {Z80_LD, Z80_A, Z80_REG, Z80_R, 0},
325+ //6
326+ {Z80_IN, Z80_H, Z80_REG_INDIRECT, Z80_C, 0},
327+ {Z80_OUT, Z80_H, Z80_REG_INDIRECT | Z80_DIR, Z80_C, 0},
328+ {Z80_SBC, Z80_HL, Z80_REG, Z80_HL, 0},
329+ {Z80_LD, Z80_HL, Z80_IMMED_INDIRECT | Z80_DIR, Z80_UNUSED, 0},
330+ {Z80_NEG, Z80_A, Z80_UNUSED, Z80_UNUSED, 0},
331+ {Z80_RETN, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
332+ {Z80_IM, Z80_UNUSED, Z80_IMMED, Z80_UNUSED, 0},
333+ {Z80_RRD, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
334+ {Z80_IN, Z80_L, Z80_REG_INDIRECT, Z80_C, 0},
335+ {Z80_OUT, Z80_L, Z80_REG_INDIRECT | Z80_DIR, Z80_C, 0},
336+ {Z80_ADC, Z80_HL, Z80_REG, Z80_HL, 0},
337+ {Z80_LD, Z80_HL, Z80_IMMED_INDIRECT, Z80_UNUSED, 0},
338+ {Z80_NEG, Z80_A, Z80_UNUSED, Z80_UNUSED, 0},
339+ {Z80_RETN, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
340+ {Z80_IM, Z80_UNUSED, Z80_IMMED, Z80_UNUSED, 3},//Set undocumented mode 0/1
341+ {Z80_RLD, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
342+ //7
343+ {Z80_IN, Z80_UNUSED, Z80_REG_INDIRECT, Z80_C, 0},
344+ {Z80_OUT, Z80_USE_IMMED, Z80_REG_INDIRECT | Z80_DIR, Z80_C, 0},
345+ {Z80_SBC, Z80_HL, Z80_REG, Z80_SP, 0},
346+ {Z80_LD, Z80_SP, Z80_IMMED_INDIRECT | Z80_DIR, Z80_UNUSED, 0},
347+ {Z80_NEG, Z80_A, Z80_UNUSED, Z80_UNUSED, 0},
348+ {Z80_RETN, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
349+ {Z80_IM, Z80_UNUSED, Z80_IMMED, Z80_UNUSED, 1},
350+ NOP,
351+ {Z80_IN, Z80_A, Z80_REG_INDIRECT, Z80_C, 0},
352+ {Z80_OUT, Z80_A, Z80_REG_INDIRECT | Z80_DIR, Z80_C, 0},
353+ {Z80_ADC, Z80_HL, Z80_REG, Z80_SP, 0},
354+ {Z80_LD, Z80_SP, Z80_IMMED_INDIRECT, Z80_UNUSED, 0},
355+ {Z80_NEG, Z80_A, Z80_UNUSED, Z80_UNUSED, 0},
356+ {Z80_RETN, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
357+ {Z80_IM, Z80_UNUSED, Z80_IMMED, Z80_UNUSED, 2},
358+ NOP,
359+ //8
360+ NOP,
361+ NOP,
362+ NOP,
363+ NOP,
364+ NOP,
365+ NOP,
366+ NOP,
367+ NOP,
368+ NOP,
369+ NOP,
370+ NOP,
371+ NOP,
372+ NOP,
373+ NOP,
374+ NOP,
375+ NOP,
376+ //9
377+ NOP,
378+ NOP,
379+ NOP,
380+ NOP,
381+ NOP,
382+ NOP,
383+ NOP,
384+ NOP,
385+ NOP,
386+ NOP,
387+ NOP,
388+ NOP,
389+ NOP,
390+ NOP,
391+ NOP,
392+ NOP,
393+ //A
394+ {Z80_LDI, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
395+ {Z80_CPI, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
396+ {Z80_INI, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
397+ {Z80_OUTI, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
398+ NOP,
399+ NOP,
400+ NOP,
401+ NOP,
402+ {Z80_LDD, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
403+ {Z80_CPD, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
404+ {Z80_IND, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
405+ {Z80_OUTD, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
406+ NOP,
407+ NOP,
408+ NOP,
409+ NOP,
410+ //B
411+ {Z80_LDIR, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
412+ {Z80_CPIR, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
413+ {Z80_INIR, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
414+ {Z80_OTIR, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
415+ NOP,
416+ NOP,
417+ NOP,
418+ NOP,
419+ {Z80_LDDR, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
420+ {Z80_CPDR, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
421+ {Z80_INDR, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
422+ {Z80_OTDR, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 0},
423+ NOP,
424+ NOP,
425+ NOP,
426+ NOP
427+};
428+
429+#define SHIFT_BLOCK(op) \
430+ {op, Z80_B, Z80_UNUSED, Z80_UNUSED, 1},\
431+ {op, Z80_C, Z80_UNUSED, Z80_UNUSED, 1},\
432+ {op, Z80_D, Z80_UNUSED, Z80_UNUSED, 1},\
433+ {op, Z80_E, Z80_UNUSED, Z80_UNUSED, 1},\
434+ {op, Z80_H, Z80_UNUSED, Z80_UNUSED, 1},\
435+ {op, Z80_L, Z80_UNUSED, Z80_UNUSED, 1},\
436+ {op, Z80_UNUSED, Z80_REG_INDIRECT, Z80_HL, 1},\
437+ {op, Z80_A, Z80_UNUSED, Z80_UNUSED, 1}
438+
439+#define BIT_BLOCK(op, bit) \
440+ {op, Z80_USE_IMMED, Z80_REG, Z80_B, bit},\
441+ {op, Z80_USE_IMMED, Z80_REG, Z80_C, bit},\
442+ {op, Z80_USE_IMMED, Z80_REG, Z80_D, bit},\
443+ {op, Z80_USE_IMMED, Z80_REG, Z80_E, bit},\
444+ {op, Z80_USE_IMMED, Z80_REG, Z80_H, bit},\
445+ {op, Z80_USE_IMMED, Z80_REG, Z80_L, bit},\
446+ {op, Z80_USE_IMMED, Z80_REG_INDIRECT, Z80_HL, bit},\
447+ {op, Z80_USE_IMMED, Z80_REG, Z80_A, bit}
448+
449+z80inst z80_tbl_bit[256] = {
450+ //0
451+ SHIFT_BLOCK(Z80_RLC),
452+ SHIFT_BLOCK(Z80_RRC),
453+ //1
454+ SHIFT_BLOCK(Z80_RL),
455+ SHIFT_BLOCK(Z80_RR),
456+ //2
457+ SHIFT_BLOCK(Z80_SLA),
458+ SHIFT_BLOCK(Z80_SRA),
459+ //3
460+ SHIFT_BLOCK(Z80_SLL),
461+ SHIFT_BLOCK(Z80_SRL),
462+ //4
463+ BIT_BLOCK(Z80_BIT, 0),
464+ BIT_BLOCK(Z80_BIT, 1),
465+ //5
466+ BIT_BLOCK(Z80_BIT, 2),
467+ BIT_BLOCK(Z80_BIT, 3),
468+ //6
469+ BIT_BLOCK(Z80_BIT, 4),
470+ BIT_BLOCK(Z80_BIT, 5),
471+ //7
472+ BIT_BLOCK(Z80_BIT, 6),
473+ BIT_BLOCK(Z80_BIT, 7),
474+ //8
475+ BIT_BLOCK(Z80_RES, 0),
476+ BIT_BLOCK(Z80_RES, 1),
477+ //9
478+ BIT_BLOCK(Z80_RES, 2),
479+ BIT_BLOCK(Z80_RES, 3),
480+ //A
481+ BIT_BLOCK(Z80_RES, 4),
482+ BIT_BLOCK(Z80_RES, 5),
483+ //B
484+ BIT_BLOCK(Z80_RES, 6),
485+ BIT_BLOCK(Z80_RES, 7),
486+ //C
487+ BIT_BLOCK(Z80_SET, 0),
488+ BIT_BLOCK(Z80_SET, 1),
489+ //D
490+ BIT_BLOCK(Z80_SET, 2),
491+ BIT_BLOCK(Z80_SET, 3),
492+ //E
493+ BIT_BLOCK(Z80_SET, 4),
494+ BIT_BLOCK(Z80_SET, 5),
495+ //F
496+ BIT_BLOCK(Z80_SET, 6),
497+ BIT_BLOCK(Z80_SET, 7)
498+};
499+
500+z80inst z80_tbl_ix[256] = {
501+ //0
502+ USE_MAIN,
503+ USE_MAIN,
504+ USE_MAIN,
505+ USE_MAIN,
506+ USE_MAIN,
507+ USE_MAIN,
508+ USE_MAIN,
509+ USE_MAIN,
510+ USE_MAIN,
511+ {Z80_ADD, Z80_IX, Z80_REG, Z80_BC, 0},
512+ USE_MAIN,
513+ USE_MAIN,
514+ USE_MAIN,
515+ USE_MAIN,
516+ USE_MAIN,
517+ USE_MAIN,
518+ //1
519+ USE_MAIN,
520+ USE_MAIN,
521+ USE_MAIN,
522+ USE_MAIN,
523+ USE_MAIN,
524+ USE_MAIN,
525+ USE_MAIN,
526+ USE_MAIN,
527+ USE_MAIN,
528+ {Z80_ADD, Z80_IX, Z80_REG, Z80_DE, 0},
529+ USE_MAIN,
530+ USE_MAIN,
531+ USE_MAIN,
532+ USE_MAIN,
533+ USE_MAIN,
534+ USE_MAIN,
535+ //2
536+ USE_MAIN,
537+ {Z80_LD, Z80_IX, Z80_IMMED, Z80_UNUSED, 0},
538+ {Z80_LD, Z80_IX, Z80_IMMED_INDIRECT | Z80_DIR, Z80_UNUSED, 0},
539+ {Z80_INC, Z80_IX, Z80_UNUSED, Z80_UNUSED, 0},
540+ {Z80_INC, Z80_IXH, Z80_UNUSED, Z80_UNUSED, 0},
541+ {Z80_DEC, Z80_IXH, Z80_UNUSED, Z80_UNUSED, 0},
542+ {Z80_LD, Z80_IXH, Z80_IMMED, Z80_UNUSED, 0},
543+ USE_MAIN,
544+ USE_MAIN,
545+ {Z80_ADD, Z80_IX, Z80_REG, Z80_IX, 0},
546+ {Z80_LD, Z80_IX, Z80_IMMED_INDIRECT, Z80_UNUSED, 0},
547+ {Z80_DEC, Z80_IX, Z80_UNUSED, Z80_UNUSED, 0},
548+ {Z80_INC, Z80_IXL, Z80_UNUSED, Z80_UNUSED, 0},
549+ {Z80_DEC, Z80_IXL, Z80_UNUSED, Z80_UNUSED, 0},
550+ {Z80_LD, Z80_IXL, Z80_IMMED, Z80_UNUSED, 0},
551+ USE_MAIN,
552+ //3
553+ USE_MAIN,
554+ USE_MAIN,
555+ USE_MAIN,
556+ USE_MAIN,
557+ {Z80_INC, Z80_UNUSED, Z80_IX_DISPLACE, 0, 0},
558+ {Z80_DEC, Z80_UNUSED, Z80_IX_DISPLACE, 0, 0},
559+ {Z80_LD, Z80_USE_IMMED, Z80_IX_DISPLACE | Z80_DIR, 0, 0},
560+ USE_MAIN,
561+ USE_MAIN,
562+ {Z80_ADD, Z80_IX, Z80_REG, Z80_SP, 0},
563+ USE_MAIN,
564+ USE_MAIN,
565+ USE_MAIN,
566+ USE_MAIN,
567+ USE_MAIN,
568+ USE_MAIN,
569+ //4
570+ USE_MAIN,
571+ USE_MAIN,
572+ USE_MAIN,
573+ USE_MAIN,
574+ {Z80_LD, Z80_B, Z80_REG, Z80_IXH, 0},
575+ {Z80_LD, Z80_B, Z80_REG, Z80_IXL, 0},
576+ {Z80_LD, Z80_B, Z80_IX_DISPLACE, 0, 0},
577+ USE_MAIN,
578+ USE_MAIN,
579+ USE_MAIN,
580+ USE_MAIN,
581+ USE_MAIN,
582+ {Z80_LD, Z80_C, Z80_REG, Z80_IXH, 0},
583+ {Z80_LD, Z80_C, Z80_REG, Z80_IXL, 0},
584+ {Z80_LD, Z80_C, Z80_IX_DISPLACE, 0, 0},
585+ USE_MAIN,
586+ //5
587+ USE_MAIN,
588+ USE_MAIN,
589+ USE_MAIN,
590+ USE_MAIN,
591+ {Z80_LD, Z80_D, Z80_REG, Z80_IXH, 0},
592+ {Z80_LD, Z80_D, Z80_REG, Z80_IXL, 0},
593+ {Z80_LD, Z80_D, Z80_IX_DISPLACE, 0, 0},
594+ USE_MAIN,
595+ USE_MAIN,
596+ USE_MAIN,
597+ USE_MAIN,
598+ USE_MAIN,
599+ {Z80_LD, Z80_E, Z80_REG, Z80_IXH, 0},
600+ {Z80_LD, Z80_E, Z80_REG, Z80_IXL, 0},
601+ {Z80_LD, Z80_E, Z80_IX_DISPLACE, 0, 0},
602+ USE_MAIN,
603+ //6
604+ {Z80_LD, Z80_IXH, Z80_REG, Z80_B, 0},
605+ {Z80_LD, Z80_IXH, Z80_REG, Z80_C, 0},
606+ {Z80_LD, Z80_IXH, Z80_REG, Z80_D, 0},
607+ {Z80_LD, Z80_IXH, Z80_REG, Z80_E, 0},
608+ {Z80_LD, Z80_IXH, Z80_REG, Z80_IXH, 0},
609+ {Z80_LD, Z80_IXH, Z80_REG, Z80_IXL, 0},
610+ {Z80_LD, Z80_H, Z80_IX_DISPLACE, 0, 0},
611+ {Z80_LD, Z80_IXH, Z80_REG, Z80_A, 0},
612+ {Z80_LD, Z80_IXL, Z80_REG, Z80_B, 0},
613+ {Z80_LD, Z80_IXL, Z80_REG, Z80_C, 0},
614+ {Z80_LD, Z80_IXL, Z80_REG, Z80_D, 0},
615+ {Z80_LD, Z80_IXL, Z80_REG, Z80_E, 0},
616+ {Z80_LD, Z80_IXL, Z80_REG, Z80_IXH, 0},
617+ {Z80_LD, Z80_IXL, Z80_REG, Z80_IXL, 0},
618+ {Z80_LD, Z80_L, Z80_IX_DISPLACE, 0, 0},
619+ {Z80_LD, Z80_IXL, Z80_REG, Z80_A, 0},
620+ //7
621+ {Z80_LD, Z80_B, Z80_IX_DISPLACE | Z80_DIR, 0, 0},
622+ {Z80_LD, Z80_C, Z80_IX_DISPLACE | Z80_DIR, 0, 0},
623+ {Z80_LD, Z80_D, Z80_IX_DISPLACE | Z80_DIR, 0, 0},
624+ {Z80_LD, Z80_E, Z80_IX_DISPLACE | Z80_DIR, 0, 0},
625+ {Z80_LD, Z80_H, Z80_IX_DISPLACE | Z80_DIR, 0, 0},
626+ {Z80_LD, Z80_L, Z80_IX_DISPLACE | Z80_DIR, 0, 0},
627+ USE_MAIN,
628+ {Z80_LD, Z80_A, Z80_IX_DISPLACE | Z80_DIR, 0, 0},
629+ USE_MAIN,
630+ USE_MAIN,
631+ USE_MAIN,
632+ USE_MAIN,
633+ {Z80_LD, Z80_A, Z80_REG, Z80_IXH, 0},
634+ {Z80_LD, Z80_A, Z80_REG, Z80_IXL, 0},
635+ {Z80_LD, Z80_A, Z80_IX_DISPLACE, 0, 0},
636+ USE_MAIN,
637+ //8
638+ USE_MAIN,
639+ USE_MAIN,
640+ USE_MAIN,
641+ USE_MAIN,
642+ {Z80_ADD, Z80_A, Z80_REG, Z80_IXH, 0},
643+ {Z80_ADD, Z80_A, Z80_REG, Z80_IXL, 0},
644+ {Z80_ADD, Z80_A, Z80_IX_DISPLACE, 0, 0},
645+ USE_MAIN,
646+ USE_MAIN,
647+ USE_MAIN,
648+ USE_MAIN,
649+ USE_MAIN,
650+ {Z80_ADC, Z80_A, Z80_REG, Z80_IXH, 0},
651+ {Z80_ADC, Z80_A, Z80_REG, Z80_IXL, 0},
652+ {Z80_ADC, Z80_A, Z80_IX_DISPLACE, 0, 0},
653+ USE_MAIN,
654+ //9
655+ USE_MAIN,
656+ USE_MAIN,
657+ USE_MAIN,
658+ USE_MAIN,
659+ {Z80_SUB, Z80_A, Z80_REG, Z80_IXH, 0},
660+ {Z80_SUB, Z80_A, Z80_REG, Z80_IXL, 0},
661+ {Z80_SUB, Z80_A, Z80_IX_DISPLACE, 0, 0},
662+ USE_MAIN,
663+ USE_MAIN,
664+ USE_MAIN,
665+ USE_MAIN,
666+ USE_MAIN,
667+ {Z80_SBC, Z80_A, Z80_REG, Z80_IXH, 0},
668+ {Z80_SBC, Z80_A, Z80_REG, Z80_IXL, 0},
669+ {Z80_SBC, Z80_A, Z80_IX_DISPLACE, 0, 0},
670+ USE_MAIN,
671+ //A
672+ USE_MAIN,
673+ USE_MAIN,
674+ USE_MAIN,
675+ USE_MAIN,
676+ {Z80_AND, Z80_A, Z80_REG, Z80_IXH, 0},
677+ {Z80_AND, Z80_A, Z80_REG, Z80_IXL, 0},
678+ {Z80_AND, Z80_A, Z80_IX_DISPLACE, 0, 0},
679+ USE_MAIN,
680+ USE_MAIN,
681+ USE_MAIN,
682+ USE_MAIN,
683+ USE_MAIN,
684+ {Z80_XOR, Z80_A, Z80_REG, Z80_IXH, 0},
685+ {Z80_XOR, Z80_A, Z80_REG, Z80_IXL, 0},
686+ {Z80_XOR, Z80_A, Z80_IX_DISPLACE, 0, 0},
687+ USE_MAIN,
688+ //B
689+ USE_MAIN,
690+ USE_MAIN,
691+ USE_MAIN,
692+ USE_MAIN,
693+ {Z80_OR, Z80_A, Z80_REG, Z80_IXH, 0},
694+ {Z80_OR, Z80_A, Z80_REG, Z80_IXL, 0},
695+ {Z80_OR, Z80_A, Z80_IX_DISPLACE, 0, 0},
696+ USE_MAIN,
697+ USE_MAIN,
698+ USE_MAIN,
699+ USE_MAIN,
700+ USE_MAIN,
701+ {Z80_CP, Z80_A, Z80_REG, Z80_IXH, 0},
702+ {Z80_CP, Z80_A, Z80_REG, Z80_IXL, 0},
703+ {Z80_CP, Z80_A, Z80_IX_DISPLACE, 0, 0},
704+ USE_MAIN,
705+ //C
706+ USE_MAIN,
707+ USE_MAIN,
708+ USE_MAIN,
709+ USE_MAIN,
710+ USE_MAIN,
711+ USE_MAIN,
712+ USE_MAIN,
713+ USE_MAIN,
714+ USE_MAIN,
715+ USE_MAIN,
716+ USE_MAIN,
717+ USE_MAIN,
718+ USE_MAIN,
719+ USE_MAIN,
720+ USE_MAIN,
721+ USE_MAIN,
722+ //D
723+ USE_MAIN,
724+ USE_MAIN,
725+ USE_MAIN,
726+ USE_MAIN,
727+ USE_MAIN,
728+ USE_MAIN,
729+ USE_MAIN,
730+ USE_MAIN,
731+ USE_MAIN,
732+ USE_MAIN,
733+ USE_MAIN,
734+ USE_MAIN,
735+ USE_MAIN,
736+ USE_MAIN,
737+ USE_MAIN,
738+ USE_MAIN,
739+ //E
740+ USE_MAIN,
741+ {Z80_POP, Z80_IX, Z80_UNUSED, Z80_UNUSED, 0},
742+ USE_MAIN,
743+ {Z80_EX, Z80_IX, Z80_REG_INDIRECT | Z80_DIR, Z80_SP, 0},
744+ USE_MAIN,
745+ {Z80_PUSH, Z80_IX, Z80_UNUSED, Z80_UNUSED, 0},
746+ USE_MAIN,
747+ USE_MAIN,
748+ USE_MAIN,
749+ {Z80_JP, Z80_UNUSED, Z80_REG_INDIRECT, Z80_IX, 0},
750+ USE_MAIN,
751+ USE_MAIN,
752+ USE_MAIN,
753+ USE_MAIN,
754+ USE_MAIN,
755+ USE_MAIN,
756+ //F
757+ USE_MAIN,
758+ USE_MAIN,
759+ USE_MAIN,
760+ USE_MAIN,
761+ USE_MAIN,
762+ USE_MAIN,
763+ USE_MAIN,
764+ USE_MAIN,
765+ USE_MAIN,
766+ {Z80_LD, Z80_SP, Z80_REG, Z80_IX, 0},
767+ USE_MAIN,
768+ USE_MAIN,
769+ USE_MAIN,
770+ USE_MAIN,
771+ USE_MAIN,
772+ USE_MAIN
773+};
774+
775+#define SHIFT_BLOCK_IX(op) \
776+ {op, Z80_B, Z80_IX_DISPLACE | Z80_DIR, 0, 1},\
777+ {op, Z80_C, Z80_IX_DISPLACE | Z80_DIR, 0, 1},\
778+ {op, Z80_D, Z80_IX_DISPLACE | Z80_DIR, 0, 1},\
779+ {op, Z80_E, Z80_IX_DISPLACE | Z80_DIR, 0, 1},\
780+ {op, Z80_H, Z80_IX_DISPLACE | Z80_DIR, 0, 1},\
781+ {op, Z80_L, Z80_IX_DISPLACE | Z80_DIR, 0, 1},\
782+ {op, Z80_UNUSED, Z80_IX_DISPLACE | Z80_DIR, 0, 1},\
783+ {op, Z80_A, Z80_IX_DISPLACE | Z80_DIR, 0, 1}
784+
785+#define BIT_BLOCK_IX(bit) \
786+ {Z80_BIT, Z80_USE_IMMED, Z80_IX_DISPLACE, 0, bit},\
787+ {Z80_BIT, Z80_USE_IMMED, Z80_IX_DISPLACE, 0, bit},\
788+ {Z80_BIT, Z80_USE_IMMED, Z80_IX_DISPLACE, 0, bit},\
789+ {Z80_BIT, Z80_USE_IMMED, Z80_IX_DISPLACE, 0, bit},\
790+ {Z80_BIT, Z80_USE_IMMED, Z80_IX_DISPLACE, 0, bit},\
791+ {Z80_BIT, Z80_USE_IMMED, Z80_IX_DISPLACE, 0, bit},\
792+ {Z80_BIT, Z80_USE_IMMED, Z80_IX_DISPLACE, 0, bit},\
793+ {Z80_BIT, Z80_USE_IMMED, Z80_IX_DISPLACE, 0, bit}
794+
795+#define BIT_BLOCK_IX_REG(op, bit) \
796+ {op, Z80_B, Z80_IX_DISPLACE | Z80_DIR, 0, bit},\
797+ {op, Z80_C, Z80_IX_DISPLACE | Z80_DIR, 0, bit},\
798+ {op, Z80_D, Z80_IX_DISPLACE | Z80_DIR, 0, bit},\
799+ {op, Z80_E, Z80_IX_DISPLACE | Z80_DIR, 0, bit},\
800+ {op, Z80_H, Z80_IX_DISPLACE | Z80_DIR, 0, bit},\
801+ {op, Z80_L, Z80_IX_DISPLACE | Z80_DIR, 0, bit},\
802+ {op, Z80_USE_IMMED, Z80_IX_DISPLACE, 0, bit},\
803+ {op, Z80_A, Z80_IX_DISPLACE | Z80_DIR, 0, bit}
804+
805+z80inst z80_tbl_ix_bit[256] = {
806+ //0
807+ SHIFT_BLOCK_IX(Z80_RLC),
808+ SHIFT_BLOCK_IX(Z80_RRC),
809+ //1
810+ SHIFT_BLOCK_IX(Z80_RL),
811+ SHIFT_BLOCK_IX(Z80_RR),
812+ //2
813+ SHIFT_BLOCK_IX(Z80_SLA),
814+ SHIFT_BLOCK_IX(Z80_SRA),
815+ //3
816+ SHIFT_BLOCK_IX(Z80_SLL),
817+ SHIFT_BLOCK_IX(Z80_SRL),
818+ //4
819+ BIT_BLOCK_IX(0),
820+ BIT_BLOCK_IX(1),
821+ //5
822+ BIT_BLOCK_IX(2),
823+ BIT_BLOCK_IX(3),
824+ //6
825+ BIT_BLOCK_IX(4),
826+ BIT_BLOCK_IX(5),
827+ //7
828+ BIT_BLOCK_IX(6),
829+ BIT_BLOCK_IX(7),
830+ //8
831+ BIT_BLOCK_IX_REG(Z80_RES, 0),
832+ BIT_BLOCK_IX_REG(Z80_RES, 1),
833+ //9
834+ BIT_BLOCK_IX_REG(Z80_RES, 2),
835+ BIT_BLOCK_IX_REG(Z80_RES, 3),
836+ //A
837+ BIT_BLOCK_IX_REG(Z80_RES, 4),
838+ BIT_BLOCK_IX_REG(Z80_RES, 5),
839+ //B
840+ BIT_BLOCK_IX_REG(Z80_RES, 6),
841+ BIT_BLOCK_IX_REG(Z80_RES, 7),
842+ //C
843+ BIT_BLOCK_IX_REG(Z80_SET, 0),
844+ BIT_BLOCK_IX_REG(Z80_SET, 1),
845+ //D
846+ BIT_BLOCK_IX_REG(Z80_SET, 2),
847+ BIT_BLOCK_IX_REG(Z80_SET, 3),
848+ //E
849+ BIT_BLOCK_IX_REG(Z80_SET, 4),
850+ BIT_BLOCK_IX_REG(Z80_SET, 5),
851+ //F
852+ BIT_BLOCK_IX_REG(Z80_SET, 6),
853+ BIT_BLOCK_IX_REG(Z80_SET, 7),
854+};
855+
856+z80inst z80_tbl_iy[256] = {
857+ //0
858+ USE_MAIN,
859+ USE_MAIN,
860+ USE_MAIN,
861+ USE_MAIN,
862+ USE_MAIN,
863+ USE_MAIN,
864+ USE_MAIN,
865+ USE_MAIN,
866+ USE_MAIN,
867+ {Z80_ADD, Z80_IY, Z80_REG, Z80_BC, 0},
868+ USE_MAIN,
869+ USE_MAIN,
870+ USE_MAIN,
871+ USE_MAIN,
872+ USE_MAIN,
873+ USE_MAIN,
874+ //1
875+ USE_MAIN,
876+ USE_MAIN,
877+ USE_MAIN,
878+ USE_MAIN,
879+ USE_MAIN,
880+ USE_MAIN,
881+ USE_MAIN,
882+ USE_MAIN,
883+ USE_MAIN,
884+ {Z80_ADD, Z80_IY, Z80_REG, Z80_DE, 0},
885+ USE_MAIN,
886+ USE_MAIN,
887+ USE_MAIN,
888+ USE_MAIN,
889+ USE_MAIN,
890+ USE_MAIN,
891+ //2
892+ USE_MAIN,
893+ {Z80_LD, Z80_IY, Z80_IMMED, Z80_UNUSED, 0},
894+ {Z80_LD, Z80_IY, Z80_IMMED_INDIRECT | Z80_DIR, Z80_UNUSED, 0},
895+ {Z80_INC, Z80_IY, Z80_UNUSED, Z80_UNUSED, 0},
896+ {Z80_INC, Z80_IYH, Z80_UNUSED, Z80_UNUSED, 0},
897+ {Z80_DEC, Z80_IYH, Z80_UNUSED, Z80_UNUSED, 0},
898+ {Z80_LD, Z80_IYH, Z80_IMMED, Z80_UNUSED, 0},
899+ USE_MAIN,
900+ USE_MAIN,
901+ {Z80_ADD, Z80_IY, Z80_REG, Z80_IY, 0},
902+ {Z80_LD, Z80_IY, Z80_IMMED_INDIRECT, Z80_UNUSED, 0},
903+ {Z80_DEC, Z80_IY, Z80_UNUSED, Z80_UNUSED, 0},
904+ {Z80_INC, Z80_IYL, Z80_UNUSED, Z80_UNUSED, 0},
905+ {Z80_DEC, Z80_IYL, Z80_UNUSED, Z80_UNUSED, 0},
906+ {Z80_LD, Z80_IYL, Z80_IMMED, Z80_UNUSED, 0},
907+ USE_MAIN,
908+ //3
909+ USE_MAIN,
910+ USE_MAIN,
911+ USE_MAIN,
912+ USE_MAIN,
913+ {Z80_INC, Z80_UNUSED, Z80_IY_DISPLACE, 0, 0},
914+ {Z80_DEC, Z80_UNUSED, Z80_IY_DISPLACE, 0, 0},
915+ {Z80_LD, Z80_USE_IMMED, Z80_IY_DISPLACE | Z80_DIR, 0, 0},
916+ USE_MAIN,
917+ USE_MAIN,
918+ {Z80_ADD, Z80_IY, Z80_REG, Z80_SP, 0},
919+ USE_MAIN,
920+ USE_MAIN,
921+ USE_MAIN,
922+ USE_MAIN,
923+ USE_MAIN,
924+ USE_MAIN,
925+ //4
926+ USE_MAIN,
927+ USE_MAIN,
928+ USE_MAIN,
929+ USE_MAIN,
930+ {Z80_LD, Z80_B, Z80_REG, Z80_IYH, 0},
931+ {Z80_LD, Z80_B, Z80_REG, Z80_IYL, 0},
932+ {Z80_LD, Z80_B, Z80_IY_DISPLACE, 0, 0},
933+ USE_MAIN,
934+ USE_MAIN,
935+ USE_MAIN,
936+ USE_MAIN,
937+ USE_MAIN,
938+ {Z80_LD, Z80_C, Z80_REG, Z80_IYH, 0},
939+ {Z80_LD, Z80_C, Z80_REG, Z80_IYL, 0},
940+ {Z80_LD, Z80_C, Z80_IY_DISPLACE, 0, 0},
941+ USE_MAIN,
942+ //5
943+ USE_MAIN,
944+ USE_MAIN,
945+ USE_MAIN,
946+ USE_MAIN,
947+ {Z80_LD, Z80_D, Z80_REG, Z80_IYH, 0},
948+ {Z80_LD, Z80_D, Z80_REG, Z80_IYL, 0},
949+ {Z80_LD, Z80_D, Z80_IY_DISPLACE, 0, 0},
950+ USE_MAIN,
951+ USE_MAIN,
952+ USE_MAIN,
953+ USE_MAIN,
954+ USE_MAIN,
955+ {Z80_LD, Z80_E, Z80_REG, Z80_IYH, 0},
956+ {Z80_LD, Z80_E, Z80_REG, Z80_IYL, 0},
957+ {Z80_LD, Z80_E, Z80_IY_DISPLACE, 0, 0},
958+ USE_MAIN,
959+ //6
960+ {Z80_LD, Z80_IYH, Z80_REG, Z80_B, 0},
961+ {Z80_LD, Z80_IYH, Z80_REG, Z80_C, 0},
962+ {Z80_LD, Z80_IYH, Z80_REG, Z80_D, 0},
963+ {Z80_LD, Z80_IYH, Z80_REG, Z80_E, 0},
964+ {Z80_LD, Z80_IYH, Z80_REG, Z80_IYH, 0},
965+ {Z80_LD, Z80_IYH, Z80_REG, Z80_IYL, 0},
966+ {Z80_LD, Z80_H, Z80_IY_DISPLACE, 0, 0},
967+ {Z80_LD, Z80_IYH, Z80_REG, Z80_A, 0},
968+ {Z80_LD, Z80_IYL, Z80_REG, Z80_B, 0},
969+ {Z80_LD, Z80_IYL, Z80_REG, Z80_C, 0},
970+ {Z80_LD, Z80_IYL, Z80_REG, Z80_D, 0},
971+ {Z80_LD, Z80_IYL, Z80_REG, Z80_E, 0},
972+ {Z80_LD, Z80_IYL, Z80_REG, Z80_IYH, 0},
973+ {Z80_LD, Z80_IYL, Z80_REG, Z80_IYL, 0},
974+ {Z80_LD, Z80_L, Z80_IY_DISPLACE, 0, 0},
975+ {Z80_LD, Z80_IYL, Z80_REG, Z80_A, 0},
976+ //7
977+ {Z80_LD, Z80_B, Z80_IY_DISPLACE | Z80_DIR, 0, 0},
978+ {Z80_LD, Z80_C, Z80_IY_DISPLACE | Z80_DIR, 0, 0},
979+ {Z80_LD, Z80_D, Z80_IY_DISPLACE | Z80_DIR, 0, 0},
980+ {Z80_LD, Z80_E, Z80_IY_DISPLACE | Z80_DIR, 0, 0},
981+ {Z80_LD, Z80_H, Z80_IY_DISPLACE | Z80_DIR, 0, 0},
982+ {Z80_LD, Z80_L, Z80_IY_DISPLACE | Z80_DIR, 0, 0},
983+ USE_MAIN,
984+ {Z80_LD, Z80_A, Z80_IY_DISPLACE | Z80_DIR, 0, 0},
985+ USE_MAIN,
986+ USE_MAIN,
987+ USE_MAIN,
988+ USE_MAIN,
989+ {Z80_LD, Z80_A, Z80_REG, Z80_IYH, 0},
990+ {Z80_LD, Z80_A, Z80_REG, Z80_IYL, 0},
991+ {Z80_LD, Z80_A, Z80_IY_DISPLACE, 0, 0},
992+ USE_MAIN,
993+ //8
994+ USE_MAIN,
995+ USE_MAIN,
996+ USE_MAIN,
997+ USE_MAIN,
998+ {Z80_ADD, Z80_A, Z80_REG, Z80_IYH, 0},
999+ {Z80_ADD, Z80_A, Z80_REG, Z80_IYL, 0},
1000+ {Z80_ADD, Z80_A, Z80_IY_DISPLACE, 0, 0},
1001+ USE_MAIN,
1002+ USE_MAIN,
1003+ USE_MAIN,
1004+ USE_MAIN,
1005+ USE_MAIN,
1006+ {Z80_ADC, Z80_A, Z80_REG, Z80_IYH, 0},
1007+ {Z80_ADC, Z80_A, Z80_REG, Z80_IYL, 0},
1008+ {Z80_ADC, Z80_A, Z80_IY_DISPLACE, 0, 0},
1009+ USE_MAIN,
1010+ //9
1011+ USE_MAIN,
1012+ USE_MAIN,
1013+ USE_MAIN,
1014+ USE_MAIN,
1015+ {Z80_SUB, Z80_A, Z80_REG, Z80_IYH, 0},
1016+ {Z80_SUB, Z80_A, Z80_REG, Z80_IYL, 0},
1017+ {Z80_SUB, Z80_A, Z80_IY_DISPLACE, 0, 0},
1018+ USE_MAIN,
1019+ USE_MAIN,
1020+ USE_MAIN,
1021+ USE_MAIN,
1022+ USE_MAIN,
1023+ {Z80_SBC, Z80_A, Z80_REG, Z80_IYH, 0},
1024+ {Z80_SBC, Z80_A, Z80_REG, Z80_IYL, 0},
1025+ {Z80_SBC, Z80_A, Z80_IY_DISPLACE, 0, 0},
1026+ USE_MAIN,
1027+ //A
1028+ USE_MAIN,
1029+ USE_MAIN,
1030+ USE_MAIN,
1031+ USE_MAIN,
1032+ {Z80_AND, Z80_A, Z80_REG, Z80_IYH, 0},
1033+ {Z80_AND, Z80_A, Z80_REG, Z80_IYL, 0},
1034+ {Z80_AND, Z80_A, Z80_IY_DISPLACE, 0, 0},
1035+ USE_MAIN,
1036+ USE_MAIN,
1037+ USE_MAIN,
1038+ USE_MAIN,
1039+ USE_MAIN,
1040+ {Z80_XOR, Z80_A, Z80_REG, Z80_IYH, 0},
1041+ {Z80_XOR, Z80_A, Z80_REG, Z80_IYL, 0},
1042+ {Z80_XOR, Z80_A, Z80_IY_DISPLACE, 0, 0},
1043+ USE_MAIN,
1044+ //B
1045+ USE_MAIN,
1046+ USE_MAIN,
1047+ USE_MAIN,
1048+ USE_MAIN,
1049+ {Z80_OR, Z80_A, Z80_REG, Z80_IYH, 0},
1050+ {Z80_OR, Z80_A, Z80_REG, Z80_IYL, 0},
1051+ {Z80_OR, Z80_A, Z80_IY_DISPLACE, 0, 0},
1052+ USE_MAIN,
1053+ USE_MAIN,
1054+ USE_MAIN,
1055+ USE_MAIN,
1056+ USE_MAIN,
1057+ {Z80_CP, Z80_A, Z80_REG, Z80_IYH, 0},
1058+ {Z80_CP, Z80_A, Z80_REG, Z80_IYL, 0},
1059+ {Z80_CP, Z80_A, Z80_IY_DISPLACE, 0, 0},
1060+ USE_MAIN,
1061+ //C
1062+ USE_MAIN,
1063+ USE_MAIN,
1064+ USE_MAIN,
1065+ USE_MAIN,
1066+ USE_MAIN,
1067+ USE_MAIN,
1068+ USE_MAIN,
1069+ USE_MAIN,
1070+ USE_MAIN,
1071+ USE_MAIN,
1072+ USE_MAIN,
1073+ USE_MAIN,
1074+ USE_MAIN,
1075+ USE_MAIN,
1076+ USE_MAIN,
1077+ USE_MAIN,
1078+ //D
1079+ USE_MAIN,
1080+ USE_MAIN,
1081+ USE_MAIN,
1082+ USE_MAIN,
1083+ USE_MAIN,
1084+ USE_MAIN,
1085+ USE_MAIN,
1086+ USE_MAIN,
1087+ USE_MAIN,
1088+ USE_MAIN,
1089+ USE_MAIN,
1090+ USE_MAIN,
1091+ USE_MAIN,
1092+ USE_MAIN,
1093+ USE_MAIN,
1094+ USE_MAIN,
1095+ //E
1096+ USE_MAIN,
1097+ {Z80_POP, Z80_IY, Z80_UNUSED, Z80_UNUSED, 0},
1098+ USE_MAIN,
1099+ {Z80_EX, Z80_IY, Z80_REG_INDIRECT | Z80_DIR, Z80_SP, 0},
1100+ USE_MAIN,
1101+ {Z80_PUSH, Z80_IY, Z80_UNUSED, Z80_UNUSED, 0},
1102+ USE_MAIN,
1103+ USE_MAIN,
1104+ USE_MAIN,
1105+ {Z80_JP, Z80_UNUSED, Z80_REG_INDIRECT, Z80_IY, 0},
1106+ USE_MAIN,
1107+ USE_MAIN,
1108+ USE_MAIN,
1109+ USE_MAIN,
1110+ USE_MAIN,
1111+ USE_MAIN,
1112+ //F
1113+ USE_MAIN,
1114+ USE_MAIN,
1115+ USE_MAIN,
1116+ USE_MAIN,
1117+ USE_MAIN,
1118+ USE_MAIN,
1119+ USE_MAIN,
1120+ USE_MAIN,
1121+ USE_MAIN,
1122+ {Z80_LD, Z80_SP, Z80_REG, Z80_IY, 0},
1123+ USE_MAIN,
1124+ USE_MAIN,
1125+ USE_MAIN,
1126+ USE_MAIN,
1127+ USE_MAIN,
1128+ USE_MAIN
1129+};
1130+
1131+#define SHIFT_BLOCK_IY(op) \
1132+ {op, Z80_B, Z80_IY_DISPLACE | Z80_DIR, 0, 1},\
1133+ {op, Z80_C, Z80_IY_DISPLACE | Z80_DIR, 0, 1},\
1134+ {op, Z80_D, Z80_IY_DISPLACE | Z80_DIR, 0, 1},\
1135+ {op, Z80_E, Z80_IY_DISPLACE | Z80_DIR, 0, 1},\
1136+ {op, Z80_H, Z80_IY_DISPLACE | Z80_DIR, 0, 1},\
1137+ {op, Z80_L, Z80_IY_DISPLACE | Z80_DIR, 0, 1},\
1138+ {op, Z80_UNUSED, Z80_IY_DISPLACE | Z80_DIR, 0, 1},\
1139+ {op, Z80_A, Z80_IY_DISPLACE | Z80_DIR, 0, 1}
1140+
1141+#define BIT_BLOCK_IY(bit) \
1142+ {Z80_BIT, Z80_USE_IMMED, Z80_IY_DISPLACE, 0, bit},\
1143+ {Z80_BIT, Z80_USE_IMMED, Z80_IY_DISPLACE, 0, bit},\
1144+ {Z80_BIT, Z80_USE_IMMED, Z80_IY_DISPLACE, 0, bit},\
1145+ {Z80_BIT, Z80_USE_IMMED, Z80_IY_DISPLACE, 0, bit},\
1146+ {Z80_BIT, Z80_USE_IMMED, Z80_IY_DISPLACE, 0, bit},\
1147+ {Z80_BIT, Z80_USE_IMMED, Z80_IY_DISPLACE, 0, bit},\
1148+ {Z80_BIT, Z80_USE_IMMED, Z80_IY_DISPLACE, 0, bit},\
1149+ {Z80_BIT, Z80_USE_IMMED, Z80_IY_DISPLACE, 0, bit}
1150+
1151+#define BIT_BLOCK_IY_REG(op, bit) \
1152+ {op, Z80_B, Z80_IY_DISPLACE | Z80_DIR, 0, bit},\
1153+ {op, Z80_C, Z80_IY_DISPLACE | Z80_DIR, 0, bit},\
1154+ {op, Z80_D, Z80_IY_DISPLACE | Z80_DIR, 0, bit},\
1155+ {op, Z80_E, Z80_IY_DISPLACE | Z80_DIR, 0, bit},\
1156+ {op, Z80_H, Z80_IY_DISPLACE | Z80_DIR, 0, bit},\
1157+ {op, Z80_L, Z80_IY_DISPLACE | Z80_DIR, 0, bit},\
1158+ {op, Z80_USE_IMMED, Z80_IY_DISPLACE, 0, bit},\
1159+ {op, Z80_A, Z80_IY_DISPLACE | Z80_DIR, 0, bit}
1160+
1161+z80inst z80_tbl_iy_bit[256] = {
1162+ //0
1163+ SHIFT_BLOCK_IY(Z80_RLC),
1164+ SHIFT_BLOCK_IY(Z80_RRC),
1165+ //1
1166+ SHIFT_BLOCK_IY(Z80_RL),
1167+ SHIFT_BLOCK_IY(Z80_RR),
1168+ //2
1169+ SHIFT_BLOCK_IY(Z80_SLA),
1170+ SHIFT_BLOCK_IY(Z80_SRA),
1171+ //3
1172+ SHIFT_BLOCK_IY(Z80_SLL),
1173+ SHIFT_BLOCK_IY(Z80_SRL),
1174+ //4
1175+ BIT_BLOCK_IY(0),
1176+ BIT_BLOCK_IY(1),
1177+ //5
1178+ BIT_BLOCK_IY(2),
1179+ BIT_BLOCK_IY(3),
1180+ //6
1181+ BIT_BLOCK_IY(4),
1182+ BIT_BLOCK_IY(5),
1183+ //7
1184+ BIT_BLOCK_IY(6),
1185+ BIT_BLOCK_IY(7),
1186+ //8
1187+ BIT_BLOCK_IY_REG(Z80_RES, 0),
1188+ BIT_BLOCK_IY_REG(Z80_RES, 1),
1189+ //9
1190+ BIT_BLOCK_IY_REG(Z80_RES, 2),
1191+ BIT_BLOCK_IY_REG(Z80_RES, 3),
1192+ //A
1193+ BIT_BLOCK_IY_REG(Z80_RES, 4),
1194+ BIT_BLOCK_IY_REG(Z80_RES, 5),
1195+ //B
1196+ BIT_BLOCK_IY_REG(Z80_RES, 6),
1197+ BIT_BLOCK_IY_REG(Z80_RES, 7),
1198+ //C
1199+ BIT_BLOCK_IY_REG(Z80_SET, 0),
1200+ BIT_BLOCK_IY_REG(Z80_SET, 1),
1201+ //D
1202+ BIT_BLOCK_IY_REG(Z80_SET, 2),
1203+ BIT_BLOCK_IY_REG(Z80_SET, 3),
1204+ //E
1205+ BIT_BLOCK_IY_REG(Z80_SET, 4),
1206+ BIT_BLOCK_IY_REG(Z80_SET, 5),
1207+ //F
1208+ BIT_BLOCK_IY_REG(Z80_SET, 6),
1209+ BIT_BLOCK_IY_REG(Z80_SET, 7),
1210+};
1211+
1212+enum {
1213+ NORMAL,
1214+ USE_IX,
1215+ USE_IY
1216+};
1217+
1218+uint8_t * z80_decode(uint8_t * istream, z80inst * decoded)
1219+{
1220+ uint8_t tmp;
1221+ uint8_t *start = istream;
1222+ uint8_t ixiy = NORMAL;
1223+ uint16_t ixiy_disp = 0x100;
1224+ z80inst *base = NULL;
1225+ while(!base)
1226+ {
1227+ switch (*istream)
1228+ {
1229+ case 0xCB:
1230+ istream++;
1231+ if (ixiy == NORMAL) {
1232+ base = z80_tbl_bit + *istream;
1233+ } else if (ixiy == USE_IX) {
1234+ ixiy_disp = *(istream++);
1235+ base = z80_tbl_ix_bit + *istream;
1236+ } else {
1237+ ixiy_disp = *(istream++);
1238+ base = z80_tbl_iy_bit + *istream;
1239+ }
1240+ break;
1241+ case 0xED:
1242+ istream++;
1243+ ixiy = NORMAL;
1244+ if (*istream < 0x40 || *istream >= 0xC0) {
1245+ base = z80_tbl_extd + 0xBF;
1246+ } else {
1247+ base = z80_tbl_extd + *istream - 0x40;
1248+ }
1249+ break;
1250+ case 0xDD:
1251+ istream++;
1252+ ixiy = USE_IX;
1253+ break;
1254+ case 0xFD:
1255+ istream++;
1256+ ixiy = USE_IY;
1257+ break;
1258+ default:
1259+ if (ixiy == NORMAL) {
1260+ base = z80_tbl_a + *istream;
1261+ } else if (ixiy == USE_IX) {
1262+ base = z80_tbl_ix + *istream;
1263+ } else {
1264+ base = z80_tbl_iy + *istream;
1265+ }
1266+ }
1267+ }
1268+ if (base->op == Z80_USE_MAIN) {
1269+ base = z80_tbl_a + *istream;
1270+ ixiy = NORMAL;
1271+ }
1272+ memcpy(decoded, base, offsetof(z80inst, opcode_bytes));
1273+ decoded->opcode_bytes = istream - start + 1;
1274+ if (ixiy != NORMAL) {
1275+ if (ixiy_disp < 0x100) {
1276+ decoded->ea_reg = ixiy_disp;
1277+ //don't count displacement byte as an opcode byte
1278+ decoded->opcode_bytes--;
1279+ } else if ((decoded->addr_mode & 0x1F) == Z80_IX_DISPLACE || (decoded->addr_mode & 0x1F) == Z80_IY_DISPLACE) {
1280+ decoded->ea_reg = *(++istream);
1281+ }
1282+ }
1283+
1284+ if ((decoded->addr_mode & 0x1F) == Z80_IMMED && decoded->op != Z80_RST && decoded->op != Z80_IM) {
1285+ decoded->immed = *(++istream);
1286+ if ((decoded->reg >= Z80_BC && decoded->reg < Z80_UNUSED) || decoded->op == Z80_CALL || decoded->op == Z80_CALLCC || decoded->op == Z80_JP || decoded->op == Z80_JPCC) {
1287+ decoded->immed |= *(++istream) << 8;
1288+ } else if (decoded->immed & 0x80) {
1289+ decoded->immed |= 0xFF00;
1290+ }
1291+ } else if ((decoded->addr_mode & 0x1F) == Z80_IMMED_INDIRECT) {
1292+ decoded->immed = *(++istream);
1293+ if (decoded->op != Z80_OUT && decoded->op != Z80_IN) {
1294+ decoded->immed |= *(++istream) << 8;
1295+ }
1296+ }
1297+ if (decoded->reg == Z80_USE_IMMED && decoded->op != Z80_BIT && decoded->op != Z80_RES && decoded->op != Z80_SET && decoded->op != Z80_OUT) {
1298+ decoded->immed = *(++istream);
1299+ }
1300+ return istream+1;
1301+}
1302+
1303+char *z80_mnemonics[Z80_OTDR+1] = {
1304+ "ld",
1305+ "push",
1306+ "pop",
1307+ "ex",
1308+ "exx",
1309+ "ldi",
1310+ "ldir",
1311+ "ldd",
1312+ "lddr",
1313+ "cpi",
1314+ "cpir",
1315+ "cpd",
1316+ "cpdr",
1317+ "add",
1318+ "adc",
1319+ "sub",
1320+ "sbc",
1321+ "and",
1322+ "or",
1323+ "xor",
1324+ "cp",
1325+ "inc",
1326+ "dec",
1327+ "daa",
1328+ "cpl",
1329+ "neg",
1330+ "ccf",
1331+ "scf",
1332+ "nop",
1333+ "halt",
1334+ "di",
1335+ "ei",
1336+ "im",
1337+ "rlc",
1338+ "rl",
1339+ "rrc",
1340+ "rr",
1341+ "sla",
1342+ "sra",
1343+ "sll",
1344+ "srl",
1345+ "rld",
1346+ "rrd",
1347+ "bit",
1348+ "set",
1349+ "res",
1350+ "jp",
1351+ "jp",
1352+ "jr",
1353+ "jr",
1354+ "djnz",
1355+ "call",
1356+ "call",
1357+ "ret",
1358+ "ret",
1359+ "reti",
1360+ "retn",
1361+ "rst",
1362+ "in",
1363+ "ini",
1364+ "inir",
1365+ "ind",
1366+ "indr",
1367+ "out",
1368+ "outi",
1369+ "otir",
1370+ "outd",
1371+ "otdr"
1372+};
1373+
1374+char * z80_regs[Z80_USE_IMMED] = {
1375+ "c",
1376+ "b",
1377+ "e",
1378+ "d",
1379+ "l",
1380+ "h",
1381+ "ixl",
1382+ "ixh",
1383+ "iyl",
1384+ "iyh",
1385+ "i",
1386+ "r",
1387+ "a",
1388+ "bc",
1389+ "de",
1390+ "hl",
1391+ "sp",
1392+ "af",
1393+ "ix",
1394+ "iy",
1395+};
1396+
1397+char * z80_conditions[Z80_CC_M+1] = {
1398+ "nz",
1399+ "z",
1400+ "nc",
1401+ "c",
1402+ "po",
1403+ "pe",
1404+ "p",
1405+ "m"
1406+};
1407+
1408+int z80_disasm(z80inst * decoded, char * dst, uint16_t address)
1409+{
1410+ int len = sprintf(dst, "%s", z80_mnemonics[decoded->op]);
1411+ uint8_t needcomma;
1412+ if (decoded->addr_mode & Z80_DIR) {
1413+ needcomma = 1;
1414+ switch (decoded->addr_mode & 0x1F)
1415+ {
1416+ case Z80_REG:
1417+ len += sprintf(dst+len, " %s", z80_regs[decoded->ea_reg]);
1418+ break;
1419+ case Z80_REG_INDIRECT:
1420+ len += sprintf(dst+len, " (%s)", z80_regs[decoded->ea_reg]);
1421+ break;
1422+ case Z80_IMMED:
1423+ if (decoded->immed >= 63 || decoded->op == Z80_JP || decoded->op == Z80_JPCC || decoded->op == Z80_CALL || decoded->op == Z80_CALLCC || decoded->op == Z80_RST)
1424+ {
1425+ len += sprintf(dst+len, " $%X", decoded->immed);
1426+ } else {
1427+ len += sprintf(dst+len, " %d", decoded->immed);
1428+ }
1429+ break;
1430+ case Z80_IMMED_INDIRECT:
1431+ len += sprintf(dst+len, " ($%X)", decoded->immed);
1432+ break;
1433+ case Z80_IX_DISPLACE:
1434+ len += sprintf(dst+len, " (ix+%d)", decoded->ea_reg & 0x80 ? decoded->ea_reg - 256 : decoded->ea_reg);
1435+ break;
1436+ case Z80_IY_DISPLACE:
1437+ len += sprintf(dst+len, " (iy+%d)", decoded->ea_reg & 0x80 ? decoded->ea_reg - 256 : decoded->ea_reg);
1438+ break;
1439+ default:
1440+ needcomma = 0;
1441+ }
1442+ if (decoded->reg & Z80_IMMED_FLAG) {
1443+ len += sprintf(dst+len, "%s %d", needcomma ? "," : "", decoded->immed);
1444+ }
1445+ if ((decoded->reg & 0x1F) != Z80_UNUSED) {
1446+ if (decoded->op == Z80_JRCC || decoded->op == Z80_JPCC || decoded->op == Z80_CALLCC || decoded->op == Z80_RETCC) {
1447+ len += sprintf(dst+len, "%s %s", needcomma ? "," : "", z80_conditions[decoded->reg & 0x1F]);
1448+ } else {
1449+ len += sprintf(dst+len, "%s %s", needcomma ? "," : "", z80_regs[decoded->reg & 0x1F]);
1450+ }
1451+ }
1452+ } else {
1453+ needcomma = 0;
1454+ if (decoded->reg & Z80_IMMED_FLAG) {
1455+ len += sprintf(dst+len, " %d", decoded->immed);
1456+ needcomma = 1;
1457+ }
1458+ if ((decoded->reg & 0x1F) != Z80_UNUSED) {
1459+ if (decoded->op == Z80_JRCC || decoded->op == Z80_JPCC || decoded->op == Z80_CALLCC || decoded->op == Z80_RETCC) {
1460+ len += sprintf(dst+len, " %s", z80_conditions[decoded->reg & 0x1F]);
1461+ } else {
1462+ len += sprintf(dst+len, " %s", z80_regs[decoded->reg & 0x1F]);
1463+ }
1464+ needcomma = 1;
1465+ }
1466+ switch (decoded->addr_mode)
1467+ {
1468+ case Z80_REG:
1469+ len += sprintf(dst+len, "%s %s", needcomma ? "," : "" , z80_regs[decoded->ea_reg]);
1470+ break;
1471+ case Z80_REG_INDIRECT:
1472+ len += sprintf(dst+len, "%s (%s)", needcomma ? "," : "" , z80_regs[decoded->ea_reg]);
1473+ break;
1474+ case Z80_IMMED:
1475+ if (decoded->op == Z80_JR || decoded->op == Z80_JRCC || decoded->op == Z80_DJNZ) {
1476+ address += 2 + decoded->immed;
1477+ len += sprintf(dst+len, "%s %X", needcomma ? "," : "" , address);
1478+ } else if (decoded->immed >= 63 || decoded->op == Z80_JP || decoded->op == Z80_JPCC || decoded->op == Z80_CALL || decoded->op == Z80_CALLCC || decoded->op == Z80_RST)
1479+ {
1480+ len += sprintf(dst+len, "%s $%X", needcomma ? "," : "" , decoded->immed);
1481+ } else {
1482+ len += sprintf(dst+len, "%s %d", needcomma ? "," : "" , decoded->immed);
1483+ }
1484+ break;
1485+ case Z80_IMMED_INDIRECT:
1486+ len += sprintf(dst+len, "%s ($%X)", needcomma ? "," : "" , decoded->immed);
1487+ break;
1488+ case Z80_IX_DISPLACE:
1489+ len += sprintf(dst+len, "%s (ix+%d)", needcomma ? "," : "" , decoded->ea_reg & 0x80 ? decoded->ea_reg - 256 : decoded->ea_reg);
1490+ break;
1491+ case Z80_IY_DISPLACE:
1492+ len += sprintf(dst+len, "%s (iy+%d)", needcomma ? "," : "" , decoded->ea_reg & 0x80 ? decoded->ea_reg - 256 : decoded->ea_reg);
1493+ break;
1494+ }
1495+ }
1496+ return len;
1497+}
1498+
1499+uint8_t z80_high_reg(uint8_t reg)
1500+{
1501+ switch(reg)
1502+ {
1503+ case Z80_C:
1504+ case Z80_BC:
1505+ return Z80_B;
1506+ case Z80_E:
1507+ case Z80_DE:
1508+ return Z80_D;
1509+ case Z80_L:
1510+ case Z80_HL:
1511+ return Z80_H;
1512+ case Z80_IXL:
1513+ case Z80_IX:
1514+ return Z80_IXH;
1515+ case Z80_IYL:
1516+ case Z80_IY:
1517+ return Z80_IYH;
1518+ default:
1519+ return Z80_UNUSED;
1520+ }
1521+}
1522+
1523+uint8_t z80_low_reg(uint8_t reg)
1524+{
1525+ switch(reg)
1526+ {
1527+ case Z80_B:
1528+ case Z80_BC:
1529+ return Z80_C;
1530+ case Z80_D:
1531+ case Z80_DE:
1532+ return Z80_E;
1533+ case Z80_H:
1534+ case Z80_HL:
1535+ return Z80_L;
1536+ case Z80_IXH:
1537+ case Z80_IX:
1538+ return Z80_IXL;
1539+ case Z80_IYH:
1540+ case Z80_IY:
1541+ return Z80_IYL;
1542+ default:
1543+ return Z80_UNUSED;
1544+ }
1545+}
1546+
1547+uint8_t z80_word_reg(uint8_t reg)
1548+{
1549+ switch(reg)
1550+ {
1551+ case Z80_B:
1552+ case Z80_C:
1553+ return Z80_BC;
1554+ case Z80_D:
1555+ case Z80_E:
1556+ return Z80_DE;
1557+ case Z80_H:
1558+ case Z80_L:
1559+ return Z80_HL;
1560+ case Z80_IXH:
1561+ case Z80_IXL:
1562+ return Z80_IX;
1563+ case Z80_IYH:
1564+ case Z80_IYL:
1565+ return Z80_IY;
1566+ default:
1567+ return Z80_UNUSED;
1568+ }
1569+}
1570+
1571+uint8_t z80_is_terminal(z80inst * inst)
1572+{
1573+ return inst->op == Z80_RET || inst->op == Z80_RETI || inst->op == Z80_RETN || inst->op == Z80_JP
1574+ || inst->op == Z80_JR || inst->op == Z80_HALT || (inst->op == Z80_NOP && inst->immed == 42);
1575+}
1576+
1577+
1578+
+148,
-0
1@@ -0,0 +1,148 @@
2+/*
3+ Copyright 2013 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#ifndef Z80INST_H_
8+#define Z80INST_H_
9+
10+#include <stdint.h>
11+
12+enum {
13+ Z80_LD,
14+ Z80_PUSH,
15+ Z80_POP,
16+ Z80_EX,
17+ Z80_EXX,
18+ Z80_LDI,
19+ Z80_LDIR,
20+ Z80_LDD,
21+ Z80_LDDR,
22+ Z80_CPI,
23+ Z80_CPIR,
24+ Z80_CPD,
25+ Z80_CPDR,
26+ Z80_ADD,
27+ Z80_ADC,
28+ Z80_SUB,
29+ Z80_SBC,
30+ Z80_AND,
31+ Z80_OR,
32+ Z80_XOR,
33+ Z80_CP,
34+ Z80_INC,
35+ Z80_DEC,
36+ Z80_DAA,
37+ Z80_CPL,
38+ Z80_NEG,
39+ Z80_CCF,
40+ Z80_SCF,
41+ Z80_NOP,
42+ Z80_HALT,
43+ Z80_DI,
44+ Z80_EI,
45+ Z80_IM,
46+ Z80_RLC,
47+ Z80_RL,
48+ Z80_RRC,
49+ Z80_RR,
50+ Z80_SLA,
51+ Z80_SRA,
52+ Z80_SLL,
53+ Z80_SRL,
54+ Z80_RLD,
55+ Z80_RRD,
56+ Z80_BIT,
57+ Z80_SET,
58+ Z80_RES,
59+ Z80_JP,
60+ Z80_JPCC,
61+ Z80_JR,
62+ Z80_JRCC,
63+ Z80_DJNZ,
64+ Z80_CALL,
65+ Z80_CALLCC,
66+ Z80_RET,
67+ Z80_RETCC,
68+ Z80_RETI,
69+ Z80_RETN,
70+ Z80_RST,
71+ Z80_IN,
72+ Z80_INI,
73+ Z80_INIR,
74+ Z80_IND,
75+ Z80_INDR,
76+ Z80_OUT,
77+ Z80_OUTI,
78+ Z80_OTIR,
79+ Z80_OUTD,
80+ Z80_OTDR,
81+ Z80_USE_MAIN
82+};
83+
84+enum {
85+ Z80_C=0,
86+ Z80_B,
87+ Z80_E,
88+ Z80_D,
89+ Z80_L,
90+ Z80_H,
91+ Z80_IXL,
92+ Z80_IXH,
93+ Z80_IYL,
94+ Z80_IYH,
95+ Z80_I,
96+ Z80_R,
97+ Z80_A,
98+ Z80_BC,
99+ Z80_DE,
100+ Z80_HL,
101+ Z80_SP,
102+ Z80_AF,
103+ Z80_IX,
104+ Z80_IY,
105+ Z80_UNUSED
106+};
107+
108+#define Z80_IMMED_FLAG 0x80
109+#define Z80_USE_IMMED (Z80_IMMED_FLAG|Z80_UNUSED)
110+
111+enum {
112+ Z80_CC_NZ,
113+ Z80_CC_Z,
114+ Z80_CC_NC,
115+ Z80_CC_C,
116+ Z80_CC_PO,
117+ Z80_CC_PE,
118+ Z80_CC_P,
119+ Z80_CC_M
120+};
121+
122+enum {
123+ Z80_REG,
124+ Z80_REG_INDIRECT,
125+ Z80_IMMED,
126+ Z80_IMMED_INDIRECT,
127+ Z80_IX_DISPLACE,
128+ Z80_IY_DISPLACE
129+};
130+#define Z80_DIR 0x80
131+
132+typedef struct {
133+ uint8_t op;
134+ uint8_t reg;
135+ uint8_t addr_mode;
136+ uint8_t ea_reg;
137+ uint16_t immed;
138+ uint16_t opcode_bytes;
139+} z80inst;
140+
141+uint8_t * z80_decode(uint8_t * istream, z80inst * decoded);
142+int z80_disasm(z80inst * decoded, char * dst, uint16_t address);
143+uint8_t z80_high_reg(uint8_t reg);
144+uint8_t z80_low_reg(uint8_t reg);
145+uint8_t z80_word_reg(uint8_t reg);
146+uint8_t z80_is_terminal(z80inst * inst);
147+
148+#endif //Z80INST_H_
149+
+58,
-0
1@@ -0,0 +1,58 @@
2+#!/usr/bin/env python
3+from glob import glob
4+import subprocess
5+from sys import exit,argv
6+
7+prefixes = []
8+skip = set()
9+for i in range(1, len(argv)):
10+ if '.' in argv[i]:
11+ f = open(argv[i])
12+ for line in f:
13+ parts = line.split()
14+ for part in parts:
15+ if part.endswith('.bin'):
16+ skip.add(part)
17+ f.close()
18+ print 'Skipping',len(skip),'entries from previous report.'
19+ else:
20+ prefixes.append(argv[i])
21+
22+for path in glob('ztests/*/*.bin'):
23+ if path in skip:
24+ continue
25+ if prefixes:
26+ good = False
27+ fname = path.split('/')[-1]
28+ for prefix in prefixes:
29+ if fname.startswith(prefix):
30+ good = True
31+ break
32+ if not good:
33+ continue
34+ try:
35+ b = subprocess.check_output(['./ztestrun', path])
36+ try:
37+ m = subprocess.check_output(['gxz80/gxzrun', path])
38+ #_,_,b = b.partition('\n')
39+ if b != m:
40+ print '-----------------------------'
41+ print 'Mismatch in ' + path
42+ print 'blastem output:'
43+ print b
44+ print 'gxz80 output:'
45+ print m
46+ print '-----------------------------'
47+ else:
48+ print path, 'passed'
49+ except subprocess.CalledProcessError as e:
50+ print '-----------------------------'
51+ print 'gxz80 exited with code', e.returncode, 'for test', path
52+ print 'blastem output:'
53+ print b
54+ print '-----------------------------'
55+ except subprocess.CalledProcessError as e:
56+ print '-----------------------------'
57+ print 'blastem exited with code', e.returncode, 'for test', path
58+ print '-----------------------------'
59+
A
zdis.c
+221,
-0
1@@ -0,0 +1,221 @@
2+/*
3+ Copyright 2013 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#include "z80inst.h"
8+#include <stdio.h>
9+#include <stdlib.h>
10+#include <stdarg.h>
11+
12+uint8_t visited[(64*1024)/8];
13+uint8_t label[(64*1024)/8];
14+
15+void fatal_error(char *format, ...)
16+{
17+ va_list args;
18+ va_start(args, format);
19+ vfprintf(stderr, format, args);
20+ va_end(args);
21+ exit(1);
22+}
23+
24+void visit(uint16_t address)
25+{
26+ visited[address/8] |= 1 << (address % 8);
27+}
28+
29+void reference(uint16_t address)
30+{
31+ //printf("referenced: %X\n", address);
32+ label[address/8] |= 1 << (address % 8);
33+}
34+
35+uint8_t is_visited(uint16_t address)
36+{
37+ return visited[address/8] & (1 << (address % 8));
38+}
39+
40+uint8_t is_label(uint16_t address)
41+{
42+ return label[address/8] & (1 << (address % 8));
43+}
44+
45+typedef struct deferred {
46+ uint16_t address;
47+ struct deferred *next;
48+} deferred;
49+
50+deferred * defer(uint16_t address, deferred * next)
51+{
52+ if (is_visited(address)) {
53+ return next;
54+ }
55+ //printf("deferring %X\n", address);
56+ deferred * d = malloc(sizeof(deferred));
57+ d->address = address;
58+ d->next = next;
59+ return d;
60+}
61+
62+uint8_t labels = 0;
63+uint8_t addr = 0;
64+uint8_t only = 0;
65+
66+int main(int argc, char ** argv)
67+{
68+ long filesize;
69+ uint8_t *filebuf;
70+ char disbuf[1024];
71+ z80inst instbuf;
72+ uint8_t * cur;
73+ FILE * f = fopen(argv[1], "rb");
74+ fseek(f, 0, SEEK_END);
75+ filesize = ftell(f);
76+ fseek(f, 0, SEEK_SET);
77+ filebuf = malloc(filesize);
78+ fread(filebuf, 1, filesize, f);
79+ fclose(f);
80+ deferred *def = NULL, *tmpd;
81+ uint16_t offset = 0;
82+ for(uint8_t opt = 2; opt < argc; ++opt) {
83+ if (argv[opt][0] == '-') {
84+ FILE * address_log;
85+ switch (argv[opt][1])
86+ {
87+ case 'l':
88+ labels = 1;
89+ break;
90+ case 'a':
91+ addr = 1;
92+ break;
93+ case 'o':
94+ only = 1;
95+ break;
96+ case 'f':
97+ opt++;
98+ if (opt >= argc) {
99+ fputs("-f must be followed by a filename\n", stderr);
100+ exit(1);
101+ }
102+ address_log = fopen(argv[opt], "r");
103+ if (!address_log) {
104+ fprintf(stderr, "Failed to open %s for reading\n", argv[opt]);
105+ exit(1);
106+ }
107+ while (fgets(disbuf, sizeof(disbuf), address_log)) {
108+ if (disbuf[0]) {
109+ uint16_t address = strtol(disbuf, NULL, 16);
110+ if (address) {
111+ def = defer(address, def);
112+ reference(address);
113+ }
114+ }
115+ }
116+ fclose(address_log);
117+ break;
118+ case 's':
119+ opt++;
120+ if (opt >= argc) {
121+ fputs("-s must be followed by a start offset in hex\n", stderr);
122+ exit(1);
123+ }
124+ offset = strtol(argv[opt], NULL, 16);
125+ break;
126+ }
127+ } else {
128+ uint16_t address = strtol(argv[opt], NULL, 16);
129+ def = defer(address, def);
130+ reference(address);
131+ }
132+ }
133+ uint16_t start = offset;
134+ uint8_t *encoded, *next;
135+ uint32_t size;
136+ if (!def || !only) {
137+ def = defer(start, def);
138+ }
139+ uint16_t address;
140+ while(def) {
141+ do {
142+ encoded = NULL;
143+ address = def->address;
144+ if (!is_visited(address)) {
145+ encoded = filebuf + address - offset;
146+ }
147+ tmpd = def;
148+ def = def->next;
149+ free(tmpd);
150+ } while(def && encoded == NULL);
151+ if (!encoded) {
152+ break;
153+ }
154+ for(;;) {
155+ if ((address - offset) > filesize || is_visited(address) || address < offset) {
156+ break;
157+ }
158+ visit(address);
159+ next = z80_decode(encoded, &instbuf);
160+ address += (next-encoded);
161+ encoded = next;
162+
163+ //z80_disasm(&instbuf, disbuf);
164+ //printf("%X: %s\n", address, disbuf);
165+ switch (instbuf.op)
166+ {
167+ case Z80_JR:
168+ address += instbuf.immed;
169+ encoded = filebuf + address - offset;
170+ break;
171+ case Z80_JRCC:
172+ reference(address + instbuf.immed);
173+ def = defer(address + instbuf.immed, def);
174+ break;
175+ case Z80_JP:
176+ address = instbuf.immed;
177+ encoded = filebuf + address - offset;
178+ break;
179+ case Z80_JPCC:
180+ case Z80_CALL:
181+ case Z80_CALLCC:
182+ case Z80_RST:
183+ reference(instbuf.immed);
184+ def = defer(instbuf.immed, def);
185+ break;
186+ default:
187+ if (z80_is_terminal(&instbuf)) {
188+ address = filesize + 1;
189+ }
190+ }
191+ }
192+ }
193+ if (labels) {
194+ for (address = filesize; address < (64*1024); address++) {
195+ if (is_label(address)) {
196+ printf("ADR_%X equ $%X\n", address, address);
197+ }
198+ }
199+ puts("");
200+ }
201+ for (address = offset; address < filesize + offset; address++) {
202+ if (is_visited(address)) {
203+ encoded = filebuf + address - offset;
204+ z80_decode(encoded, &instbuf);
205+ if (labels) {
206+ /*m68k_disasm_labels(&instbuf, disbuf);
207+ if (is_label(instbuf.address)) {
208+ printf("ADR_%X:\n", instbuf.address);
209+ }
210+ if (addr) {
211+ printf("\t%s\t;%X\n", disbuf, instbuf.address);
212+ } else {
213+ printf("\t%s\n", disbuf);
214+ }*/
215+ } else {
216+ z80_disasm(&instbuf, disbuf, address);
217+ printf("%X: %s\n", address, disbuf);
218+ }
219+ }
220+ }
221+ return 0;
222+}
A
zip.c
+196,
-0
1@@ -0,0 +1,196 @@
2+#include <stdio.h>
3+#include <stdlib.h>
4+#include <stddef.h>
5+#include <string.h>
6+#include "util.h"
7+#include "zip.h"
8+#include <zlib.h>
9+
10+static const char cdfd_magic[4] = {'P', 'K', 1, 2};
11+static const char eocd_magic[4] = {'P', 'K', 5, 6};
12+#define MIN_EOCD_SIZE 22
13+#define MIN_CDFD_SIZE 46
14+#define ZIP_MAX_EOCD_OFFSET (64*1024+MIN_EOCD_SIZE)
15+
16+enum {
17+ ZIP_STORE = 0,
18+ ZIP_DEFLATE = 8
19+};
20+
21+zip_file *zip_open(const char *filename)
22+{
23+ FILE *f = fopen(filename, "rb");
24+ if (!f) {
25+ return NULL;
26+ }
27+ long fsize = file_size(f);
28+ if (fsize < MIN_EOCD_SIZE) {
29+ //too small to be a zip file
30+ goto fail;
31+ }
32+
33+ long max_offset = fsize > ZIP_MAX_EOCD_OFFSET ? ZIP_MAX_EOCD_OFFSET : fsize;
34+ fseek(f, -max_offset, SEEK_END);
35+ uint8_t *buf = malloc(max_offset);
36+ if (max_offset != fread(buf, 1, max_offset, f)) {
37+ goto fail;
38+ }
39+
40+ long current_offset;
41+ uint32_t cd_start, cd_size;
42+ uint16_t cd_count;
43+ for (current_offset = max_offset - MIN_EOCD_SIZE; current_offset >= 0; current_offset--)
44+ {
45+ if (memcmp(eocd_magic, buf + current_offset, sizeof(eocd_magic))) {
46+ continue;
47+ }
48+ uint16_t comment_size = buf[current_offset + 20] | buf[current_offset + 21] << 8;
49+ if (comment_size != (max_offset - current_offset - MIN_EOCD_SIZE)) {
50+ continue;
51+ }
52+ cd_start = buf[current_offset + 16] | buf[current_offset + 17] << 8
53+ | buf[current_offset + 18] << 16 | buf[current_offset + 19] << 24;
54+ if (cd_start > (fsize - (max_offset - current_offset))) {
55+ continue;
56+ }
57+ cd_size = buf[current_offset + 12] | buf[current_offset + 13] << 8
58+ | buf[current_offset + 14] << 16 | buf[current_offset + 15] << 24;
59+ if ((cd_start + cd_size) > (fsize - (max_offset - current_offset))) {
60+ continue;
61+ }
62+ cd_count = buf[current_offset + 10] | buf[current_offset + 11] << 8;
63+ break;
64+ }
65+ free(buf);
66+ if (current_offset < 0) {
67+ //failed to find EOCD
68+ goto fail;
69+ }
70+ buf = malloc(cd_size);
71+ fseek(f, cd_start, SEEK_SET);
72+ if (cd_size != fread(buf, 1, cd_size, f)) {
73+ goto fail_free;
74+ }
75+ zip_entry *entries = calloc(cd_count, sizeof(zip_entry));
76+ uint32_t cd_max_last = cd_size - MIN_CDFD_SIZE;
77+ zip_entry *cur_entry = entries;
78+ for (uint32_t off = 0; cd_count && off <= cd_max_last; cur_entry++, cd_count--)
79+ {
80+ if (memcmp(buf + off, cdfd_magic, sizeof(cdfd_magic))) {
81+ goto fail_entries;
82+ }
83+ uint32_t name_length = buf[off + 28] | buf[off + 29] << 8;
84+ uint32_t extra_length = buf[off + 30] | buf[off + 31] << 8;
85+ //TODO: verify name length doesn't go past end of CD
86+
87+ cur_entry->name = malloc(name_length + 1);
88+ memcpy(cur_entry->name, buf + off + MIN_CDFD_SIZE, name_length);
89+ cur_entry->name[name_length] = 0;
90+
91+ cur_entry->compressed_size = buf[off + 20] | buf[off + 21] << 8
92+ | buf[off + 22] << 16 | buf[off + 23] << 24;
93+ cur_entry->size = buf[off + 24] | buf[off + 25] << 8
94+ | buf[off + 26] << 16 | buf[off + 27] << 24;
95+
96+ cur_entry->local_header_off = buf[off + 42] | buf[off + 43] << 8
97+ | buf[off + 44] << 16 | buf[off + 45] << 24;
98+
99+ cur_entry->compression_method = buf[off + 10] | buf[off + 11] << 8;
100+
101+ off += name_length + extra_length + MIN_CDFD_SIZE;
102+ }
103+
104+ zip_file *z = malloc(sizeof(zip_file));
105+ z->entries = entries;
106+ z->file = f;
107+ z->num_entries = cur_entry - entries;
108+ return z;
109+
110+fail_entries:
111+ for (cur_entry--; cur_entry >= entries; cur_entry--)
112+ {
113+ free(cur_entry->name);
114+ }
115+ free(entries);
116+fail_free:
117+ free(buf);
118+fail:
119+ fclose(f);
120+ return NULL;
121+}
122+
123+uint8_t *zip_read(zip_file *f, uint32_t index, size_t *out_size)
124+{
125+
126+ fseek(f->file, f->entries[index].local_header_off + 26, SEEK_SET);
127+ uint8_t tmp[4];
128+ if (sizeof(tmp) != fread(tmp, 1, sizeof(tmp), f->file)) {
129+ return NULL;
130+ }
131+ uint32_t local_variable = (tmp[0] | tmp[1] << 8) + (tmp[2] | tmp[3] << 8);
132+ fseek(f->file, f->entries[index].local_header_off + local_variable + 30, SEEK_SET);
133+
134+ size_t int_size;
135+ if (!out_size) {
136+ out_size = &int_size;
137+ int_size = f->entries[index].size;
138+ }
139+
140+ uint8_t *buf = malloc(*out_size);
141+ if (*out_size > f->entries[index].size) {
142+ *out_size = f->entries[index].size;
143+ }
144+ switch(f->entries[index].compression_method)
145+ {
146+ case ZIP_STORE:
147+ if (*out_size != fread(buf, 1, *out_size, f->file)) {
148+ free(buf);
149+ return NULL;
150+ }
151+ break;
152+ case ZIP_DEFLATE: {
153+ //note in unzip.c in zlib/contrib suggests a dummy byte is needed, so we allocate an extra byte here
154+ uint8_t *src_buf = malloc(f->entries[index].compressed_size + 1);
155+ if (f->entries[index].compressed_size != fread(src_buf, 1, f->entries[index].compressed_size, f->file)) {
156+ free(src_buf);
157+ return NULL;
158+ }
159+ uLongf destLen = *out_size;
160+ z_stream stream;
161+ memset(&stream, 0, sizeof(stream));
162+ stream.avail_in = f->entries[index].compressed_size + 1;
163+ stream.next_in = src_buf;
164+ stream.next_out = buf;
165+ stream.avail_out = *out_size;
166+ if (Z_OK == inflateInit2(&stream, -15)) {
167+ int result = inflate(&stream, Z_FINISH);
168+ *out_size = stream.total_out;
169+ free(src_buf);
170+ inflateEnd(&stream);
171+ if (result != Z_OK && result != Z_STREAM_END && result != Z_BUF_ERROR) {
172+ free(buf);
173+ return NULL;
174+ }
175+ }
176+ break;
177+ }
178+ default:
179+ free(buf);
180+ return NULL;
181+ }
182+
183+ return buf;
184+}
185+
186+void zip_close(zip_file *f)
187+{
188+ fclose(f->file);
189+ for (uint32_t i = 0; i < f->num_entries; i++)
190+ {
191+ free(f->entries[i].name);
192+ }
193+ free(f->entries);
194+ free(f);
195+}
196+
197+
A
zip.h
+25,
-0
1@@ -0,0 +1,25 @@
2+#ifndef ZIP_H_
3+#define ZIP_H_
4+
5+#include <stdint.h>
6+#include <stdio.h>
7+
8+typedef struct {
9+ uint64_t compressed_size;
10+ uint64_t size;
11+ uint64_t local_header_off;
12+ char *name;
13+ uint16_t compression_method;
14+} zip_entry;
15+
16+typedef struct {
17+ zip_entry *entries;
18+ FILE *file;
19+ uint32_t num_entries;
20+} zip_file;
21+
22+zip_file *zip_open(const char *filename);
23+uint8_t *zip_read(zip_file *f, uint32_t index, size_t *out_size);
24+void zip_close(zip_file *f);
25+
26+#endif //ZIP_H_
+437,
-0
1@@ -0,0 +1,437 @@
2+z_inccycles_io:
3+ cmp %edi, %ebp
4+ jnb do_limit
5+no_sync_io:
6+ add $4, %ebp
7+ ret
8+do_limit_io:
9+ cmp 112(%rsi), %ebp
10+ jb no_sync_io
11+ jmp sync_io
12+
13+z_inccycles:
14+ cmp %edi, %ebp
15+ jnb do_limit
16+no_sync:
17+ add $3, %ebp
18+ ret
19+do_limit:
20+ cmp 112(%rsi), %ebp
21+ jb no_sync
22+sync_io:
23+ movw $0, 164(%rsi)
24+ call z80_save_context_scratch
25+ pop %rax /*return address in read/write func*/
26+ pop 104(%rsi) /*return address in native code*/
27+ sub $5, %rax /* adjust return addres to point to the call instruction that got us here */
28+ mov %rax, (%rsi)
29+
30+ pop %r15 /* restore callee saved regsiters */
31+ pop %r14
32+ pop %r13
33+ pop %r12
34+ pop %rbp
35+ pop %rbx
36+ ret /* return to caller of z80_run */
37+
38+forced_sync:
39+ movw $0, 164(%rsi)
40+ call z80_save_context_scratch
41+ pop (%rsi) /*return address in read/write func*/
42+ pop 104(%rsi) /*return address in native code*/
43+
44+ pop %r15 /* restore callee saved regsiters */
45+ pop %r14
46+ pop %r13
47+ pop %r12
48+ pop %rbp
49+ pop %rbx
50+ ret /* return to caller of z80_run */
51+
52+ .global z80_handle_cycle_limit_int
53+z80_handle_cycle_limit_int:
54+ cmp 116(%rsi), %ebp
55+ jb zskip_int
56+ mov 112(%rsi), %ebp /* set cycle limit to sync cycle */
57+ /* not sure this is really necessary now that IFF1 and IFF2 are geting cleared */
58+ movl $0xFFFFFFFF, 116(%rsi) /* make sure the interrupt doesn't fire more than once */
59+ /* disable interrupts */
60+ movb $0, 96(%rsi)
61+ movb $0, 97(%rsi)
62+ add $7, %ebp
63+ sub $2, %r9w
64+ mov %r9w, %r14w
65+ call z_inccycles
66+ push %r13
67+ call z80_write_byte_noinc
68+ pop %r13
69+ mov %r9w, %r14w
70+ add $1, %r14w
71+ shr $8, %r13w
72+ call z_inccycles
73+ call z80_write_byte_noinc
74+ pop %r14 /*dispose of return address */
75+ /* TODO: Support interrupt mode 0 and 2 */
76+ mov $0x38, %r13w
77+ call z80_native_addr
78+ jmp *%r13
79+zskip_int:
80+ cmp 112(%rsi), %ebp
81+ jb zskip_sync
82+mov %r13w, 164(%rsi)
83+ .global z80_do_sync
84+z80_do_sync:
85+ call z80_save_context
86+ pop (%rsi) /*return address in native code*/
87+ pop %r15 /* restore callee saved regsiters */
88+ pop %r14
89+ pop %r13
90+ pop %r12
91+ pop %rbp
92+ pop %rbx
93+zskip_sync:
94+ ret
95+
96+ .global z80_halt
97+z80_halt:
98+ mov %edi, %r14d
99+ sub %ebp, %r14d
100+ and $0xFFFFFFFC, %r14d
101+ add %r14d, %ebp
102+ cmp %edi, %ebp
103+ jnb z80_handle_cycle_limit_int
104+ add $4, %ebp
105+ jmp z80_handle_cycle_limit_int
106+
107+ .global z80_read_byte
108+z80_read_byte:
109+ call z_inccycles
110+z80_read_byte_noinc:
111+ cmp $0x4000, %r13w
112+ jb z80_read_ram
113+ cmp $0x8000, %r13w
114+ jae z80_read_bank
115+ cmp $0x6000, %r13w
116+ jb z80_read_ym2612
117+ /* TODO: Bank reg, YM-2612, PSG/VDP */
118+ mov $0xFF, %r13b
119+ ret
120+z80_read_ram:
121+ and $0x1FFF, %r13
122+ mov (%r11, %r13), %r13b
123+ ret
124+z80_read_bank:
125+ /* approximation of wait states for normal 68K bus access */
126+ add $3, %ebp
127+ push %rsi
128+ mov 144(%rsi), %rsi /* get system context pointer */
129+ cmpb $0, 120(%rsi) /* check bus busy flag */
130+ pop %rsi
131+ jne bus_busy
132+z80_read_bank_cont:
133+ and $0x7FFF, %r13
134+ cmp $0, %r12
135+ je slow_bank_read
136+ /* 68K memory is byte swapped */
137+ xor $1, %r13
138+ mov (%r12, %r13), %r13b
139+ ret
140+slow_bank_read:
141+ /* TODO: Call into C to implement this */
142+ ret
143+bus_busy:
144+ cmp %ebp, %edi
145+ jbe no_adjust
146+ mov %edi, %ebp
147+no_adjust:
148+ call forced_sync
149+ jmp z80_read_bank_cont
150+z80_read_ym2612:
151+ call z80_save_context
152+ mov %r13w, %di
153+ push %rsi
154+ test $8, %rsp
155+ jnz 0f
156+ call z80_read_ym
157+ jmp 1f
158+0:
159+ sub $8, %rsp
160+ call z80_read_ym
161+ add $8, %rsp
162+1:
163+ pop %rsi
164+ mov %al, %r13b
165+ call z80_load_context
166+ ret
167+
168+ .global z80_write_byte
169+z80_write_byte:
170+ call z_inccycles
171+z80_write_byte_noinc:
172+ cmp $0x4000, %r14w
173+ jb z80_write_ram
174+ cmp $0x8000, %r14w
175+ jae z80_write_bank
176+ cmp $0x6000, %r14w
177+ jb z80_write_ym2612
178+ cmp $0x6100, %r14w
179+ jb z80_write_bank_reg
180+ cmp $0x7F00, %r14w
181+ jae z80_write_vdp
182+ ret
183+z80_write_ram:
184+ and $0x1FFF, %r14
185+ mov %r13b, (%r11, %r14)
186+ mov %r14d, %r13d
187+ shr $7, %r13d
188+ bt %r13d, 152(%rsi)
189+ jnc not_code
190+ call z80_save_context
191+ mov %r14d, %edi
192+ call z80_handle_code_write
193+ mov %rax, %rsi
194+ call z80_load_context
195+not_code:
196+ ret
197+z80_write_bank:
198+slow_bank_write:
199+ /* approximation of wait states for 68K bus access */
200+ add $3, %ebp
201+ /* TODO: Call into C to implement this */
202+ ret
203+z80_write_ym2612:
204+ and $0x3, %r14w
205+ call z80_save_context
206+ mov %r14w, %di
207+ mov %r13b, %dl
208+ test $8, %rsp
209+ jnz 0f
210+ call z80_write_ym
211+ jmp 1f
212+0:
213+ sub $8, %rsp
214+ call z80_write_ym
215+ add $8, %rsp
216+1:
217+ mov %rax, %rsi
218+ jmp z80_load_context
219+z80_write_bank_reg:
220+ and $1, %r13w
221+ shr %r15w
222+ shl $8, %r13w
223+ xor %r12, %r12
224+ or %r13w, %r15w
225+ and $0x1FF, %r15w
226+ cmp $0x80, %r15w
227+ jb update_bank_ptr
228+ ret
229+update_bank_ptr:
230+ mov %r15w, %r12w
231+ shl $15, %r12
232+ add 80(%rsi), %r12
233+ ret
234+z80_write_vdp:
235+ and $0xFF, %r14w
236+ call z80_save_context
237+ mov %r14w, %di
238+ mov %r13b, %dl
239+ test $8, %rsp
240+ jnz 0f
241+ call z80_vdp_port_write
242+ jmp 1f
243+0:
244+ sub $8, %rsp
245+ call z80_vdp_port_write
246+ add $8, %rsp
247+1:
248+ mov %rax, %rsi
249+ jmp z80_load_context
250+
251+ .global z80_read_word
252+z80_read_word:
253+ call z_inccycles
254+ cmp $0x8000, %r13w
255+ jae z80_read_bank_word
256+ push %r13
257+ call z80_read_byte_noinc
258+ mov %r13b, %r14b
259+ pop %r13
260+ inc %r13
261+ call z_inccycles
262+ call z80_read_byte_noinc
263+ shl $8, %r13w
264+ mov %r14b, %r13b
265+ ret
266+
267+z80_read_bank_word:
268+ add $3, %ebp /* first read typically has 3 wait states */
269+ push %rsi
270+ mov 144(%rsi), %rsi /* get system context pointer */
271+ cmpb $0, 120(%rsi) /* check bus busy flag */
272+ pop %rsi
273+ jne bus_busy_word
274+z80_read_bank_word_cont:
275+ push %r13
276+ call z80_read_bank_cont
277+ mov %r13b, %r14b
278+ pop %r13
279+ inc %r13
280+ call z_inccycles
281+ add $4, %ebp /* second read typically has 4 wait states */
282+ push %rsi
283+ mov 144(%rsi), %rsi /* get system context pointer */
284+ cmpb $0, 120(%rsi) /* check bus busy flag */
285+ pop %rsi
286+ jne bus_busy_word2
287+z80_read_bank_word_cont2:
288+ call z80_read_bank_cont
289+ shl $8, %r13w
290+ mov %r14b, %r13b
291+ ret
292+
293+bus_busy_word:
294+ cmp %ebp, %edi
295+ jb no_adjust_word
296+ mov %edi, %ebp
297+no_adjust_word:
298+ call forced_sync
299+ jmp z80_read_bank_word_cont
300+
301+foofoo:
302+ jmp foofoo
303+
304+bus_busy_word2:
305+ cmp %ebp, %edi
306+ jb no_adjust_word2
307+ mov %edi, %ebp
308+no_adjust_word2:
309+ call forced_sync
310+ jmp z80_read_bank_word_cont2
311+blahblah:
312+ jmp blahblah
313+
314+ .global z80_write_word_highfirst
315+z80_write_word_highfirst:
316+ call z_inccycles
317+ push %r14
318+ push %r13
319+ add $1, %r14w
320+ shr $8, %r13w
321+ call z80_write_byte_noinc
322+ pop %r13
323+ pop %r14
324+ call z_inccycles
325+ call z80_write_byte_noinc
326+ ret
327+
328+ .global z80_write_word_lowfirst
329+z80_write_word_lowfirst:
330+ call z_inccycles
331+ push %r14
332+ push %r13
333+ call z80_write_byte_noinc
334+ pop %r13
335+ pop %r14
336+ add $1, %r14w
337+ shr $8, %r13w
338+ call z_inccycles
339+ call z80_write_byte_noinc
340+ ret
341+
342+ .global z80_io_read
343+z80_io_read:
344+ call z_inccycles_io
345+ /* genesis Z80 has no IO port hardware and always returns FF */
346+ mov $0xFF, %r13
347+ ret
348+
349+ .global z80_io_write
350+z80_io_write:
351+ call z_inccycles_io
352+ /* genesis Z80 has no IO port hardware and writes have no effect */
353+ ret
354+
355+ .global z80_retrans_stub
356+z80_retrans_stub:
357+ pop %r14
358+ call z80_save_context
359+ /* adjust for mov and call instructions */
360+ sub $11, %r14
361+ mov %r13d, %edi
362+ mov %r14, %rdx
363+ push %rsi
364+ call z80_retranslate_inst
365+ pop %rsi
366+ mov %rax, %r13
367+ call z80_load_context
368+ jmp *%r13
369+
370+ .global z80_native_addr
371+z80_native_addr:
372+ call z80_save_context
373+ push %rsi
374+ mov %rsi, %rdi
375+ movzx %r13w, %esi
376+ call z80_get_native_address_trans
377+ mov %rax, %r13
378+ pop %rsi
379+ call z80_load_context
380+ ret
381+
382+z80_save_context_scratch:
383+ mov %r13w, 98(%rsi) /* scratch1 */
384+ mov %r14w, 100(%rsi) /* scratch2 */
385+
386+ .global z80_save_context
387+z80_save_context:
388+ mov %r9w, 8(%rsi) /* SP */
389+ mov %r15w, 16(%rsi) /* bank register */
390+ mov %bx, 18(%rsi) /* BC */
391+ mov %cx, 20(%rsi) /* DE */
392+ mov %ax, 22(%rsi) /* HL */
393+ mov %dx, 24(%rsi) /* IX */
394+ mov %r8w, 26(%rsi) /* IY */
395+ mov %r10b, 30(%rsi) /* A */
396+ mov %edi, 48(%rsi) /* target_cycle */
397+ mov %ebp, 52(%rsi) /* current_cycle */
398+ mov %r12, 72(%rsi) /* cartridge bank pointer */
399+ ret
400+
401+
402+z80_load_context_scratch:
403+ mov 98(%rsi), %r13w /* scratch1 */
404+ mov 100(%rsi), %r14w /* scratch2 */
405+
406+ .global z80_load_context
407+z80_load_context:
408+ mov 8(%rsi), %r9w /* SP */
409+ mov 16(%rsi), %r15w /* bank register */
410+ mov 18(%rsi), %bx /* BC */
411+ mov 20(%rsi), %cx /* DE */
412+ mov 22(%rsi), %ax /* HL */
413+ mov 24(%rsi), %dx /* IX */
414+ mov 26(%rsi), %r8w /* IY */
415+ mov 30(%rsi), %r10b /* A */
416+ mov 48(%rsi), %edi /* target_cycle */
417+ mov 52(%rsi), %ebp /* current_cycle */
418+ mov 64(%rsi), %r11 /* z80 RAM */
419+ mov 72(%rsi), %r12 /* cartridge bank pointer */
420+ ret
421+
422+ .global z80_run
423+z80_run:
424+ push %rbx
425+ push %rbp
426+ push %r12
427+ push %r13
428+ push %r14
429+ push %r15
430+ mov %rdi, %rsi
431+ call z80_load_context_scratch
432+ cmpq $0, 104(%rsi)
433+ je no_extra
434+ push 104(%rsi)
435+ movq $0, 104(%rsi)
436+no_extra:
437+ jmp *(%rsi)
438+
+537,
-0
1@@ -0,0 +1,537 @@
2+/*
3+ Copyright 2013 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#include "z80inst.h"
8+#include <stdlib.h>
9+#include <string.h>
10+#include <stdint.h>
11+#include <stdio.h>
12+#include <sys/stat.h>
13+#include <sys/types.h>
14+#include <errno.h>
15+#include <time.h>
16+
17+extern z80inst z80_tbl_a[256];
18+extern z80inst z80_tbl_extd[0xC0-0x40];
19+extern z80inst z80_tbl_bit[256];
20+extern z80inst z80_tbl_ix[256];
21+extern z80inst z80_tbl_iy[256];
22+extern z80inst z80_tbl_ix_bit[256];
23+extern z80inst z80_tbl_iy_bit[256];
24+extern char *z80_mnemonics[Z80_OTDR+1];
25+extern char * z80_regs[Z80_USE_IMMED];
26+#define PRE_IX 0xDD
27+#define PRE_IY 0xFD
28+#define LD_IR16 0x01
29+#define INC_R8 0x04
30+#define LD_IR8 0x06
31+#define LD_RR8 0x40
32+#define AND_R 0xA0
33+#define PUSH 0xC5
34+#define POP 0xC1
35+
36+uint8_t * ld_ir16(uint8_t * dst, uint8_t reg, uint16_t val)
37+{
38+ if (reg == Z80_IX) {
39+ *(dst++) = PRE_IX;
40+ return ld_ir16(dst, Z80_HL, val);
41+ } else if(reg == Z80_IY) {
42+ *(dst++) = PRE_IY;
43+ return ld_ir16(dst, Z80_HL, val);
44+ } else {
45+ *(dst++) = LD_IR16 | ((reg - Z80_BC) << 4);
46+ *(dst++) = val & 0xFF;
47+ *(dst++) = val >> 8;
48+ return dst;
49+ }
50+}
51+
52+uint8_t * ld_ir8(uint8_t * dst, uint8_t reg, uint8_t val)
53+{
54+ if (reg <= Z80_H) {
55+ reg = (reg - Z80_C) ^ 1;
56+ } else {
57+ reg = 0x7;
58+ }
59+ *(dst++) = LD_IR8 | (reg << 3);
60+ *(dst++) = val;
61+ return dst;
62+}
63+
64+uint8_t * ld_rr8(uint8_t * dst, uint8_t src, uint8_t dstr)
65+{
66+ if (src <= Z80_H) {
67+ src = (src - Z80_C) ^ 1;
68+ } else {
69+ src = 0x7;
70+ }
71+ if (dstr <= Z80_H) {
72+ dstr = (dstr - Z80_C) ^ 1;
73+ } else {
74+ dstr = 0x7;
75+ }
76+ *(dst++) = LD_RR8 | (dstr << 3) | src;
77+ return dst;
78+}
79+
80+uint8_t * ld_amem(uint8_t * dst, uint16_t address)
81+{
82+ *(dst++) = 0x32;
83+ *(dst++) = address & 0xFF;
84+ *(dst++) = address >> 8;
85+ return dst;
86+}
87+
88+uint8_t * ld_mema(uint8_t * dst, uint16_t address)
89+{
90+ *(dst++) = 0x3A;
91+ *(dst++) = address & 0xFF;
92+ *(dst++) = address >> 8;
93+ return dst;
94+}
95+
96+uint8_t * push(uint8_t * dst, uint8_t reg)
97+{
98+ if (reg == Z80_IX) {
99+ *(dst++) = PRE_IX;
100+ return push(dst, Z80_HL);
101+ } else if(reg == Z80_IY) {
102+ *(dst++) = PRE_IY;
103+ return push(dst, Z80_HL);
104+ } else {
105+ if (reg == Z80_AF) {
106+ reg--;
107+ }
108+ *(dst++) = PUSH | ((reg - Z80_BC) << 4);
109+ return dst;
110+ }
111+}
112+
113+uint8_t * pop(uint8_t * dst, uint8_t reg)
114+{
115+ if (reg == Z80_IX) {
116+ *(dst++) = PRE_IX;
117+ return pop(dst, Z80_HL);
118+ } else if(reg == Z80_IY) {
119+ *(dst++) = PRE_IY;
120+ return pop(dst, Z80_HL);
121+ } else {
122+ if (reg == Z80_AF) {
123+ reg--;
124+ }
125+ *(dst++) = POP | ((reg - Z80_BC) << 4);
126+ return dst;
127+ }
128+}
129+
130+uint8_t * and_r(uint8_t * dst, uint8_t reg)
131+{
132+ if (reg == Z80_IXH || reg == Z80_IXL) {
133+ *(dst++) = PRE_IX;
134+ return and_r(dst, reg - (Z80_IXL - Z80_L));
135+ } else if(reg == Z80_IYH || reg == Z80_IYL) {
136+ *(dst++) = PRE_IY;
137+ return and_r(dst, reg - (Z80_IYL - Z80_L));
138+ } else {
139+ if (reg == Z80_A) {
140+ reg = 7;
141+ } else {
142+ reg = (reg - Z80_C) ^ 1;
143+ }
144+ *(dst++) = AND_R | reg;
145+ return dst;
146+ }
147+}
148+
149+uint8_t * inc_r(uint8_t *dst, uint8_t reg)
150+{
151+ if (reg == Z80_IXH || reg == Z80_IXL) {
152+ *(dst++) = PRE_IX;
153+ return inc_r(dst, reg - (Z80_IXL - Z80_L));
154+ } else if(reg == Z80_IYH || reg == Z80_IYL) {
155+ *(dst++) = PRE_IY;
156+ return inc_r(dst, reg - (Z80_IYL - Z80_L));
157+ } else {
158+ *(dst++) = INC_R8 | reg << 3;
159+ return dst;
160+ }
161+}
162+
163+void mark_used8(uint8_t *reg_usage, uint16_t *reg_values, uint8_t reg, uint8_t init_value)
164+{
165+ reg_usage[reg] = 1;
166+ reg_values[reg] = init_value;
167+ uint8_t word_reg = z80_word_reg(reg);
168+ if (word_reg != Z80_UNUSED) {
169+ reg_usage[word_reg] = 1;
170+ reg_values[word_reg] = (reg_values[z80_high_reg(word_reg)] << 8) | (reg_values[z80_low_reg(word_reg)] & 0xFF);
171+ }
172+}
173+
174+uint8_t alloc_reg8(uint8_t *reg_usage, uint16_t *reg_values, uint8_t init_value)
175+{
176+ for (uint8_t reg = 0; reg < Z80_BC; reg++)
177+ {
178+ if (!reg_usage[reg]) {
179+ mark_used8(reg_usage, reg_values, reg, init_value);
180+ return reg;
181+ }
182+ }
183+ return Z80_UNUSED;
184+}
185+
186+void z80_gen_test(z80inst * inst, uint8_t *instbuf, uint8_t instlen)
187+{
188+ z80inst copy;
189+ uint16_t reg_values[Z80_UNUSED];
190+ uint8_t reg_usage[Z80_UNUSED];
191+ memset(reg_values, 0, sizeof(reg_values));
192+ memset(reg_usage, 0, sizeof(reg_usage));
193+ uint8_t addr_mode = inst->addr_mode & 0x1F;
194+ uint8_t word_sized = ((inst->reg != Z80_USE_IMMED && inst->reg != Z80_UNUSED && inst->reg >= Z80_BC) || (addr_mode == Z80_REG && inst->ea_reg >= Z80_BC)) ? 1 : 0;
195+
196+ if (inst->reg == Z80_USE_IMMED || addr_mode == Z80_IMMED || addr_mode == Z80_IMMED_INDIRECT
197+ || addr_mode == Z80_IX_DISPLACE || addr_mode == Z80_IY_DISPLACE)
198+ {
199+ memcpy(©, inst, sizeof(copy));
200+ inst = ©
201+ if ((inst->reg == Z80_USE_IMMED && inst->op != Z80_BIT && inst->op != Z80_RES && inst->op != Z80_SET)
202+ || (addr_mode == Z80_IMMED && inst->op != Z80_IM))
203+ {
204+ copy.immed = rand() % (word_sized ? 65536 : 256);
205+ }
206+ if (addr_mode == Z80_IX_DISPLACE || addr_mode == Z80_IY_DISPLACE) {
207+ copy.ea_reg = rand() % 256;
208+ }
209+ if (addr_mode == Z80_IMMED_INDIRECT) {
210+ copy.immed = 0x1000 + (rand() % 256 - 128);
211+ }
212+ }
213+ uint8_t is_mem = 0;
214+ uint16_t address;
215+ int16_t offset;
216+ switch(addr_mode)
217+ {
218+ case Z80_REG:
219+ reg_usage[inst->ea_reg] = 1;
220+ if (word_sized) {
221+ reg_values[inst->ea_reg] = rand() % 65536;
222+ reg_values[z80_high_reg(inst->ea_reg)] = reg_values[inst->ea_reg] >> 8;
223+ reg_usage[z80_high_reg(inst->ea_reg)] = 1;
224+ reg_values[z80_low_reg(inst->ea_reg)] = reg_values[inst->ea_reg] & 0xFF;
225+ reg_usage[z80_low_reg(inst->ea_reg)] = 1;
226+ } else {
227+ mark_used8(reg_usage, reg_values, inst->ea_reg, rand() % 256);
228+ }
229+ break;
230+ case Z80_REG_INDIRECT:
231+ is_mem = 1;
232+ reg_values[inst->ea_reg] = 0x1000 + (rand() % 256 - 128);
233+ reg_usage[inst->ea_reg] = 1;
234+ address = reg_values[inst->ea_reg];
235+ reg_usage[z80_high_reg(inst->ea_reg)] = 1;
236+ reg_values[z80_high_reg(inst->ea_reg)] = reg_values[inst->ea_reg] >> 8;
237+ reg_usage[z80_low_reg(inst->ea_reg)] = 1;
238+ reg_values[z80_low_reg(inst->ea_reg)] = reg_values[inst->ea_reg] & 0xFF;
239+ break;
240+ case Z80_IMMED_INDIRECT:
241+ is_mem = 1;
242+ address = inst->immed;
243+ break;
244+ case Z80_IX_DISPLACE:
245+ reg_values[Z80_IX] = 0x1000;
246+ reg_usage[Z80_IX] = 1;
247+ reg_values[Z80_IXH] = 0x10;
248+ reg_usage[Z80_IXH] = 1;
249+ reg_values[Z80_IXL] = 0;
250+ reg_usage[Z80_IXL] = 1;
251+ is_mem = 1;
252+ offset = inst->ea_reg;
253+ if (offset > 0x7F) {
254+ offset -= 256;
255+ }
256+ address = 0x1000 + offset;
257+ break;
258+ case Z80_IY_DISPLACE:
259+ reg_values[Z80_IY] = 0x1000;
260+ reg_usage[Z80_IY] = 1;
261+ reg_values[Z80_IYH] = 0x10;
262+ reg_usage[Z80_IYH] = 1;
263+ reg_values[Z80_IYL] = 0;
264+ reg_usage[Z80_IYL] = 1;
265+ is_mem = 1;
266+ offset = inst->ea_reg;
267+ if (offset > 0x7F) {
268+ offset -= 256;
269+ }
270+ address = 0x1000 + offset;
271+ break;
272+ }
273+ if (inst->reg != Z80_UNUSED && inst->reg != Z80_USE_IMMED) {
274+
275+ if (word_sized) {
276+ reg_values[inst->reg] = rand() % 65536;
277+ reg_usage[z80_high_reg(inst->reg)] = 1;
278+ reg_values[z80_high_reg(inst->reg)] = reg_values[inst->reg] >> 8;
279+ reg_usage[z80_low_reg(inst->reg)] = 1;
280+ reg_values[z80_low_reg(inst->reg)] = reg_values[inst->reg] & 0xFF;
281+ } else {
282+ if (!reg_usage[inst->reg]) {
283+ reg_values[inst->reg] = rand() % 255;
284+ uint8_t word_reg = z80_word_reg(inst->reg);
285+ if (word_reg != Z80_UNUSED) {
286+ reg_usage[word_reg] = 1;
287+ reg_values[word_reg] = (reg_values[z80_high_reg(word_reg)] << 8) | (reg_values[z80_low_reg(word_reg)] & 0xFF);
288+ }
289+ }
290+ }
291+ reg_usage[inst->reg] = 1;
292+ }
293+ uint8_t counter_reg = Z80_UNUSED;
294+ if (inst->op >= Z80_JP && inst->op <= Z80_JRCC) {
295+ counter_reg = alloc_reg8(reg_usage, reg_values, 0);
296+ }
297+ puts("--------------");
298+ for (uint8_t reg = 0; reg < Z80_UNUSED; reg++) {
299+ if (reg_values[reg]) {
300+ printf("%s: %X\n", z80_regs[reg], reg_values[reg]);
301+ }
302+ }
303+ char disbuf[80];
304+ z80_disasm(inst, disbuf, 0);
305+ puts(disbuf);
306+ char pathbuf[128];
307+ sprintf(pathbuf, "ztests/%s", z80_mnemonics[inst->op]);
308+ if (mkdir(pathbuf, 0777) != 0) {
309+ if (errno != EEXIST) {
310+ fprintf(stderr, "Failed to create directory %s\n", disbuf);
311+ exit(1);
312+ }
313+ }
314+ uint8_t prog[200];
315+ uint8_t *cur = prog;
316+ uint8_t mem_val;
317+ //disable interrupts
318+ *(cur++) = 0xF3;
319+ //setup SP
320+ cur = ld_ir16(cur, Z80_SP, 0x2000);
321+ for (int i = 0; i < 2; i ++) {
322+ //setup memory
323+ if (is_mem) {
324+ mem_val = rand() % 256;
325+ cur = ld_ir8(cur, Z80_A, mem_val);
326+ cur = ld_amem(cur, address);
327+ }
328+ //setup AF
329+ cur = ld_ir16(cur, Z80_BC, reg_values[Z80_A] << 8 | (i ? 0xFF : 0));
330+ cur = push(cur, Z80_BC);
331+ cur = pop(cur, Z80_AF);
332+
333+ //setup other regs
334+ for (uint8_t reg = Z80_BC; reg <= Z80_IY; reg++) {
335+ if (reg != Z80_AF && reg != Z80_SP && (inst->op != Z80_JP || addr_mode != Z80_REG_INDIRECT || inst->ea_reg != reg)) {
336+ if (i == 1 && (z80_high_reg(reg) == counter_reg || z80_low_reg(reg) == counter_reg)) {
337+ if (z80_high_reg(reg) == counter_reg) {
338+ if (reg_usage[z80_low_reg(reg)]) {
339+ cur = ld_ir8(cur, z80_low_reg(reg), reg_values[z80_low_reg(reg)]);
340+ }
341+ } else if (reg_usage[z80_high_reg(reg)]) {
342+ cur = ld_ir8(cur, z80_high_reg(reg), reg_values[z80_high_reg(reg)]);
343+ }
344+ } else {
345+ cur = ld_ir16(cur, reg, reg_values[reg]);
346+ }
347+ }
348+ }
349+
350+ if (inst->op == Z80_JP && addr_mode == Z80_REG_INDIRECT) {
351+ uint16_t address = cur - prog + (inst->ea_reg == Z80_HL ? 3 : 4) + instlen + 1 + i;
352+ cur = ld_ir16(cur, inst->ea_reg, address);
353+ }
354+
355+ //copy instruction
356+ if (instlen == 3) {
357+ memcpy(cur, instbuf, 2);
358+ cur += 2;
359+ } else {
360+ memcpy(cur, instbuf, instlen);
361+ cur += instlen;
362+ }
363+
364+ //immed/displacement byte(s)
365+ if (addr_mode == Z80_IX_DISPLACE || addr_mode == Z80_IY_DISPLACE) {
366+ *(cur++) = inst->ea_reg;
367+ } else if ((inst->op == Z80_JP || inst->op == Z80_JPCC) && addr_mode == Z80_IMMED) {
368+ uint16_t address = cur - prog + 3 + i; //2 for immed address, 1/2 for instruction(s) to skip
369+ *(cur++) = address;
370+ *(cur++) = address >> 8;
371+ } else if(inst->op == Z80_JR || inst->op == Z80_JRCC) {
372+ *(cur++) = 1 + i; //skip one or 2 instructions based on value of i
373+ } else if (addr_mode == Z80_IMMED & inst->op != Z80_IM) {
374+ *(cur++) = inst->immed & 0xFF;
375+ if (word_sized) {
376+ *(cur++) = inst->immed >> 8;
377+ }
378+ } else if (addr_mode == Z80_IMMED_INDIRECT) {
379+ *(cur++) = inst->immed & 0xFF;
380+ *(cur++) = inst->immed >> 8;
381+ }
382+ if (inst->reg == Z80_USE_IMMED && inst->op != Z80_BIT && inst->op != Z80_RES && inst->op != Z80_SET) {
383+ *(cur++) = inst->immed & 0xFF;
384+ }
385+ if (instlen == 3) {
386+ *(cur++) = instbuf[2];
387+ }
388+ if (inst->op >= Z80_JP && inst->op <= Z80_JRCC) {
389+ cur = inc_r(cur, counter_reg);
390+ if (i) {
391+ //inc twice on second iteration so we can differentiate the two
392+ cur = inc_r(cur, counter_reg);
393+ }
394+ }
395+ if (!i) {
396+ //Save AF from first run
397+ cur = push(cur, Z80_AF);
398+ if (is_mem) {
399+ //Save memory location from frist run
400+ cur = ld_mema(cur, address);
401+ cur = push(cur, Z80_AF);
402+ }
403+ } else {
404+ //Pop AF from first run for final result
405+ for (int reg = Z80_BC; reg <= Z80_IY; reg++) {
406+ if (reg != Z80_AF && !reg_usage[reg]) {
407+ cur = pop(cur, reg);
408+ cur = push(cur, Z80_AF);
409+ cur = ld_ir8(cur, Z80_A, 0xC7);
410+ cur = and_r(cur, z80_low_reg(reg));
411+ cur = ld_rr8(cur, Z80_A, z80_low_reg(reg));
412+ cur = pop(cur, Z80_AF);
413+ reg_usage[reg] = 1;
414+ reg_usage[z80_low_reg(reg)] = 1;
415+ break;
416+ }
417+ }
418+ if (is_mem) {
419+ //Pop memory location from frist run
420+ for (int reg = Z80_BC; reg <= Z80_IY; reg++) {
421+ if (reg != Z80_AF && !reg_usage[reg]) {
422+ cur = pop(cur, reg);
423+ cur = push(cur, Z80_AF);
424+ cur = ld_mema(cur, address);
425+ cur = ld_rr8(cur, Z80_A, z80_low_reg(reg));
426+ cur = pop(cur, Z80_AF);
427+ reg_usage[reg] = 1;
428+ reg_usage[z80_low_reg(reg)] = 1;
429+ break;
430+ }
431+ }
432+ }
433+ }
434+ }
435+
436+ for (char * cur = disbuf; *cur != 0; cur++) {
437+ if (*cur == ',' || *cur == ' ') {
438+ *cur = '_';
439+ }
440+ }
441+ //save memory result
442+ if (is_mem) {
443+ if (reg_usage[Z80_A]) {
444+ cur = push(cur, Z80_AF);
445+ }
446+ cur = ld_mema(cur, address);
447+ if (reg_usage[Z80_A]) {
448+ for (int reg = 0; reg < Z80_I; reg++) {
449+ if (!reg_usage[reg]) {
450+ cur = ld_rr8(cur, Z80_A, reg);
451+ break;
452+ }
453+ }
454+ cur = pop(cur, Z80_AF);
455+ }
456+ }
457+
458+ //halt
459+ *(cur++) = 0x76;
460+ sprintf(pathbuf + strlen(pathbuf), "/%s.bin", disbuf);
461+ FILE * progfile = fopen(pathbuf, "wb");
462+ fwrite(prog, 1, cur - prog, progfile);
463+ fclose(progfile);
464+}
465+
466+
467+uint8_t should_skip(z80inst * inst)
468+{
469+ return inst->op >= Z80_DJNZ || (inst->op >= Z80_LDI && inst->op <= Z80_CPDR) || inst->op == Z80_HALT
470+ || inst->op == Z80_RLD || inst->op == Z80_RRD || inst->op == Z80_NOP
471+ || inst->op == Z80_DI || inst->op == Z80_EI;
472+}
473+
474+void z80_gen_all()
475+{
476+ uint8_t inst[3];
477+ for (int op = 0; op < 256; op++) {
478+ inst[0] = op;
479+ if (op == 0xCB) {
480+ for (int subop = 0; subop < 256; subop++) {
481+ if (!should_skip(z80_tbl_bit + subop)) {
482+ inst[1] = subop;
483+ z80_gen_test(z80_tbl_bit + subop, inst, 2);
484+ }
485+ }
486+ } else if(op == 0xDD) {
487+ for (int ixop = 0; ixop < 256; ixop++) {
488+ inst[1] = ixop;
489+ if (ixop == 0xCB) {
490+ for (int subop = 0; subop < 256; subop++) {
491+ if (!should_skip(z80_tbl_ix_bit + subop)) {
492+ inst[2] = subop;
493+ z80_gen_test(z80_tbl_ix_bit + subop, inst, 3);
494+ }
495+ }
496+ } else {
497+ if (!should_skip(z80_tbl_ix + ixop)) {
498+ z80_gen_test(z80_tbl_ix + ixop, inst, 2);
499+ }
500+ }
501+ }
502+ } else if(op == 0xED) {
503+ for (int subop = 0; subop < sizeof(z80_tbl_extd)/sizeof(z80inst); subop++) {
504+ if (!should_skip(z80_tbl_extd + subop)) {
505+ inst[1] = subop + 0x40;
506+ z80_gen_test(z80_tbl_extd + subop, inst, 2);
507+ }
508+ }
509+ } else if(op == 0xFD) {
510+ for (int iyop = 0; iyop < 256; iyop++) {
511+ inst[1] = iyop;
512+ if (iyop == 0xCB) {
513+ for (int subop = 0; subop < 256; subop++) {
514+ if (!should_skip(z80_tbl_iy_bit + subop)) {
515+ inst[2] = subop;
516+ z80_gen_test(z80_tbl_iy_bit + subop, inst, 3);
517+ }
518+ }
519+ } else {
520+ if (!should_skip(z80_tbl_iy + iyop)) {
521+ z80_gen_test(z80_tbl_iy + iyop, inst, 2);
522+ }
523+ }
524+ }
525+ } else {
526+ if (!should_skip(z80_tbl_a + op)) {
527+ z80_gen_test(z80_tbl_a + op, inst, 1);
528+ }
529+ }
530+ }
531+}
532+
533+int main(int argc, char ** argv)
534+{
535+ srand(time(NULL));
536+ z80_gen_all();
537+ return 0;
538+}
+126,
-0
1@@ -0,0 +1,126 @@
2+/*
3+ Copyright 2013 Michael Pavone
4+ This file is part of BlastEm.
5+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
6+*/
7+#include "z80inst.h"
8+#include "z80_to_x86.h"
9+#include "mem.h"
10+#include "vdp.h"
11+#include <stdio.h>
12+#include <stdlib.h>
13+#include <stddef.h>
14+#include <stdarg.h>
15+
16+void fatal_error(char *format, ...)
17+{
18+ va_list args;
19+ va_start(args, format);
20+ vfprintf(stderr, format, args);
21+ va_end(args);
22+ exit(1);
23+}
24+
25+uint8_t z80_ram[0x2000];
26+
27+uint8_t z80_unmapped_read(uint32_t location, void * context)
28+{
29+ return 0xFF;
30+}
31+
32+void * z80_unmapped_write(uint32_t location, void * context, uint8_t value)
33+{
34+ return context;
35+}
36+
37+const memmap_chunk z80_map[] = {
38+ { 0x0000, 0x4000, 0x1FFF, 0, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, z80_ram, NULL, NULL, NULL, NULL },
39+ { 0x4000, 0x10000, 0xFFFF, 0, 0, 0, NULL, NULL, NULL, z80_unmapped_read, z80_unmapped_write}
40+};
41+
42+const memmap_chunk port_map[] = {
43+ { 0x0000, 0x100, 0xFF, 0, 0, 0, NULL, NULL, NULL, z80_unmapped_read, z80_unmapped_write}
44+};
45+
46+void z80_next_int_pulse(z80_context * context)
47+{
48+ context->int_pulse_start = context->int_pulse_end = CYCLE_NEVER;
49+}
50+
51+int main(int argc, char ** argv)
52+{
53+ long filesize;
54+ uint8_t *filebuf;
55+ z80_options opts;
56+ z80_context *context;
57+ char *fname = NULL;
58+ uint8_t retranslate = 0;
59+ for (int i = 1; i < argc; i++)
60+ {
61+ if (argv[i][0] == '-') {
62+ switch(argv[i][1])
63+ {
64+ case 'r':
65+ retranslate = 1;
66+ break;
67+ default:
68+ fprintf(stderr, "Unrecognized switch -%c\n", argv[i][1]);
69+ exit(1);
70+ }
71+ } else if (!fname) {
72+ fname = argv[i];
73+ }
74+ }
75+ if (!fname) {
76+ fputs("usage: ztestrun zrom [cartrom]\n", stderr);
77+ exit(1);
78+ }
79+ FILE * f = fopen(fname, "rb");
80+ if (!f) {
81+ fprintf(stderr, "unable to open file %s\n", fname);
82+ exit(1);
83+ }
84+ fseek(f, 0, SEEK_END);
85+ filesize = ftell(f);
86+ fseek(f, 0, SEEK_SET);
87+ filesize = filesize < sizeof(z80_ram) ? filesize : sizeof(z80_ram);
88+ if (fread(z80_ram, 1, filesize, f) != filesize) {
89+ fprintf(stderr, "error reading %s\n",fname);
90+ exit(1);
91+ }
92+ fclose(f);
93+ init_z80_opts(&opts, z80_map, 2, port_map, 1, 1, 0xFF);
94+ context = init_z80_context(&opts);
95+ //Z80 RAM
96+ context->mem_pointers[0] = z80_ram;
97+ if (retranslate) {
98+ //run core long enough to translate code
99+ z80_run(context, 1);
100+ for (int i = 0; i < filesize; i++)
101+ {
102+ z80_handle_code_write(i, context);
103+ }
104+ z80_assert_reset(context, context->current_cycle);
105+ z80_clear_reset(context, context->current_cycle + 3);
106+ z80_adjust_cycles(context, context->current_cycle);
107+ }
108+ z80_run(context, 1000);
109+ printf("A: %X\nB: %X\nC: %X\nD: %X\nE: %X\nHL: %X\nIX: %X\nIY: %X\nSP: %X\n\nIM: %d, IFF1: %d, IFF2: %d\n",
110+ context->regs[Z80_A], context->regs[Z80_B], context->regs[Z80_C],
111+ context->regs[Z80_D], context->regs[Z80_E],
112+ (context->regs[Z80_H] << 8) | context->regs[Z80_L],
113+ (context->regs[Z80_IXH] << 8) | context->regs[Z80_IXL],
114+ (context->regs[Z80_IYH] << 8) | context->regs[Z80_IYL],
115+ context->sp, context->im, context->iff1, context->iff2);
116+ printf("Flags: SZYHXVNC\n"
117+ " %d%d%d%d%d%d%d%d\n",
118+ context->flags[ZF_S], context->flags[ZF_Z], context->flags[ZF_XY] >> 5 & 1, context->flags[ZF_H],
119+ context->flags[ZF_XY] >> 3 & 1, context->flags[ZF_PV], context->flags[ZF_N], context->flags[ZF_C]
120+ );
121+ puts("--Alternate Regs--");
122+ printf("A: %X\nB: %X\nC: %X\nD: %X\nE: %X\nHL: %X\n",
123+ context->alt_regs[Z80_A], context->alt_regs[Z80_B], context->alt_regs[Z80_C],
124+ context->alt_regs[Z80_D], context->alt_regs[Z80_E],
125+ (context->alt_regs[Z80_H] << 8) | context->alt_regs[Z80_L]);
126+ return 0;
127+}