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
;
61 int serial_input_available
= 0;
63 static unsigned framebuffer_generation
;
65 static void RenderItem(struct font
*font
, int index
, int x
, int y
)
67 SDL_Rect dest
= { x
, y
, font
->w
, font
->h
};
68 SDL_Rect clip
= { 0, index
* font
->h_pitch
, font
->w
, font
->h
};
69 SDL_BlitSurface(font
->surf
, &clip
, screen
, &dest
);
72 void RenderLetters(struct font
*font
, char *s
, int x
, int y
)
74 for (; *s
; ++s
, x
+= font
->w
)
75 RenderItem(font
, *s
, x
, y
);
78 int mysetup(int argc
, char **argv
)
80 if (SDL_Init(SDL_INIT_VIDEO
) < 0) {
81 fprintf(stderr
, "Unable to init SDL: %s\n", SDL_GetError());
89 screen
= SDL_SetVideoMode(48 * FONT_W
, 16 * FONT_H
, 8, SDL_SWSURFACE
);
91 fprintf(stderr
, "Unable to set video: %s\n", SDL_GetError());
95 /* Set the window caption */
96 SDL_WM_SetCaption("Nascom II", "Nascom II");
99 /* Populate the palette */
100 SDL_Color colors
[256];
102 colors
[0].r
= colors
[0].g
= colors
[0].b
= 0;
103 colors
[255].r
= colors
[255].b
= 0;
107 if (!SDL_SetColors(screen
, colors
, 0, 256)) {
108 fprintf(stderr
, "Unable to create framebuffer palette: %s\n",
110 screen
= 0; //XXX should free it
116 extern uint8_t nascom_font_raw
[];
120 SDL_CreateRGBSurfaceFrom(
130 nascom_font
.w
= FONT_W
;
131 nascom_font
.h
= FONT_H
;
132 nascom_font
.h_pitch
= FONT_H_PITCH
;
134 if (!nascom_font
.surf
) {
135 fprintf(stderr
, "no font :-( \n");
139 nascom_font
.surf
= SDL_DisplayFormat(nascom_font
.surf
);
148 unsigned char keym
[9] = {
149 0, /* ? ? ? Shift ? ? ? ? */
150 0, /* ?!TXF5BH ! = Up*/
151 0, /* ?!YZD6NJ ! = Left*/
152 0, /* ?!USE7MK ! = Down */
153 0, /* ?!IAW8,L ! = Right */
157 0 /* ? ? CR - Newline BS */
160 unsigned char keyp
= 0;
167 "Usage: %s {flags} {commands}\n"
168 " -m <file> use <file> as monitor (default is nassys3.nal)\n"
174 void load_nascom(const char *file
)
176 FILE *f
= fopen(file
, "r");
177 int a
, b1
, b2
, b3
, b4
, b5
, b6
, b7
, b8
;
187 printf("Loading %s", file
);
190 if (fscanf(f
, "%x %x %x %x %x %x %x %x %x",
191 &a
, &b1
, &b2
, &b3
, &b4
, &b5
, &b6
, &b7
, &b8
) == 9) {
205 while (ch
!= -1 && ch
!= '\n');
213 printf(". Successfully loaded %d bytes\n", count
);
217 f
= fopen("blob", "w");
218 fwrite((const void *) ram
, 1, 2048, f
);
223 static char * kbd_translation
[] = {
232 /* 8 */ "xzxxx-\r\010"
240 unsigned last_generation
= 0;
245 while (SDL_PollEvent(&event
)) {
246 switch (event
.type
) {
247 case SDL_MOUSEMOTION
:
248 /*printf("Mouse moved by %d,%d to (%d,%d)\n",
249 event.motion.xrel, event.motion.yrel,
250 event.motion.x, event.motion.y);*/
252 case SDL_MOUSEBUTTONDOWN
:
253 /*printf("Mouse button %d pressed at (%d,%d)\n",
254 event.button.button, event.button.x, event.button.y);*/
258 if (event
.key
.keysym
.sym
== '\\' && event
.type
== SDL_KEYDOWN
) {
263 if (event
.key
.keysym
.sym
== 27)
266 if (event
.key
.keysym
.sym
< 128) {
267 int ch
= toupper(event
.key
.keysym
.sym
);
268 for (i
= 0; i
< 9; ++i
)
269 for (bit
= 0; bit
< 8; ++bit
)
270 if (kbd_translation
[i
][7-bit
] == ch
) {
271 //printf(" -> %d/%d", i, bit);
275 //printf("%d?\n", event.key.keysym.sym);
279 switch (event
.key
.keysym
.sym
) {
280 case SDLK_LCTRL
: i
= 0, bit
= 3; break;
282 case SDLK_RSHIFT
: i
= 0, bit
= 4; break;
283 case SDLK_RCTRL
: i
= 0, bit
= 5; break;
284 case SDLK_UP
: i
= 1, bit
= 6; break;
285 case SDLK_LEFT
: i
= 2, bit
= 6; break;
286 case SDLK_DOWN
: i
= 3, bit
= 6; break;
287 case SDLK_RIGHT
: i
= 4, bit
= 6; break;
291 case SDLK_LALT
: i
= 5, bit
= 6; break;
292 case SDLK_KP_ENTER
:i
= 8, bit
= 6; break;
294 /* Undocumented hack */
296 f
= fopen("screendump", "w");
297 fwrite((const void *) (ram
+0x800), 1, 1024, f
);
299 if (vflag
) printf("Screen dumped\n");
303 //printf("%d? ", event.key.keysym.sym);
304 //printf(" keysym %s\n", SDL_GetKeyName(event.key.keysym.sym));
310 if (event
.type
== SDL_KEYDOWN
)
313 keym
[i
] &= ~(1 << bit
);
320 //printf("Unknown event: %d\n", event.type);
325 /* Only update the screen if the framebuffer has been written
327 if (last_generation
!= framebuffer_generation
) {
329 unsigned p
= 0x800 + 10;
330 last_generation
= framebuffer_generation
;
332 for (y
= 1; y
< 16; ++y
, p
+= 64) {
333 for (x
= 0; x
< 48; ++x
)
334 RenderItem(&nascom_font
, RAM(p
+ x
), x
* FONT_W
, y
* FONT_H
);
337 // Nascom is strange in that the last line is the first line!
338 for (x
= 0; x
< 48; ++x
)
339 RenderItem(&nascom_font
, RAM(p
+ x
), x
* FONT_W
, 0);
341 SDL_UpdateRect(screen
, 0, 0, screen
->w
, screen
->h
);
342 // SDL_Flip(screen); either seem to work
345 SDL_Delay(1000 / 30); // 30 fps
361 void simulate(void *dummy
)
363 simz80(pc
, 900, sim_delay
);
366 int main(int argc
, char **argv
)
370 serial_out
= fopen("serialout.txt", "w+");
375 if (mysetup(argc
, argv
))
378 monitor
= "nassys3.nal";
383 for (c
=0; c
<MEMSIZE
/4; ++c
) pagetable
[c
]=ram
+(c
<<12);
386 while ((c
= getopt(argc
, argv
, "i:m:v")) != EOF
)
389 serial_in
= fopen(optarg
, "r");
390 //printf("serial input %s -> %p\n", optarg, serial_in);
391 serial_input_available
= !feof(serial_in
);
404 puts("VirtualNascom, a Nascom 2 emulator version " VERSION
"\n"
405 "Copyright 2000,2009 Tommy Thorn.\n"
406 "Uses software from \n"
407 "Yet Another Z80 Emulator version " YAZEVERSION
408 ", Copyright 1995,1998 Frank D. Cringle.\n"
409 "VirtualNascom comes with ABSOLUTELY NO WARRANTY; for details\n"
410 "see the file \"COPYING\" in the distribution directory.\n");
412 load_nascom(monitor
);
413 load_nascom("basic.nal");
415 for (; optind
< argc
; optind
++)
416 load_nascom(argv
[optind
]);
418 SDL_CreateThread((int (*)(void *))simulate
, NULL
);
422 fprintf(stderr
,"HALT\n");
423 fprintf(stderr
,"PC SP IR IX IY AF BC DE HL AF' BC' DE' HL'\n");
424 fprintf(stderr
,"%04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x\n",
425 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
);
429 * 1.7 Input/output port addressing
432 * P0 7 Not available 7 Unused
433 * 6 Not used 6 Keyboard S6
434 * 5 Unused 5 Keyboard S3
435 * 4 Tape drive LED 4 Keyboard S5
436 * 3 Single step 3 Keyboard S4
437 * 2 Unused 2 Keyboard S0
438 * 1 Reset keyb'd count 1 Keyboard S2
439 * 0 Clock keyb'd count 0 Keyboard S1
442 #define P0_OUT_TAPE_DRIVE_LED 16
443 #define P0_OUT_SINGLE_STEP 8
444 #define P0_OUT_KEYBOARD_RESET 2
445 #define P0_OUT_KEYBOARD_CLOCK 1
448 * P1 0 - 7 Data to UART 0 - 7 Data from UART
449 * (Serial port) (Serial port)
451 * P2 0 - 7 Not assigned 7 Data received from UART
461 #define UART_DATA_READY 128
462 #define UART_TBR_EMPTY 64
463 #define UART_F_ERROR 8
464 #define UART_P_ERROR 4
465 #define UART_O_ERROR 2
468 * P3 Not assigned Not assigned
470 * P4 PIO port A data input and output
472 * P5 PIO port B data input and output
474 * P6 PIO port A control
476 * P7 PIO port B control
479 void out(unsigned int port
, unsigned char value
)
481 unsigned int down_trans
;
483 if (0) fprintf(stdout
, "[%02x] <- %02x\n", port
, value
);
488 down_trans
= port0
& ~value
;
491 if ((down_trans
& P0_OUT_KEYBOARD_CLOCK
) && keyp
< 9)
493 if (down_trans
& P0_OUT_KEYBOARD_RESET
)
497 if (tape_led
!= !!(value
& P0_OUT_TAPE_DRIVE_LED
))
498 fprintf(stderr
, "Tape LED = %d\n", !!(value
& P0_OUT_TAPE_DRIVE_LED
));
500 tape_led
= !!(value
& P0_OUT_TAPE_DRIVE_LED
);
504 fputc(value
, serial_out
);
508 fprintf(stdout
, "OUT [%02x] <- %02x\n", port
, value
);
512 int in(unsigned int port
)
514 if (0) fprintf(stdout
, "<- [%02x]\n", port
);
519 /* printf("[%d]", keyp); */
522 if (serial_input_available
& tape_led
) {
523 char ch
= fgetc(serial_in
);
524 serial_input_available
= !feof(serial_in
);
530 /* Status port on the UART */
531 return UART_TBR_EMPTY
|
532 (serial_input_available
& tape_led
? UART_DATA_READY
: 0);
534 fprintf(stdout
, "IN <- [%02x]\n", port
);
539 void slow_write(unsigned int a
, unsigned char v
)
542 unsigned int y
= (a
-0x800) / 64;
543 unsigned int x
= (a
-0x800) % 64;
544 /* fprintf(stdout, "putbyte %04x %02x '%c'\n", a, v, v); */
545 if (10 <= x
&& x
< 58 && ' ' <= v
) {
551 //xputch(x-10, y, v);
552 //fprintf(stderr, "\033[%d;%dH%c", 1+y, 1+x-10, v);
553 framebuffer_generation
++;
557 if (0x800 <= a
&& a
<= 0xE000)