summaryrefslogtreecommitdiff
path: root/device/lib/ds390
diff options
context:
space:
mode:
authorXavier ASUS <xavi92psx@gmail.com>2019-10-18 00:31:54 +0200
committerXavier ASUS <xavi92psx@gmail.com>2019-10-18 00:31:54 +0200
commit268a53de823a6750d6256ee1fb1e7707b4b45740 (patch)
tree42c1799a9a82b2f7d9790ee9fe181d72a7274751 /device/lib/ds390
downloadsdcc-gas-268a53de823a6750d6256ee1fb1e7707b4b45740.tar.gz
sdcc-3.9.0 fork implementing GNU assembler syntax
This fork aims to provide better support for stm8-binutils
Diffstat (limited to 'device/lib/ds390')
-rw-r--r--device/lib/ds390/Makefile67
-rw-r--r--device/lib/ds390/Makefile.dep18
-rw-r--r--device/lib/ds390/Makefile.in67
-rw-r--r--device/lib/ds390/examples/MOVED1
-rw-r--r--device/lib/ds390/gptr_cmp.c98
-rw-r--r--device/lib/ds390/i2c390.c372
-rw-r--r--device/lib/ds390/lcd390.c178
-rw-r--r--device/lib/ds390/memcpyx.c121
-rw-r--r--device/lib/ds390/putchar.c43
-rw-r--r--device/lib/ds390/rtc390.c111
-rw-r--r--device/lib/ds390/setjmp.c72
-rw-r--r--device/lib/ds390/tinibios.c571
12 files changed, 1719 insertions, 0 deletions
diff --git a/device/lib/ds390/Makefile b/device/lib/ds390/Makefile
new file mode 100644
index 0000000..b0717d1
--- /dev/null
+++ b/device/lib/ds390/Makefile
@@ -0,0 +1,67 @@
+# libc/ds390 Makefile
+
+
+srcdir = .
+top_builddir = ../../..
+
+LIB_TYPE = RANLIB
+
+CC = $(top_builddir)/bin/sdcc
+
+# override PORTDIR defined by super (parent) makefile
+override PORTDIR = ../build/ds390
+
+#VERBOSE = --verbose
+
+OBJECTS = tinibios.rel memcpyx.rel lcd390.rel i2c390.rel rtc390.rel putchar.rel gptr_cmp.rel
+
+SOURCES = $(patsubst %.rel,%.c,$(OBJECTS))
+
+CPPFLAGS = -I$(srcdir)/../../include
+CFLAGS = -mds390 $(CPPFLAGS) $(VERBOSE) --std-c11
+
+all: $(OBJECTS) $(PORTDIR)/libds390.lib
+
+clean:
+ rm -f *.lst *.rel *.sym *.cdb *.asm \#* *~ *.rst *.hex
+ rm -f *.ihx temp.lnk *.map *.lib
+
+distclean: clean
+ rm -f Makefile Makefile.dep
+
+$(PORTDIR)/libds390.lib: $(OBJECTS)
+ifeq ($(LIB_TYPE), SDCCLIB)
+ rm -f $@; \
+ $(top_builddir)/bin/sdcclib -a $@ $(OBJECTS)
+else
+ ifeq ($(LIB_TYPE), AR)
+ $(top_builddir)/bin/sdar -rcSD $@ $(OBJECTS)
+ else
+ ifeq ($(LIB_TYPE), RANLIB)
+ $(top_builddir)/bin/sdar -rcD $@ $(OBJECTS)
+ else
+ rm -f $@;
+ for libfile in $(basename $(OBJECTS)); do echo $$libfile >>$@; done
+ cp $(OBJECTS) $(PORTDIR)
+ endif
+ endif
+endif
+
+%.rel: %.c
+ $(CC) -c $(CFLAGS) $<
+
+# Creating dependencies
+# ---------------------
+depend: Makefile.dep
+
+Makefile.dep: $(SOURCES)
+ rm -f Makefile.dep
+ for i in $^; do \
+ $(CC) -M $(CPPFLAGS) $$i >$${i}.dep; \
+ cat $${i}.dep >>Makefile.dep; \
+ rm $${i}.dep; \
+ done
+
+ifeq "$(findstring $(MAKECMDGOALS),clean distclean)" ""
+ -include Makefile.dep
+endif
diff --git a/device/lib/ds390/Makefile.dep b/device/lib/ds390/Makefile.dep
new file mode 100644
index 0000000..143598d
--- /dev/null
+++ b/device/lib/ds390/Makefile.dep
@@ -0,0 +1,18 @@
+tinibios.rel: tinibios.c ../../include/tinibios.h \
+ ../../include/ds80c390.h ../../include/time.h ../../include/stdio.h \
+ ../../include/stdarg.h ../../include/sdcc-lib.h \
+ ../../include/asm/mcs51/features.h
+memcpyx.rel: memcpyx.c ../../include/string.h
+lcd390.rel: lcd390.c ../../include/tinibios.h ../../include/ds80c390.h \
+ ../../include/time.h ../../include/stdio.h ../../include/stdarg.h \
+ ../../include/sdcc-lib.h ../../include/asm/mcs51/features.h
+i2c390.rel: i2c390.c ../../include/tinibios.h ../../include/ds80c390.h \
+ ../../include/time.h
+rtc390.rel: rtc390.c ../../include/tinibios.h ../../include/ds80c390.h \
+ ../../include/time.h ../../include/stdio.h ../../include/stdarg.h \
+ ../../include/sdcc-lib.h ../../include/asm/mcs51/features.h \
+ ../../include/ctype.h
+putchar.rel: putchar.c ../../include/tinibios.h ../../include/ds80c390.h \
+ ../../include/time.h ../../include/stdio.h ../../include/stdarg.h \
+ ../../include/sdcc-lib.h ../../include/asm/mcs51/features.h
+gptr_cmp.rel: gptr_cmp.c
diff --git a/device/lib/ds390/Makefile.in b/device/lib/ds390/Makefile.in
new file mode 100644
index 0000000..e2656e4
--- /dev/null
+++ b/device/lib/ds390/Makefile.in
@@ -0,0 +1,67 @@
+# libc/ds390 Makefile
+
+VPATH = @srcdir@
+srcdir = @srcdir@
+top_builddir = @top_builddir@
+
+LIB_TYPE = @LIB_TYPE@
+
+CC = $(top_builddir)/bin/sdcc
+
+# override PORTDIR defined by super (parent) makefile
+override PORTDIR = ../build/ds390
+
+#VERBOSE = --verbose
+
+OBJECTS = tinibios.rel memcpyx.rel lcd390.rel i2c390.rel rtc390.rel putchar.rel gptr_cmp.rel
+
+SOURCES = $(patsubst %.rel,%.c,$(OBJECTS))
+
+CPPFLAGS = -I$(srcdir)/../../include
+CFLAGS = -mds390 $(CPPFLAGS) $(VERBOSE) --std-c11
+
+all: $(OBJECTS) $(PORTDIR)/libds390.lib
+
+clean:
+ rm -f *.lst *.rel *.sym *.cdb *.asm \#* *~ *.rst *.hex
+ rm -f *.ihx temp.lnk *.map *.lib
+
+distclean: clean
+ rm -f Makefile Makefile.dep
+
+$(PORTDIR)/libds390.lib: $(OBJECTS)
+ifeq ($(LIB_TYPE), SDCCLIB)
+ rm -f $@; \
+ $(top_builddir)/bin/sdcclib -a $@ $(OBJECTS)
+else
+ ifeq ($(LIB_TYPE), AR)
+ $(top_builddir)/bin/sdar -rcSD $@ $(OBJECTS)
+ else
+ ifeq ($(LIB_TYPE), RANLIB)
+ $(top_builddir)/bin/sdar -rcD $@ $(OBJECTS)
+ else
+ rm -f $@;
+ for libfile in $(basename $(OBJECTS)); do echo $$libfile >>$@; done
+ cp $(OBJECTS) $(PORTDIR)
+ endif
+ endif
+endif
+
+%.rel: %.c
+ $(CC) -c $(CFLAGS) $<
+
+# Creating dependencies
+# ---------------------
+depend: Makefile.dep
+
+Makefile.dep: $(SOURCES)
+ rm -f Makefile.dep
+ for i in $^; do \
+ $(CC) -M $(CPPFLAGS) $$i >$${i}.dep; \
+ cat $${i}.dep >>Makefile.dep; \
+ rm $${i}.dep; \
+ done
+
+ifeq "$(findstring $(MAKECMDGOALS),clean distclean)" ""
+ -include Makefile.dep
+endif
diff --git a/device/lib/ds390/examples/MOVED b/device/lib/ds390/examples/MOVED
new file mode 100644
index 0000000..a1e8808
--- /dev/null
+++ b/device/lib/ds390/examples/MOVED
@@ -0,0 +1 @@
+Moved and unpacked to sdcc/device/examples/ds390
diff --git a/device/lib/ds390/gptr_cmp.c b/device/lib/ds390/gptr_cmp.c
new file mode 100644
index 0000000..5453a6a
--- /dev/null
+++ b/device/lib/ds390/gptr_cmp.c
@@ -0,0 +1,98 @@
+/*-------------------------------------------------------------------------
+; gptr_cmp.asm - C run-time: compare two generic pointers
+;
+; Copyright (C) 2011, Maarten Brock
+;
+; This library 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 2, or (at your option) any
+; later version.
+;
+; This library 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 library; see the file COPYING. If not, write to the
+; Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
+; MA 02110-1301, USA.
+;
+; As a special exception, if you link this library with other files,
+; some of which are compiled with SDCC, to produce an executable,
+; this library does not by itself cause the resulting executable to
+; be covered by the GNU General Public License. This exception does
+; not however invalidate any other reasons why the executable file
+; might be covered by the GNU General Public License.
+;------------------------------------------------------------------------*/
+
+#ifdef __SDCC_MODEL_FLAT24
+
+static void dummy(void) __naked
+{
+ __asm
+ .area HOME (CODE)
+
+; compares two generic pointers.
+; if p1 < p2 return NZ and C
+; if p1 == p2 return Z and NC
+; if p1 > p2 return NZ and NC
+; if both are a NULL pointer (yes, we have several) also return Z and NC
+
+___gptr_cmp::
+ mov a,sp
+ add a,#0xFA
+ mov dpl1,a
+ mov a,esp
+ anl a,#0x03
+ addc a,#0xFF
+ mov dph1,a
+ mov dpx1,#0x40
+ inc dps ;select dptr1
+ movx a,@dptr
+ mov ap,a
+ inc dptr
+ movx a,@dptr
+ orl ap,a
+ inc dptr
+ movx a,@dptr
+ orl a,ap
+ clr c
+ jnz 00001$
+ mov a,dpl
+ orl a,dph
+ orl a,dpx
+; if both are NULL, return Z and NC
+ jz 00002$
+00001$:
+ orl dps,#0x80 ;decrement dptr1
+ inc dptr
+ inc dptr
+ anl dps,#0x7F ;increment dptr1
+ movx a,@dptr
+ subb a,dpl
+ mov ap,a
+ inc dptr
+ movx a,@dptr
+ subb a,dph
+ orl ap,a
+ inc dptr
+ movx a,@dptr
+ subb a,dpx
+ orl ap,a
+ inc dptr
+ movx a,@dptr
+ subb a,b
+ orl a,ap
+; p2 < p1, return NZ and C
+; p2 = p1, return Z and NC
+; p2 > p1, return NZ and NC
+00002$:
+ dec dps ;select dptr0
+ ret
+
+ __endasm;
+}
+
+#endif
+
diff --git a/device/lib/ds390/i2c390.c b/device/lib/ds390/i2c390.c
new file mode 100644
index 0000000..e3c115f
--- /dev/null
+++ b/device/lib/ds390/i2c390.c
@@ -0,0 +1,372 @@
+/*-------------------------------------------------------------------------
+ i2c390.c
+
+ Copyright (C) 2001, Johan Knol <johan.knol AT iduna.nl>
+
+ This library 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 2, or (at your option) any
+ later version.
+
+ This library 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 library; see the file COPYING. If not, write to the
+ Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
+ MA 02110-1301, USA.
+
+ As a special exception, if you link this library with other files,
+ some of which are compiled with SDCC, to produce an executable,
+ this library does not by itself cause the resulting executable to
+ be covered by the GNU General Public License. This exception does
+ not however invalidate any other reasons why the executable file
+ might be covered by the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+/* This implemenation is based on an example I once grabbed from
+ the Philips bbs.
+ Don't know who wrote it, but is has been hacked so heavily, he/she wouldn't
+ recogize it anyway */
+
+//#define DEBUG_I2C ==> DON'T DO THIS, THIS IS A LIBRARY <==
+
+#ifdef DEBUG_I2C
+#include <stdio.h>
+#else
+#include <tinibios.h>
+#endif
+
+// we are (ab)using the CAN CTX and CRX for serial data and serial clock
+#define SCL_HIGH (P5 |= 1)
+#define SCL_LOW (P5 &= ~1)
+#define SDA_HIGH (P5 |= 2)
+#define SDA_LOW (P5 &= ~2)
+
+#define SDA_OUT(b) (b ? SDA_HIGH : SDA_LOW)
+#define SDA_IN ((P5>>1)&1)
+#define SCL_IN (P5&1)
+
+/*
+ * I2C error values
+ */
+
+#define I2CERR_OK 0 /* No error */
+#define I2CERR_NAK 1 /* No ACK from slave */
+#define I2CERR_LOST 2 /* Arbitration lost */
+#define I2CERR_BUS 3 /* Bus is stuck (not used yet) */
+#define I2CERR_TIMEOUT 4 /* Timeout on bus */
+
+char i2cTransmitBuffer[I2C_BUFSIZE]; /* Global transfer buffers */
+char i2cReceiveBuffer[I2C_BUFSIZE];
+
+static char i2cError = 0; /* Last error */
+
+#define I2CDELAY 1
+
+void I2CDelay(volatile long delay) {
+ while (delay--)
+ ;
+}
+
+void I2CDumpError(char error);
+
+/*
+ * Makes sure that the bus is in a known condition. Returns 1 on success,
+ * 0 if some other device is pulling on the bus.
+ */
+
+char I2CReset(void)
+{
+ SDA_LOW;
+ SCL_LOW;
+ SCL_HIGH;
+ SDA_HIGH;
+ i2cError = 0;
+ return (SCL_IN && SDA_IN);
+}
+
+
+/*
+ * Generates a start condition on the bus. Returns 0 on success, 1 if some
+ * other device is holding the bus.
+ */
+
+char I2CStart(void)
+{
+ SDA_HIGH;
+ SCL_HIGH;
+ I2CDelay(I2CDELAY);
+ SDA_LOW; /* Pull SDA down... */
+ I2CDelay(I2CDELAY);
+ SCL_LOW; /* ...and then SCL -> start condition. */
+ I2CDelay(I2CDELAY);
+ return 0;
+}
+
+
+/*
+ * Generates a stop condition on the bus. Returns 0 on success, 1 if some
+ * other device is holding the bus.
+ */
+
+char I2CStop(void)
+{
+ SDA_LOW;
+ SCL_HIGH; /* Let SCL go up */
+ I2CDelay(I2CDELAY);
+ SDA_HIGH; /* ...and then SDA up -> stop condition. */
+ I2CDelay(I2CDELAY);
+
+ return (SCL_IN && SDA_IN); /* Both will be up, if everything is fine */
+}
+
+
+/*
+ * Clock out one bit.
+ * Returns 0 on success, 1 if we lose arbitration.
+ */
+
+char BitOutI2C(unsigned char bout)
+{
+ SDA_OUT(bout); /* Put data out on SDA */
+ I2CDelay(I2CDELAY);
+ SCL_HIGH; /* Let SCL go up */
+ while(!SCL_IN) /* Wait until all other devices are ready */
+ {
+ // should do a timeout here
+ }
+
+ if (SDA_IN != bout) /* Arbitration lost, release bus and return */
+ {
+ SDA_HIGH; /* Should be up anyway, but make sure */
+ i2cError = I2CERR_LOST;
+ I2CDumpError(i2cError);
+ return 1;
+ }
+ I2CDelay(I2CDELAY);
+ SCL_LOW; /* Pull SCL back down */
+ I2CDelay(I2CDELAY);
+ return 0; /* OK */
+}
+
+
+/*
+ * Clock in one bit.
+ */
+
+char BitInI2C(void)
+{
+ char bin;
+
+ // SDA is opencollector, so:
+ SDA_HIGH;
+
+ SCL_HIGH; /* Let SCL go up */
+ while(!SCL_IN) /* Wait for other devices */
+ {
+ // should do a timeout here
+ }
+ bin = SDA_IN; /* Read in data */
+ I2CDelay(I2CDELAY);
+ SCL_LOW; /* Pull SCL back up */
+ I2CDelay(I2CDELAY);
+ return bin; /* Return the sampled bit */
+}
+
+
+/*
+ * Send one byte on the bus. No start or stop conditions are generated here,
+ * but i2cError will be set according to the result.
+ * Returns 0 on success, 1 if we lose arbitration or if the slave doesn't
+ * acknowledge the byte. Check i2cError for the actual result on error.
+ */
+
+char ByteOutI2C(char dat)
+{
+ char bit_count;
+
+ bit_count = 8;
+ while(bit_count) {
+ if (dat & 0x80) {
+ if (BitOutI2C(1)) {
+ I2CDumpError(i2cError);
+ return 1;
+ }
+ } else {
+ if (BitOutI2C(0)) {
+ I2CDumpError(i2cError);
+ return 1;
+ }
+ }
+ dat <<= 1;
+ bit_count--;
+ }
+
+ if (BitInI2C()) {
+ i2cError = I2CERR_NAK;
+ I2CDumpError(i2cError);
+ return 1;
+ }
+ return 0;
+}
+
+
+/*
+ * Reads one byte in from the slave. Ack must be 1 if this is the last byte
+ * to be read during this transfer, 0 otherwise (as per I2C bus specification,
+ * the receiving master must acknowledge all but the last byte during a
+ * transfer).
+ */
+
+char I2CByteIn(char ack)
+{
+ char bit_count, byte_in;
+
+ bit_count = 8;
+ byte_in = 0;
+
+ while(bit_count)
+ {
+ byte_in <<= 1;
+ if (BitInI2C()) byte_in |= 0x01;
+ bit_count--;
+ }
+
+ BitOutI2C(ack);
+ SDA_HIGH; /* Added 18-Jul-95 - thanks to Ray Bellis */
+ return byte_in;
+}
+
+
+/*
+ * Send 'count' bytes to slave 'addr'.
+ * Returns 0 on success. Stop condition is sent only when send_stop is true.
+ */
+
+char I2CSendStop(char addr, char count, char send_stop)
+{
+ char byteptr, byte_out;
+
+ if (I2CStart()) return 1;
+ i2cError = 0;
+
+ byte_out = addr & 0xfe; /* Ensure that it's a write address */
+ count++; /* Include slave address to byte count */
+ byteptr = 0;
+ while(count)
+ {
+ if (ByteOutI2C(byte_out))
+ {
+ if (i2cError == I2CERR_NAK && send_stop) I2CStop();
+ return i2cError;
+ }
+ byte_out = i2cTransmitBuffer[byteptr];
+ byteptr++;
+ count--;
+ }
+
+ if (send_stop) I2CStop();
+ return 0;
+}
+
+
+/*
+ * Read in 'count' bytes from slave 'addr'.
+ * Returns 0 on success.
+ */
+
+char i2c_recv(char addr, char count)
+{
+ char byteptr, byte_in;
+
+ if (I2CStart()) return 1;
+ i2cError = 0;
+ byteptr = 0;
+
+ byte_in = addr | 0x01;
+
+ if (ByteOutI2C(byte_in))
+ {
+ if (i2cError == I2CERR_NAK) I2CStop();
+ return i2cError;
+ }
+
+ while(count)
+ {
+ count-=1;
+ if (count) {
+ byte_in = I2CByteIn(0);
+ } else {
+ byte_in = I2CByteIn(1); /* No ACK during last byte */
+ }
+ i2cReceiveBuffer[byteptr] = byte_in;
+ byteptr++;
+ }
+
+ I2CStop();
+
+ return (i2cError ? 1 : 0);
+}
+
+
+/*
+ * Write 'tx_count' bytes to slave 'addr', then use a repeated start condition
+ * to read 'rx_count' bytes from the same slave during the same transfer.
+ * Returns 0 on success, 1 otherwise. On error, check i2cError for the actual
+ * error value.
+ */
+
+char I2CSendReceive(char addr, char tx_count, char rx_count)
+{
+ if (I2CSendStop(addr, tx_count, 0))
+ {
+ /* If send fails, abort but don't send a stop condition if we lost
+ arbitration */
+
+ if (i2cError != I2CERR_LOST) I2CStop();
+ return 1;
+ }
+
+ SDA_HIGH; /* One of these may be low now, in which case the next */
+ SCL_HIGH; /* start condition wouldn't be detected so make */
+ I2CDelay(I2CDELAY); /* sure that they're up and wait for one delay slot */
+
+ if (i2c_recv((char)(addr|0x01), rx_count)) return 1;
+ return (i2cError ? 1 : 0);
+}
+
+/*
+ * Dump an error message.
+ */
+
+void I2CDumpError(char error)
+{
+#ifdef DEBUG_I2C
+ switch(error)
+ {
+ case 0:
+ puts("I2C: OK.");
+ break;
+ case I2CERR_NAK:
+ puts("I2C: Slave didn't acknowledge");
+ break;
+ case I2CERR_LOST:
+ puts("I2C: Lost arbitration with another master");
+ break;
+ case I2CERR_TIMEOUT:
+ puts("I2C: Timeout on bus");
+ break;
+ case I2CERR_BUS:
+ puts("I2C: The bus is stuck");
+ break;
+ default:
+ puts("I2C: Unknown error");
+ break;
+ }
+#else
+ error; // hush the compiler
+#endif
+}
diff --git a/device/lib/ds390/lcd390.c b/device/lib/ds390/lcd390.c
new file mode 100644
index 0000000..5a70acf
--- /dev/null
+++ b/device/lib/ds390/lcd390.c
@@ -0,0 +1,178 @@
+/*-------------------------------------------------------------------------
+ lcd.c - lcd routines for the DS80C390 (tested on TINI)
+
+ Copyright (C) 2001, Johan Knol <johan.knol AT iduna.nl>
+
+ This library 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 2, or (at your option) any
+ later version.
+
+ This library 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 library; see the file COPYING. If not, write to the
+ Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
+ MA 02110-1301, USA.
+
+ As a special exception, if you link this library with other files,
+ some of which are compiled with SDCC, to produce an executable,
+ this library does not by itself cause the resulting executable to
+ be covered by the GNU General Public License. This exception does
+ not however invalidate any other reasons why the executable file
+ might be covered by the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+#include <tinibios.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#define LCD_COLLUMNS 20
+#define LCD_ROWS 4
+
+/* set the dd ram addresses for the rows
+ this one is for a 20x4 LCD
+*/
+static unsigned char lcdLinesStart[LCD_ROWS]={0, 0x40, 0x14, 0x54};
+
+/* Commercial TINI stick connector boards don't support rw
+ control for the lcd-display.
+ My own board does, and it makes it much faster.
+*/
+
+//#define LCD_RW
+
+__xdata __at (0x380002) static unsigned char lcdIwr;
+__xdata __at (0x38000a) static unsigned char lcdDwr;
+
+#ifdef LCD_RW
+
+__xdata __at (0x380003) static unsigned char lcdIrd;
+__xdata __at (0x38000b) static unsigned char lcdDrd;
+
+#define LcdWait { while (lcdIrd&0x80) ; }
+
+#else // ifdef LCD_RW
+
+// wait for 100us
+#define LcdWait { ClockMicroSecondsDelay(100) ; }
+
+#endif // ifdef LCD_RW
+
+void LcdInit() {
+
+ ClockMilliSecondsDelay(16); // >15 ms
+
+ lcdIwr=0x38 ;
+ ClockMilliSecondsDelay(5); // >4.1 ms
+
+ lcdIwr=0x38;
+ ClockMicroSecondsDelay(101); // >100 us
+
+ lcdIwr=0x38;
+ ClockMicroSecondsDelay(101); // >100 us
+
+ lcdIwr=0x38; // interface 8 bit
+ ClockMicroSecondsDelay(41); // >40 us
+
+ lcdIwr=0x0c; // display on
+ ClockMicroSecondsDelay(41); // >40 us
+
+ LcdClear();
+}
+
+void LcdOn() {
+ lcdIwr=0x0c; // display on
+ LcdWait;
+}
+
+void LcdOff() {
+ lcdIwr=0x08; // display off
+ LcdWait;
+}
+
+void LcdCursorOn() {
+ // TODO
+}
+
+void LcdCursorOff() {
+ // TODO
+}
+
+void LcdScrollOn() {
+ // TODO
+}
+
+void LcdScrollOff() {
+ // TODO
+}
+
+void LcdCharDefine() {
+ // TODO
+}
+
+void LcdClear() {
+ lcdIwr=0x01; // display clear
+ ClockMilliSecondsDelay(6); // > 5ms
+}
+
+void LcdHome() {
+ lcdIwr=0x80; // set dd ram address 0
+ LcdWait;
+}
+
+void LcdGoto(unsigned int collumnRow) { // msb=collumn, lsb=row
+ lcdIwr=0x80 + \
+ lcdLinesStart[collumnRow&0xff] + (collumnRow>>8);
+ LcdWait;
+}
+
+void LcdPutChar(char c) {
+ lcdDwr=c;
+ LcdWait;
+}
+
+void LcdPutString (char *string) {
+ char c;
+ while (c=*string++) {
+ LcdPutChar (c);
+ }
+}
+
+void LcdLPutString (unsigned int collumnRow, char *string) {
+ LcdGoto(collumnRow);
+ LcdPutString(string);
+}
+
+// let's hope that no one ever printf's more than the display width,
+// however they will :), so to be sure
+static char lcdPrintfBuffer[LCD_COLLUMNS*4];
+
+void LcdPrintf (const char *format, ...) __reentrant {
+ va_list arg;
+
+ va_start (arg, format);
+ vsprintf (lcdPrintfBuffer, format, arg);
+ puts (lcdPrintfBuffer);
+ LcdPutString(lcdPrintfBuffer);
+
+ va_end (arg);
+}
+
+void LcdLPrintf (unsigned int collumnRow, const char *format, ...) __reentrant {
+ va_list arg;
+
+ LcdGoto(collumnRow);
+
+ // we can not just call LcdPrintf since we have no idea what is on the stack,
+ // so we have to do it all over again
+ va_start (arg, format);
+ vsprintf (lcdPrintfBuffer, format, arg);
+
+ LcdPutString(lcdPrintfBuffer);
+
+ va_end (arg);
+}
diff --git a/device/lib/ds390/memcpyx.c b/device/lib/ds390/memcpyx.c
new file mode 100644
index 0000000..5ec6eba
--- /dev/null
+++ b/device/lib/ds390/memcpyx.c
@@ -0,0 +1,121 @@
+/*-------------------------------------------------------------------------
+ memcpyx.c
+
+ Copyright (C) 2000, Kevin Vigor
+
+ This library 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 2, or (at your option) any
+ later version.
+
+ This library 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 library; see the file COPYING. If not, write to the
+ Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
+ MA 02110-1301, USA.
+
+ As a special exception, if you link this library with other files,
+ some of which are compiled with SDCC, to produce an executable,
+ this library does not by itself cause the resulting executable to
+ be covered by the GNU General Public License. This exception does
+ not however invalidate any other reasons why the executable file
+ might be covered by the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+#include <string.h>
+
+void __xdata * memcpyx (
+ void __xdata * dst,
+ void __xdata * src,
+ int count
+ ) __naked
+{
+ /* Shut compiler up about unused parameters. */
+ dst; src; count;
+
+/* AUTO_TOGGLE uses the '390 DPTS toggle bit. */
+#define AUTO_TOGGLE
+__asm
+ ; Destination is in DPTR. Save it on stack so we can return it at end.
+
+ push dpx
+ push dph
+ push dpl
+
+ mov dps, #0x1 ; Alternate DPTR.
+
+ ; count is in _memcpyx_PARM_3
+ mov dptr, #_memcpyx_PARM_3
+ movx a, @dptr
+ inc dptr
+ mov r2, a
+ movx a, @dptr
+ mov r3, a
+
+ ; src is in _memcpyx_PARM_2
+ mov dptr, #_memcpyx_PARM_2
+ movx a, @dptr
+ inc dptr
+ push acc
+ movx a, @dptr
+ inc dptr
+ push acc
+ movx a, @dptr
+ mov dpx1, a
+ pop dph1
+ pop dpl1
+
+#ifdef AUTO_TOGGLE
+ mov dps, #0x21 ; Current DPTR is alt DPTR, toggle after each op.
+#else
+ mov dps, #0x0 ; Current DPTR is normal DPTR, no toggle.
+#endif
+
+ ; src is in alt DPTR, dst is in normal DPTR, count is in r2/r3.
+
+ ; If we have zero bytes to copy, quick out.
+ mov a, r2
+ orl a, r3
+ jz _memcpy_done
+
+ ; increment r3 if r2 != 0 (makes djnz end-of-loop sequence possible).
+ inc r3
+ cjne r2, #0x0, _memcpyx_loopTop
+ dec r3
+
+_memcpyx_loopTop:
+
+#ifdef AUTO_TOGGLE
+ movx a, @dptr
+ movx @dptr, a
+ inc dptr
+ inc dptr
+#else
+ inc dps
+ movx a, @dptr
+ inc dptr
+ dec dps
+ movx @dptr, a
+ inc dptr
+#endif
+
+ djnz r2, _memcpyx_loopTop
+ djnz r3, _memcpyx_loopTop
+
+_memcpy_done:
+
+#ifdef AUTO_TOGGLE
+ mov dps, #0x0
+#endif
+
+ pop dpl
+ pop dph
+ pop dpx
+ ret
+__endasm;
+
+}
diff --git a/device/lib/ds390/putchar.c b/device/lib/ds390/putchar.c
new file mode 100644
index 0000000..51d0fe8
--- /dev/null
+++ b/device/lib/ds390/putchar.c
@@ -0,0 +1,43 @@
+/*-------------------------------------------------------------------------
+ putchar.c - putchar implementation for DS80C390
+
+ Copyright (C) 2006, Maarten Brock, sourceforge.brock@dse.nl
+
+ This library 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 2, or (at your option) any
+ later version.
+
+ This library 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 library; see the file COPYING. If not, write to the
+ Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
+ MA 02110-1301, USA.
+
+ As a special exception, if you link this library with other files,
+ some of which are compiled with SDCC, to produce an executable,
+ this library does not by itself cause the resulting executable to
+ be covered by the GNU General Public License. This exception does
+ not however invalidate any other reasons why the executable file
+ might be covered by the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+
+#include <tinibios.h>
+#include <stdio.h>
+
+int putchar (int c)
+{
+ Serial0PutChar(c);
+ return(c);
+}
+
+extern int getchar(void)
+{
+ return Serial0GetChar();
+}
+
diff --git a/device/lib/ds390/rtc390.c b/device/lib/ds390/rtc390.c
new file mode 100644
index 0000000..9910f0d
--- /dev/null
+++ b/device/lib/ds390/rtc390.c
@@ -0,0 +1,111 @@
+/*-------------------------------------------------------------------------
+ rtc390.c - rtc routines for the DS1315 (tested on TINI)
+
+ Copyright (C) 2001, Johan Knol <johan.knol AT iduna.nl>
+
+ This library 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 2, or (at your option) any
+ later version.
+
+ This library 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 library; see the file COPYING. If not, write to the
+ Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
+ MA 02110-1301, USA.
+
+ As a special exception, if you link this library with other files,
+ some of which are compiled with SDCC, to produce an executable,
+ this library does not by itself cause the resulting executable to
+ be covered by the GNU General Public License. This exception does
+ not however invalidate any other reasons why the executable file
+ might be covered by the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+#include <tinibios.h>
+#include <stdio.h>
+#include <time.h>
+#include <ctype.h>
+
+/* this is the address of the ds1315 phantom time chip, although
+ it doesn't really matter as long as it's in the 300000-3fffff
+ range since the chip only uses CE3*
+*/
+
+__xdata __at (0x310000) static volatile unsigned char rtc;
+
+// this is the 64bit pattern that has to be recognized by the ds1315
+__code unsigned char rtcMagic[8]={0xc5,0x3a,0xa3,0x5c,0xc5,0x3a,0xa3,0x5c};
+
+#define BCDtoINT(x) (((x)&0x0f)+((x)>>4)*10)
+#define INTtoBCD(x) (((x)%10)+(((x)/10)<<4))
+
+static void RtcSync(void) {
+ unsigned char dummy, byte,bitMask;
+
+ // reset rtc chip
+ dummy=rtc;
+
+ // say the magic word
+ for (byte=0; byte<8; byte++) {
+ for (bitMask=0x01; bitMask; bitMask<<=1) {
+ rtc = (rtcMagic[byte]&bitMask) ? 0xff : 0x00;
+ }
+ }
+}
+
+unsigned char RtcRead(struct tm *rtcDate) {
+ unsigned char rtcBytes[8];
+ unsigned char byte,bitMask;
+
+ RtcSync();
+
+ for (byte=0; byte<8; byte++) {
+ rtcBytes[byte]=0;
+ for (bitMask=0x01; bitMask; bitMask<<=1) {
+ if (rtc&1) {
+ rtcBytes[byte]|=bitMask;
+ }
+ }
+ }
+ rtcDate->tm_year=BCDtoINT(rtcBytes[7])+100; // year since 1900
+ rtcDate->tm_mon=BCDtoINT(rtcBytes[6])-1; // jan=0
+ rtcDate->tm_mday=BCDtoINT(rtcBytes[5]);
+ rtcDate->tm_wday=(rtcBytes[4]&0x07)-1; // monday=0?
+ rtcDate->tm_hour=BCDtoINT(rtcBytes[3]);
+ rtcDate->tm_min=BCDtoINT(rtcBytes[2]);
+ rtcDate->tm_sec=BCDtoINT(rtcBytes[1]);
+ rtcDate->tm_hundredth=BCDtoINT(rtcBytes[0]);
+ if ((rtcBytes[4]&0x30) || (rtcBytes[3]&0x80)) {
+ //oscillator not running, reset not active or in 12h mode
+ return 0;
+ }
+ return 1;
+}
+
+void RtcWrite(struct tm *rtcDate) {
+ unsigned char rtcBytes[8];
+ unsigned char byte,bitMask;
+
+ rtcBytes[7]=INTtoBCD(rtcDate->tm_year%100);
+ rtcBytes[6]=INTtoBCD(rtcDate->tm_mon)+1;
+ rtcBytes[5]=INTtoBCD(rtcDate->tm_mday);
+ rtcBytes[4]=(INTtoBCD(rtcDate->tm_wday)+1)&0x07; //set 24h mode
+ rtcBytes[3]=INTtoBCD(rtcDate->tm_hour)&0x3f; // oscilator on, reset on
+ rtcBytes[2]=INTtoBCD(rtcDate->tm_min);
+ rtcBytes[1]=INTtoBCD(rtcDate->tm_sec);
+ //rtcBytes[0]=INTtoBCD(rtcDate->hundredth);
+ rtcBytes[0]=0;
+
+ RtcSync();
+
+ for (byte=0; byte<8; byte++) {
+ for (bitMask=0x01; bitMask; bitMask<<=1) {
+ rtc = (rtcBytes[byte]&bitMask) ? 0xff : 0x00;
+ }
+ }
+}
diff --git a/device/lib/ds390/setjmp.c b/device/lib/ds390/setjmp.c
new file mode 100644
index 0000000..0bb4ec4
--- /dev/null
+++ b/device/lib/ds390/setjmp.c
@@ -0,0 +1,72 @@
+/*-------------------------------------------------------------------------
+ setjmp.c - source file for ANSI routines setjmp & longjmp
+
+ Copyright (C) 1999, Sandeep Dutta . sandeep.dutta@usa.net
+
+ This library 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 2, or (at your option) any
+ later version.
+
+ This library 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 library; see the file COPYING. If not, write to the
+ Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
+ MA 02110-1301, USA.
+
+ As a special exception, if you link this library with other files,
+ some of which are compiled with SDCC, to produce an executable,
+ this library does not by itself cause the resulting executable to
+ be covered by the GNU General Public License. This exception does
+ not however invalidate any other reasons why the executable file
+ might be covered by the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+#include <ds80c390.h>
+#include <sdcc-lib.h>
+#define __SDCC_HIDE_LONGJMP
+#include <setjmp.h>
+
+int __setjmp (jmp_buf buf)
+{
+ unsigned char sp, esp;
+ unsigned long lsp;
+
+ /* registers would have been saved on the
+ stack anyway so we need to save SP
+ and the return address */
+ __critical {
+ sp = SP;
+ esp = ESP;
+ }
+ lsp = sp;
+ lsp |= (unsigned int)(esp << 8);
+ lsp |= 0x400000;
+ *buf++ = lsp;
+ *buf++ = lsp >> 8;
+ *buf++ = *((unsigned char __xdata *) lsp - 0);
+ *buf++ = *((unsigned char __xdata *) lsp - 1);
+ *buf++ = *((unsigned char __xdata *) lsp - 2);
+ return 0;
+}
+
+int longjmp (jmp_buf buf, int rv)
+{
+ unsigned long lsp;
+
+ lsp = *buf++;
+ lsp |= (unsigned int)(*buf++ << 8);
+ lsp |= 0x400000;
+ *((unsigned char __xdata *) lsp - 0) = *buf++;
+ *((unsigned char __xdata *) lsp - 1) = *buf++;
+ *((unsigned char __xdata *) lsp - 2) = *buf++;
+ __critical {
+ SP = lsp;
+ ESP = lsp >> 8;
+ }
+ return rv ? rv : 1;
+}
diff --git a/device/lib/ds390/tinibios.c b/device/lib/ds390/tinibios.c
new file mode 100644
index 0000000..8c38d97
--- /dev/null
+++ b/device/lib/ds390/tinibios.c
@@ -0,0 +1,571 @@
+/*-------------------------------------------------------------------------
+ tinibios.c - startup and serial routines for the DS80C390 (tested on TINI)
+
+ Copyright (C) 2001, Johan Knol <johan.knol AT iduna.nl>
+
+ This library 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 2, or (at your option) any
+ later version.
+
+ This library 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 library; see the file COPYING. If not, write to the
+ Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
+ MA 02110-1301, USA.
+
+ As a special exception, if you link this library with other files,
+ some of which are compiled with SDCC, to produce an executable,
+ this library does not by itself cause the resulting executable to
+ be covered by the GNU General Public License. This exception does
+ not however invalidate any other reasons why the executable file
+ might be covered by the GNU General Public License.
+-------------------------------------------------------------------------*/
+
+#include <tinibios.h>
+#include <stdio.h>
+
+#define TIMED_ACCESS(sfr,value) { TA=0xaa; TA=0x55; sfr=value; }
+
+unsigned char _sdcc_external_startup(void)
+{
+ IE=0; // disable ALL interrupts
+
+ // use A19..16 and !CE3..0, no CAN
+ TIMED_ACCESS(P4CNT,0x3f);
+
+ // use !PCE3..0, serial 1 at P5.2/3
+ TIMED_ACCESS(P5CNT,0x27);
+
+ // disable watchdog
+ EWT=0;
+
+ // watchdog set to 9.1 seconds
+ // CKCON|=0xc0;
+
+ // default stretch cycles for MOVX
+ //CKCON = (CKCON&0xf8)|(CPU_MOVX_STRETCH&0x07);
+ CKCON=0xf9;
+
+ // use internal 4k RAM as data(stack) memory at 0x400000 and
+ // move CANx memory access to 0x401000 and upwards
+ // use !CE* for program and/or data memory access
+ TIMED_ACCESS(MCON,0xaf);
+
+ // select default cpu speed
+ CpuSpeed(CPU_SPEED);
+
+ // Copy the Interrupt Vector Table (128 bytes) from 0x10000 to 0x100000
+ // This isn't needed for older bootloaders than the 0515, but it won't harm
+ __asm
+ push dpx
+ push dph
+ push dpl
+ push dps
+ push b
+ push acc
+ mov dps,#0x00 ; make sure no autoincrement in progress
+ mov dptr,#0x10000 ; from
+ inc dps ; switch to alternate dptr
+ mov dptr,#0x100000 ; to
+ mov b,#0x80 ; count
+
+_Startup390CopyIVT:
+ inc dps
+ movx a,@dptr
+ inc dptr
+ inc dps
+ movx @dptr,a
+ inc dptr
+ djnz b,_Startup390CopyIVT
+
+ pop acc
+ pop b
+ pop dps
+ pop dpl
+ pop dph
+ pop dpx
+ __endasm;
+
+ // global interrupt enable, all masks cleared
+ // let the Gods be with us :)
+ IE = 0x80;
+
+ Serial0Init(SERIAL_0_BAUD,1);
+ //Serial1Init(SERIAL_1_BAUD,1);
+ ClockInit();
+ //RtcInit();
+ //WatchDogInit();
+
+ // signal _sdcc_gsinit_startup to initialize data (call _sdcc_init_data)
+ return 0;
+}
+
+/* Set the cpu speed in clocks per machine cycle, valid values are:
+ 1024: Power management mode
+ 4: Divide-by-4 mode
+ 2: Use frequency multiplier (2x)
+ 1: Use frequency multiplier (4x) (Don't do this on a TINI at 18.432MHz)
+
+ TODO: TINI seems to support only 2 and 4: write only bits in PMR ?
+*/
+
+unsigned int cpuSpeed;
+
+void CpuSpeed(unsigned int speed)
+{
+#if 0
+ while (0 && (EXIF&0x04))
+ ; // cpu operates from ring buffer
+#endif
+ PMR = 0x80; // div4, CTM off, multiplier 2x
+ switch (speed)
+ {
+ case 1:
+ PMR=0x88; // div4, CTM off, multiplier 4x
+ PMR=0x98; // div4, CTM on, multiplier 4x
+ while ((EXIF&0x08)==0) {
+ ; // wait for the multiplier to be ready
+ }
+ PMR = 0x18; // use multiplier
+ cpuSpeed=speed;
+ break;
+ case 2:
+ PMR=0x90; // div4, CTM on, multilier 2x
+ while ((EXIF&0x08)==0) {
+ ; // wait for the multiplier to be ready
+ }
+ PMR = 0x10; // use multiplier
+ cpuSpeed=speed;
+ break;
+ case 4:
+ // nothing to do
+ cpuSpeed=speed;
+ break;
+ case 1024:
+ PMR = 0xc0; // div1024, CTM off
+ cpuSpeed=speed;
+ break;
+ }
+}
+
+// now the serial0 stuff
+
+// just to make the code more readable
+#define S0RBS SERIAL_0_RECEIVE_BUFFER_SIZE
+
+// this is a ring buffer and can overflow at anytime!
+static volatile unsigned char receive0Buffer[S0RBS];
+static volatile int receive0BufferHead=0;
+static volatile int receive0BufferTail=0;
+// no buffering for transmit
+static volatile char transmit0IsBusy=0;
+
+static __data unsigned char serial0Buffered;
+
+/* Initialize serial0.
+
+ Available baudrates are from 110 upto 115200 (using 16-bit timer 2)
+ If baud==0, the port is disabled.
+
+ If buffered!=0, characters received are buffered using an interrupt
+*/
+
+void Serial0Init (unsigned long baud, unsigned char buffered)
+{
+ if (baud==0) {
+ ES0=0; // disable interrupts
+ SCON0 &= 0xef; // disable receiver
+ return;
+ }
+
+ ES0 = 0; // disable serial channel 0 interrupt
+ TR2 = 0; // stop timer 2
+
+ // set 8 bit uart with variable baud from timer 1/2
+ // enable receiver and clear RI and TI
+ SCON0 = 0x50;
+
+ PCON |= 0x80; // clock is 16x bitrate
+ CKCON|=0x20; // timer uses xtal/4
+
+ T2MOD=0; // no fancy functions
+ T2CON=0x34; // start timer as a baudrate generator for serial0
+
+ // set the baud rate
+ Serial0Baud(baud);
+
+ serial0Buffered=buffered;
+
+ if (buffered) {
+ RI_0=TI_0=0; // clear "pending" interrupts
+ ES0 = 1; // enable serial channel 0 interrupt
+ } else {
+ RI_0=0; // receive buffer empty
+ TI_0=1; // transmit buffer empty
+ }
+}
+
+void Serial0Baud(unsigned long baud)
+{
+ TR2=0; // stop timer
+ baud=-((long)OSCILLATOR/(32*baud));
+ TL2=RCAP2L= baud;
+ TH2=RCAP2H= baud>>8;
+ TF2=0; // clear overflow flag
+ TR2=1; // start timer
+}
+
+void Serial0IrqHandler (void) __interrupt 4
+{
+ if (RI_0) {
+ receive0Buffer[receive0BufferHead]=SBUF0;
+ receive0BufferHead=(receive0BufferHead+1)&(S0RBS-1);
+ if (receive0BufferHead==receive0BufferTail) {
+ /* buffer overrun, sorry :) */
+ receive0BufferTail=(receive0BufferTail+1)&(S0RBS-1);
+ }
+ RI_0=0;
+ }
+ if (TI_0) {
+ TI_0=0;
+ transmit0IsBusy=0;
+ }
+}
+
+char Serial0CharArrived(void)
+{
+ if (serial0Buffered) {
+ if (receive0BufferHead!=receive0BufferTail)
+ return receive0Buffer[receive0BufferTail];
+ } else {
+ if (RI_0)
+ return SBUF0;
+ }
+ return 0;
+}
+
+void Serial0PutChar (char c)
+{
+ if (serial0Buffered) {
+ while (transmit0IsBusy)
+ ;
+ transmit0IsBusy=1;
+ SBUF0=c;
+ } else {
+ while (!TI_0)
+ ;
+ SBUF0=c;
+ TI_0=0;
+ }
+}
+
+char Serial0GetChar (void)
+{
+ char c;
+ if (serial0Buffered) {
+ while (receive0BufferHead==receive0BufferTail)
+ ;
+ c=receive0Buffer[receive0BufferTail];
+ ES0=0; // disable serial interrupts
+ receive0BufferTail=(receive0BufferTail+1)&(S0RBS-1);
+ ES0=1; // enable serial interrupts
+ } else {
+ while (!RI_0)
+ ;
+ c=SBUF0;
+ RI_0=0;
+ }
+ return c;
+}
+
+void Serial0SendBreak()
+{
+ P3 &= ~0x02;
+ ClockMilliSecondsDelay(2);
+ P3 |= 0x02;
+}
+
+void Serial0Flush()
+{
+ ES0=0; // disable interrupts
+ receive0BufferHead=receive0BufferTail=0;
+ RI_0=0;
+ if (serial0Buffered) {
+ TI_0=0;
+ ES0=1; // enable interrupts
+ } else {
+ TI_0=1;
+ }
+}
+
+/* now let's go for the serial1 stuff, basically it's a replicate of
+ serial0 except it uses timer 1
+*/
+
+// just to make the code more readable
+#define S1RBS SERIAL_1_RECEIVE_BUFFER_SIZE
+
+// this is a ring buffer and can overflow at anytime!
+static volatile unsigned char receive1Buffer[S1RBS];
+static volatile int receive1BufferHead=0;
+static volatile int receive1BufferTail=0;
+// no buffering for transmit
+static volatile char transmit1IsBusy=0;
+
+static __data unsigned char serial1Buffered;
+
+/* Initialize serial1.
+
+ Available baudrates are from 4800 upto 115200 (using 8-bit timer 1)
+ If baud==0, the port is disabled.
+
+ If buffered!=0, characters received are buffered using an interrupt
+*/
+
+void Serial1Init (unsigned long baud, unsigned char buffered)
+{
+ if (baud==0) {
+ ES1=0; // disable interrupt
+ SCON1 &= 0xef; // disable receiver
+ return; // and don't touch it
+ }
+
+ ES1 = 0; // disable channel 1 interrupt
+ TR1 = 0; // stop timer 1
+
+ // set 8 bit uart with variable baud from timer 1
+ // enable receiver and clear RI and TI
+ SCON1 = 0x50;
+
+ WDCON |= 0x80; // clock is 16x bitrate
+ CKCON|=0x10; // timer uses xtal/4
+
+ TMOD = (TMOD&0x0f) | 0x20; // timer 1 is an 8bit auto-reload counter
+
+ // set the baud rate
+ Serial1Baud(baud);
+
+ serial1Buffered=buffered;
+
+ if (buffered) {
+ RI_1=TI_1=0; // clear "pending" interrupts
+ ES1 = 1; // enable serial channel 1 interrupt
+ } else {
+ RI_1=0; // receive buffer empty
+ TI_1=1; // transmit buffer empty
+ }
+}
+
+void Serial1Baud(unsigned long baud)
+{
+ TR1=0; // stop timer
+ baud=-((long)OSCILLATOR/(32*baud));
+ TL1=TH1 = baud;
+ TF1=0; // clear overflow flag
+ TR1=1; // start timer
+}
+
+void Serial1IrqHandler (void) __interrupt 7
+{
+ if (RI_1) {
+ receive1Buffer[receive1BufferHead]=SBUF1;
+ receive1BufferHead=(receive1BufferHead+1)&(S1RBS-1);
+ if (receive1BufferHead==receive1BufferTail) /* buffer overrun, sorry :) */
+ receive1BufferTail=(receive1BufferTail+1)&(S1RBS-1);
+ RI_1=0;
+ }
+ if (TI_1) {
+ TI_1=0;
+ transmit1IsBusy=0;
+ }
+}
+
+char Serial1CharArrived(void)
+{
+ if (serial1Buffered) {
+ if (receive1BufferHead!=receive1BufferTail)
+ return receive1Buffer[receive1BufferTail];
+ } else {
+ if (RI_1)
+ return SBUF1;
+ }
+ return 0;
+}
+
+void Serial1PutChar (char c)
+{
+ if (serial1Buffered) {
+ while (transmit1IsBusy)
+ ;
+ transmit1IsBusy=1;
+ SBUF1=c;
+ } else {
+ while (!TI_1)
+ ;
+ SBUF1=c;
+ TI_1=0;
+ }
+}
+
+char Serial1GetChar (void)
+{
+ char c;
+ if (serial1Buffered) {
+ while (receive1BufferHead==receive1BufferTail)
+ ;
+ c=receive1Buffer[receive1BufferTail];
+ ES1=0; // disable serial interrupts
+ receive1BufferTail=(receive1BufferTail+1)&(S1RBS-1);
+ ES1=1; // enable serial interrupts
+ } else {
+ while (!RI_1)
+ ;
+ c=SBUF1;
+ RI_1=0;
+ }
+ return c;
+}
+
+void Serial1SendBreak()
+{
+ P5 &= ~0x08;
+ ClockMilliSecondsDelay(2);
+ P5 |= 0x08;
+}
+
+void Serial1Flush()
+{
+ ES1=0; // disable interrupts
+ receive1BufferHead=receive1BufferTail=0;
+ RI_1=0;
+ if (serial1Buffered) {
+ TI_1=0;
+ ES1=1; // enable interrupts
+ } else {
+ TI_1=1;
+ }
+}
+
+// now let's go for the clock stuff
+
+// these REALLY need to be in data space for the irq routine!
+static __data unsigned long milliSeconds=0;
+static __data unsigned int timer0ReloadValue;
+
+void ClockInit()
+{
+ unsigned long timerReloadValue=OSCILLATOR/1000;
+
+ switch (cpuSpeed) {
+ case 4: timerReloadValue/=4; break;
+ case 1: // not tested yet
+ case 2: // not tested yet
+ default: timerReloadValue/=2; break;
+ }
+ timer0ReloadValue=~timerReloadValue;
+ // initialise timer 0
+ ET0=0; // disable timer interrupts initially
+ TCON = (TCON&0xcc)|0x00; // stop timer, clear overflow
+ TMOD = (TMOD&0xf0)|0x01; // 16 bit counter
+ CKCON|=0x08; // timer uses xtal/4
+
+ TL0=timer0ReloadValue&0xff;
+ TH0=timer0ReloadValue>>8;
+
+ ET0=1; // enable timer interrupts
+ TR0=1; // start timer
+}
+
+// This needs to be SUPER fast. What we really want is:
+
+#if 0
+void junk_ClockIrqHandler (void) __interrupt 10
+{
+ TL0 = timer0ReloadValue & 0xff;
+ TH0 = timer0ReloadValue >> 8;
+ milliSeconds++;
+}
+#else
+// but look at the code, and the pushes and pops, so:
+void ClockIrqHandler (void) __interrupt 1 __naked
+{
+ __asm
+ push acc
+ push psw
+ mov _TL0,_timer0ReloadValue
+ mov _TH0,_timer0ReloadValue+1
+ clr a
+ inc _milliSeconds+0
+ cjne a,_milliSeconds+0,_ClockIrqHandlerDone
+ inc _milliSeconds+1
+ cjne a,_milliSeconds+1,_ClockIrqHandlerDone
+ inc _milliSeconds+2
+ cjne a,_milliSeconds+2,_ClockIrqHandlerDone
+ inc _milliSeconds+3
+ _ClockIrqHandlerDone:
+ pop psw
+ pop acc
+ reti
+ __endasm;
+}
+#endif
+
+// we can't just use milliSeconds
+unsigned long ClockTicks(void)
+{
+ unsigned long ms;
+ ET0=0;
+ ms=milliSeconds;
+ ET0=1;
+ return ms;
+}
+
+void ClockMilliSecondsDelay(unsigned long delay)
+{
+ long ms=ClockTicks()+delay;
+
+ while (ms>ClockTicks())
+ ;
+}
+
+// stolen from Kevin Vigor, works only for TINI at default speed
+void ClockMicroSecondsDelay(unsigned int delay)
+{
+ delay; /* shut compiler up. */
+
+ __asm
+
+ ; delay is in dpl/dph
+ mov r0, dpl
+ mov r1, dph
+
+ mov a, r0
+ orl a, r1 ; quick out for zero case.
+ jz _usDelayDone
+
+ inc r1
+ cjne r0, #0, _usDelayLoop
+ dec r1
+
+ _usDelayLoop:
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop ; 7 nops
+ djnz r0, _usDelayLoop ; 3 cycles x 1 = 3 cycles
+ ; 10 cycles per iter
+ ; we want 9.216, but more is better
+ ; than less.
+ djnz r1, _usDelayLoop
+ _usDelayDone:
+
+ __endasm;
+}