diff --git a/Makefile b/Makefile index ae64433..f28abaa 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ BIN=curta.bin -GEN_ASM=a2e.stdjoy.s a2e.hi.s +GEN_ASM=a2e.hi.s SRCS=$(wildcard *.c) ASM=$(filter-out $(GEN_ASM),$(wildcard *.s)) $(GEN_ASM) @@ -16,17 +16,6 @@ MAPFILE=curta.map all: $(BIN) -# Big hack here. The joystick library from cc65 only considers a -# jostick centered if it is within 20 of 127 which is very tight. -# Thus the tests for $6B and $93. The good news is that the only -# occurrences of these bytes in the binary image are for these -# comparisons. So, I just do a global search and replace. The -# new threshold I am using is +/- 60 from 127. -a2e.stdjoy.s: - co65 --code-label _a2e_stdjoy -o $@ $(CC65_HOME)/joy/a2e.stdjoy.joy - sed -i .tmp 's/\$$6B/$$43/g' a2e.stdjoy.s - sed -i .tmp 's/\$$93/$$BB/g' a2e.stdjoy.s - a2e.hi.s: co65 --code-label _a2e_hi -o $@ $(CC65_HOME)/tgi/a2e.hi.tgi diff --git a/curta.c b/curta.c index 168bebb..d3a7f7e 100644 --- a/curta.c +++ b/curta.c @@ -6,6 +6,9 @@ // +#include +#include + #include "curtaUI.h" diff --git a/curtaModel.c b/curtaModel.c index 834d278..0e01b2b 100644 --- a/curtaModel.c +++ b/curtaModel.c @@ -7,6 +7,8 @@ #include +#include +#include #include "curtaModel.h" diff --git a/curtaModel.h b/curtaModel.h index ddc5a79..7226cd7 100644 --- a/curtaModel.h +++ b/curtaModel.h @@ -6,10 +6,6 @@ // -#include -#include - - #ifndef _CURTAMODEL_H #define _CURTAMODEL_H diff --git a/curtaUI.c b/curtaUI.c index 27721f4..a2925d7 100644 --- a/curtaUI.c +++ b/curtaUI.c @@ -7,6 +7,9 @@ #include +#include +#include +#include #include #include #include @@ -15,11 +18,11 @@ #include #include "curtaModel.h" +#include "joystick.h" #include "curtaUI.h" -// Extern symbols for joystick and graphics drivers -extern char a2e_stdjoy; +// Extern symbols for graphics drivers extern char a2e_hi; @@ -37,19 +40,6 @@ typedef int8_t tAction; #define ACTION_NULL 9 -typedef int8_t tJoyPos; - -#define JOY_POS_CENTER 0 -#define JOY_POS_DOWN 1 -#define JOY_POS_DOWN_LEFT 2 -#define JOY_POS_LEFT 3 -#define JOY_POS_UP_LEFT 4 -#define JOY_POS_UP 5 -#define JOY_POS_UP_RIGHT 6 -#define JOY_POS_RIGHT 7 -#define JOY_POS_DOWN_RIGHT 8 - - #define OPERAND_COLOR COLOR_WHITE #define OPERAND_OFFSET 4 #define SLIDER_BAR_COLOR COLOR_BLUE @@ -87,7 +77,7 @@ static char displayBuffer[] = #define BASE_OFFSET 103 -static void playSound(int freq, int duration) +static void playSound(int8_t freq, int8_t duration) { while (duration > 0) { asm ("STA %w", 0xc030); @@ -235,59 +225,25 @@ static void drawOperand(tDigitPos pos) } -static tJoyPos getJoyPos(char joyState) -{ - if (JOY_BTN_UP(joyState)) { - if (JOY_BTN_LEFT(joyState)) { - return JOY_POS_UP_LEFT; - } else if (JOY_BTN_RIGHT(joyState)) { - return JOY_POS_UP_RIGHT; - } else { - return JOY_POS_UP; - } - } else if (JOY_BTN_DOWN(joyState)) { - if (JOY_BTN_LEFT(joyState)) { - return JOY_POS_DOWN_LEFT; - } else if (JOY_BTN_RIGHT(joyState)) { - return JOY_POS_DOWN_RIGHT; - } else { - return JOY_POS_DOWN; - } - } else { - if (JOY_BTN_LEFT(joyState)) { - return JOY_POS_LEFT; - } else if (JOY_BTN_RIGHT(joyState)) { - return JOY_POS_RIGHT; - } else { - return JOY_POS_CENTER; - } - } -} - - static tAction getNextAction(void) { static bool firstCall = true; - static char oldJoyState; static tJoyPos oldJoyPos; static unsigned int possibleActions = 0xffff; - char joyState; - tJoyPos joyPos; + tJoyState joyState; tAction result = ACTION_NULL; if (firstCall) { - oldJoyState = joy_read(JOY_1); - oldJoyPos = getJoyPos(oldJoyState); + oldJoyPos = JOY_POS_CENTER; firstCall = false; return result; } - joyState = joy_read(JOY_1); - joyPos = getJoyPos(joyState); + getJoystickState(&joyState); - if ((joyPos != JOY_POS_CENTER) && - (joyPos != JOY_POS_DOWN)) { + if ((joyState.position != JOY_POS_CENTER) && + (joyState.position != JOY_POS_DOWN)) { if (possibleActions == (1 << ACTION_ADD)) { playSound(400, 10); } @@ -296,29 +252,28 @@ static tAction getNextAction(void) } } - if (joyPos == oldJoyPos) { - oldJoyState = joyState; + if (joyState.position == oldJoyPos) { return result; } else if (oldJoyPos == JOY_POS_CENTER) { - if (joyPos == JOY_POS_LEFT) { - if (JOY_BTN_FIRE(joyState)) { + if (joyState.position == JOY_POS_LEFT) { + if (joyState.button0) { possibleActions = (1 << ACTION_RESULT_SHIFT_LEFT); } else { possibleActions = (1 << ACTION_OPERAND_SHIFT_LEFT); } - } else if (joyPos == JOY_POS_RIGHT) { - if (JOY_BTN_FIRE(joyState)) { + } else if (joyState.position == JOY_POS_RIGHT) { + if (joyState.button0) { possibleActions = (1 << ACTION_RESULT_SHIFT_RIGHT); } else { possibleActions = (1 << ACTION_OPERAND_SHIFT_RIGHT); } - } else if (joyPos == JOY_POS_UP) { + } else if (joyState.position == JOY_POS_UP) { possibleActions = (1 << ACTION_OPERAND_DEC); - } else if (joyPos == JOY_POS_DOWN) { + } else if (joyState.position == JOY_POS_DOWN) { possibleActions = (1 << ACTION_OPERAND_INC); - if (JOY_BTN_FIRE(joyState)) { + if (joyState.button0) { possibleActions |= (1 << ACTION_SUBTRACT); - } else if (JOY_BTN_FIRE2(joyState)) { + } else if (joyState.button1) { possibleActions |= (1 << ACTION_CLEAR); } else { possibleActions |= (1 << ACTION_ADD); @@ -326,7 +281,7 @@ static tAction getNextAction(void) } } else { if (possibleActions & (1 << ACTION_OPERAND_SHIFT_LEFT)) { - if (joyPos == JOY_POS_CENTER) { + if (joyState.position == JOY_POS_CENTER) { result = ACTION_OPERAND_SHIFT_LEFT; } else { possibleActions &= (~(1 << ACTION_OPERAND_SHIFT_LEFT)); @@ -334,7 +289,7 @@ static tAction getNextAction(void) } if (possibleActions & (1 << ACTION_OPERAND_SHIFT_RIGHT)) { - if (joyPos == JOY_POS_CENTER) { + if (joyState.position == JOY_POS_CENTER) { result = ACTION_OPERAND_SHIFT_RIGHT; } else { possibleActions &= (~(1 << ACTION_OPERAND_SHIFT_RIGHT)); @@ -342,7 +297,7 @@ static tAction getNextAction(void) } if (possibleActions & (1 << ACTION_OPERAND_INC)) { - if (joyPos == JOY_POS_CENTER) { + if (joyState.position == JOY_POS_CENTER) { result = ACTION_OPERAND_INC; } else { possibleActions &= (~(1 << ACTION_OPERAND_INC)); @@ -350,7 +305,7 @@ static tAction getNextAction(void) } if (possibleActions & (1 << ACTION_OPERAND_DEC)) { - if (joyPos == JOY_POS_CENTER) { + if (joyState.position == JOY_POS_CENTER) { result = ACTION_OPERAND_DEC; } else { possibleActions &= (~(1 << ACTION_OPERAND_DEC)); @@ -358,7 +313,7 @@ static tAction getNextAction(void) } if (possibleActions & (1 << ACTION_RESULT_SHIFT_LEFT)) { - if (joyPos == JOY_POS_CENTER) { + if (joyState.position == JOY_POS_CENTER) { result = ACTION_RESULT_SHIFT_LEFT; } else { possibleActions &= (~(1 << ACTION_RESULT_SHIFT_LEFT)); @@ -366,7 +321,7 @@ static tAction getNextAction(void) } if (possibleActions & (1 << ACTION_RESULT_SHIFT_RIGHT)) { - if (joyPos == JOY_POS_CENTER) { + if (joyState.position == JOY_POS_CENTER) { result = ACTION_RESULT_SHIFT_RIGHT; } else { possibleActions &= (~(1 << ACTION_RESULT_SHIFT_RIGHT)); @@ -374,41 +329,40 @@ static tAction getNextAction(void) } if (possibleActions & (1 << ACTION_ADD)) { - if ((joyPos == JOY_POS_DOWN) && + if ((joyState.position == JOY_POS_DOWN) && (oldJoyPos == JOY_POS_DOWN_RIGHT)) { result = ACTION_ADD; possibleActions = 0; - } else if (joyPos != oldJoyPos + 1) { + } else if (joyState.position != oldJoyPos + 1) { possibleActions &= (~(1 << ACTION_ADD)); } } else if (possibleActions & (1 << ACTION_SUBTRACT)) { - if ((joyPos == JOY_POS_DOWN) && + if ((joyState.position == JOY_POS_DOWN) && (oldJoyPos == JOY_POS_DOWN_RIGHT)) { result = ACTION_SUBTRACT; possibleActions = 0; - } else if (joyPos != oldJoyPos + 1) { + } else if (joyState.position != oldJoyPos + 1) { possibleActions &= (~(1 << ACTION_SUBTRACT)); } } else if (possibleActions & (1 << ACTION_CLEAR)) { - if ((joyPos == JOY_POS_DOWN) && + if ((joyState.position == JOY_POS_DOWN) && (oldJoyPos == JOY_POS_DOWN_RIGHT)) { result = ACTION_CLEAR; possibleActions = 0; - } else if (joyPos != oldJoyPos + 1) { + } else if (joyState.position != oldJoyPos + 1) { possibleActions &= (~(1 << ACTION_CLEAR)); - } else if ((joyPos == JOY_POS_UP_LEFT) || - (joyPos == JOY_POS_DOWN_RIGHT)) { + } else if ((joyState.position == JOY_POS_UP_LEFT) || + (joyState.position == JOY_POS_DOWN_RIGHT)) { playSound(100, 50); } } - if (joyPos == JOY_POS_CENTER) { + if (joyState.position == JOY_POS_CENTER) { possibleActions = -1; } } - oldJoyPos = joyPos; - oldJoyState = joyState; + oldJoyPos = joyState.position; return result; } @@ -421,7 +375,6 @@ void initUI(void) initDevice(changeOperand, changeSelectedOperand); - joy_install(&a2e_stdjoy); tgi_install(&a2e_hi); tgi_init(); @@ -502,5 +455,4 @@ void shutdownUI(void) { // Uninstall drivers tgi_uninstall(); - joy_uninstall(); } diff --git a/curtaUI.h b/curtaUI.h index 06212f5..bf02239 100644 --- a/curtaUI.h +++ b/curtaUI.h @@ -5,8 +5,6 @@ // This is the interface for the Curta emulator UI. // -#include - #ifndef _CURTAUI_H #define _CURTAUI_H diff --git a/joystick.c b/joystick.c new file mode 100644 index 0000000..b83d615 --- /dev/null +++ b/joystick.c @@ -0,0 +1,127 @@ +// +// Author: Jeremy Rand +// Date: July 20, 2012 +// +// This is the implementation for the Curta emulator UI. +// + + +#include + +#include "joystick.h" + + +#define PREAD 0xFB1E +#define ROM_SWITCH 0xC082 +#define RAM_SWITCH 0xC080 +#define BTN0 0xC061 +#define BTN1 0xC062 + + +#define JOYSTICK_CENTER 127 +#define JOYSTICK_THRESHOLD 60 +#define LOWER_THRESHOLD (JOYSTICK_CENTER - JOYSTICK_THRESHOLD) +#define UPPER_THRESHOLD (JOYSTICK_CENTER + JOYSTICK_THRESHOLD) + + +static uint8_t joystickTemp; + + +static bool isButtonPressed(int8_t buttonNum) +{ + if (buttonNum) { + __asm__("LDA %w", BTN1); + __asm__("STA %v", joystickTemp); + } else { + __asm__("LDA %w", BTN0); + __asm__("STA %v", joystickTemp); + } + return ((joystickTemp > 127) ? true : false); +} + + +static uint8_t joystickLeftRight(void) +{ + __asm__("BIT %w", ROM_SWITCH); + __asm__("LDX #0"); + __asm__("JSR %w", PREAD); + __asm__("STY %v", joystickTemp); + __asm__("BIT %w", RAM_SWITCH); + return joystickTemp; +} + + +static uint8_t joystickUpDown(void) +{ + __asm__("BIT %w", ROM_SWITCH); + __asm__("LDX #1"); + __asm__("JSR %w", PREAD); + __asm__("STY %v", joystickTemp); + __asm__("BIT %w", RAM_SWITCH); + return joystickTemp; +} + + +void getJoystickState(tJoyState *state) +{ + static bool readLeftRight = true; + static uint8_t axisLeftRight = 127; + static uint8_t axisUpDown = 127; + + tJoyPos pos = JOY_POS_CENTER; + + if (readLeftRight) { + int temp = joystickLeftRight(); // Get left/right position + temp *= 3; + temp /= 4; + axisLeftRight /= 4; + axisLeftRight += temp; + readLeftRight = false; + } else { + int temp = joystickUpDown(); + temp *= 3; + temp /= 4; + axisUpDown /= 4; + axisUpDown += temp; + readLeftRight = true; + } + + if (axisLeftRight < LOWER_THRESHOLD) { + pos = JOY_POS_LEFT; + } else if (axisLeftRight > UPPER_THRESHOLD) { + pos = JOY_POS_RIGHT; + } + + state->button0 = isButtonPressed(0); + state->button1 = isButtonPressed(1); + + if (axisUpDown < LOWER_THRESHOLD) { + switch (pos) { + case JOY_POS_LEFT: + pos = JOY_POS_UP_LEFT; + break; + case JOY_POS_RIGHT: + pos = JOY_POS_UP_RIGHT; + break; + default: + pos = JOY_POS_UP; + break; + } + } else if (axisUpDown > UPPER_THRESHOLD) { + switch (pos) { + case JOY_POS_LEFT: + pos = JOY_POS_DOWN_LEFT; + break; + case JOY_POS_RIGHT: + pos = JOY_POS_DOWN_RIGHT; + break; + default: + pos = JOY_POS_DOWN; + break; + } + } + state->position = pos; + // Add in a bit of extra delay also + for (pos = 0; pos < 100; pos++) + ; +} diff --git a/joystick.h b/joystick.h new file mode 100644 index 0000000..dfce8a4 --- /dev/null +++ b/joystick.h @@ -0,0 +1,35 @@ +// +// Author: Jeremy Rand +// Date: July 29, 2012 +// +// This is an interface for the Apple // joystick. Note that I used to use +// the cc65 joystck interface but found it lacking on real hardware. It +// worked fine on an emulator but I think it was testing the second axis of +// the joystick too quickly leading to inaccuracies. +// + + +#include +#include + + +typedef int8_t tJoyPos; +typedef struct tJoyState { + tJoyPos position; + bool button0; + bool button1; +} tJoyState; + + +#define JOY_POS_CENTER 0 +#define JOY_POS_DOWN 1 +#define JOY_POS_DOWN_LEFT 2 +#define JOY_POS_LEFT 3 +#define JOY_POS_UP_LEFT 4 +#define JOY_POS_UP 5 +#define JOY_POS_UP_RIGHT 6 +#define JOY_POS_RIGHT 7 +#define JOY_POS_DOWN_RIGHT 8 + + +void getJoystickState(tJoyState *state);