commit de2dc16c6af24e03ed1b03768c80c47bef532e21 Author: Jeremy Rand Date: Fri Jul 20 09:30:41 2012 -0500 Initial commit diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..adb74e8 --- /dev/null +++ b/Makefile @@ -0,0 +1,37 @@ +BIN=curta.bin + +GEN_ASM=a2e.stdjoy.s a2e.hi.s +SRCS=$(wildcard *.c) +ASM=$(filter-out $(GEN_ASM),$(wildcard *.s)) $(GEN_ASM) + +C_OBJS=$(SRCS:.c=.o) +ASM_OBJS=$(ASM:.s=.o) +OBJS=$(C_OBJS) $(ASM_OBJS) + +PLATFORM=apple2enh +#PLATFORM_CFG=-C $(PLATFORM)-loader.cfg +PLATFORM_CFG=--start-addr '$$4000' + +MAPFILE=curta.map + +all: $(BIN) + +a2e.stdjoy.s: + co65 --code-label _a2e_stdjoy -o $@ $(CC65_HOME)/joy/a2e.stdjoy.joy + +a2e.hi.s: + co65 --code-label _a2e_hi -o $@ $(CC65_HOME)/tgi/a2e.hi.tgi + +%.o: %.s + ca65 -t $(PLATFORM) -o $@ $< + +$(BIN): $(ASM_OBJS) $(SRCS) + cl65 -t $(PLATFORM) $(PLATFORM_CFG) --mapfile $(MAPFILE) -o $(BIN).tmp $(SRCS) $(addprefix --obj ,$(ASM_OBJS)) + dd if=$(BIN).tmp of=$(BIN) bs=4 skip=1 + rm -f $(BIN).tmp + +clean: + rm -f $(BIN) $(OBJS) $(GEN_ASM) $(MAPFILE) + +install: $(BIN) + cp $(BIN) ~/Documents/"Apple ]["/Transfer diff --git a/curtaEm.c b/curtaEm.c new file mode 100644 index 0000000..b1721a3 --- /dev/null +++ b/curtaEm.c @@ -0,0 +1,531 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +// Extern symbols for joystick and graphics drivers +extern char a2e_stdjoy; +extern char a2e_hi; + +#define NUM_OPERAND_DIGITS 11 +#define NUM_RESULT_DIGITS 15 +#define NUM_COUNTER_DIGITS 8 + +typedef int8_t tDigit; +typedef int8_t tDigitPos; +typedef int8_t tAction; +typedef int8_t tJoyPos; + +#define ACTION_OPERAND_SHIFT_LEFT 0 +#define ACTION_OPERAND_SHIFT_RIGHT 1 +#define ACTION_OPERAND_INC 2 +#define ACTION_OPERAND_DEC 3 +#define ACTION_RESULT_SHIFT_LEFT 4 +#define ACTION_RESULT_SHIFT_RIGHT 5 +#define ACTION_ADD 6 +#define ACTION_SUBTRACT 7 +#define ACTION_CLEAR 8 +#define ACTION_NULL 9 + +#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 + +tDigit operand[NUM_OPERAND_DIGITS]; +tDigit result[NUM_RESULT_DIGITS]; +tDigit counter[NUM_COUNTER_DIGITS]; + +// Ranges from 0 to 8 +#define RESULT_POS_MIN 0 +#define RESULT_POS_MAX 8 +tDigitPos resultPos; +tDigitPos selectedOperand; + + +#define OPERAND_COLOR COLOR_WHITE +#define OPERAND_OFFSET 4 +#define SLIDER_BAR_COLOR COLOR_BLUE +#define SELECTED_SLIDER_BAR_COLOR COLOR_VIOLET +#define SLIDER_COLOR COLOR_ORANGE +#define SELECTED_SLIDER_COLOR COLOR_BLACK +#define SLIDER_X_BORDER 8 +#define SLIDER_Y_BORDER 15 +#define SLIDER_BAR_WIDTH 12 +#define SLIDER_BAR_HEIGHT 130 +#define SLIDER_BAR_SPACING 20 + +#define SLIDER_X_OFFSET 2 +#define SLIDER_Y_OFFSET 1 +#define SLIDER_WIDTH 8 +#define SLIDER_HEIGHT 11 +#define SLIDER_Y_SPACING (SLIDER_HEIGHT + (2 * SLIDER_Y_OFFSET)) + + +void drawOperand(tDigitPos pos); + + +void clearDevice(void) +{ + tDigitPos pos; + + for (pos = 0; pos < NUM_RESULT_DIGITS; pos++) { + result[pos] = 0; + } + for (pos = 0; pos < NUM_COUNTER_DIGITS; pos++) { + counter[pos] = 0; + } +} + + +void resetDevice(void) +{ + tDigitPos pos; + + clearDevice(); + resultPos = 0; + selectedOperand = 0; + + for (pos = 0; pos < NUM_OPERAND_DIGITS; pos++) { + result[pos] = 0; + } +} + + +void incOperandPos(tDigitPos pos) +{ + if (pos >= NUM_OPERAND_DIGITS) + return; + + if (operand[pos] == 9) + return; + + operand[pos]++; + drawOperand(pos); +} + + +void decOperandPos(tDigitPos pos) +{ + if (pos >= NUM_OPERAND_DIGITS) + return; + + if (operand[pos] == 0) + return; + + operand[pos]--; + drawOperand(pos); +} + + +void shiftOperandPos(bool left) +{ + tDigitPos newPos = selectedOperand; + tDigitPos oldPos = selectedOperand; + + if (left) { + newPos++; + if (newPos >= NUM_OPERAND_DIGITS) { + return; + } + } else { + newPos--; + if (newPos < 0) { + return; + } + } + + selectedOperand = newPos; + drawOperand(oldPos); + drawOperand(newPos); +} + +void shiftResultPos(bool left) +{ + if (left) { + if (resultPos + 1 >= RESULT_POS_MAX) + return; + resultPos++; + } else { + if (resultPos <= RESULT_POS_MIN) + return; + resultPos--; + } +} + + +void subOperation(tDigit *digits, tDigitPos pos, tDigitPos maxPos, tDigit toSub) +{ + if (toSub == 0) + return; + + if (pos >= maxPos) + return; + + digits[pos]-=toSub; + while (digits[pos] < 0) { + digits[pos]+=10; + subOperation(digits, pos+1, maxPos, 1); + } +} + + +void addOperation(tDigit *digits, tDigitPos pos, tDigitPos maxPos, tDigit toAdd) +{ + if (toAdd == 0) + return; + + if (pos >= maxPos) + return; + + digits[pos]+=toAdd; + while (digits[pos] > 9) { + digits[pos]-=10; + addOperation(digits, pos+1, maxPos, 1); + } +} + + +void crank(bool isSubtract) +{ + tDigitPos pos; + if (isSubtract) { + subOperation(counter, resultPos, NUM_COUNTER_DIGITS, 1); + for (pos = 0; pos < NUM_OPERAND_DIGITS; pos++) { + subOperation(result, resultPos+pos, NUM_RESULT_DIGITS, operand[pos]); + } + } else { + addOperation(counter, resultPos, NUM_COUNTER_DIGITS, 1); + for (pos = 0; pos < NUM_OPERAND_DIGITS; pos++) { + addOperation(result, resultPos+pos, NUM_RESULT_DIGITS, operand[pos]); + } + } +} + + +void printDigits(char *label, tDigit *digits, tDigitPos maxPos) +{ + tDigitPos pos; + + printf("%7s:", label); + for(pos = maxPos - 1; pos >= 0; pos--) { + printf(" %d", digits[pos]); + } + printf("\n"); +} + + +void printState(void) +{ + tDigitPos pos; + printDigits("Counter", counter, NUM_COUNTER_DIGITS); + printDigits("Result", result, NUM_RESULT_DIGITS); + + printf(" "); + for(pos = 0; pos < NUM_RESULT_DIGITS - resultPos; pos++) { + printf(" "); + } + printf(" ^\n"); +} + + +void drawOperand(tDigitPos pos) +{ + char xPos; + char buffer[2]; + tDigit digit; + + if (pos < 0) + return; + if (pos >= NUM_OPERAND_DIGITS) + return; + + xPos = SLIDER_X_BORDER + (SLIDER_BAR_SPACING * (NUM_OPERAND_DIGITS - pos - 1)); + digit = operand[pos]; + + // Clear old bar + tgi_setcolor(COLOR_BLACK); + tgi_bar(xPos, 0, xPos + SLIDER_BAR_WIDTH, SLIDER_Y_BORDER + SLIDER_BAR_HEIGHT); + + // Draw text label + buffer[0] = digit + '0'; + buffer[1] = '\0'; + tgi_setcolor(OPERAND_COLOR); + tgi_outtextxy(xPos + OPERAND_OFFSET, 0, buffer); + + // Draw slider bar + if (selectedOperand == pos) { + tgi_setcolor(SELECTED_SLIDER_BAR_COLOR); + } else { + tgi_setcolor(SLIDER_BAR_COLOR); + } + tgi_bar(xPos, SLIDER_Y_BORDER, xPos + SLIDER_BAR_WIDTH, SLIDER_Y_BORDER + SLIDER_BAR_HEIGHT); + + // Draw slider + if (selectedOperand == pos) { + tgi_setcolor(SELECTED_SLIDER_COLOR); + } else { + tgi_setcolor(SLIDER_COLOR); + } + tgi_bar(xPos + SLIDER_X_OFFSET, + SLIDER_Y_BORDER + SLIDER_Y_OFFSET + (SLIDER_Y_SPACING * digit), + xPos + SLIDER_X_OFFSET + SLIDER_WIDTH, + SLIDER_Y_BORDER + SLIDER_Y_OFFSET + (SLIDER_Y_SPACING * digit) + SLIDER_HEIGHT); +} + + +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; + } + } +} + + +tAction getNextAction(void) +{ + static bool firstCall = true; + static char oldJoyState; + static tJoyPos oldJoyPos; + static unsigned int possibleActions = 0xffff; + + char joyState; + tJoyPos joyPos; + tAction result = ACTION_NULL; + + if (firstCall) { + oldJoyState = joy_read(JOY_1); + oldJoyPos = getJoyPos(oldJoyState); + firstCall = false; + return result; + } + + joyState = joy_read(JOY_1); + joyPos = getJoyPos(joyState); + + if ((JOY_BTN_FIRE2(oldJoyState) && + (!JOY_BTN_FIRE2(joyState)))) { + oldJoyState = joyState; + result = ACTION_CLEAR; + } else if (joyPos == oldJoyPos) { + oldJoyState = joyState; + return result; + } else if (oldJoyPos == JOY_POS_CENTER) { + if (joyPos == JOY_POS_LEFT) { + if (JOY_BTN_FIRE(joyState)) { + possibleActions = (1 << ACTION_RESULT_SHIFT_LEFT); + } else { + possibleActions = (1 << ACTION_OPERAND_SHIFT_LEFT); + } + } else if (joyPos == JOY_POS_RIGHT) { + if (JOY_BTN_FIRE(joyState)) { + possibleActions = (1 << ACTION_RESULT_SHIFT_RIGHT); + } else { + possibleActions = (1 << ACTION_OPERAND_SHIFT_RIGHT); + } + } else if (joyPos == JOY_POS_UP) { + possibleActions = (1 << ACTION_OPERAND_DEC); + } else if (joyPos == JOY_POS_DOWN) { + possibleActions = (1 << ACTION_OPERAND_INC); + if (JOY_BTN_FIRE(joyState)) { + possibleActions |= (1 << ACTION_SUBTRACT); + } else { + possibleActions |= (1 << ACTION_ADD); + } + } + } else { + if (possibleActions & (1 << ACTION_OPERAND_SHIFT_LEFT)) { + if (joyPos == JOY_POS_CENTER) { + result = ACTION_OPERAND_SHIFT_LEFT; + } else { + possibleActions &= (~(1 << ACTION_OPERAND_SHIFT_LEFT)); + } + } + + if (possibleActions & (1 << ACTION_OPERAND_SHIFT_RIGHT)) { + if (joyPos == JOY_POS_CENTER) { + result = ACTION_OPERAND_SHIFT_RIGHT; + } else { + possibleActions &= (~(1 << ACTION_OPERAND_SHIFT_RIGHT)); + } + } + + if (possibleActions & (1 << ACTION_OPERAND_INC)) { + if (joyPos == JOY_POS_CENTER) { + result = ACTION_OPERAND_INC; + } else { + possibleActions &= (~(1 << ACTION_OPERAND_INC)); + } + } + + if (possibleActions & (1 << ACTION_OPERAND_DEC)) { + if (joyPos == JOY_POS_CENTER) { + result = ACTION_OPERAND_DEC; + } else { + possibleActions &= (~(1 << ACTION_OPERAND_DEC)); + } + } + + if (possibleActions & (1 << ACTION_RESULT_SHIFT_LEFT)) { + if (joyPos == JOY_POS_CENTER) { + result = ACTION_RESULT_SHIFT_LEFT; + } else { + possibleActions &= (~(1 << ACTION_RESULT_SHIFT_LEFT)); + } + } + + if (possibleActions & (1 << ACTION_RESULT_SHIFT_RIGHT)) { + if (joyPos == JOY_POS_CENTER) { + result = ACTION_RESULT_SHIFT_RIGHT; + } else { + possibleActions &= (~(1 << ACTION_RESULT_SHIFT_RIGHT)); + } + } + + if (possibleActions & (1 << ACTION_ADD)) { + if ((joyPos == JOY_POS_DOWN) && + (oldJoyPos == JOY_POS_DOWN_RIGHT)) { + result = ACTION_ADD; + possibleActions = 0; + } else if (joyPos != oldJoyPos + 1) { + possibleActions &= (~(1 << ACTION_ADD)); + } + } else if (possibleActions & (1 << ACTION_SUBTRACT)) { + if ((joyPos == JOY_POS_DOWN) && + (oldJoyPos == JOY_POS_DOWN_RIGHT)) { + result = ACTION_SUBTRACT; + possibleActions = 0; + } else if (joyPos != oldJoyPos + 1) { + possibleActions &= (~(1 << ACTION_SUBTRACT)); + } + } + + if (joyPos == JOY_POS_CENTER) { + possibleActions = -1; + } + } + + oldJoyPos = joyPos; + oldJoyState = joyState; + + return result; +} + + +void graphicalInterface(void) +{ + // Install drivers + tDigitPos pos; + + joy_install(&a2e_stdjoy); + tgi_install(&a2e_hi); + + tgi_init(); + tgi_clear(); + for (pos = 0; pos < NUM_OPERAND_DIGITS; pos++) { + drawOperand(pos); + } + + // Mixed text and graphics mode + asm ("STA %w", 0xc053); + printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); + printState(); + + while (true) { + if ((kbhit()) && + (cgetc() == ' ')) { + break; + } + switch (getNextAction()) { + case ACTION_NULL: + break; + case ACTION_OPERAND_SHIFT_LEFT: + shiftOperandPos(true); + break; + + case ACTION_OPERAND_SHIFT_RIGHT: + shiftOperandPos(false); + break; + + case ACTION_OPERAND_INC: + incOperandPos(selectedOperand); + break; + + case ACTION_OPERAND_DEC: + decOperandPos(selectedOperand); + break; + + case ACTION_RESULT_SHIFT_LEFT: + shiftResultPos(true); + printState(); + break; + + case ACTION_RESULT_SHIFT_RIGHT: + shiftResultPos(false); + printState(); + break; + + case ACTION_ADD: + crank(false); + printState(); + break; + + case ACTION_SUBTRACT: + crank(true); + printState(); + break; + + case ACTION_CLEAR: + clearDevice(); + printState(); + break; + } + } + + // Uninstall drivers + tgi_uninstall(); + joy_uninstall(); +} + + +int main(void) +{ + graphicalInterface(); + return 0; +}