Ryukojiro-apple1/apple1/pia.c
Daniel Loffgren 552fb8fcc2 Explain to the user what is happening when the debugger steps over the keyboard data register. Before this only the readiness register would alert the debugger user.
git-svn-id: svn+ssh://svn.phoenixbox.net/svn/apple1/trunk@69 64f78de7-aa59-e511-a0e8-0002a5492df0
2015-12-10 05:23:16 +00:00

177 lines
4.1 KiB
C

//
// pia.c
// apple1
//
// Created by Daniel Loffgren on 9/12/15.
// Copyright (c) 2015 Daniel Loffgren. All rights reserved.
//
#include "pia.h"
#include <stdio.h>
#include <as6502/color.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#define FIXME_I_SHOULDNT_BE_NULL NULL
#define KEYBOARD_READY 0xFF // This just needs to meet the requirements of being a negative number in the eyes of the 6502
#define KEYBOARD_NOTREADY 0x00
#define ANSI_BGCOLOR_GREEN "\x1b[42;1m"
void saveFreeze(v6502_memory *mem, const char *fname) {
FILE *f = fopen(fname, "w");
if (!f) {
endwin();
fprintf(stderr, "Couldn't open %s for writing\n", fname);
}
for (uint16_t offset = 0; offset < v6502_memoryStartCeiling; offset++) {
uint8_t byte = v6502_read(mem, offset, NO);
fwrite(&byte, sizeof(uint8_t), 1, f);
}
fclose(f);
}
char asciiCharFromCursesKey(int key) {
return (char)key;
}
char asciiCharFromA1Char(uint8_t c) {
return (char)c & ~0x80;
}
uint8_t a1CharFromAsciiChar(char c) {
if (c >= 'a' && c <= 'z') {
c -= 0x20;
}
return (char)c | 0x80;
}
void videoWriteCharCallback(struct _v6502_memory *memory, uint16_t offset, uint8_t value, a1pia *context) {
if (value) {
char c = asciiCharFromA1Char(value);
if (c == '\r') {
waddch(context->screen, '\n');
}
if (c == 0x7f) {
int y, x;
getyx(context->screen, y, x);
if (x < 0) {
move(y, x-1);
}
delch();
refresh();
}
else {
// printf(ANSI_COLOR_BRIGHT_GREEN);
waddch(context->screen, c);
// printf(ANSI_COLOR_RESET);
}
//memory->bytes[offset] = value;
}
}
void videoWriteNewlineCallback(struct _v6502_memory *memory, uint16_t offset, uint8_t value, a1pia *context) {
// fprintf(stdout, "\r\n");
// fflush(stdout);
}
uint8_t keyboardReadReadyCallback(struct _v6502_memory *memory, uint16_t offset, int trap, a1pia *context) {
if (!trap) {
return 0xbf;
}
if (context->buf) {
return KEYBOARD_READY;
}
saveFreeze(memory, "freeze.ram");
if (context->suspended) {
printf("Keyboard readiness register ($D011) trap read.\n");
printf("Press a key for input to keyboard register ($D010): ");
fflush(stdout);
crmode();
}
int c = getch();
if (context->suspended) {
printf("%c\r\n", c);
}
if (c == '`') {
context->signalled++;
return KEYBOARD_NOTREADY;
}
if (c != ERR) {
context->buf = asciiCharFromCursesKey(c);
return KEYBOARD_READY;
}
return KEYBOARD_NOTREADY;
}
uint8_t keyboardReadCharacterCallback(struct _v6502_memory *memory, uint16_t offset, int trap, a1pia *context) {
// This means we are in the debugger, but the CPU actually stepped over an instruction (rather than a tool peeking at memory)
if (context->suspended && trap) {
printf("Keyboard register ($D010) read.\n");
printf("Buffered character was #$%02x, now empty.\n", a1CharFromAsciiChar(context->buf));
fflush(stdout);
crmode();
}
if (context->buf) {
uint8_t a = a1CharFromAsciiChar(context->buf);
if (trap) {
context->buf = '\0';
}
return a;
}
return 0;
}
a1pia *pia_create(v6502_memory *mem) {
a1pia *pia = malloc(sizeof(a1pia));
pia->memory = mem;
pia->screen = NULL;
pia->buf = '\0';
assert(v6502_map(mem, A1PIA_KEYBOARD_INPUT_REGISTER, 1, (v6502_readFunction *)keyboardReadCharacterCallback, NULL, pia));
assert(v6502_map(mem, A1PIA_KEYBOARD_READY_REGISTER, 1, (v6502_readFunction *)keyboardReadReadyCallback, NULL, pia));
assert(v6502_map(mem, A1PIA_VIDEO_OUTPUT_REGISTER, 1, FIXME_I_SHOULDNT_BE_NULL, (v6502_writeFunction *)videoWriteCharCallback, pia));
assert(v6502_map(mem, A1PIA_VIDEO_ATTR_REGISTER, 1, FIXME_I_SHOULDNT_BE_NULL, (v6502_writeFunction *)videoWriteNewlineCallback, pia));
return pia;
}
void pia_destroy(a1pia *pia) {
endwin();
free(pia);
}
void pia_start(a1pia *pia, int continuous) {
if (!pia->screen) {
pia->screen = initscr();
}
nodelay(stdscr, continuous);
crmode();
noecho();
nonl();
scrollok(pia->screen, YES);
pia->signalled = 0;
pia->suspended = 0;
wrefresh(pia->screen);
start_color();
init_pair(1, COLOR_GREEN, COLOR_BLACK);
attron(COLOR_PAIR(1) | A_BOLD);
}
void pia_stop(a1pia *pia) {
pia->suspended = 1;
pia->screen = NULL;
endwin();
}