First working SDL version with lots of keyboard improvements
[virtual-nascom.git] / sdl-nascom.c
blob179c860ba64ac95b5b5d6b340a7b68aad4116e5a
1 /* VirtualNascom, a Nascom II emulator.
3 Copyright (C) 2000,2009 Tommy Thorn
5 Z80 emulator portition Copyright (C) 1995,1998 Frank D. Cringle.
7 NasEmu is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA.
23 A Nascom consists of:
25 - a Z80 CPU,
26 - an UART,
27 - a bitmapped keyboard,
28 - memory:
29 0000 - 07ff 2 KB ROM monitor,
30 0800 - 0bff 1 KB screen memory,
31 0c00 - 0fff 1 KB workspace
32 1000 - dfff memory
33 e000 - ffff 8 KB of MS Basic
35 With the Z80 emulator in place the first thing to get working is the
36 screen memory. The "correct" way to simulate screen memory is to
37 trap upon writes, but that would be slow. We do it any just to get
38 started.
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <getopt.h>
44 #include <ctype.h>
45 #include "simz80.h"
46 #include "nascom.h"
47 #include <SDL.h>
49 #define FONT_H 16
50 #define FONT_W 8
52 static SDL_Surface *screen;
53 static struct font {
54 SDL_Surface *surf;
55 int w, h;
56 } nascom_font;
58 static unsigned framebuffer_generation;
60 static void RenderItem(struct font *font, int index, int x, int y)
62 SDL_Rect dest = { x, y, font->w, font->h };
63 SDL_Rect clip = { 0, index * font->h, font->w, font->h };
64 SDL_BlitSurface(font->surf, &clip, screen, &dest);
67 void RenderLetters(struct font *font, char *s, int x, int y)
69 for (; *s; ++s, x += font->w)
70 RenderItem(font, *s, x, y);
73 int mysetup(int argc, char **argv)
75 if (SDL_Init(SDL_INIT_VIDEO) < 0) {
76 fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError());
77 return 1;
81 atexit(SDL_Quit);
84 screen = SDL_SetVideoMode(48 * FONT_W, 16 * FONT_H, 8, SDL_SWSURFACE);
85 if (screen == NULL) {
86 fprintf(stderr, "Unable to set video: %s\n", SDL_GetError());
87 return 1;
90 /* Set the window caption */
91 SDL_WM_SetCaption("Nascom II", "Nascom II");
93 #if 0
94 /* Populate the palette */
95 SDL_Color colors[256];
97 colors[0].r = colors[0].g = colors[0].b = 0;
98 colors[255].r = colors[255].b = 0;
99 colors[255].g = 255;
101 /* Set palette */
102 if (!SDL_SetColors(screen, colors, 0, 256)) {
103 fprintf(stderr, "Unable to create framebuffer palette: %s\n",
104 SDL_GetError());
105 screen = 0; //XXX should free it
106 return 1;
108 #endif
110 /* Load font */
111 extern uint8_t nascom_font_raw[];
113 // Unsuccessful :-(
114 nascom_font.surf =
115 SDL_CreateRGBSurfaceFrom(
116 nascom_font_raw,
117 8 /* width */,
118 256*16 /* height */,
119 1 /* depth */,
120 1 /* pitch */,
121 0 /* Rmask */,
122 1 /* Gmask */,
123 0 /* Bmask */,
124 0 /* Amask */);
125 nascom_font.w = FONT_W;
126 nascom_font.h = FONT_H;
128 if (!nascom_font.surf) {
129 fprintf(stderr, "no font :-( \n");
130 return 1;
133 nascom_font.surf = SDL_DisplayFormat(nascom_font.surf);
135 return 0;
140 /* */
142 unsigned char keym[9] = {
143 0, /* ? ? ? Shift ? ? ? ? */
144 0, /* ?!TXF5BH ! = Up*/
145 0, /* ?!YZD6NJ ! = Left*/
146 0, /* ?!USE7MK ! = Down */
147 0, /* ?!IAW8,L ! = Right */
148 0, /* ??OQ39.; */
149 0, /* ?[P120/: */
150 0, /* ?]R C4VG */
151 0 /* ? ? CR - Newline BS */
154 unsigned char keyp = 0;
155 unsigned char port0;
157 static void
158 usage(void)
160 fprintf(stderr,
161 "Usage: %s {flags} {commands}\n"
162 " -m <file> use <file> as monitor (default is nassys3.nal)\n"
163 " -v verbose\n"
164 ,progname);
165 exit (1);
168 void load_nascom(const char *file)
170 FILE *f = fopen(file, "r");
171 int a, b1, b2, b3, b4, b5, b6, b7, b8;
172 int count = 0;
173 int ch;
175 if (!f) {
176 perror(file);
177 exit(1);
180 if (vflag = 1)
181 printf("Loading %s", file);
183 for (; !feof(f) ;) {
184 if (fscanf(f, "%x %x %x %x %x %x %x %x %x",
185 &a, &b1, &b2, &b3, &b4, &b5, &b6, &b7, &b8) == 9) {
186 RAM(a) = b1;
187 RAM(a+1) = b2;
188 RAM(a+2) = b3;
189 RAM(a+3) = b4;
190 RAM(a+4) = b5;
191 RAM(a+5) = b6;
192 RAM(a+6) = b7;
193 RAM(a+7) = b8;
194 count += 8;
198 ch = fgetc(f);
199 while (ch != -1 && ch != '\n');
201 if (ch == -1)
202 break;
205 fclose(f);
206 if (vflag)
207 printf(". Successfully loaded %d bytes\n", count);
209 if (count == 2048) {
210 FILE *f;
211 f = fopen("blob", "w");
212 fwrite((const void *) ram, 1, 2048, f);
213 fclose(f);
217 static char * kbd_translation[] = {
218 /* 0 */ "xxzzzxxx",
219 /* 1 */ "xzTXF5BH",
220 /* 2 */ "xzYZD6NJ",
221 /* 3 */ "xzUSE7MK",
222 /* 4 */ "xzIAW8,L",
223 /* 5 */ "xzOQ39.;",
224 /* 6 */ "x[P120/'",
225 /* 7 */ "x]R C4VG",
226 /* 8 */ "xzxxx-\r\010"
229 int reset = 0;
231 void mainloop(void)
233 int i = -1, bit = 0;
234 unsigned last_generation = 0;
236 for (;;) {
237 SDL_Event event;
239 while (SDL_PollEvent(&event)) {
240 switch (event.type) {
241 case SDL_MOUSEMOTION:
242 /*printf("Mouse moved by %d,%d to (%d,%d)\n",
243 event.motion.xrel, event.motion.yrel,
244 event.motion.x, event.motion.y);*/
245 break;
246 case SDL_MOUSEBUTTONDOWN:
247 /*printf("Mouse button %d pressed at (%d,%d)\n",
248 event.button.button, event.button.x, event.button.y);*/
249 break;
250 case SDL_KEYDOWN:
251 case SDL_KEYUP:
252 if (event.key.keysym.sym == 27 && event.type == SDL_KEYDOWN) {
253 reset = 1;
254 break;
257 if (event.key.keysym.sym < 128) {
258 int ch = toupper(event.key.keysym.sym);
259 for (i = 0; i < 9; ++i)
260 for (bit = 0; bit < 8; ++bit)
261 if (kbd_translation[i][7-bit] == ch) {
262 //printf(" -> %d/%d", i, bit);
263 goto found;
265 i = -1;
266 printf("%d?\n", event.key.keysym.sym);
267 found:;
268 //printf("\n");
269 } else {
270 switch (event.key.keysym.sym) {
271 case SDLK_LCTRL: i = 0, bit = 3; break;
272 case SDLK_LSHIFT:
273 case SDLK_RSHIFT: i = 0, bit = 4; break;
274 case SDLK_RCTRL: i = 0, bit = 5; break;
275 case SDLK_UP: i = 1, bit = 6; break;
276 case SDLK_LEFT: i = 2, bit = 6; break;
277 case SDLK_DOWN: i = 3, bit = 6; break;
278 case SDLK_RIGHT: i = 4, bit = 6; break;
279 case SDLK_RMETA:
280 case SDLK_LMETA:
281 case SDLK_RALT:
282 case SDLK_LALT: i = 5, bit = 6; break;
283 case SDLK_KP_ENTER:i = 8, bit = 6; break;
284 case SDLK_END: {
285 /* Undocumented hack */
286 FILE *f;
287 f = fopen("screendump", "w");
288 fwrite((const void *) (ram+0x800), 1, 1024, f);
289 fclose(f);
290 if (vflag) printf("Screen dumped\n");
291 break;
293 default:
294 printf("%d? ", event.key.keysym.sym);
295 printf(" keysym %s\n", SDL_GetKeyName(event.key.keysym.sym));
299 if (i != -1) {
300 if (event.type == SDL_KEYDOWN)
301 keym[i] |= 1 << bit;
302 else
303 keym[i] &= ~(1 << bit);
305 break;
306 case SDL_QUIT:
307 printf("Quit\n");
308 return;
309 default:
310 printf("Unknown event: %d\n", event.type);
311 break;
315 /* Only update the screen if the framebuffer has been written
316 since last update */
317 if (last_generation != framebuffer_generation) {
318 int x, y;
319 unsigned p = 0x800 + 10;
320 last_generation = framebuffer_generation;
322 for (y = 1; y < 16; ++y, p += 64) {
323 for (x = 0; x < 48; ++x)
324 RenderItem(&nascom_font, RAM(p + x), x * FONT_W, y * FONT_H);
327 // Nascom is strange in that the last line is the first line!
328 for (x = 0; x < 48; ++x)
329 RenderItem(&nascom_font, RAM(p + x), x * FONT_W, 0);
331 SDL_UpdateRect(screen, 0, 0, screen->w, screen->h);
332 // SDL_Flip(screen); either seem to work
335 SDL_Delay(1000 / 30); // 30 fps
339 int sim_delay()
341 if (reset) {
342 reset = 0;
343 return 1;
346 SDL_Delay(2);
348 return 0;
351 void simulate(void *dummy)
353 simz80(pc, 1000, sim_delay);
356 int main(int argc, char **argv)
358 int c;
360 if (mysetup(argc, argv))
361 return 1;
363 monitor = "nassys3.nal";
364 progname = argv[0];
367 #ifdef MMU
368 for (c=0; c<MEMSIZE/4; ++c) pagetable[c]=ram+(c<<12);
369 #endif
371 while ((c = getopt(argc, argv, "m:v")) != EOF)
372 switch (c) {
373 case 'm':
374 monitor = optarg;
375 break;
376 case 'v':
377 vflag = 1;
378 break;
379 case '?':
380 usage();
383 if (vflag)
384 puts("VirtualNascom, a Nascom 2 emulator version " VERSION "\n"
385 "Copyright 2000 Tommy Thorn. Based on\n"
386 "Yet Another Z80 Emulator version " YAZEVERSION
387 ", Copyright 1995,1998 Frank D. Cringle.\n"
388 "NasEmu comes with ABSOLUTELY NO WARRANTY; for details\n"
389 "see the file \"COPYING\" in the distribution directory.\n");
391 load_nascom(monitor);
392 load_nascom("basic.nal");
394 for (; optind < argc; optind++)
395 load_nascom(argv[optind]);
397 SDL_CreateThread((int (*)(void *))simulate, NULL);
398 mainloop();
399 exit(0);
401 fprintf(stderr,"HALT\n");
402 fprintf(stderr,"PC SP IR IX IY AF BC DE HL AF' BC' DE' HL'\n");
403 fprintf(stderr,"%04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x\n",
404 pc,sp,ir,ix,iy,af[af_sel],regs[regs_sel].bc,regs[regs_sel].de,regs[regs_sel].hl,af[1-af_sel],regs[1-regs_sel].bc,regs[1-regs_sel].de,regs[1-regs_sel].hl);
407 void out(unsigned int port, unsigned char value)
409 unsigned int down_trans;
411 if (0) fprintf(stdout, "[%02x] <- %02x\n", port, value);
413 switch (port) {
414 case 0:
415 /* KBD */
416 down_trans = port0 & ~value;
417 port0 = value;
419 if ((1 & down_trans) && keyp < 9) keyp++;
420 if (2 & down_trans) keyp = 0;
421 break;
423 default: ;
427 int in(unsigned int port)
429 if (0) fprintf(stdout, "<- [%02x]\n", port);
431 switch (port) {
432 case 0:
433 /* KBD */
434 /* printf("[%d]", keyp); */
435 return ~keym[keyp];
436 case 2:
437 /* Status port on the UART */
438 return 0;
439 default:
440 return 0;
444 void slow_write(unsigned int a, unsigned char v)
446 if (INSCREEN(a)) {
447 unsigned int y = (a-0x800) / 64;
448 unsigned int x = (a-0x800) % 64;
449 /* fprintf(stdout, "putbyte %04x %02x '%c'\n", a, v, v); */
450 if (10 <= x && x < 58 && ' ' <= v) {
451 if (y == 15)
452 y = 0;
453 else
454 ++y;
456 //xputch(x-10, y, v);
457 //fprintf(stderr, "\033[%d;%dH%c", 1+y, 1+x-10, v);
458 framebuffer_generation++;
462 if (0x800 <= a && a <= 0xE000)
463 RAM(a) = v;