diff --git a/a2p.c b/a2p.c index 05eae48..2c7aa68 100644 --- a/a2p.c +++ b/a2p.c @@ -52,6 +52,11 @@ #define EWM_A2P_SS_SETAN3 0xc05e #define EWM_A2P_SS_CLRAN3 0xc05f +#define EWM_A2P_SS_PB0 0xC061 +#define EWM_A2P_SS_PB1 0xC062 +#define EWM_A2P_SS_PB2 0xC063 +#define EWM_A2P_SS_PB3 0xC060 // TODO On the gs only? + uint8_t a2p_iom_read(struct cpu_t *cpu, struct mem_t *mem, uint16_t addr) { struct a2p_t *a2p = (struct a2p_t*) mem->obj; switch (addr) { @@ -101,6 +106,15 @@ uint8_t a2p_iom_read(struct cpu_t *cpu, struct mem_t *mem, uint16_t addr) { // TODO Implement speaker support break; + case EWM_A2P_SS_PB0: + return a2p->buttons[0]; + case EWM_A2P_SS_PB1: + return a2p->buttons[1]; + case EWM_A2P_SS_PB2: + return a2p->buttons[2]; + case EWM_A2P_SS_PB3: + return a2p->buttons[3]; + default: printf("[A2P] Unexpected read at $%.4X\n", addr); break; diff --git a/a2p.h b/a2p.h index 13b3a02..00a2c30 100644 --- a/a2p.h +++ b/a2p.h @@ -40,6 +40,12 @@ struct ewm_dsk_t; #define EWM_A2P_SCREEN_PAGE1 0 #define EWM_A2P_SCREEN_PAGE2 1 +#define EWM_A2P_BUTTON1 0 +#define EWM_A2P_BUTTON2 1 +#define EWM_A2P_BUTTON3 2 +#define EWM_A2P_BUTTON4 3 // Only exists on the gs? +#define EWM_A2P_BUTTON_COUNT 4 + struct a2p_t { struct cpu_t *cpu; @@ -62,6 +68,7 @@ struct a2p_t { int screen_dirty; uint8_t key; + uint8_t buttons[EWM_A2P_BUTTON_COUNT]; }; int a2p_init(struct a2p_t *a2p, struct cpu_t *cpu); diff --git a/sdl.c b/sdl.c index 4b27214..06c40e9 100644 --- a/sdl.c +++ b/sdl.c @@ -57,138 +57,159 @@ void sdl_initialize() { } } -Uint32 my_callbackfunc(Uint32 interval, void *param) { - SDL_Event event; - SDL_UserEvent userevent; - - userevent.type = SDL_USEREVENT; - userevent.code = 0; - userevent.data1 = NULL; - userevent.data2 = NULL; - - event.type = SDL_USEREVENT; - event.user = userevent; - - SDL_PushEvent(&event); - - return interval; -} - -void sdl_main(struct cpu_t *cpu, struct a2p_t *a2p, struct scr_t *scr) { - bool quit = false; - - int fps = 0; - Uint32 next_time = SDL_GetTicks() + (1000 / 50); - - SDL_StartTextInput(); - - (void) SDL_AddTimer(1000, my_callbackfunc, NULL); - - while (quit == false) - { - // Events - - SDL_Event event; - while (SDL_PollEvent(&event) != 0) { - switch (event.type) { - case SDL_QUIT: - quit = true; - break; - case SDL_KEYDOWN: - if (event.key.keysym.mod & KMOD_CTRL) { - if (event.key.keysym.sym >= SDLK_a && event.key.keysym.sym <= SDLK_z) { - a2p->key = (event.key.keysym.sym - SDLK_a) | 0x80; - } else { - // TODO Implement control codes 1b - 1f - } - } else if (event.key.keysym.mod & KMOD_GUI) { - switch (event.key.keysym.sym) { - case SDLK_ESCAPE: - fprintf(stderr, "[SDL] Reset\n"); - cpu_reset(cpu); - break; - } - } else if (event.key.keysym.mod == KMOD_NONE) { - switch (event.key.keysym.sym) { - case SDLK_RETURN: - a2p->key = 0x0d | 0x80; // CR - break; - case SDLK_TAB: - a2p->key = 0x09 | 0x80; // HT - case SDLK_DELETE: - a2p->key = 0x7f | 0x80; // DEL - break; - case SDLK_LEFT: - a2p->key = 0x08 | 0x80; // BS - break; - case SDLK_RIGHT: - a2p->key = 0x15 | 0x80; // NAK - break; - case SDLK_UP: - a2p->key = 0x0b | 0x80; // VT - break; - case SDLK_DOWN: - a2p->key = 0x0a | 0x80; // LF - break; - case SDLK_ESCAPE: - a2p->key = 0x1b | 0x80; // ESC - break; - } - } - break; - case SDL_TEXTINPUT: - if (strlen(event.text.text) == 1) { - a2p->key = toupper(event.text.text[0]) | 0x80; - } - break; - case SDL_USEREVENT: - printf("fps = %d\n", fps); - fps = 0; - break; - } - } - - // Logic - for (int i = 0; i < 5000; i++) { - int ret = cpu_step(cpu); - if (ret != 0) { - switch (ret) { - case EWM_CPU_ERR_UNIMPLEMENTED_INSTRUCTION: - fprintf(stderr, "CPU: Exited because of unimplemented instructions 0x%.2x at 0x%.4x\n", - mem_get_byte(cpu, cpu->state.pc), cpu->state.pc); - break; - case EWM_CPU_ERR_STACK_OVERFLOW: - fprintf(stderr, "CPU: Exited because of stack overflow at 0x%.4x\n", cpu->state.pc); - break; - case EWM_CPU_ERR_STACK_UNDERFLOW: - fprintf(stderr, "CPU: Exited because of stack underflow at 0x%.4x\n", cpu->state.pc); - break; - } - - cpu_nmi(cpu); - - //exit(1); - } - } - - SDL_Delay(10); - - // Render - - if (a2p->screen_dirty) { - if (SDL_GetTicks() >= next_time) { - ewm_scr_update(scr); - a2p->screen_dirty = false; - SDL_RenderPresent(scr->renderer); - fps++; - - next_time = SDL_GetTicks() + (1000 / 50); - } - } - } - - printf("sdl_main done\n"); - +void sdl_destroy() { SDL_DestroyWindow(window); SDL_Quit(); } + +static bool sdl_poll_event(struct cpu_t *cpu, struct a2p_t *a2p, struct scr_t *scr) { + SDL_Event event; + while (SDL_PollEvent(&event) != 0) { + switch (event.type) { + case SDL_QUIT: + return false; + + case SDL_JOYBUTTONDOWN: + if (event.jbutton.button < EWM_A2P_BUTTON_COUNT) { + a2p->buttons[event.jbutton.button] = 1; + } + break; + case SDL_JOYBUTTONUP: + if (event.jbutton.button < EWM_A2P_BUTTON_COUNT) { + a2p->buttons[event.jbutton.button] = 0; + } + break; + + case SDL_KEYDOWN: + if (event.key.keysym.mod & KMOD_ALT) { + switch (event.key.keysym.sym) { + case SDLK_1: + a2p->buttons[0] = 1; + break; + case SDLK_2: + a2p->buttons[1] = 1; + break; + case SDLK_3: + a2p->buttons[2] = 1; + break; + case SDLK_4: + a2p->buttons[3] = 1; + break; + } + } else if (event.key.keysym.mod & KMOD_CTRL) { + if (event.key.keysym.sym >= SDLK_a && event.key.keysym.sym <= SDLK_z) { + a2p->key = (event.key.keysym.sym - SDLK_a) | 0x80; + } else { + // TODO Implement control codes 1b - 1f + } + } else if (event.key.keysym.mod & KMOD_GUI) { + switch (event.key.keysym.sym) { + case SDLK_ESCAPE: + fprintf(stderr, "[SDL] Reset\n"); + cpu_reset(cpu); + break; + } + } else if (event.key.keysym.mod == KMOD_NONE) { + switch (event.key.keysym.sym) { + case SDLK_RETURN: + a2p->key = 0x0d | 0x80; // CR + break; + case SDLK_TAB: + a2p->key = 0x09 | 0x80; // HT + case SDLK_DELETE: + a2p->key = 0x7f | 0x80; // DEL + break; + case SDLK_LEFT: + a2p->key = 0x08 | 0x80; // BS + break; + case SDLK_RIGHT: + a2p->key = 0x15 | 0x80; // NAK + break; + case SDLK_UP: + a2p->key = 0x0b | 0x80; // VT + break; + case SDLK_DOWN: + a2p->key = 0x0a | 0x80; // LF + break; + case SDLK_ESCAPE: + a2p->key = 0x1b | 0x80; // ESC + break; + } + } + break; + + case SDL_KEYUP: + if (event.key.keysym.mod & KMOD_ALT) { + switch (event.key.keysym.sym) { + case SDLK_1: + a2p->buttons[0] = 0; + break; + case SDLK_2: + a2p->buttons[1] = 0; + break; + case SDLK_3: + a2p->buttons[2] = 0; + break; + case SDLK_4: + a2p->buttons[3] = 0; + break; + } + } + break; + + case SDL_TEXTINPUT: + if (strlen(event.text.text) == 1) { + a2p->key = toupper(event.text.text[0]) | 0x80; + } + break; + } + } + + return true; +} + +static bool sdl_step_cpu(struct cpu_t *cpu, struct a2p_t *a2p, struct scr_t *scr) { + for (int i = 0; i < 5000; i++) { + int ret = cpu_step(cpu); + if (ret != 0) { + switch (ret) { + case EWM_CPU_ERR_UNIMPLEMENTED_INSTRUCTION: + fprintf(stderr, "CPU: Exited because of unimplemented instructions 0x%.2x at 0x%.4x\n", + mem_get_byte(cpu, cpu->state.pc), cpu->state.pc); + break; + case EWM_CPU_ERR_STACK_OVERFLOW: + fprintf(stderr, "CPU: Exited because of stack overflow at 0x%.4x\n", cpu->state.pc); + break; + case EWM_CPU_ERR_STACK_UNDERFLOW: + fprintf(stderr, "CPU: Exited because of stack underflow at 0x%.4x\n", cpu->state.pc); + break; + } + cpu_nmi(cpu); + } + } + return true; +} + +void sdl_main(struct cpu_t *cpu, struct a2p_t *a2p, struct scr_t *scr) { + SDL_StartTextInput(); + + while (true) { + if (!sdl_poll_event(cpu, a2p, scr)) { + break; + } + + if (!sdl_step_cpu(cpu, a2p, scr)) { + break; + } + + SDL_Delay(10); // TODO This should really not be here. Implement proper throttling. + + if (a2p->screen_dirty) { + ewm_scr_update(scr); + a2p->screen_dirty = false; + SDL_RenderPresent(scr->renderer); + } + } + + sdl_destroy(); +} diff --git a/tests/apple2/buttons.s b/tests/apple2/buttons.s new file mode 100644 index 0000000..63e1cfe --- /dev/null +++ b/tests/apple2/buttons.s @@ -0,0 +1,35 @@ + + .org $8000 + +cout = $fded +home = $fc58 + +pb0 = $c061 +pb1 = $c062 +pb2 = $c063 +pb3 = $c060 + + jsr home + +check0: lda pb0 + beq check1 + lda #'0' + jsr cout + +check1: lda pb1 + beq check2 + lda #'1' + jsr cout + +check2: lda pb2 + beq check3 + lda #'2' + jsr cout + +check3: lda pb3 + beq check0 + lda #'3' + jsr cout + + jmp check0 +