Merge branch 'srtlg/development-trigonometric'

This commit is contained in:
Jeff Wang 2020-09-13 02:06:33 -04:00
commit 5f6a375c06
21 changed files with 804 additions and 116 deletions

View File

@ -3,6 +3,12 @@ project(stc_rpncalc C CXX)
# 3rd party tools
find_package(Qt5 COMPONENTS Widgets Qml Quick REQUIRED)
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
message(STATUS "using address sanitizer")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls")
link_libraries(asan)
endif()
set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Build type (for tests debug make sense)")
# Compiler warnings

View File

@ -1,11 +1,12 @@
SDCC ?= sdcc
STCCODESIZE ?= 13312
SDCCOPTS ?= --code-size $(STCCODESIZE) --xram-size 256 --idata-loc 0x80
SDCCOPTS ?= --code-size $(STCCODESIZE) --xram-size 256 --idata-loc 0x70
#SDCCOPTS ?= --code-size $(STCCODESIZE) --xram-size 256 --stack-auto --model-large
FLASHFILE ?= main.hex
LARGE_LDFLAGS += -L/usr/share/sdcc/lib/large/
# CFLAGS += -DSTACK_DEBUG # write the stack pointer to P3_4
SRC = src/lcd.c src/key.c src/utils.c src/decn/decn.c src/calc.c
SRC = src/lcd.c src/key.c src/utils.c src/decn/decn.c src/calc.c src/stack_debug.c
OBJ=$(patsubst src%.c,build%.rel, $(SRC))
@ -13,7 +14,7 @@ all: main
build/%.rel: src/%.c src/%.h
mkdir -p $(dir $@)
$(SDCC) $(SDCCOPTS) -o $@ -c $<
$(SDCC) $(SDCCOPTS) $(CFLAGS) -o $@ -c $<
main: $(OBJ)
$(SDCC) -o build/ src/$@.c $(SDCCOPTS) $(CFLAGS) $^
@ -21,7 +22,7 @@ main: $(OBJ)
@ tail -n 5 build/main.mem | head -n 2
@ tail -n 1 build/main.mem
cp build/$@.ihx $@.hex
eeprom:
sed -ne '/:..1/ { s/1/0/2; p }' main.hex > eeprom.hex

View File

