struct / union in initializer, RFE #901.
[sdcc.git] / sdcc-extra / emu / rrgb / main.c
bloba67201123bb1c8386f79af306730408ecc257dc1
1 /* rrgb, a rough and ready game boy emulator
2 * Copyright (C) 1994 Ian Collier. rrgb changes (c) 1998 Michael Hope
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 #include <math.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <signal.h>
24 #include <sys/time.h>
25 #if !defined(__sun__) && !defined(__APPLE__)
26 #include <getopt.h>
27 #endif
28 #include <sys/socket.h>
29 #include <sys/types.h>
30 #include <netinet/in.h>
31 #include <unistd.h>
32 #include "csock.h"
33 #include "z80.h"
34 #include "disgb.h"
35 #include "debugger.h"
37 #define ALLOW_WRITE 1
39 #ifdef SEG
40 unsigned char *segments[NUM_SEGS];
41 #endif
42 unsigned char mem[65536];
43 unsigned long tstates=0;
44 char bank_file_name[50];
45 int last_bank;
46 int tsocket;
47 int flags;
49 int loadImage(char *imageName, int flags);
51 /** Names for the system traps. Set A to one of these and call RST 08
52 with parameteres in HL. Any return value will also be in HL.
54 enum {
55 /** Exit the emulator (normal exit). */
56 RST_08_EXIT_EMU,
57 /** Print the character in L to the screen. */
58 RST_08_PUTCHAR,
59 /** Returns the run time in 1/100s. */
60 RST_08_GET_CLOCK,
61 RST_08_PROFILE_ENTER,
62 RST_08_PROFILE_EXIT,
63 RST_08_PROFILE_ENTER_LEAF
66 enum {
67 CPU_SPEED = 4000000,
68 CPU_CLOCKS_PER_SECOND = 100
71 void usage(void)
73 printf("rrgb: Rough 'n Ready processor only Gameboy emulator.\n"
74 "\tM.Hope " __DATE__ "\n"
75 "Useage:\n"
76 "\trrgb [-i] [-t] [-p] [-m] [-d] [-s name.bin] image.gb\n"
77 "\t\t-p - Profile code.\n"
78 "\t\t-m - Load map file.\n"
79 "\t\t-d - Enter debugger before running.\n"
80 "\t\t-s - Use name.bin as a segment file.\n"
81 "\t\t-t - Open port 6808 for input.\n"
82 "\t\t-i - Enable 100Hz timer interrupts.\n"
83 "\t\t-k - Run for at most 20s.\n"
87 void exitEmu(void)
89 exit(0);
92 void handleRST08(struct sregs *pregs)
94 switch (*pregs->a) {
95 case RST_08_EXIT_EMU:
96 exitEmu();
97 break;
98 case RST_08_PUTCHAR:
99 putchar(*pregs->l);
100 fflush(stdout);
101 if (*pregs->l == '\n' || *pregs->l == '\r') {
102 fflush(stdout);
104 break;
105 case RST_08_GET_CLOCK: {
106 unsigned ticks = tstates / (CPU_SPEED/CPU_CLOCKS_PER_SECOND);
107 *pregs->e = (unsigned char)ticks;
108 *pregs->d = (unsigned char)(ticks >> 8);
109 break;
111 case RST_08_PROFILE_ENTER:
112 case RST_08_PROFILE_EXIT:
113 case RST_08_PROFILE_ENTER_LEAF:
114 break;
115 default:
116 printf("Unsupported RST 08 code %02Xh\n", *pregs->a);
120 int main(int argc,char **argv)
122 int i, c;
123 struct sockaddr_in sock;
124 socklen_t sock_len;
125 int hsocket = 0;
127 flags=0;
129 while ((c=getopt(argc, argv, "kpms:dti"))!=-1) {
130 switch (c) {
131 case 'p': {
132 flags|=DPROFILE;
133 break;
135 case 'm': {
136 flags|=DMAP;
137 break;
139 case 's': {
140 strcpy(bank_file_name, optarg);
141 break;
143 case 'd': {
144 flags|=DSTARTDEBUG;
145 break;
147 case 't': {
148 flags|=DSOCKETS;
149 break;
151 case 'i': {
152 flags|=DTIMERINT;
153 break;
155 case 'k': {
156 flags|=DLIMITEDRUN;
157 break;
159 default: {
160 usage();
161 return -1;
162 break;
167 #ifdef SEG
168 for (i=0; i< NUM_SEGS; i++) {
169 segments[i] = &mem[i*SEG_SIZE];
171 #endif
172 if (optind<argc) {
173 loadImage(argv[optind], flags);
175 else {
176 printf("%s:Error: No image file specified.\n",argv[0]);
177 return -2;
179 if (flags&DSOCKETS) {
180 /* Open up the socket connection before proceeding */
181 printf("Opening socket 6808...");
182 fflush(stdout);
184 hsocket = socket_init(6808);
185 if (hsocket<0) {
186 printf("Failed.\n");
187 return -2;
189 else {
190 printf("Done.\n");
191 printf("Waiting for connection...");
192 fflush(stdout);
194 sock_len=sizeof(struct sockaddr_in);
195 tsocket = accept( hsocket, (struct sockaddr *)&sock, &sock_len );
196 if (tsocket==-1) {
197 printf("Failed.\n");
198 return -1;
200 else {
201 printf("Done.\n");
206 mainloop(flags);
208 if (flags&DPROFILE)
209 profile();
210 if (flags&DSOCKETS) {
211 close(tsocket);
212 close(hsocket);
214 printf("\nrrgb: Total tstates: %lu.\n", tstates );
216 return 0;
220 int loadImage(char *imageName, int flags)
222 FILE *in;
223 char *dot;
224 char map_name[100];
226 if((in=fopen(imageName,"rb"))!=NULL) {
227 size_t got = fread( mem, 1, 32768, in );
228 if (ferror(in)) {
229 perror("Error while reading the rom image");
230 return -1;
232 fclose(in);
234 if (flags&DMAP) {
235 /* Try to find the map file */
236 areas = NULL;
237 sorted_globals = NULL;
239 if ((dot=strrchr( imageName, '.'))!=NULL) {
240 *dot = '\0';
241 strcpy( map_name, imageName );
242 strcat( map_name, ".map");
243 if (!parse_map( map_name, &areas )) {
244 sort_globals( &sorted_globals, areas );
246 *dot = '.';
248 if (sorted_globals==NULL) {
249 printf("Warning: no map file loaded.\n");
252 return 0;
254 else {
255 printf("Couldn't load image %s.\n", imageName);
256 return -1;
260 /* Print out the floating point number stored in HLDE */
261 /* Format: H = Sign|Exponent, LDE = Mantissa */
263 void printGBfloat(unsigned fhl, unsigned fde)
265 double a;
267 /* Get mantissa */
268 a = (65536.0 * (double)(fhl&0x0ff))+(double)fde;
270 /* Multiply by 2^exponent */
271 /* Seems to be normalised or something */
272 a*=pow(2.0,(double)((fhl>>8)&~0x080)-88.0);
274 /* Negative? */
275 if (fhl & 0x08000)
276 a = -a;
277 printf("%f", a);
280 /* Switch in bank /bank to segment /segment */
281 void switchBank( int segment, unsigned bank )
283 FILE *binFP;
285 if (last_bank==bank)
286 return;
288 #ifdef ALLOW_WRITE
289 if (last_bank!=-1) {
290 binFP = fopen( bank_file_name, "r+b" );
291 if (binFP) {
292 /* Commit the last block first */
293 if (fseek( binFP, last_bank*SEG_SIZE, SEEK_SET)==0) {
294 if (fwrite(segments[segment], 1, SEG_SIZE, binFP )<SEG_SIZE) {
295 printf("\nrrgb: Failed write of bank %u.\n", last_bank );
297 else
298 printf("\nrrgb: commited block %u.\n", last_bank );
300 fclose(binFP);
302 else {
303 printf("\nrrgb: Failed write of bank %u.\n", last_bank );
306 #endif
308 binFP = fopen( bank_file_name, "rb" );
309 if (binFP) {
310 if (fseek( binFP, bank*SEG_SIZE, SEEK_SET)==0) {
311 if (fread( segments[segment], 1, SEG_SIZE, binFP )<SEG_SIZE) {
312 printf("\nrrgb: Incomplete read in bank %u.\n", bank );
314 last_bank = bank;
316 /* printf("%02X %02X %02X %02X\n", segments[segment][0], segments[segment][1], segments[segment][2], segments[segment][3] );*/
318 else {
319 printf("\nrrgb: Unable to seek to bank %u.\n", bank );
321 fclose( binFP );
323 else
324 printf("\nrrgb: Warning: No block file open.\n");
327 /* Handle a RST 38 (system call) */
328 int handle_sys(int scall, int parameter)
330 char buffer[2];
331 switch (scall) {
332 case 0: {
333 /* Read in from telnet */
334 if (flags&DSOCKETS) {
335 return socket_get(tsocket);
337 return 0;
338 break;
340 case 1: {
341 /* Write to telnet */
342 if (flags&DSOCKETS) {
343 buffer[0]=(parameter&0x0ff);
344 return socket_write( tsocket, buffer, 1);
346 return -1;
348 case 2: {
349 /* Return !0 if data is available */
350 if (flags&DSOCKETS) {
351 return socket_poll( tsocket );
353 return -1;
356 return 0;