1 /* Virtual Nascom, 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 extern uint8_t nascom_font_raw
[];
55 static SDL_Surface
*screen
;
61 FILE *serial_out
, *serial_in
;
63 int serial_input_available
= 0;
65 static unsigned framebuffer_generation
;
67 static void RenderItem(struct font
*font
, int idx
, int x
, int y
)
69 auto SDL_Rect dest
= { x
, y
, font
->w
, font
->h
};
70 SDL_Rect clip
= { 0, idx
* font
->h_pitch
, font
->w
, font
->h
};
71 SDL_BlitSurface(font
->surf
, &clip
, screen
, &dest
);
74 void RenderLetters(struct font
*font
, char *s
, int x
, int y
)
76 for (; *s
; ++s
, x
+= font
->w
)
77 RenderItem(font
, *s
, x
, y
);
80 int mysetup(int argc
, char **argv
)
82 if (SDL_Init(SDL_INIT_VIDEO
) < 0) {
83 fprintf(stderr
, "Unable to init SDL: %s\n", SDL_GetError());
91 screen
= SDL_SetVideoMode(48 * FONT_W
, 16 * FONT_H
, 8, SDL_SWSURFACE
);
93 fprintf(stderr
, "Unable to set video: %s\n", SDL_GetError());
97 /* Set the window caption */
98 SDL_WM_SetCaption("Nascom II", "Nascom II");
101 /* Populate the palette */
102 SDL_Color colors
[256];
104 colors
[0].r
= colors
[0].g
= colors
[0].b
= 0;
105 colors
[255].r
= colors
[255].b
= 0;
109 if (!SDL_SetColors(screen
, colors
, 0, 256)) {
110 fprintf(stderr
, "Unable to create framebuffer palette: %s\n",
112 screen
= 0; //XXX should free it
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 perror("Couldn't load the 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;
162 void load_nascom(const char *file
)
164 FILE *f
= fopen(file
, "r");
165 int a
, b1
, b2
, b3
, b4
, b5
, b6
, b7
, b8
;
175 printf("Loading %s", file
);
178 if (fscanf(f
, "%x %x %x %x %x %x %x %x %x",
179 &a
, &b1
, &b2
, &b3
, &b4
, &b5
, &b6
, &b7
, &b8
) == 9) {
193 while (ch
!= -1 && ch
!= '\n');
201 printf(". Successfully loaded %d bytes\n", count
);
205 f
= fopen("blob", "w");
206 fwrite((const void *) ram
, 1, 2048, f
);
211 static char * kbd_translation
[] = {
220 /* 8 */ "xzxxx-\r\010"
228 unsigned last_generation
= 0;
233 while (SDL_PollEvent(&event
)) {
234 switch (event
.type
) {
235 case SDL_MOUSEMOTION
:
236 /*printf("Mouse moved by %d,%d to (%d,%d)\n",
237 event.motion.xrel, event.motion.yrel,
238 event.motion.x, event.motion.y);*/
240 case SDL_MOUSEBUTTONDOWN
:
241 /*printf("Mouse button %d pressed at (%d,%d)\n",
242 event.button.button, event.button.x, event.button.y);*/
246 if (event
.key
.keysym
.sym
== '\\' && event
.type
== SDL_KEYDOWN
) {
251 if (event
.key
.keysym
.sym
== 27)
254 if (event
.key
.keysym
.sym
< 128) {
255 int ch
= toupper(event
.key
.keysym
.sym
);
256 for (i
= 0; i
< 9; ++i
)
257 for (bit
= 0; bit
< 8; ++bit
)
258 if (kbd_translation
[i
][7-bit
] == ch
) {
264 switch (event
.key
.keysym
.sym
) {
265 case SDLK_LCTRL
: i
= 0, bit
= 3; break;
267 case SDLK_RSHIFT
: i
= 0, bit
= 4; break;
268 case SDLK_RCTRL
: i
= 0, bit
= 5; break;
269 case SDLK_UP
: i
= 1, bit
= 6; break;
270 case SDLK_LEFT
: i
= 2, bit
= 6; break;
271 case SDLK_DOWN
: i
= 3, bit
= 6; break;
272 case SDLK_RIGHT
: i
= 4, bit
= 6; break;
276 case SDLK_LALT
: i
= 5, bit
= 6; break;
277 case SDLK_KP_ENTER
:i
= 8, bit
= 6; break;
279 /* Undocumented hack */
281 f
= fopen("screendump", "w");
282 fwrite((const void *) (ram
+0x800), 1, 1024, f
);
284 if (vflag
) printf("Screen dumped\n");
288 //printf("%d? ", event.key.keysym.sym);
289 //printf(" keysym %s\n", SDL_GetKeyName(event.key.keysym.sym));
295 if (event
.type
== SDL_KEYDOWN
)
298 keym
[i
] &= ~(1 << bit
);
305 //printf("Unknown event: %d\n", event.type);
310 /* Only update the screen if the framebuffer has been written
312 if (last_generation
!= framebuffer_generation
) {
314 unsigned p
= 0x800 + 10;
315 last_generation
= framebuffer_generation
;
317 for (y
= 1; y
< 16; ++y
, p
+= 64) {
318 for (x
= 0; x
< 48; ++x
)
319 RenderItem(&nascom_font
, RAM(p
+ x
), x
* FONT_W
, y
* FONT_H
);
322 // Nascom is strange in that the last line is the first line!
323 for (x
= 0; x
< 48; ++x
)
324 RenderItem(&nascom_font
, RAM(p
+ x
), x
* FONT_W
, 0);
326 SDL_UpdateRect(screen
, 0, 0, screen
->w
, screen
->h
);
327 // SDL_Flip(screen); either seem to work
330 SDL_Delay(1000 / 30); // 30 fps
346 void simulate(void *dummy
)
348 simz80(pc
, 900, sim_delay
);
355 "Usage: %s {flags} {commands}\n"
356 " -i <file> take serial port input from file (when tape led is on)\n"
357 " -m <file> use <file> as monitor (default is nassys3.nal)\n"
363 int main(int argc
, char **argv
)
367 serial_out
= fopen("serialout.txt", "w+");
372 if (mysetup(argc
, argv
))
375 monitor
= "nassys3.nal";
380 for (c
=0; c
<MEMSIZE
/4; ++c
) pagetable
[c
]=ram
+(c
<<12);
383 while ((c
= getopt(argc
, argv
, "i:m:v")) != EOF
)
386 serial_in
= fopen(optarg
, "r");
387 //printf("serial input %s -> %p\n", optarg, serial_in);
388 serial_input_available
= !feof(serial_in
);
401 puts("Virtual Nascom, a Nascom 2 emulator version " VERSION
"\n"
402 "Copyright 2000,2009 Tommy Thorn.\n"
403 "Uses software from \n"
404 "Yet Another Z80 Emulator version " YAZEVERSION
405 ", Copyright 1995,1998 Frank D. Cringle.\n"
406 "VirtualNascom comes with ABSOLUTELY NO WARRANTY; for details\n"
407 "see the file \"COPYING\" in the distribution directory.\n");
409 load_nascom(monitor
);
410 load_nascom("basic.nal");
412 for (; optind
< argc
; optind
++)
413 load_nascom(argv
[optind
]);
415 SDL_CreateThread((int (*)(void *))simulate
, NULL
);
422 * 1.7 Input/output port addressing
425 * P0 7 Not available 7 Unused
426 * 6 Not used 6 Keyboard S6
427 * 5 Unused 5 Keyboard S3
428 * 4 Tape drive LED 4 Keyboard S5
429 * 3 Single step 3 Keyboard S4
430 * 2 Unused 2 Keyboard S0
431 * 1 Reset keyb'd count 1 Keyboard S2
432 * 0 Clock keyb'd count 0 Keyboard S1
435 #define P0_OUT_TAPE_DRIVE_LED 16
436 #define P0_OUT_SINGLE_STEP 8
437 #define P0_OUT_KEYBOARD_RESET 2
438 #define P0_OUT_KEYBOARD_CLOCK 1
441 * P1 0 - 7 Data to UART 0 - 7 Data from UART
442 * (Serial port) (Serial port)
444 * P2 0 - 7 Not assigned 7 Data received from UART
454 #define UART_DATA_READY 128
455 #define UART_TBR_EMPTY 64
456 #define UART_F_ERROR 8
457 #define UART_P_ERROR 4
458 #define UART_O_ERROR 2
461 * P3 Not assigned Not assigned
463 * P4 PIO port A data input and output
465 * P5 PIO port B data input and output
467 * P6 PIO port A control
469 * P7 PIO port B control
472 void out(unsigned int port
, unsigned char value
)
474 unsigned int down_trans
;
476 if (0) fprintf(stdout
, "[%02x] <- %02x\n", port
, value
);
481 down_trans
= port0
& ~value
;
484 if ((down_trans
& P0_OUT_KEYBOARD_CLOCK
) && keyp
< 9)
486 if (down_trans
& P0_OUT_KEYBOARD_RESET
)
490 if (tape_led
!= !!(value
& P0_OUT_TAPE_DRIVE_LED
))
491 fprintf(stderr
, "Tape LED = %d\n", !!(value
& P0_OUT_TAPE_DRIVE_LED
));
493 tape_led
= !!(value
& P0_OUT_TAPE_DRIVE_LED
);
497 fputc(value
, serial_out
);
501 fprintf(stdout
, "OUT [%02x] <- %02x\n", port
, value
);
505 int in(unsigned int port
)
507 if (0) fprintf(stdout
, "<- [%02x]\n", port
);
512 /* printf("[%d]", keyp); */
515 if (serial_input_available
& tape_led
) {
516 char ch
= fgetc(serial_in
);
517 serial_input_available
= !feof(serial_in
);
523 /* Status port on the UART */
524 return UART_TBR_EMPTY
|
525 (serial_input_available
& tape_led
? UART_DATA_READY
: 0);
527 fprintf(stdout
, "IN <- [%02x]\n", port
);
532 void slow_write(unsigned int a
, unsigned char v
)
535 unsigned int y
= (a
-0x800) / 64;
536 unsigned int x
= (a
-0x800) % 64;
537 /* fprintf(stdout, "putbyte %04x %02x '%c'\n", a, v, v); */
538 if (10 <= x
&& x
< 58 && ' ' <= v
) {
544 //xputch(x-10, y, v);
545 //fprintf(stderr, "\033[%d;%dH%c", 1+y, 1+x-10, v);
546 framebuffer_generation
++;
550 if (0x800 <= a
&& a
<= 0xE000)