git.haldean.org x6502 / af49983
Functioning vterm mode. This creates a virtual terminal that the emulated program can get direct character access to. It uses the same dimensions as the C64 terminal (40 rows, 25 cols). The screen of the virtual terminal is mapped to memory addresses $FB00-$FEE7, and is in row-major format. Will Haldean Brown 7 years ago
9 changed file(s) with 84 addition(s) and 34 deletion(s). Raw diff Collapse all Expand all
5454 To disable these extensions, compile with
5555 -DDISABLE_EXTENSIONS (right now, this can be done by
5656 adding that flag to the Makefile).
57
58 This also implements a subset of the 65C02 and 65C816
59 instruction set, in particular the WAI (0xCB)
60 instruction. The WAI instruction pauses the emulator
61 until an I/O interrupt is thrown.
5762
5863 I/O memory map:
5964
2424 // branch_offset is an offset that will be added to the program counter
2525 // after we move to the next instruction
2626 int8_t branch_offset = 0;
27
28 // if set to true, the next instruction will not be executed until an
29 // interrupt is fired from the IO bus and handled.
30 uint8_t wait_for_interrupt = 0;
2731
2832 init_io();
2933
5559 #include "opcode_handlers/compare.h"
5660 #include "opcode_handlers/flags.h"
5761 #include "opcode_handlers/incdec.h"
62 #include "opcode_handlers/interrupts.h"
5863 #include "opcode_handlers/jump.h"
5964 #include "opcode_handlers/load.h"
6065 #include "opcode_handlers/logical.h"
7378 }
7479 m->pc += branch_offset;
7580
76 handle_io(m);
81 do {
82 handle_io(m);
83 } while (wait_for_interrupt && !m->interrupt_waiting);
84 wait_for_interrupt = 0;
7785
7886 if (m->interrupt_waiting && !get_flag(m, FLAG_INTERRUPT)) {
7987 STACK_PUSH(m) = (m->pc & 0xFF00) >> 8;
+14
-13
io.c less more
66
77 #include "functions.h"
88
9 #define VTERM_ROWS 40
10 #define VTERM_COLS 25
9 #define VTERM_ROWS 25
10 #define VTERM_COLS 40
1111
1212 uint8_t io_modeflags = 0x00;
13
14 WINDOW *window = NULL;
1315
1416 void init_vterm();
1517 void update_vterm(cpu *, uint16_t);
3234 initscr();
3335 // reinit IO after initializing the ncurses window
3436 init_io();
37
38 window = newwin(VTERM_ROWS + 2, VTERM_COLS + 2, 0, 0);
39 box(window, 0, 0);
3540 }
3641
3742 void finish_vterm() {
38 if (io_modeflags & IO_MODEFLAG_WAIT_TERMINATE) {
39 // wait for user to hit enter to quit
40 printw("\nterminated. hit any key to exit.");
41 nodelay(stdscr, FALSE);
42 getch();
43 }
4443 endwin();
4544 }
4645
6261 // this is in the unused 24 bytes at the end of the page, ignore it
6362 return;
6463 }
65 uint8_t r = offset / VTERM_COLS;
66 uint8_t c = offset % VTERM_COLS;
67 mvprintw(r, c, "%c", m->mem[dirty]);
64 // 1 offsets to avoid overwriting the border
65 uint8_t r = offset / VTERM_COLS + 1;
66 uint8_t c = offset % VTERM_COLS + 1;
67 mvwprintw(window, r, c, "%c", m->mem[dirty]);
68 wrefresh(window);
6869 }
6970
7071 void handle_io(cpu *m) {
7879 uint16_t addr = m->dirty_mem_addr;
7980 if (addr == IO_PUTCHAR) {
8081 if (io_modeflags & IO_MODEFLAG_VTERM) {
81 addch(m->mem[addr]);
82 refresh();
82 wprintw(window, "%c", m->mem[addr]);
83 wrefresh(window);
8384 } else {
8485 printf("%c", m->mem[addr]);
8586 }
88 #define IO_VTERM_START 0xFB00
99 #define IO_VTERM_END 0xFF00
1010
11 #define IO_MODEFLAG_WAIT_TERMINATE 0x01
12 #define IO_MODEFLAG_VTERM 0x02
11 #define IO_MODEFLAG_VTERM 0x01
1312
1413 void init_io();
1514 void finish_io();
0 case BRK:
1 set_flag(m, FLAG_BREAK, 1);
2 m->interrupt_waiting = 1;
3 break;
4
5 case RTI:
6 m->sr = STACK_POP(m);
7 arg1 = STACK_POP(m);
8 m->pc = mem_abs(arg1, STACK_POP(m), 0);
9 break;
10
11 case WAI:
12 wait_for_interrupt = 1;
13 break;
2323 arg1 = STACK_POP(m);
2424 m->pc = mem_abs(arg1, STACK_POP(m), 0) + 1;
2525 break;
26
27 case BRK:
28 set_flag(m, FLAG_BREAK, 1);
29 m->interrupt_waiting = 1;
30 break;
31
32 case RTI:
33 m->sr = STACK_POP(m);
34 arg1 = STACK_POP(m);
35 m->pc = mem_abs(arg1, STACK_POP(m), 0);
36 break;
217217 #define TXS 0x9A
218218 #define TYA 0x98
219219
220 #define WAI 0xCB
221
220222 #endif
00 Test 6502 assembler programs. Generate binaries with:
11
2 xa -bt0 -Istdlib/ sample_programs/test.s
2 xa -w -bt0 -Istdlib/ sample_programs/test.s
33
44 xa is a cross-assembler and utility suite for 65xx series processors. It's
55 included in many package repositories as `xa65', including Homebrew on OSX in
00 counter = $0100
1 supercounter = $0101
2 page = $FF
3 char = $FD
14
2 lda #$03 ; set WAIT_TERMINATE flag
5 lda #$01 ; go into vterm mode
36 sta $FF02
47
58 lda #$FF
69 sta counter ; init counter
710
8 ldx #$0
11 lda #$FB
12 sta page
13 lda #$00
14 sta page-1
915
10 loop lda #$41 ; 41 == 'A'
11 sta $FF00,X
12 inx
13 cpx counter
16 lda #$41 ; 41 == 'A'
17 sta char
18
19 ldy #$00
20
21 loop:
22 lda char
23 sta (page-1),Y
24 jsr incchar
25
26 iny
27 cpy #$00
1428 bne loop
29
30 inc page
31 lda page
32 cmp #$FF
33 bne loop
34
35 wai
36 .byt $FF
37
38 incchar:
39 inc char
40 lda char
41 cmp #$5B
42 bne chardone
43 lda #$41
44 chardone:
45 sta char
46 rts