Fix joystick support for real hardware

This commit is contained in:
Jeremy Rand 2012-07-28 23:45:19 -04:00
parent 57970d78a3
commit ec025d166f
8 changed files with 204 additions and 102 deletions

View File

@ -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

View File

@ -6,6 +6,9 @@
//
#include <stdint.h>
#include <stdbool.h>
#include "curtaUI.h"

View File

@ -7,6 +7,8 @@
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include "curtaModel.h"

View File

@ -6,10 +6,6 @@
//
#include <stdint.h>
#include <stdbool.h>
#ifndef _CURTAMODEL_H
#define _CURTAMODEL_H

120
curtaUI.c
View File

@ -7,6 +7,9 @@
#include <stdio.h>
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <conio.h>
#include <apple2.h>
@ -15,11 +18,11 @@
#include <tgi/tgi-mode.h>
#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();
}

View File

@ -5,8 +5,6 @@
// This is the interface for the Curta emulator UI.
//
#include <stdbool.h>
#ifndef _CURTAUI_H
#define _CURTAUI_H

127
joystick.c Normal file
View File

@ -0,0 +1,127 @@
//
// Author: Jeremy Rand
// Date: July 20, 2012
//
// This is the implementation for the Curta emulator UI.
//
#include <stdio.h>
#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++)
;
}

35
joystick.h Normal file
View File

@ -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 <stdint.h>
#include <stdbool.h>
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);