More programs
[virtual-nascom.git] / sdl-nascom.c
blob701ab6a54e0bb015185d61b409034a7bc6fee5b8
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_PITCH 16
50 #define FONT_H 15
51 #define FONT_W 8
53 static SDL_Surface *screen;
54 static struct font {
55 SDL_Surface *surf;
56 int w, h, h_pitch;
57 } nascom_font;
59 static unsigned framebuffer_generation;
61 static void RenderItem(struct font *font, int index, int x, int y)
63 SDL_Rect dest = { x, y, font->w, font->h };
64 SDL_Rect clip = { 0, index * font->h_pitch, font->w, font->h };
65 SDL_BlitSurface(font->surf, &clip, screen, &dest);
68 void RenderLetters(struct font *font, char *s, int x, int y)
70 for (; *s; ++s, x += font->w)
71 RenderItem(font, *s, x, y);
74 int mysetup(int argc, char **argv)
76 if (SDL_Init(SDL_INIT_VIDEO) < 0) {
77 fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError());
78 return 1;
82 atexit(SDL_Quit);
85 screen = SDL_SetVideoMode(48 * FONT_W, 16 * FONT_H, 8, SDL_SWSURFACE);
86 if (screen == NULL) {
87 fprintf(stderr, "Unable to set video: %s\n", SDL_GetError());
88 return 1;
91 /* Set the window caption */
92 SDL_WM_SetCaption("Nascom II", "Nascom II");
94 #if 0
95 /* Populate the palette */
96 SDL_Color colors[256];
98 colors[0].r = colors[0].g = colors[0].b = 0;
99 colors[255].r = colors[255].b = 0;
100 colors[255].g = 255;
102 /* Set palette */
103 if (!SDL_SetColors(screen, colors, 0, 256)) {
104 fprintf(stderr, "Unable to create framebuffer palette: %s\n",
105 SDL_GetError());
106 screen = 0; //XXX should free it
107 return 1;
109 #endif
111 /* Load font */
112 extern uint8_t nascom_font_raw[];
114 // Unsuccessful :-(
115 nascom_font.surf =
116 SDL_CreateRGBSurfaceFrom(
117 nascom_font_raw,
118 8 /* width */,
119 256*16 /* height */,
120 1 /* depth */,
121 1 /* pitch */,
122 0 /* Rmask */,
123 1 /* Gmask */,
124 0 /* Bmask */,
125 0 /* Amask */);
126 nascom_font.w = FONT_W;
127 nascom_font.h = FONT_H;
128 nascom_font.h_pitch = FONT_H_PITCH;
130 if (!nascom_font.surf) {
131 fprintf(stderr, "no font :-( \n");
132 return 1;
135 nascom_font.surf = SDL_DisplayFormat(nascom_font.surf);
137 return 0;
142 /* */
144 unsigned char keym[9] = {
145 0, /* ? ? ? Shift ? ? ? ? */
146 0, /* ?!TXF5BH ! = Up*/
147 0, /* ?!YZD6NJ ! = Left*/
148 0, /* ?!USE7MK ! = Down */
149 0, /* ?!IAW8,L ! = Right */
150 0, /* ??OQ39.; */
151 0, /* ?[P120/: */
152 0, /* ?]R C4VG */
153 0 /* ? ? CR - Newline BS */
156 unsigned char keyp = 0;
157 unsigned char port0;
159 static void
160 usage(void)
162 fprintf(stderr,
163 "Usage: %s {flags} {commands}\n"
164 " -m <file> use <file> as monitor (default is nassys3.nal)\n"
165 " -v verbose\n"
166 ,progname);
167 exit (1);
170 void load_nascom(const char *file)
172 FILE *f = fopen(file, "r");
173 int a, b1, b2, b3, b4, b5, b6, b7, b8;
174 int count = 0;
175 int ch;
177 if (!f) {
178 perror(file);
179 exit(1);
182 if (vflag)
183 printf("Loading %s", file);
185 for (; !feof(f) ;) {
186 if (fscanf(f, "%x %x %x %x %x %x %x %x %x",
187 &a, &b1, &b2, &b3, &b4, &b5, &b6, &b7, &b8) == 9) {
188 RAM(a) = b1;
189 RAM(a+1) = b2;
190 RAM(a+2) = b3;
191 RAM(a+3) = b4;
192 RAM(a+4) = b5;
193 RAM(a+5) = b6;
194 RAM(a+6) = b7;
195 RAM(a+7) = b8;
196 count += 8;
200 ch = fgetc(f);
201 while (ch != -1 && ch != '\n');
203 if (ch == -1)
204 break;
207 fclose(f);
208 if (vflag)
209 printf(". Successfully loaded %d bytes\n", count);
211 if (count == 2048) {
212 FILE *f;
213 f = fopen("blob", "w");
214 fwrite((const void *) ram, 1, 2048, f);
215 fclose(f);
219 static char * kbd_translation[] = {
220 /* 0 */ "xxzzzxxx",
221 /* 1 */ "xzTXF5BH",
222 /* 2 */ "xzYZD6NJ",
223 /* 3 */ "xzUSE7MK",
224 /* 4 */ "xzIAW8,L",
225 /* 5 */ "xzOQ39.;",
226 /* 6 */ "x[P120/'",
227 /* 7 */ "x]R C4VG",
228 /* 8 */ "xzxxx-\r\010"
231 int reset = 0;
233 void mainloop(void)
235 int i = -1, bit = 0;
236 unsigned last_generation = 0;
238 for (;;) {
239 SDL_Event event;
241 while (SDL_PollEvent(&event)) {
242 switch (event.type) {
243 case SDL_MOUSEMOTION:
244 /*printf("Mouse moved by %d,%d to (%d,%d)\n",
245 event.motion.xrel, event.motion.yrel,
246 event.motion.x, event.motion.y);*/
247 break;
248 case SDL_MOUSEBUTTONDOWN:
249 /*printf("Mouse button %d pressed at (%d,%d)\n",
250 event.button.button, event.button.x, event.button.y);*/
251 break;
252 case SDL_KEYDOWN:
253 case SDL_KEYUP:
254 if (event.key.keysym.sym == 27 && event.type == SDL_KEYDOWN) {
255 reset = 1;
256 break;
259 if (event.key.keysym.sym < 128) {
260 int ch = toupper(event.key.keysym.sym);
261 for (i = 0; i < 9; ++i)
262 for (bit = 0; bit < 8; ++bit)
263 if (kbd_translation[i][7-bit] == ch) {
264 //printf(" -> %d/%d", i, bit);
265 goto found;
267 i = -1;
268 //printf("%d?\n", event.key.keysym.sym);
269 found:;
270 //printf("\n");
271 } else {
272 switch (event.key.keysym.sym) {
273 case SDLK_LCTRL: i = 0, bit = 3; break;
274 case SDLK_LSHIFT:
275 case SDLK_RSHIFT: i = 0, bit = 4; break;
276 case SDLK_RCTRL: i = 0, bit = 5; break;
277 case SDLK_UP: i = 1, bit = 6; break;
278 case SDLK_LEFT: i = 2, bit = 6; break;
279 case SDLK_DOWN: i = 3, bit = 6; break;
280 case SDLK_RIGHT: i = 4, bit = 6; break;
281 case SDLK_RMETA:
282 case SDLK_LMETA:
283 case SDLK_RALT:
284 case SDLK_LALT: i = 5, bit = 6; break;
285 case SDLK_KP_ENTER:i = 8, bit = 6; break;
286 case SDLK_END: {
287 /* Undocumented hack */
288 FILE *f;
289 f = fopen("screendump", "w");
290 fwrite((const void *) (ram+0x800), 1, 1024, f);
291 fclose(f);
292 if (vflag) printf("Screen dumped\n");
293 break;
295 default:
296 //printf("%d? ", event.key.keysym.sym);
297 //printf(" keysym %s\n", SDL_GetKeyName(event.key.keysym.sym));
302 if (i != -1) {
303 if (event.type == SDL_KEYDOWN)
304 keym[i] |= 1 << bit;
305 else
306 keym[i] &= ~(1 << bit);
308 break;
309 case SDL_QUIT:
310 //printf("Quit\n");
311 return;
312 default:
313 //printf("Unknown event: %d\n", event.type);
314 break;
318 /* Only update the screen if the framebuffer has been written
319 since last update */
320 if (last_generation != framebuffer_generation) {
321 int x, y;
322 unsigned p = 0x800 + 10;
323 last_generation = framebuffer_generation;
325 for (y = 1; y < 16; ++y, p += 64) {
326 for (x = 0; x < 48; ++x)
327 RenderItem(&nascom_font, RAM(p + x), x * FONT_W, y * FONT_H);
330 // Nascom is strange in that the last line is the first line!
331 for (x = 0; x < 48; ++x)
332 RenderItem(&nascom_font, RAM(p + x), x * FONT_W, 0);
334 SDL_UpdateRect(screen, 0, 0, screen->w, screen->h);
335 // SDL_Flip(screen); either seem to work
338 SDL_Delay(1000 / 30); // 30 fps
342 int sim_delay()
344 if (reset) {
345 reset = 0;
346 return 1;
349 SDL_Delay(2);
351 return 0;
354 void simulate(void *dummy)
356 simz80(pc, 1000, sim_delay);
359 int main(int argc, char **argv)
361 int c;
363 if (mysetup(argc, argv))
364 return 1;
366 monitor = "nassys3.nal";
367 progname = argv[0];
370 #ifdef MMU
371 for (c=0; c<MEMSIZE/4; ++c) pagetable[c]=ram+(c<<12);
372 #endif
374 while ((c = getopt(argc, argv, "m:v")) != EOF)
375 switch (c) {
376 case 'm':
377 monitor = optarg;
378 break;
379 case 'v':
380 vflag = 1;
381 break;
382 case '?':
383 usage();
386 if (vflag)
387 puts("VirtualNascom, a Nascom 2 emulator version " VERSION "\n"
388 "Copyright 2000 Tommy Thorn. Based on\n"
389 "Yet Another Z80 Emulator version " YAZEVERSION
390 ", Copyright 1995,1998 Frank D. Cringle.\n"
391 "NasEmu comes with ABSOLUTELY NO WARRANTY; for details\n"
392 "see the file \"COPYING\" in the distribution directory.\n");
394 load_nascom(monitor);
395 load_nascom("basic.nal");
397 for (; optind < argc; optind++)
398 load_nascom(argv[optind]);
400 SDL_CreateThread((int (*)(void *))simulate, NULL);
401 mainloop();
402 exit(0);
404 fprintf(stderr,"HALT\n");
405 fprintf(stderr,"PC SP IR IX IY AF BC DE HL AF' BC' DE' HL'\n");
406 fprintf(stderr,"%04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x\n",
407 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);
410 void out(unsigned int port, unsigned char value)
412 unsigned int down_trans;
414 if (0) fprintf(stdout, "[%02x] <- %02x\n", port, value);
416 switch (port) {
417 case 0:
418 /* KBD */
419 down_trans = port0 & ~value;
420 port0 = value;
422 if ((1 & down_trans) && keyp < 9) keyp++;
423 if (2 & down_trans) keyp = 0;
424 break;
426 default: ;
430 int in(unsigned int port)
432 if (0) fprintf(stdout, "<- [%02x]\n", port);
434 switch (port) {
435 case 0:
436 /* KBD */
437 /* printf("[%d]", keyp); */
438 return ~keym[keyp];
439 case 2:
440 /* Status port on the UART */
441 return 0;
442 default:
443 return 0;
447 void slow_write(unsigned int a, unsigned char v)
449 if (INSCREEN(a)) {
450 unsigned int y = (a-0x800) / 64;
451 unsigned int x = (a-0x800) % 64;
452 /* fprintf(stdout, "putbyte %04x %02x '%c'\n", a, v, v); */
453 if (10 <= x && x < 58 && ' ' <= v) {
454 if (y == 15)
455 y = 0;
456 else
457 ++y;
459 //xputch(x-10, y, v);
460 //fprintf(stderr, "\033[%d;%dH%c", 1+y, 1+x-10, v);
461 framebuffer_generation++;
465 if (0x800 <= a && a <= 0xE000)
466 RAM(a) = v;