/*****************************************************************************/ /* */ /* */ /* CP/M emulator version 0.1 */ /* */ /* written by Michael Bischoff (mbi@mo.math.nat.tu-bs.de) */ /* June-1994 */ /* */ /* This file is distributed under the GNU COPYRIGHT */ /* see COPYRIGHT.GNU for Copyright details */ /* */ /* */ /*****************************************************************************/ /* according to an email I got from Michael a few years back, the * restrict-to-2MHz stuff and speaker access is for some sort of * minimal (I think) TRS-80 support - just enough to get some TRS-80 * space-invaders-type game working, I think it was. :-) -rjm */ #include #include "cpmemu.h" #include #include #include #include #include #include #define HZ 13 /* frequency of screen updates */ /* Note: Signal handling is POSIX, not ANSI */ static unsigned char *cptr; static int OFF = 16; static int WIDTH = 2*80; int slowdown = 0; int tickercnt = 0; extern int hardware_access; static void tickerint(int arg) { int i, j; static int inited = 0; unsigned char *r, *w; if (z80mem[4] != 0x4f) { inited = 0; return; } if (!inited) { inited = 1; for (i = 0; i < 18; ++i) for (j = 0; j < 66; ++j) cptr[WIDTH*i+OFF+2*j-1] = 7; for (i = 0; i < 66; ++i) { cptr[2*i + OFF-2] = 0xb0; cptr[2*i + OFF-2+17*WIDTH] = 0x83; } for (i = 1; i < 17; ++i) { cptr[WIDTH*i + OFF-2] = 0xff; cptr[WIDTH*i + OFF-2+2*65] = 0xff; } } r = z80mem + 0xcc00; w = cptr + OFF + WIDTH; for (i = 0; i < 16; ++i) { for (j = 0; j < 64; ++j) { *w = *r++; w += 2; } w += 2*OFF; } #if HZ == 1 alarm(1); #endif } static int childpid; static void kill_child(void) { kill(childpid, SIGTERM); } void lowlevel_init(void) { struct sigaction sa; int memfd; /* get access to sound port */ cptr = NULL; hardware_access = 0; /* no access to speaker port */ return; /* install signal handler */ sa.sa_handler = tickerint; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sigaction(SIGALRM, &sa, NULL); /* make video memory accessible */ memfd = open("/dev/mem", O_RDWR); if (memfd > 0) cptr = mmap((void *)0, (size_t) 2048, PROT_READ|PROT_WRITE, MAP_SHARED, memfd, (off_t) 0xb8000); /* printf("fd=%d, ptr=%p\n", memfd, cptr); */ { char *s; if (!(s = getenv("COLUMNS")) || !(WIDTH = 2 * atoi(s))) WIDTH = 160; OFF = (WIDTH/2-64); /* horizontally center a 64x16 screen */ } /* benchmark */ { int i, usecspercall; struct timeval tv1, tv2; struct timezone tz; gettimeofday(&tv1, &tz); for (i = 0; i < 100; ++i) gettimeofday(&tv2, &tz); usecspercall = ((tv2.tv_usec - tv1.tv_usec) + 1000000 * (tv2.tv_sec-tv1.tv_sec)) / 100; if (usecspercall < 3 || usecspercall > 1000000) printf("Time for gettimeofday() cannot be determined\n"); else { /* tune down to 2 MHz Z80 */ slowdown = usecspercall / 4; tickercnt = 70 / usecspercall; /* 10 KHz interrupt */ printf("Time for gettimeofday() is %d us\n", usecspercall); printf("INT performed every %d times\n", tickercnt); } } #if HZ == 1 alarm(1); #else { pid_t galpid; galpid = getpid(); if (!(childpid = fork())) { int usecs = 1000000 / HZ; do { usleep(usecs); } while (!kill(galpid, SIGALRM)); } else atexit(kill_child); } #endif }