mirror of
https://github.com/jeremysrand/CurtaSim.git
synced 2024-09-25 15:54:24 +00:00
171 lines
3.1 KiB
C
171 lines
3.1 KiB
C
|
//
|
||
|
// Author: Jeremy Rand
|
||
|
// Date: July 20, 2012
|
||
|
//
|
||
|
// This is the implementation for the Curta emulator model.
|
||
|
//
|
||
|
|
||
|
|
||
|
#include <stddef.h>
|
||
|
|
||
|
#include "curtaModel.h"
|
||
|
|
||
|
|
||
|
tDigit operand[NUM_OPERAND_DIGITS];
|
||
|
tDigit result[NUM_RESULT_DIGITS];
|
||
|
tDigit counter[NUM_COUNTER_DIGITS];
|
||
|
|
||
|
tDigitPos basePos;
|
||
|
|
||
|
tDigitPos selectedOperand;
|
||
|
|
||
|
|
||
|
static operandChangeNotif operandCallback = NULL;
|
||
|
|
||
|
|
||
|
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 initDevice(operandChangeNotif callback)
|
||
|
{
|
||
|
tDigitPos pos;
|
||
|
|
||
|
operandCallback = callback;
|
||
|
|
||
|
clearDevice();
|
||
|
basePos = 0;
|
||
|
selectedOperand = 0;
|
||
|
|
||
|
for (pos = 0; pos < NUM_OPERAND_DIGITS; pos++) {
|
||
|
result[pos] = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void incOperandPos(tDigitPos pos)
|
||
|
{
|
||
|
if (!IS_VALID_OPERAND_POS(pos))
|
||
|
return;
|
||
|
|
||
|
if (operand[pos] == 9)
|
||
|
return;
|
||
|
|
||
|
operand[pos]++;
|
||
|
if (operandCallback != NULL)
|
||
|
operandCallback(pos);
|
||
|
}
|
||
|
|
||
|
|
||
|
void decOperandPos(tDigitPos pos)
|
||
|
{
|
||
|
if (!IS_VALID_OPERAND_POS(pos))
|
||
|
return;
|
||
|
|
||
|
if (operand[pos] == 0)
|
||
|
return;
|
||
|
|
||
|
operand[pos]--;
|
||
|
if (operandCallback != NULL)
|
||
|
operandCallback(pos);
|
||
|
}
|
||
|
|
||
|
|
||
|
void shiftOperandPos(bool left)
|
||
|
{
|
||
|
tDigitPos newPos = selectedOperand;
|
||
|
tDigitPos oldPos = selectedOperand;
|
||
|
|
||
|
if (left) {
|
||
|
newPos++;
|
||
|
if (!IS_VALID_OPERAND_POS(newPos)) {
|
||
|
return;
|
||
|
}
|
||
|
} else {
|
||
|
newPos--;
|
||
|
if (!IS_VALID_OPERAND_POS(newPos)) {
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
selectedOperand = newPos;
|
||
|
if (operandCallback != NULL) {
|
||
|
operandCallback(oldPos);
|
||
|
operandCallback(newPos);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void shiftResultPos(bool left)
|
||
|
{
|
||
|
tDigitPos newPos = basePos;
|
||
|
if (left) {
|
||
|
newPos++;
|
||
|
if (!IS_VALID_BASE_POS(newPos))
|
||
|
return;
|
||
|
} else {
|
||
|
newPos--;
|
||
|
if (!IS_VALID_BASE_POS(newPos))
|
||
|
return;
|
||
|
}
|
||
|
basePos = newPos;
|
||
|
}
|
||
|
|
||
|
|
||
|
static 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);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
static 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, basePos, NUM_COUNTER_DIGITS, 1);
|
||
|
for (pos = 0; pos < NUM_OPERAND_DIGITS; pos++) {
|
||
|
subOperation(result, basePos+pos, NUM_RESULT_DIGITS, operand[pos]);
|
||
|
}
|
||
|
} else {
|
||
|
addOperation(counter, basePos, NUM_COUNTER_DIGITS, 1);
|
||
|
for (pos = 0; pos < NUM_OPERAND_DIGITS; pos++) {
|
||
|
addOperation(result, basePos+pos, NUM_RESULT_DIGITS, operand[pos]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|