#include <stdio.h> #include <stdint.h> #include <string.h> #include <stdlib.h> #include <ctype.h> #ifndef FALSE #define FALSE (0!=0) #endif #ifndef TRUE #define TRUE (0==0) #endif int DEBUG = TRUE; static int exit_rc = EXIT_SUCCESS; typedef uint32_t UINT32; typedef int32_t SINT32; typedef uint16_t UINT16; typedef int16_t SINT16; typedef uint8_t UINT8; typedef int8_t SINT8; UINT8 memory[0x10000], *memory_DP = &memory[0xD000]; // Modify this header to suit your target... SINT32 res, A, B, D, C; UINT16 PC, X, Y, S, U, Z, DP, arg, ea, val; UINT8 E, F, I, N, H, V, CC, msn, lsn; static inline void checkDP(void) { // hook for specific roms eg starwars to assert that DP never points to I/O space! } #define JUMP continue // We use an alternative convention for flags in order to reduce the operations applied to them most frequently // reduce flags to the individual bits in CC #define simplify_flags() do { N = (((SINT8)N < 0)?1:0); \ V = (((SINT8)V < 0)?1:0); \ Z = ((Z == 0)?1:0); \ C = ((C != 0)?1:0); \ H = (((H & 0x10) != 0)?1:0); \ } while (0) // make individual bits from CC compatible with our optimised version of the flags #define restore_flags() do { N = (N ? 0x80:0); \ V = (V ? 0x80:0); \ Z = (Z ? 0 : 1); \ C = (C ? 0x100 : 0); \ H = (H ? 0x10 : 0); \ } while (0) // These must be procedures because the parameters may include ++ static inline void wr_mem(int addr, unsigned char value) { // This is where we pull out access to device space. // We may want to also mirror the values in the memory[] array for convenience memory[addr] = value; } static inline unsigned int rd_mem(int addr) { // This is where we pull out access to device space. // We may want to also mirror the values in the memory[] array for convenience return memory[addr&0xffff]&0xff; } void mon(char *s) { fflush(stdout); if (DEBUG) fprintf(stderr, "A=%02x B=%02x X=%04x Y=%04x S=%04x U=%04x CC=%02x DP=%02x E%cF%cH%cI%cC%cZ%cV%cN%c %s", A, B, X, Y, S, U, CC, (UINT8)(DP>>8), E+'0', F+'0', (((H & 0x10) != 0)?1:0)+'0', I+'0', (((C & 0x100) != 0)?1:0)+'0', ((Z != 0)?1:0)+'0', (((SINT8)V < 0)?1:0)+'0', (((SINT8)N < 0)?1:0)+'0', s); } int main (int argc, char **argv) { FILE *bin = fopen ("cputest.bin", "rb"); X = 0x8100; for (;;) { A = fgetc (bin); if (A == EOF) break; memory[X++] = A; } fclose(bin); PC = 0x8100; S = 0x4000; A = B = X = Y = U = 0; CC = E = F = H = I = C = Z = V = N = 0; DP = 0; memory_DP = memory; for (;;) { switch (PC) { #include "cputest.c" case 0xCD1E: /*PSTRING*/ // X points to string! LCD1E: if (X == 0x93A3) exit_rc = EXIT_SUCCESS; if (X == 0x9395) exit_rc = EXIT_FAILURE; { static char errmess[128]; int s = 0; for (;;) { int i = memory[X++]; if (i == 4) break; if (isprint (i)) { putchar (i); errmess[s++] = i; errmess[s] = '\0'; } else printf ("<%02x>", i); } // putchar (10); printf(" *******************************\n"); fflush(stdout); //if (strstr(errmess, "Failed Test:") != NULL) exit_rc = EXIT_FAILURE; } PC = memory[S++] << 8; PC |= memory[S++]; JUMP; case 0xCD03: /*WARMS*/ LCD03: exit(exit_rc); default: fprintf (stderr, "Unknown jump to %04x\n", PC); exit (1); } } }