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
27 - a bitmapped keyboard,
29 0000 - 07ff 2 KB ROM monitor,
30 0800 - 0bff 1 KB screen memory,
31 0c00 - 0fff 1 KB workspace
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
49 #define FONT_H_PITCH 16
53 static SDL_Surface
*screen
;
59 FILE *serial_out
, *serial_in
;
62 static unsigned framebuffer_generation
;
64 static void RenderItem(struct font
*font
, int index
, int x
, int y
)
66 SDL_Rect dest
= { x
, y
, font
->w
, font
->h
};
67 SDL_Rect clip
= { 0, index
* font
->h_pitch
, font
->w
, font
->h
};
68 SDL_BlitSurface(font
->surf
, &clip
, screen
, &dest
);
71 void RenderLetters(struct font
*font
, char *s
, int x
, int y
)
73 for (; *s
; ++s
, x
+= font
->w
)
74 RenderItem(font
, *s
, x
, y
);
77 int mysetup(int argc
, char **argv
)
79 if (SDL_Init(SDL_INIT_VIDEO
) < 0) {
80 fprintf(stderr
, "Unable to init SDL: %s\n", SDL_GetError());
88 screen
= SDL_SetVideoMode(48 * FONT_W
, 16 * FONT_H
, 8, SDL_SWSURFACE
);
90 fprintf(stderr
, "Unable to set video: %s\n", SDL_GetError());
94 /* Set the window caption */
95 SDL_WM_SetCaption("Nascom II", "Nascom II");
98 /* Populate the palette */
99 SDL_Color colors
[256];
101 colors
[0].r
= colors
[0].g
= colors
[0].b
= 0;
102 colors
[255].r
= colors
[255].b
= 0;
106 if (!SDL_SetColors(screen
, colors
, 0, 256)) {
107 fprintf(stderr
, "Unable to create framebuffer palette: %s\n",
109 screen
= 0; //XXX should free it
115 extern uint8_t nascom_font_raw
[];
119 SDL_CreateRGBSurfaceFrom(
129 nascom_font
.w
= FONT_W
;
130 nascom_font
.h
= FONT_H
;
131 nascom_font
.h_pitch
= FONT_H_PITCH
;
133 if (!nascom_font
.surf
) {
134 fprintf(stderr
, "no font :-( \n");
138 nascom_font
.surf
= SDL_DisplayFormat(nascom_font
.surf
);
147 unsigned char keym
[9] = {
148 0, /* ? ? ? Shift ? ? ? ? */
149 0, /* ?!TXF5BH ! = Up*/
150 0, /* ?!YZD6NJ ! = Left*/
151 0, /* ?!USE7MK ! = Down */
152 0, /* ?!IAW8,L ! = Right */
156 0 /* ? ? CR - Newline BS */
159 unsigned char keyp
= 0;
166 "Usage: %s {flags} {commands}\n"
167 " -m <file> use <file> as monitor (default is nassys3.nal)\n"
173 void load_nascom(const char *file
)
175 FILE *f
= fopen(file
, "r");
176 int a
, b1
, b2
, b3
, b4
, b5
, b6
, b7
, b8
;
186 printf("Loading %s", file
);
189 if (fscanf(f
, "%x %x %x %x %x %x %x %x %x",
190 &a
, &b1
, &b2
, &b3
, &b4
, &b5
, &b6
, &b7
, &b8
) == 9) {
204 while (ch
!= -1 && ch
!= '\n');
212 printf(". Successfully loaded %d bytes\n", count
);
216 f
= fopen("blob", "w");
217 fwrite((const void *) ram
, 1, 2048, f
);
222 static char * kbd_translation
[] = {
231 /* 8 */ "xzxxx-\r\010"
239 unsigned last_generation
= 0;
244 while (SDL_PollEvent(&event
)) {
245 switch (event
.type
) {
246 case SDL_MOUSEMOTION
:
247 /*printf("Mouse moved by %d,%d to (%d,%d)\n",
248 event.motion.xrel, event.motion.yrel,
249 event.motion.x, event.motion.y);*/
251 case SDL_MOUSEBUTTONDOWN
:
252 /*printf("Mouse button %d pressed at (%d,%d)\n",
253 event.button.button, event.button.x, event.button.y);*/
257 if (event
.key
.keysym
.sym
== '\\' && event
.type
== SDL_KEYDOWN
) {
262 if (event
.key
.keysym
.sym
== 27)
265 if (event
.key
.keysym
.sym
< 128) {
266 int ch
= toupper(event
.key
.keysym
.sym
);
267 for (i
= 0; i
< 9; ++i
)
268 for (bit
= 0; bit
< 8; ++bit
)
269 if (kbd_translation
[i
][7-bit
] == ch
) {
270 //printf(" -> %d/%d", i, bit);
274 //printf("%d?\n", event.key.keysym.sym);
278 switch (event
.key
.keysym
.sym
) {
279 case SDLK_LCTRL
: i
= 0, bit
= 3; break;
281 case SDLK_RSHIFT
: i
= 0, bit
= 4; break;
282 case SDLK_RCTRL
: i
= 0, bit
= 5; break;
283 case SDLK_UP
: i
= 1, bit
= 6; break;
284 case SDLK_LEFT
: i
= 2, bit
= 6; break;
285 case SDLK_DOWN
: i
= 3, bit
= 6; break;
286 case SDLK_RIGHT
: i
= 4, bit
= 6; break;
290 case SDLK_LALT
: i
= 5, bit
= 6; break;
291 case SDLK_KP_ENTER
:i
= 8, bit
= 6; break;
293 /* Undocumented hack */
295 f
= fopen("screendump", "w");
296 fwrite((const void *) (ram
+0x800), 1, 1024, f
);
298 if (vflag
) printf("Screen dumped\n");
302 //printf("%d? ", event.key.keysym.sym);
303 //printf(" keysym %s\n", SDL_GetKeyName(event.key.keysym.sym));
309 if (event
.type
== SDL_KEYDOWN
)
312 keym
[i
] &= ~(1 << bit
);
319 //printf("Unknown event: %d\n", event.type);
324 /* Only update the screen if the framebuffer has been written
326 if (last_generation
!= framebuffer_generation
) {
328 unsigned p
= 0x800 + 10;
329 last_generation
= framebuffer_generation
;
331 for (y
= 1; y
< 16; ++y
, p
+= 64) {
332 for (x
= 0; x
< 48; ++x
)
333 RenderItem(&nascom_font
, RAM(p
+ x
), x
* FONT_W
, y
* FONT_H
);
336 // Nascom is strange in that the last line is the first line!
337 for (x
= 0; x
< 48; ++x
)
338 RenderItem(&nascom_font
, RAM(p
+ x
), x
* FONT_W
, 0);
340 SDL_UpdateRect(screen
, 0, 0, screen
->w
, screen
->h
);
341 // SDL_Flip(screen); either seem to work
344 SDL_Delay(1000 / 30); // 30 fps
360 void simulate(void *dummy
)
362 simz80(pc
, 1000, sim_delay
);
365 int main(int argc
, char **argv
)
369 serial_out
= fopen("serialout.txt", "w+");
374 if (mysetup(argc
, argv
))
377 monitor
= "nassys3.nal";
382 for (c
=0; c
<MEMSIZE
/4; ++c
) pagetable
[c
]=ram
+(c
<<12);
385 while ((c
= getopt(argc
, argv
, "i:m:v")) != EOF
)
388 serial_in
= fopen(optarg
, "r");
389 printf("serial input %s -> %p\n", optarg
, serial_in
);
402 puts("VirtualNascom, a Nascom 2 emulator version " VERSION
"\n"
403 "Copyright 2000,2009 Tommy Thorn.\n"
404 "Uses software from \n"
405 "Yet Another Z80 Emulator version " YAZEVERSION
406 ", Copyright 1995,1998 Frank D. Cringle.\n"
407 "VirtualNascom comes with ABSOLUTELY NO WARRANTY; for details\n"
408 "see the file \"COPYING\" in the distribution directory.\n");
410 load_nascom(monitor
);
411 load_nascom("basic.nal");
413 for (; optind
< argc
; optind
++)
414 load_nascom(argv
[optind
]);
416 SDL_CreateThread((int (*)(void *))simulate
, NULL
);
420 fprintf(stderr
,"HALT\n");
421 fprintf(stderr
,"PC SP IR IX IY AF BC DE HL AF' BC' DE' HL'\n");
422 fprintf(stderr
,"%04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x\n",
423 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
);
427 * 1.7 Input/output port addressing
430 * P0 7 Not available 7 Unused
431 * 6 Not used 6 Keyboard S6
432 * 5 Unused 5 Keyboard S3
433 * 4 Tape drive LED 4 Keyboard S5
434 * 3 Single step 3 Keyboard S4
435 * 2 Unused 2 Keyboard S0
436 * 1 Reset keyb'd count 1 Keyboard S2
437 * 0 Clock keyb'd count 0 Keyboard S1
440 #define P0_OUT_TAPE_DRIVE_LED 16
441 #define P0_OUT_SINGLE_STEP 8
442 #define P0_OUT_KEYBOARD_RESET 2
443 #define P0_OUT_KEYBOARD_CLOCK 1
446 * P1 0 - 7 Data to UART 0 - 7 Data from UART
447 * (Serial port) (Serial port)
449 * P2 0 - 7 Not assigned 7 Data received from UART
459 #define UART_DATA_READY 128
460 #define UART_TBR_EMPTY 64
461 #define UART_F_ERROR 8
462 #define UART_P_ERROR 4
463 #define UART_O_ERROR 2
466 * P3 Not assigned Not assigned
468 * P4 PIO port A data input and output
470 * P5 PIO port B data input and output
472 * P6 PIO port A control
474 * P7 PIO port B control
477 void out(unsigned int port
, unsigned char value
)
479 unsigned int down_trans
;
481 if (0) fprintf(stdout
, "[%02x] <- %02x\n", port
, value
);
486 down_trans
= port0
& ~value
;
489 if ((down_trans
& P0_OUT_KEYBOARD_CLOCK
) && keyp
< 9)
491 if (down_trans
& P0_OUT_KEYBOARD_RESET
)
494 if (tape_led
!= !!(value
& P0_OUT_TAPE_DRIVE_LED
))
495 fprintf(stderr
, "Tape LED = %d\n", !!(value
& P0_OUT_TAPE_DRIVE_LED
));
496 tape_led
= !!(value
& P0_OUT_TAPE_DRIVE_LED
);
500 fputc(value
, serial_out
);
504 fprintf(stdout
, "OUT [%02x] <- %02x\n", port
, value
);
508 int in(unsigned int port
)
510 if (0) fprintf(stdout
, "<- [%02x]\n", port
);
515 /* printf("[%d]", keyp); */
518 if (tape_led
&& serial_in
&& !feof(serial_in
))
519 return fgetc(serial_in
);
523 /* Status port on the UART */
524 return UART_TBR_EMPTY
|
525 (tape_led
&& serial_in
&& !feof(serial_in
) ?
526 UART_DATA_READY
: 0);
528 fprintf(stdout
, "IN <- [%02x]\n", port
);
533 void slow_write(unsigned int a
, unsigned char v
)
536 unsigned int y
= (a
-0x800) / 64;
537 unsigned int x
= (a
-0x800) % 64;
538 /* fprintf(stdout, "putbyte %04x %02x '%c'\n", a, v, v); */
539 if (10 <= x
&& x
< 58 && ' ' <= v
) {
545 //xputch(x-10, y, v);
546 //fprintf(stderr, "\033[%d;%dH%c", 1+y, 1+x-10, v);
547 framebuffer_generation
++;
551 if (0x800 <= a
&& a
<= 0xE000)