@ -1,6 +1,6 @@
# STC DIY Calculator Firmware
This is a replacement firmware for the [diyleyuan calculator kit](http://www.diyleyuan.com/jc/L8Q.html). The calculator kit is available for purchase for less than $13 shipped from eBay by searching for "diy calculator kit". You will have to solder the kit yourself (see "hardware connections" below). The calculator uses an STC IAP15W413AS microcontroller (an 8051 instruction set-compatible microcontroller) with a built-in serial-port bootloader. See the series [summary](http://www.stcmicro.com/datasheet/STC15W408AS_Features.pdf) and full english [datasheet](https://www.stcmicro.com/datasheet/STC15F2K60S2-en.pdf). This project uses [SDCC](http://sdcc.sourceforge.net/) to compile the C code and [stcgal](https://github.com/grigorig/stcgal) to load the new firmware.
This is a replacement firmware for the [diyleyuan calculator kit](http://www.diyleyuan.com/jc/L8Q.html). The calculator kit is available for purchase for less than $13 shipped from eBay by searching for "diy calculator kit" (price has increased recently, currently closer to $18 shipped). You will have to solder the kit yourself (see "hardware connections" below). The calculator uses an STC IAP15W413AS microcontroller (an 8051 instruction set-compatible microcontroller) with a built-in serial-port bootloader. See the series [summary](http://www.stcmicro.com/datasheet/STC15W408AS_Features.pdf) and full english [datasheet](https://www.stcmicro.com/datasheet/STC15F2K60S2-en.pdf). This project uses [SDCC](http://sdcc.sourceforge.net/) to compile the C code and [stcgal](https://github.com/grigorig/stcgal) to load the new firmware.
The replacement firmware supports floating-point calculations (using 18 decimal digits plus exponent for arithmetic) with a 4-level RPN stack. Functions include basic arithmetic as well as log(), exp(), y^x, 1/x and sqrt(), all in floating point. (The original firmware supported only fixed-point calculations in chain mode.) I have not added in the resistor value calculator or the decimal/hexadecimal converter features from the original firmware.
@ -74,15 +74,26 @@ The keys on the *original* calculator map as follows:
- The 2nd press begins exponent entry.
- The 3rd and subsequent presses negates the current exponent being entered.
- Acts as STO when shifted (there is only 1 memory register)
- `mode `: acts as a shift key
- `mode `: acts as a shift key (press multiple times to toggle between shift up, shift down, and no shift)
- `ON/AC`: acts as a backspace key during digit entry, acts as `Clear X` when digit entry is finished (e.g. after an operator key is pressed)
- acts as `Clear X` when shifted
- `7 `: acts as y^x when shifted
- `8 `: acts as ln(x) when shifted
- `9 `: acts as log(x) when shifted
- `÷ `: acts as pi when shifted
- `4 `: acts as roll down when shifted
- acts as roll up when shifted down
- `5 `: acts as e^x when shifted
- `6 `: acts as 10^x when shifted
- `4 `: acts as roll down when shifted
- `1 `: acts as sin(x) when shifted
- acts as asin(x) when shifted down
- `2 `: acts as cos(x) when shifted
- acts as acos(x) when shifted down
- `3 `: acts as tan(x) when shifted
- acts as atan(x) when shifted down
- all trig functions are currently calculated in degrees
- `- `: acts as to radians when shifted
- acts as to degrees when shifted down
- `+ `: acts as LastX when shifted
- `0 `: acts as off button when shifted
@ -240,6 +251,8 @@ Disconnected!
# Bugs
1. After division by 0, ln(-), over/underflow, or other operations which give an `Error`, it's possible to still do certain operations on `Error`. Many functions do check, and will not operate on `Error`, but not all of them yet. This is somewhat similar to old soviet Elektronika calculators where `Error` is just a number, and there wasn't enough ROM space to check for errors. (There are people who explore the inner-workings of these calculators by manipulating the `Error` "number".)
1. When shifted down, keys which do not have a shifted-down function will instead be interpreted as if there were no shift.
1. Trigonometric functions are extremely slow and inaccurate.
1. There are probably more bugs waiting to be discovered.
# Internals
@ -288,10 +301,11 @@ The number `0.135` would be stored the same way, except now the exponent is `0x7
- see `src/decn/proto/exp.cpp` for initial prototyping development work
- Powers are calculated using the identity y^x = e^(x*ln(y))
- Square roots are calculated using the identity sqrt(x) = e^(0.5*ln(x))
- Trigonometric functions are calculated using algorithms similar to the [sinclair scientific](http://files.righto.com/calculator/sinclair_scientific_simulator.html), and are fairly slow and inaccurate.
## TODO
- Trigonometric functions could be implemented with algorithms similar to those described in the HP Journal articles "Personal Calculator Algorithms II: Trigonometric Functions" and "Personal Calculator Algorithms III: Inverse Trigonometric Functions", both by William Egbert.
- will probably assign to the shifted `1`, `2`, and `3` keys, and `-` for calculating inverse trig functions.
- Trigonometric functions could be implemented with algorithms similar to those used in Valentin Albillo's [implementation](http://www.hpcc.org/datafile/hp12/12c_TrigonometryFunctions.pdf) for the HP 12C, but would take more flash
- These could also use the implementation described in the HP Journal articles "Personal Calculator Algorithms II: Trigonometric Functions" and "Personal Calculator Algorithms III: Inverse Trigonometric Functions", both by William Egbert. This would likely take even more flash though.
- Special cases, such as taking the logarithms of numbers near 1, negative number raised to integer powers, etc. could be implemented separately, similar to what is described in the HP Journal note "The New Accuracy: Making 2^3 = 8" by Dennis Harms.
- The display blanking for trailing 0s assumes that 16 digits will actually be displayed, but this might not be the case if the negative sign, decimal point, or exponents are displayed
- Would be nice to have the `hex <=> dec` converter from the original firmware if there is more flash space
@ -313,7 +327,7 @@ In practice, the keyboard debouncing works much better than the original firmwar
# Implementation on an STC 8051 Microcontroller
This was my 1st time using an 8051 microcontroller. The architecture is a bit limiting for programming in "high-level" languages such as C compared to more modern architectures -- even compared to other 8-bit architectures such as the AVR (used in the arduino). Most significantly, there is no stack-pointer-relative addressing, which makes C functions takes up a lot of code space, since they have to emulate stack-pointer-relative addressing. Unfortunately, the microcontroller used only has 13K of code space. The compiler used (SDCC) also does not support using a 2nd data pointer, even though STC's implementation of the 8051 has one.
I've avoided relying on the functions being able to be re-entrant, so that they do not depend on having a stack. SDCC is *not* set to use `--stack-auto` to reduce code size (this means functions are not re-entrant). Some "large" local variables are declared as static in functions to save on the code space needed to emulate a stack. I used a lot more globals than I what I would typically like to have used, and a lot less pointers passed to functions, since these are extremely expensive (to account for the 3 different memory types).
I've avoided relying on the functions being able to be re-entrant, so that they do not depend on having a stack. SDCC is *not* set to use `--stack-auto` to reduce code size (this means functions are not re-entrant). Some "large" local variables are declared as static in functions to save on the code space needed to emulate a stack. I used a lot more globals than what I would typically like to have used, and a lot less pointers passed to functions, since these are extremely expensive (to account for the 3 different memory types).
Another weird thing about the 8051 is that not all of the memory is addressed the same way. On this microcontroller, there are 512 bytes of ram total, of which:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 67 KiB

View File

@ -121,7 +121,7 @@ ApplicationWindow
horizontalAlignment: Text.AlignHCenter
font.pointSize: 16
color: "gray"
text: {getShiftedText(parent.parent.objectName, index) + "<br><br>"}
text: {getShiftedUpText(parent.parent.objectName, index) + "<br><br>"}
textFormat: Text.RichText
anchors.centerIn: parent
}
@ -132,6 +132,14 @@ ApplicationWindow
textFormat: Text.RichText
anchors.centerIn: parent
}
Text {
horizontalAlignment: Text.AlignHCenter
font.pointSize: 16
color: "gray"
text: {"<br><br>" + getShiftedDownText(parent.parent.objectName, index)}
textFormat: Text.RichText
anchors.centerIn: parent
}
MouseArea {
//get row/column
onClicked: _calculator.buttonClicked(parent.parent.objectName + "," + index)
@ -155,18 +163,30 @@ ApplicationWindow
return "<b>" + keys[row][col] + "</b>"
}
function getShiftedText(row, col) {
function getShiftedUpText(row, col) {
var shifted_keys = [
["Shift", "1/x", " √<span style=\"text-decoration: overline\">x</span> ", "CL<i>x</i>"],
["y<sup>x</sup> ", "ln(x)", "log(x)", ""],
["🔃", "e<sup>x</sup>", "10<sup>x</sup>", ""],
["", "", "", ""],
["y<sup>x</sup> ", "ln(x)", "log(x)", "π"],
["R▼", "e<sup>x</sup>", "10<sup>x</sup>", ""],
["sin(x)", "cos(x)", "tan(x)", "►rad"],
["off", "STO", "RCL", "LAST<i>x</i>"]
]
return "<small>" + shifted_keys[row][col] + "</small>"
}
function getShiftedDownText(row, col) {
var shifted_keys = [
["", "", "", ""],
["", "", "", ""],
["R▲", "", "", ""],
["asin(x)", "acos(x)", "atan(x)", "►deg"],
["", "", "", ""]
]
return "<small>" + shifted_keys[row][col] + "</small>"
}
function getBackgroundColor(row, col) {
var background_color = [
["white", "white", "white", "#ff9494"],

View File

@ -21,6 +21,11 @@
#include "utils.h"
#include "calc.h"
#include "stack_debug.h"
#ifdef DESKTOP
#include <assert.h>
#endif
__xdata dec80 StoredDecn;
__xdata dec80 LastX;
@ -33,7 +38,8 @@ __xdata dec80 LastX;
#define STACK_T 3
uint8_t NoLift = 0;
__bit IsShifted = 0;
__bit IsShiftedUp = 0;
__bit IsShiftedDown = 0;
//stack "grows" towards 0
__xdata dec80 Stack[STACK_SIZE]; //0->x, 1->y, 2->z, 3->t initially
@ -87,10 +93,6 @@ static void do_unary_op(void (*f_ptr)(void)){
}
}
static void toggle_shifted(void){
IsShifted ^= 1;
}
void process_cmd(char cmd){
//turn off backlight before start of processing
backlight_off();
@ -98,12 +100,11 @@ void process_cmd(char cmd){
switch(cmd){
//////////
case '+':{
if (IsShifted){ // LastX
if (IsShiftedUp){ // LastX
if (NoLift != 1){
StackPtr--;
}
copy_decn(&stack(STACK_X), &LastX);
IsShifted = 0;
} else { // +
do_binary_op(add_decn);
}
@ -114,22 +115,33 @@ void process_cmd(char cmd){
} break;
//////////
case '-':{
negate_decn(&stack(STACK_X));
do_binary_op(add_decn);
negate_decn(&LastX); //stored LastX was after negation of X
if (IsShiftedUp) {
do_unary_op(to_radian_decn);
} else if (IsShiftedDown) {
do_unary_op(to_degree_decn);
} else {
negate_decn(&stack(STACK_X));
do_binary_op(add_decn);
negate_decn(&LastX); //stored LastX was after negation of X
}
} break;
//////////
case '/':{
do_binary_op(div_decn);
if (IsShiftedUp){
StackPtr--;
pi_decn();
copy_decn(&stack(STACK_X), &AccDecn);
} else {
do_binary_op(div_decn);
}
} break;
//////////
case '=':{
if (IsShifted){ //RCL
if (IsShiftedUp){ //RCL
if (NoLift != 1){
StackPtr--;
}
copy_decn(&stack(STACK_X), &StoredDecn);
IsShifted = 0;
} else { //Enter
if (!decn_is_nan(&stack(STACK_X))){
StackPtr--;
@ -139,9 +151,8 @@ void process_cmd(char cmd){
} break;
//////////
case '.':{
if (IsShifted){ //STO
if (IsShiftedUp){ //STO
copy_decn(&StoredDecn, &stack(STACK_X));
IsShifted = 0;
}
} break;
//////////
@ -150,23 +161,8 @@ void process_cmd(char cmd){
} break;
//////////
case '<':{ //use as +/- and sqrt
if (IsShifted){ //take sqrt
IsShifted = 0;
if (decn_is_zero(&stack(STACK_X))){
//sqrt(0) = 0
} else if (!decn_is_nan(&stack(STACK_X))){
copy_decn(&LastX, &stack(STACK_X)); //save LastX
copy_decn(&AccDecn, &stack(STACK_X));
if (AccDecn.exponent < 0){ //negative
set_dec80_NaN(&stack(STACK_X));
break;
}
//b = 0.5
set_dec80_zero(&BDecn);
BDecn.lsu[0] = 5;
pow_decn();
copy_decn(&stack(STACK_X), &AccDecn);
}
if (IsShiftedUp){ //take sqrt
do_unary_op(sqrt_decn);
} else { // +/-
if (!decn_is_nan(&stack(STACK_X))){
negate_decn(&stack(STACK_X));
@ -175,55 +171,84 @@ void process_cmd(char cmd){
} break;
//////////
case 'r':{ //use as swap and 1/x
if (IsShifted){ //take 1/x
IsShifted = 0;
if (IsShiftedUp){ //take 1/x
do_unary_op(recip_decn);
} else { // swap
if (!decn_is_nan(&stack(STACK_X))){
dec80 tmp;
copy_decn(&tmp, &stack(STACK_X));
copy_decn(&AccDecn, &stack(STACK_X));
copy_decn(&stack(STACK_X), &stack(STACK_Y));
copy_decn(&stack(STACK_Y), &tmp);
copy_decn(&stack(STACK_Y), &AccDecn);
}
}
} break;
//////////
case 'm':{ //use as shift
toggle_shifted();
if (IsShiftedUp) {
IsShiftedUp = 0;
IsShiftedDown = 1;
} else if (IsShiftedDown) {
IsShiftedUp = 0;
IsShiftedDown = 0;
} else {
IsShiftedUp = 1;
IsShiftedDown = 0;
}
return;
} break;
//////////
case '1':{
if (IsShiftedUp){
do_unary_op(sin_decn);
} else if (IsShiftedDown){
do_unary_op(arcsin_decn);
}
} break;
//////////
case '2':{
if (IsShiftedUp){
do_unary_op(cos_decn);
} else if (IsShiftedDown){
do_unary_op(arccos_decn);
}
} break;
//////////
case '3':{
if (IsShiftedUp){
do_unary_op(tan_decn);
} else if (IsShiftedDown){
do_unary_op(arctan_decn);
}
} break;
//////////
case '4':{
if (IsShifted){ //roll down
if (IsShiftedUp){ //roll down
StackPtr++;
IsShifted = 0;
} else if (IsShiftedDown){ //roll up
StackPtr--;
}
} break;
//////////
case '5':{
if (IsShifted){ //e^x
if (IsShiftedUp){ //e^x
do_unary_op(exp_decn);
IsShifted = 0;
}
} break;
//////////
case '6':{
if (IsShifted){ //10^x
if (IsShiftedUp){ //10^x
do_unary_op(exp10_decn);
IsShifted = 0;
}
} break;
//////////
case '9':{
if (IsShifted){ //log10(x)
if (IsShiftedUp){ //log10(x)
do_unary_op(log10_decn);
IsShifted = 0;
}
} break;
//////////
case '8':{
if (IsShifted){ //ln(x)
if (IsShiftedUp){ //ln(x)
do_unary_op(ln_decn);
IsShifted = 0;
}
} break;
//////////
@ -238,10 +263,14 @@ void process_cmd(char cmd){
copy_decn(&stack(STACK_Y), &AccDecn);
}
pop();
IsShifted = 0;
} break;
//////////
} //switch(cmd)
IsShiftedUp = 0;
IsShiftedDown = 0;
#ifdef DESKTOP
assert(TmpStackPtr == 0); // there should be no items on the temporaries stack after one global operation
#endif
}

View File

@ -32,7 +32,8 @@ void process_cmd(char cmd);
//push_decn is equivalent to "set_x()" if no_lift is true
void push_decn(__xdata const char* signif_str, __xdata exp_t exponent);
extern uint8_t NoLift;
extern __bit IsShifted;
extern __bit IsShiftedUp;
extern __bit IsShiftedDown;
void clear_x(void);
__xdata dec80* get_x(void);

View File

@ -12,7 +12,7 @@ target_compile_options(coverage_config INTERFACE -O0 -g --coverage)
target_link_libraries(coverage_config INTERFACE --coverage)
# decn library
add_library(decn decn.c)
add_library(decn decn.c ../utils.c)
# decn library with coverage
add_library(decn_cover decn.c)
@ -21,7 +21,7 @@ target_link_libraries(decn_cover PUBLIC coverage_config)
add_executable(decn_test decn_test.c ../utils.c)
target_link_libraries(decn_test decn_cover coverage_config Catch)
add_executable(decn_tests catch_main.cpp decn_tests.cpp ../utils.c)
add_executable(decn_tests catch_main.cpp decn_tests.cpp decn_tests_trig.cpp ../utils.c)
target_link_libraries(decn_tests decn_cover coverage_config mpfr Catch)
# decn prototyping

View File

@ -19,6 +19,7 @@
*/
#include "../utils.h"
#include "../stack_debug.h"
#include "decn.h"
@ -66,10 +67,14 @@ static const uint8_t num_digits_display = 16;
dec80 AccDecn;
__idata dec80 BDecn;
__idata dec80 TmpDecn; //used by add_decn() and mult_decn()
__idata dec80 Tmp2Decn; //used by recip_decn() and ln_decn()
__idata dec80 Tmp3Decn; //used by recip_decn() and ln_decn()
__xdata dec80 Tmp4Decn; //used by div_decn() and pow_decn()
__idata dec80 TmpDecn; //used by add_decn() and mult_decn() and sqrt_decn()
__idata dec80 Tmp2Decn; //used by recip_decn() and ln_decn() and sincos_decn() and sqrt_decn()
__xdata dec80 Tmp3Decn; //used by recip_decn() and ln_decn() and sincos_decn() and sqrt_decn()
__xdata dec80 Tmp4Decn; //used by sincos_decn()
__xdata dec80 TmpStackDecn[4];
#define TMP_STACK_SIZE (sizeof TmpStackDecn / sizeof TmpStackDecn[0])
__idata uint8_t TmpStackPtr;
__xdata char Buf[DECN_BUF_SIZE];
@ -83,9 +88,45 @@ const dec80 DECN_LN_10 = {
0, {23, 2, 58, 50, 92, 99, 40, 45, 68}
};
// 2 pi
const dec80 DECN_2PI = {
0, {62, 83, 18, 53, 7, 17, 95, 86, 48}
};
// pi/2
const dec80 DECN_PI2 = {
0, {15, 70, 79, 63, 26, 79, 48, 96, 62}
};
// 180/pi = 1rad in degree
const dec80 DECN_1RAD = {
1, {57, 29, 57, 79, 51, 30, 82, 32, 9}
};
void st_push_decn(const dec80 * const src)
{
copy_decn(&TmpStackDecn[TmpStackPtr], src);
TmpStackPtr++;
assert(TmpStackPtr < TMP_STACK_SIZE);
}
void st_pop_decn(dec80 * const dst)
{
assert(TmpStackPtr >= 1);
TmpStackPtr--;
if (dst) copy_decn(dst, &TmpStackDecn[TmpStackPtr]);
}
void st_load_decn(dec80 * const dst)
{
assert(TmpStackPtr >= 1);
copy_decn(dst, &TmpStackDecn[TmpStackPtr - 1]);
}
void copy_decn(dec80* const dest, const dec80* const src){
uint8_t i;
stack_debug(0x01);
dest->exponent = src->exponent;
//copy nibbles
@ -163,6 +204,7 @@ static void remove_leading_zeros(dec80* x){
uint8_t is_negative = (x->exponent < 0);
exp_t exponent = get_exponent(x);
stack_debug(0x02);
//find first non-zero digit100
for (digit100 = 0; digit100 < DEC80_NUM_LSU; digit100++){
if (x->lsu[digit100] != 0){
@ -586,6 +628,7 @@ void add_decn(void){
return;
}
//save b for restoring later
//n.b. don't use TmpStackDecn here, it is called quite often. So you'd need to increase TMP_STACK_SIZE
copy_decn(&TmpDecn, &BDecn);
//handle cases where signs differ
if (AccDecn.exponent < 0 && BDecn.exponent >= 0){
@ -792,7 +835,6 @@ void mult_decn(void){
void recip_decn(void){
#define CURR_RECIP Tmp2Decn //copy of x, holds current 1/x estimate
#define X_COPY Tmp3Decn //holds copy of original x
uint8_t i;
exp_t initial_exp;
//check divide by zero
@ -808,7 +850,7 @@ void recip_decn(void){
//normalize
remove_leading_zeros(&AccDecn);
//store copy of x
copy_decn(&X_COPY, &AccDecn);
st_push_decn(&AccDecn);
//get initial exponent of estimate for 1/x
initial_exp = get_exponent(&AccDecn);
#ifdef DEBUG_DIV
@ -841,7 +883,7 @@ void recip_decn(void){
printf("%2d: %s\n", i, Buf);
#endif
//Accum *= x_copy
copy_decn(&BDecn, &X_COPY);
st_load_decn(&BDecn);
mult_decn();
#ifdef DEBUG_DIV
decn_to_str_complete(&AccDecn);
@ -868,24 +910,20 @@ void recip_decn(void){
//new_est(Accum) = recip + (1 - recip*x)*recip, where recip is current recip estimate
copy_decn(&CURR_RECIP, &AccDecn);
}
st_pop_decn(0);
//try not to pollute namespace
#undef CURR_RECIP
#undef X_COPY
}
inline void div_decn(void){
#define ACC_COPY Tmp4Decn //holds copy of original acc
void div_decn(void){
//store copy of acc for final multiply by 1/x
copy_decn(&ACC_COPY, &AccDecn);
st_push_decn(&AccDecn);
copy_decn(&AccDecn, &BDecn);
recip_decn();
//Accum now holds 1/x, multiply by original acc to complete division
copy_decn(&BDecn, &ACC_COPY);
st_pop_decn(&BDecn);
mult_decn();
//try not to pollute namespace
#undef ACC_COPY
}
@ -1056,7 +1094,7 @@ void ln_decn(void){
#undef NUM_TIMES
}
inline void log10_decn(void){
void log10_decn(void){
ln_decn();
copy_decn(&BDecn, &DECN_LN_10);
div_decn();
@ -1226,14 +1264,14 @@ void exp_decn(void){
#undef NUM_TIMES
}
inline void exp10_decn(void){
void exp10_decn(void){
//exp10_decn() = exp_decn(AccDecn * ln(10))
copy_decn(&BDecn, &DECN_LN_10);
mult_decn();
exp_decn();
}
inline void pow_decn(void) {
void pow_decn(void) {
if (decn_is_zero(&BDecn)) {
copy_decn(&AccDecn, &DECN_1);
return;
@ -1243,13 +1281,189 @@ inline void pow_decn(void) {
return;
}
//calculate AccDecn = AccDecn ^ BDecn
copy_decn(&Tmp4Decn, &BDecn); //save b
st_push_decn(&BDecn);
ln_decn();
copy_decn(&BDecn, &Tmp4Decn); //restore b
st_pop_decn(&BDecn);
mult_decn(); //accum = b*ln(accum)
exp_decn();
}
// see W.E. Egbert, "Personal Calculator Algorithms II: Trigonometric functions"
void project_decn_into_0_2pi(void) {
const uint8_t is_negative = (AccDecn.exponent < 0);
exp_t exponent;
remove_leading_zeros(&AccDecn);
if (is_negative) {
negate_decn(&AccDecn);
}
exponent = get_exponent(&AccDecn);
copy_decn(&BDecn, &DECN_2PI);
if (compare_magn() > 0) {
do {
do {
copy_decn(&BDecn, &DECN_2PI);
BDecn.exponent = exponent;
if (compare_magn() >= 0) {
negate_decn(&BDecn);
add_decn();
} else {
break;
}
} while (1);
exponent--;
} while (exponent >= 0);
}
if (is_negative) {
negate_decn(&AccDecn);
copy_decn(&BDecn, &DECN_2PI);
add_decn();
}
}
// K. Shirriff, "Reversing Sinclair's amazing 1974 calculator hack - half the ROM of the HP-35"
// http://files.righto.com/calculator/sinclair_scientific_simulator.html
#define SIN Tmp2Decn
#define COS Tmp3Decn
#define THETA Tmp4Decn
void sincos_decn(const uint8_t sincos_arctan) {
const uint8_t is_negative = AccDecn.exponent < 0;
if (sincos_arctan) {
set_dec80_zero(&THETA);
if (is_negative) negate_decn(&AccDecn);
copy_decn(&COS, &AccDecn);
copy_decn(&SIN, &DECN_1);
} else {
project_decn_into_0_2pi();
copy_decn(&THETA, &AccDecn);
copy_decn(&COS, &DECN_1);
set_dec80_zero(&SIN);
// 0.0 00 5
SIN.lsu[2] = 50;
negate_decn(&SIN);
}
do {
if (sincos_arctan) {
// THETA is in AccDecn from previous iteration
if (COS.exponent < 0) {
if (is_negative) negate_decn(&AccDecn);
break;
}
} else {
if (THETA.exponent < 0) {
break;
}
}
// COS = COS - SIN / 1000
copy_decn(&AccDecn, &COS);
copy_decn(&BDecn, &SIN);
shift_right(&BDecn);
shift_right(&BDecn);
shift_right(&BDecn);
negate_decn(&BDecn);
add_decn();
copy_decn(&COS, &AccDecn);
// SIN = SIN + COS / 1000
copy_decn(&AccDecn, &SIN);
copy_decn(&BDecn, &COS);
shift_right(&BDecn);
shift_right(&BDecn);
shift_right(&BDecn);
add_decn();
copy_decn(&SIN, &AccDecn);
// THETA = THETA -/+ 0.0 01
copy_decn(&AccDecn, &THETA);
set_dec80_zero(&BDecn);
BDecn.lsu[1] = 1;
if (!sincos_arctan) negate_decn(&BDecn);
add_decn();
copy_decn(&THETA, &AccDecn);
} while (1);
}
void sin_decn(void) {
sincos_decn(0);
copy_decn(&AccDecn, &SIN);
}
void cos_decn(void) {
sincos_decn(0);
copy_decn(&AccDecn, &COS);
}
void tan_decn(void) {
sincos_decn(0);
copy_decn(&AccDecn, &SIN);
copy_decn(&BDecn, &COS);
div_decn();
}
void arctan_decn(void) {
sincos_decn(1);
}
// see W.E. Egbert, "Personal Calculator Algorithms III: Inverse Trigonometric Functions"
void arcsin_decn(void) {
st_push_decn(&AccDecn);
copy_decn(&BDecn, &AccDecn);
mult_decn();
negate_decn(&AccDecn);
copy_decn(&BDecn, &DECN_1);
add_decn();
sqrt_decn();
recip_decn();
st_pop_decn(&BDecn);
mult_decn();
sincos_decn(1);
}
void arccos_decn(void) {
arcsin_decn();
negate_decn(&AccDecn);
copy_decn(&BDecn, &DECN_PI2);
add_decn();
}
#undef SIN
#undef COS
#undef THETA
void to_degree_decn(void) {
copy_decn(&BDecn, &DECN_1RAD);
mult_decn();
}
void to_radian_decn(void) {
copy_decn(&BDecn, &DECN_1RAD);
div_decn();
}
void pi_decn(void) {
set_dec80_zero(&BDecn);
BDecn.lsu[0] = 5; // 0.5 00 ..
copy_decn(&AccDecn, &DECN_2PI);
mult_decn();
}
void sqrt_decn(void) {
if (decn_is_zero(&AccDecn)) {
return;
}
if (decn_is_nan(&AccDecn)) {
return;
}
if (AccDecn.exponent < 0){ //negative
set_dec80_NaN(&AccDecn);
return;
}
st_push_decn(&BDecn); // sqrt should behave like an unary operation
//b = 0.5
set_dec80_zero(&BDecn);
BDecn.lsu[0] = 5;
pow_decn();
st_pop_decn(&BDecn);
}
static void set_str_error(void){
Buf[0] = 'E';
@ -1444,4 +1658,3 @@ void build_decn_at(dec80* dest, const char* signif_str, exp_t exponent){
#endif //DESKTOP

View File

@ -64,7 +64,7 @@ void copy_decn(dec80* const dest, const dec80* const src);
extern dec80 AccDecn;
extern __idata dec80 BDecn;
extern __xdata dec80 Tmp4Decn;
extern __idata uint8_t TmpStackPtr;
void build_dec80(__xdata const char* signif_str, __xdata exp_t exponent);
@ -85,6 +85,17 @@ void log10_decn(void);
void exp_decn(void);
void exp10_decn(void);
void pow_decn(void);
void sqrt_decn(void);
void sin_decn(void);
void cos_decn(void);
void tan_decn(void);
void arctan_decn(void);
void arcsin_decn(void);
void arccos_decn(void);
void to_degree_decn(void);
void to_radian_decn(void);
void pi_decn(void);
//Buf should hold at least 18 + 4 + 5 + 1 = 28
#define DECN_BUF_SIZE 28
@ -103,6 +114,17 @@ void decn_to_str_complete(const dec80* x);
void build_decn_at(dec80* dest, const char* signif_str, exp_t exponent);
#endif
#ifdef DESKTOP
#define PRINT_DEC80(n, v) \
printf(n " %d %5d: ", v.exponent < 0, get_exponent(&v)); \
for (int i = 0; i < DEC80_NUM_LSU; i++) { \
printf("%02d ", v.lsu[i]); \
} \
fputc('\n', stdout);
#else
#define PRINT_DEC80(n, v)
#endif
#ifdef __cplusplus
}
#endif

View File

@ -20,9 +20,6 @@
#include <stdio.h>
#include "decn.h"
extern char Buf[DECN_BUF_SIZE];
static dec80 diff;
//diff = (acc - diff) / diff

View File

@ -31,10 +31,6 @@ namespace bmp = boost::multiprecision;
using Catch::Matchers::Equals;
extern char Buf[DECN_BUF_SIZE];
TEST_CASE("build decn"){
build_dec80("0.0009234567890123456", 7);
decn_to_str_complete(&AccDecn);

View File

@ -0,0 +1,203 @@
#include <string>
#include <boost/multiprecision/mpfr.hpp>
#include <catch.hpp>
#include "decn.h"
namespace bmp = boost::multiprecision;
using Catch::Matchers::Equals;
static void trig_test(void (*operation)(void), bmp::mpfr_float (*mpfr_operation)(bmp::mpfr_float x),
const char* a_str, int a_exp, double rtol, double atol)
{
CAPTURE(a_str); CAPTURE(a_exp);
build_dec80(a_str, a_exp);
operation();
decn_to_str_complete(&AccDecn);
CAPTURE(Buf);
bmp::mpfr_float::default_precision(50);
std::string a_full_str(a_str);
a_full_str += "e" + std::to_string(a_exp);
bmp::mpfr_float a_actual(a_full_str);
a_actual = mpfr_operation(a_actual);
CAPTURE(a_actual);
bmp::mpfr_float calculated(Buf);
if (rtol >= 0) {
bmp::mpfr_float rel_diff = abs((a_actual - calculated) / a_actual);
CHECK(rel_diff < rtol);
} else {
bmp::mpfr_float diff = abs(a_actual - calculated);
CHECK(diff < atol);
}
}
static void sin_test(
const char* a_str, int a_exp, double rtol=5e-3, double atol=1e-3)
{
trig_test(sin_decn, [](bmp::mpfr_float x) -> bmp::mpfr_float {return sin(x);}, a_str, a_exp, rtol, atol);
}
static void cos_test(
const char* a_str, int a_exp, double rtol=5e-3, double atol=1e-3)
{
trig_test(cos_decn, [](bmp::mpfr_float x) -> bmp::mpfr_float {return cos(x);}, a_str, a_exp, rtol, atol);
}
static void tan_test(
const char* a_str, int a_exp, double rtol=5e-3, double atol=1e-3)
{
trig_test(tan_decn, [](bmp::mpfr_float x) -> bmp::mpfr_float {return tan(x);}, a_str, a_exp, rtol, atol);
}
static void atan_test(
const char* a_str, int a_exp, double rtol=5e-3, double atol=1e-3)
{
trig_test(arctan_decn, [](bmp::mpfr_float x) -> bmp::mpfr_float {return atan(x);}, a_str, a_exp, rtol, atol);
}
static void asin_test(
const char* a_str, int a_exp, double rtol=5e-3, double atol=1e-3)
{
trig_test(arcsin_decn, [](bmp::mpfr_float x) -> bmp::mpfr_float {return asin(x);}, a_str, a_exp, rtol, atol);
}
static void acos_test(
const char* a_str, int a_exp, double rtol=5e-3, double atol=1e-3)
{
trig_test(arccos_decn, [](bmp::mpfr_float x) -> bmp::mpfr_float {return acos(x);}, a_str, a_exp, rtol, atol);
}
const char * const pi = "3.141592653589793239";
const char * const pi_threequarters = "2.356194490192344929";
const char * const pi_halfed = "1.570796326794896619";
const char * const pi_quarted = ".7853981633974483096";
TEST_CASE("sin") {
sin_test("0.1", 0);
sin_test("0.05", 0, 1e-2);
sin_test("0.01", 0, -1);
sin_test("0.001", 0, -1);
sin_test("0.0001", 0, -1);
sin_test("0.00001", 0, -1);
sin_test("0.000001", 0, -1);
sin_test("0.0", 0, -1);
sin_test("0.2", 0);
sin_test("0.3", 0);
sin_test("0.4", 0);
sin_test("0.9", 0);
sin_test("1.5", 0);
sin_test("2.0", 0);
sin_test("2.5", 0);
sin_test("3.0", 0);
sin_test(pi, 0, -1);
sin_test(pi_quarted, 0);
sin_test(pi_halfed, 0);
sin_test(pi_threequarters, 0);
sin_test("1000.0", 0);
sin_test("-0.5", 0);
sin_test("-1.5", 0);
sin_test("-2.0", 0);
sin_test("-2.5", 0);
sin_test("-3.0", 0);
sin_test("-9.0", 0);
sin_test("-18.0", 0);
sin_test("-27.0", 0);
sin_test("-1000.0", 0);
}
TEST_CASE("cos") {
cos_test("0.1", 0);
cos_test("0.05", 0);
cos_test("0.01", 0);
cos_test("0.001", 0);
cos_test("0.0001", 0);
cos_test("0.00001", 0);
cos_test("0.000001", 0);
cos_test("0.0", 0);
cos_test("0.2", 0);
cos_test("0.3", 0);
cos_test("0.4", 0);
cos_test("0.9", 0);
cos_test("1.5", 0);
cos_test("2.0", 0);
cos_test("2.5", 0);
cos_test("3.0", 0);
cos_test(pi, 0);
cos_test(pi_quarted, 0);
cos_test(pi_halfed, 0, -1);
cos_test(pi_threequarters, 0);
cos_test("1000.0", 0);
cos_test("-0.5", 0);
cos_test("-1.5", 0);
cos_test("-2.0", 0);
cos_test("-2.5", 0);
cos_test("-3.0", 0);
cos_test("-9.0", 0);
cos_test("-18.0", 0);
cos_test("-27.0", 0);
cos_test("-1000.0", 0);
}
TEST_CASE("tan") {
tan_test("0.1", 0);
tan_test("0.05", 0, 1e-2);
tan_test("0.01", 0, 5e-2);
tan_test("0.001", 0, -1);
tan_test("0.0001", 0, -1);
tan_test("0.00001", 0, -1);
tan_test("0.000001", 0, -1);
tan_test("0.0", 0, -1);
tan_test("0.2", 0);
tan_test("0.3", 0);
tan_test("0.4", 0);
tan_test("0.9", 0);
tan_test("1.5", 0);
tan_test("2.0", 0);
tan_test("2.5", 0);
tan_test("3.0", 0);
}
TEST_CASE("arctan") {
atan_test("0.001", 0, -1, 2e-3);
atan_test("-0.001", 0, -1, 2e-3);
atan_test("0.7", 0);
atan_test("-0.7", 0);
atan_test("0.1", 0);
atan_test("-0.1", 0);
atan_test("1.0", 0);
atan_test("-1.0", 0);
atan_test("2.0", 0);
atan_test("-2.0", 0);
atan_test("3.0", 0);
atan_test("-3.0", 0);
atan_test("0", 0, -1);
}
TEST_CASE("arcsin") {
asin_test("0.001", 0, -1);
asin_test("-0.001", 0, -1);
asin_test("0.7", 0);
asin_test("-0.7", 0);
asin_test("0.1", 0, 1e-2);
asin_test("-0.1", 0, 1e-2);
asin_test("0.9", 0);
asin_test("-0.9", 0);
}
TEST_CASE("arccos") {
acos_test("0.001", 0);
acos_test("-0.001", 0);
acos_test("0.7", 0);
acos_test("-0.7", 0);
acos_test("0.1", 0);
acos_test("-0.1", 0);
acos_test("0.9", 0);
acos_test("-0.9", 0);
}

View File

@ -155,9 +155,15 @@ void LCD_Open(void) {
//P2 entire port
P2M1 = 0;
P2M0 = 0xff;
#ifdef STACK_DEBUG
// P3_4 is special
P3M1 &= ~(0xe0);
P3M0 |= (0xe0);
#else
//P3 pins 7:4
P3M1 &= ~(0xf0);
P3M0 |= (0xf0);
#endif
_delay_ms(30); // to allow LCD powerup
outCsrBlindNibble(0x03); // (DL=1 8-bit mode)
@ -195,6 +201,13 @@ void LCD_Open(void) {
LCD_OutChar(0x10);
LCD_OutChar(0x1c);
}
//program shift down sign
for (i = 0; i < 5; i++){
LCD_OutChar(0x0);
}
LCD_OutChar(0x1F);
LCD_OutChar(0x0E);
LCD_OutChar(0x04);
//clear display
LCD_Clear();
@ -279,3 +292,15 @@ void LCD_Clear() {
col = 0;
}
void TERMIO_PrintU8(uint8_t x) {
uint8_t i;
for (i = 2; i; i--) {
const uint8_t upper_nibble = (x & 0xf0) >> 4;
if (upper_nibble <= 9) {
TERMIO_PutChar(upper_nibble + '0');
} else {
TERMIO_PutChar((upper_nibble - 0x0a) + 'A');
}
x <<= 4;
}
}

View File

@ -31,12 +31,14 @@ void LCD_GoTo(uint8_t row, uint8_t col);
void LCD_OutString(__xdata const char* string, uint8_t max_chars);
void LCD_OutString_Initial(__code const char* string);
short TERMIO_PutChar(unsigned char letter);
void TERMIO_PrintU8(uint8_t x);
void LCD_OutNibble(uint8_t x);
void LCD_ClearToEnd(uint8_t curr_row);
//CGRAM character address
#define CGRAM_EXP 0
#define CGRAM_EXP_NEG 1
#define CGRAM_DOWN 2
#include "utils.h"
#ifdef DESKTOP

View File

@ -131,6 +131,8 @@ short TERMIO_PutChar(unsigned char letter) {
lcd_buf[lcd_row][lcd_col] = 'E';
} else if (letter == CGRAM_EXP_NEG) {
lcd_buf[lcd_row][lcd_col] = '-';
} else if (letter == CGRAM_DOWN) {
lcd_buf[lcd_row][lcd_col] = 'V';
} else {
lcd_buf[lcd_row][lcd_col] = letter;
}

View File

@ -28,6 +28,7 @@
#else
#include "stc15.h"
#endif
#include "stack_debug.h"
#define FOSC 11583000
@ -139,7 +140,7 @@ static void latch_on(void)
__xdata char EntryBuf[MAX_CHARS_PER_LINE + 1];
__xdata uint8_t ExpBuf[2];
__code const char VER_STR[32+1] = "STC RPN Calculator v1.10";
__code const char VER_STR[32+1] = "STC RPN Calculator v1.11";
enum {
@ -225,7 +226,9 @@ int main()
LCD_Open();
KeyInit();
Timer0Init(); //for reading keyboard
BACKLIGHT_ON(); //turn on led backlight
backlight_on(); //turn on led backlight
stack_debug_init();
stack_debug(0xfe);
ExpBuf[0] = 0;
ExpBuf[1] = 0;
@ -304,7 +307,7 @@ int main()
switch(KEY_MAP[I_Key]){
//////////
case '0': {
if (IsShifted){
if (IsShiftedUp || IsShiftedDown){
//off
TURN_OFF();
} else {
@ -340,7 +343,7 @@ int main()
case '7': //fallthrough
case '8': //fallthrough
case '9': {
if (IsShifted){
if (IsShiftedUp || IsShiftedDown){
finish_process_entry();
} else if ( EnteringExp >= ENTERING_EXP){
if ( Exp_i == 0){
@ -365,7 +368,7 @@ int main()
} break;
//////////
case '.': {
if (IsShifted){
if (IsShiftedUp || IsShiftedDown){
//STO
finish_process_entry();
} else {
@ -388,7 +391,7 @@ int main()
} break;
//////////
case '=': {
if (IsShifted){ //RCL
if (IsShiftedUp || IsShiftedDown){ //RCL
finish_process_entry();
} else { //Enter
//track stack lift
@ -398,9 +401,10 @@ int main()
} break;
//////////
case 'c': {
if (IsShifted || is_entering_done()){
if (IsShiftedUp || IsShiftedDown || is_entering_done()){
//clear
IsShifted = 0;
IsShiftedUp = 0;
IsShiftedDown = 0;
NoLift = 1;
entering_done();
EnteringExp = ENTERING_DONE_CLEARED;
@ -518,8 +522,15 @@ int main()
LCD_ClearToEnd(1);
//print shifted status
if (IsShifted){
if (IsShiftedUp){
TERMIO_PutChar('^');
#if defined(STACK_DEBUG) && defined(SHOW_STACK)
TERMIO_PutChar(' ');
TERMIO_PrintU8(stack_max);
TERMIO_PutChar(' ');
#endif
} else if (IsShiftedDown){
TERMIO_PutChar(CGRAM_DOWN);
}
#ifdef DESKTOP
@ -529,7 +540,7 @@ int main()
LcdAvailable.release();
#endif
//turn backlight back on
BACKLIGHT_ON();
backlight_on();
} //while (1)
}
/* ------------------------------------------------------------------------- */

98
src/stack_debug.c Normal file
View File

@ -0,0 +1,98 @@
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <stdint.h>
#include "stack_debug.h"
#if defined(STACK_DEBUG)
inline static void HIGH() {
P3_4 = 1;
}
inline static void LOW() {
P3_4 = 1;
}
void stack_debug_init() {
P3M1 &= ~(0x10);
P3M0 |= 0x10;
LOW();
stack_debug_write(0x55);
stack_debug_write(0xAA);
stack_debug_write(0x55);
stack_debug_write(0xAA);
stack_debug_write(0x80);
stack_debug_write(0x10);
stack_debug_write(0x08);
stack_debug_write(0x01);
}
/*
for frequency of 12.000 MHz (12.005 adjusted) this gives a rate of 1'190'000 Baud
negative polarity, MSB
*/
void stack_debug_write(uint8_t value) __naked {
value;
__asm
.macro HIGH
setb _P3_4
.endm
.macro LOW
clr _P3_4
.endm
mov dph,r0
mov a,dpl
mov r0,#8
; START
HIGH ; 1
nop ; 1
nop ; 1
nop ; 1
stack_debug_1$:
rlc a ; 1
jc stack_debug_2$ ; 3
HIGH ; 1
djnz r0,stack_debug_1$ ; 4
sjmp stack_debug_3$ ; 3
stack_debug_2$:
LOW ; 1
djnz r0,stack_debug_1$ ; 4
sjmp stack_debug_3$ ; 3
stack_debug_3$:
nop ; 1
; STOP
LOW ; 1
nop ; 1
nop ; 1
mov r0,dph ; 3
ret ; 4
__endasm;
}
#if defined(STACK_DEBUG) && defined(SHOW_STACK)
__xdata uint8_t stack_max = 0x00;
#endif
void stack_debug(uint8_t marker) {
#ifdef SHOW_STACK
if (SP > stack_max) stack_max = SP;
#endif
stack_debug_write(marker);
stack_debug_write(SP);
}
#endif // defined(STACK_DEBUG)

58
src/stack_debug.h Normal file
View File

@ -0,0 +1,58 @@
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifndef SRC_STACK_DEBUG_H_
#define SRC_STACK_DEBUG_H_
#include <stdint.h>
#if !defined(DESKTOP)
#include "stc15.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
// P3_4 is connected to the cathode and the only pin that is not toggled normally
// unfortunately, the hardware uart cannot be mapped to TX = P3_4
#if defined(STACK_DEBUG)
void stack_debug_init(void);
void stack_debug(uint8_t marker);
void stack_debug_write(uint8_t value) __naked;
#else
#define stack_debug_init()
#define stack_debug(marker)
#endif
#if defined(STACK_DEBUG) && defined(SHOW_STACK)
extern __xdata uint8_t stack_max;
#endif
#if defined(DESKTOP) || defined(STACK_DEBUG)
#define backlight_on()
#define backlight_off()
#else
inline void backlight_on(void) {
P3_4 = 0;
}
inline void backlight_off(void) {
P3_4 = 1;
}
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@ -29,7 +29,6 @@ void _delay_us(uint8_t us)
(void) us;
}
#endif
void backlight_off(void){ }
#else //!DESKTOP
void _delay_ms(uint8_t ms)
{
@ -69,10 +68,6 @@ void _delay_us(uint8_t us)
}
#endif
void backlight_off(void){
P3_4 = 1;
}
#endif //ifdef desktop
#ifdef DESKTOP

View File

@ -35,9 +35,6 @@ void _delay_us(uint8_t us);
#define _delay_us(x) _delay_ms(1)
#endif
void backlight_off(void);
#ifdef __linux__
#define DESKTOP
@ -58,11 +55,9 @@ char* u32str(uint32_t x, char* buf, uint8_t base);
#define __at uint8_t*
#define SDCC_ISR(isr, reg)
#define __using(x)
#define BACKLIGHT_ON()
#define TURN_OFF()
#else
#define SDCC_ISR(isr, reg) __interrupt (isr) __using (reg)
#define BACKLIGHT_ON() P3_4 = 0
#define TURN_OFF() P3_2 = 0
#endif