summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/i386/ts_386ex/start
diff options
context:
space:
mode:
authorJoel Sherrill <joel.sherrill@OARcorp.com>1999-04-23 16:35:11 +0000
committerJoel Sherrill <joel.sherrill@OARcorp.com>1999-04-23 16:35:11 +0000
commit16a384cfb161f6a3dbcd69fc3b788b6dbc229669 (patch)
treedbbb2e908c64a7f8de5d4c99c16559158b99f1cf /c/src/lib/libbsp/i386/ts_386ex/start
parentAdded lstat(). (diff)
downloadrtems-16a384cfb161f6a3dbcd69fc3b788b6dbc229669.tar.bz2
New BSP from Tony R. Ambardar <tonya@ece.ubc.ca> from the
University of British Columbia. The BSP is for: Yes, this is the "entry model" of a series of boards from Technologic Systems. Costs <$200 I believe. They have a WWW page at www.t-systems.com. I am letting them know about the availability of this BSP too.
Diffstat (limited to 'c/src/lib/libbsp/i386/ts_386ex/start')
-rw-r--r--c/src/lib/libbsp/i386/ts_386ex/start/80386ex.h254
-rw-r--r--c/src/lib/libbsp/i386/ts_386ex/start/80386ex.inc252
-rw-r--r--c/src/lib/libbsp/i386/ts_386ex/start/Makefile.in72
-rw-r--r--c/src/lib/libbsp/i386/ts_386ex/start/macros.inc115
-rw-r--r--c/src/lib/libbsp/i386/ts_386ex/start/start.S501
-rw-r--r--c/src/lib/libbsp/i386/ts_386ex/start/ts_1325.inc50
6 files changed, 1244 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/i386/ts_386ex/start/80386ex.h b/c/src/lib/libbsp/i386/ts_386ex/start/80386ex.h
new file mode 100644
index 0000000000..24e4b9a8ee
--- /dev/null
+++ b/c/src/lib/libbsp/i386/ts_386ex/start/80386ex.h
@@ -0,0 +1,254 @@
+/*
+ * Submitted by:
+ *
+ * Erik Ivanenko
+ * University of Toronto
+ * erik.ivanenko@utoronto.ca
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * $Id$
+ */
+
+/* REMAP ADDRESSING Registers */
+#define REMAPCFGH 0x0023
+#define REMAPCFGL 0x0022
+#define REMAPCFG 0x0022
+/* INTERRUPT CONTROL REGISTERS -- SLOT 15 ADDRESSES */
+#define ICW1M 0xF020
+#define ICW1S 0xF0A0
+#define ICW2M 0xF021
+#define ICW2S 0xF0A1
+#define ICW3M 0xF021
+#define ICW3S 0xF0A1
+#define ICW4M 0xF021
+#define ICW4S 0xF0A1
+#define OCW1M 0xF021
+#define OCW1S 0xF0A1
+#define OCW2M 0xF020
+#define OCW2S 0xF0A0
+#define OCW3M 0xF020
+#define OCW3S 0xF0A0
+/* INTERRUPT CONTROL REGISTERS -- SLOT 0 ADDRESSES */
+#define ICW1MDOS 0x0020
+#define ICW1SDOS 0x00A0
+#define ICW2MDOS 0x0021
+#define ICW2SDOS 0x00A1
+#define ICW3MDOS 0x0021
+#define ICW3SDOS 0x00A1
+#define ICW4MDOS 0x0021
+#define ICW4SDOS 0x00A1
+#define OCW1MDOS 0x0021
+#define OCW1SDOS 0x00A1
+#define OCW2MDOS 0x0020
+#define OCW2SDOS 0x00A0
+#define OCW3MDOS 0x0020
+#define OCW3SDOS 0x00A0
+
+
+/* CONFIGURATION Registers */
+#define DMACFG 0xF830
+#define INTCFG 0xF832
+#define TMRCFG 0xF834
+#define SIOCFG 0xF836
+#define P1CFG 0xF820
+#define P2CFG 0xF822
+#define P3CFG 0xF824
+#define PINCFG 0xF826
+
+/* WATCHDOG TIMER Registers */
+#define WDTRLDH 0xF4C0
+#define WDTRLDL 0xF4C2
+#define WDTCNTH 0xF4C4
+#define WDTCNTL 0xF4C6
+#define WDTCLR 0xF4C8
+#define WDTSTATUS 0xF4CA
+
+/* TIMER CONTROL REGISTERS -- SLOT 15 ADDRESSES */
+#define TMR0 0xF040
+#define TMR1 0xF041
+#define TMR2 0xF042
+#define TMRCON 0xF043
+/* TIMER CONTROL REGISTERS -- SLOT 0 ADDRESSES */
+#define TMR0DOS 0x0040
+#define TMR1DOS 0x0041
+#define TMR2DOS 0x0042
+#define TMRCONDOS 0x0043
+
+/* INPUT/OUTPUT PORT UNIT Registers */
+#define P1PIN 0xF860
+#define P1LTC 0xF862
+#define P1DIR 0xF864
+#define P2PIN 0xF868
+#define P2LTC 0xF86A
+#define P2DIR 0xF86C
+#define P3PIN 0xF870
+#define P3LTC 0xF872
+#define P3DIR 0xF874
+
+/* ASYNCHRONOUS SERIAL CHANNEL 0 -- SLOT 15 ADDRESSES */
+#define RBR0 0xF4F8
+#define THR0 0xF4F8
+#define TBR0 0xF4F8
+#define DLL0 0xF4F8
+#define IER0 0xF4F9
+#define DLH0 0xF4F9
+#define IIR0 0xF4FA
+#define LCR0 0xF4FB
+#define MCR0 0xF4FC
+#define LSR0 0xF4FD
+#define MSR0 0xF4FE
+#define SCR0 0xF4FF
+/* ASYNCHRONOUS SERIAL CHANNEL 0 -- SLOT 0 ADDRESSES */
+#define RBR0DOS 0x03F8
+#define THR0DOS 0x03F8
+#define TBR0DOS 0x03F8
+#define DLL0DOS 0x03F8
+#define IER0DOS 0x03F9
+#define DLH0DOS 0x03F9
+#define IIR0DOS 0x03FA
+#define LCR0DOS 0x03FB
+#define MCR0DOS 0x03FC
+#define LSR0DOS 0x03FD
+#define MSR0DOS 0x03FE
+#define SCR0DOS 0x03FF
+
+/* ASYNCHRONOUS SERIAL CHANNEL 1 -- SLOT 15 ADDRESSES */
+#define RBR1 0xF8F8
+#define THR1 0xF8F8
+#define TBR1 0XF8F8
+#define DLL1 0xF8F8
+#define IER1 0xF8F9
+#define DLH1 0xF8F9
+#define IIR1 0xF8FA
+#define LCR1 0xF8FB
+#define MCR1 0xF8FC
+#define LSR1 0xF8FD
+#define MSR1 0xF8FE
+#define SCR1 0xF8FF
+/* ASYNCHRONOUS SERIAL CHANNEL 1 -- SLOT 0 ADDRESSES */
+#define RBR1DOS 0x02F8
+#define THR1DOS 0x02F8
+#define TBR1DOS 0x02F8
+#define DLL1DOS 0x02F8
+#define IER1DOS 0x02F9
+#define DLH1DOS 0x02F9
+#define IIR1DOS 0x02FA
+#define LCR1DOS 0x02FB
+#define MCR1DOS 0x02FC
+#define LSR1DOS 0x02FD
+#define MSR1DOS 0x02FE
+#define SCR1DOS 0x02FF
+
+/* SYNCHRONOUS SERIAL CHANNEL REGISTERS */
+#define SSIOTBUF 0xF480
+#define SSIORBUF 0xF482
+#define SSIOBAUD 0xF484
+#define SSIOCON1 0xF486
+#define SSIOCON2 0xF488
+#define SSIOCTR 0xF48A
+
+/* CHIP SELECT UNIT Registers */
+#define CS0ADL 0xF400
+#define CS0ADH 0xF402
+#define CS0MSKL 0xF404
+#define CS0MSKH 0xF406
+#define CS1ADL 0xF408
+#define CS1ADH 0xF40A
+#define CS1MSKL 0xF40C
+#define CS1MSKH 0xF40E
+#define CS2ADL 0xF410
+#define CS2ADH 0xF412
+#define CS2MSKL 0xF414
+#define CS2MSKH 0xF416
+#define CS3ADL 0xF418
+#define CS3ADH 0xF41A
+#define CS3MSKL 0xF41C
+#define CS3MSKH 0xF41E
+#define CS4ADL 0xF420
+#define CS4ADH 0xF422
+#define CS4MSKL 0xF424
+#define CS4MSKH 0xF426
+#define CS5ADL 0xF428
+#define CS5ADH 0xF42A
+#define CS5MSKL 0xF42C
+#define CS5MSKH 0xF42E
+#define CS6ADL 0xF430
+#define CS6ADH 0xF432
+#define CS6MSKL 0xF434
+#define CS6MSKH 0xF436
+#define UCSADL 0xF438
+#define UCSADH 0xF43A
+#define UCSMSKL 0xF43C
+#define UCSMSKH 0xF43E
+
+/* REFRESH CONTROL UNIT Registers */
+
+#define RFSBAD 0xF4A0
+#define RFSCIR 0xF4A2
+#define RFSCON 0xF4A4
+#define RFSADD 0xF4A6
+
+/* POWER MANAGEMENT CONTROL Registers */
+
+#define PWRCON 0xF800
+#define CLKPRS 0xF804
+
+/* DMA UNIT REGISTERS -- SLOT 15 ADDRESSES */
+#define DMA0TAR 0xF000
+#define DMA0BYC 0xF001
+#define DMA1TAR 0xF002
+#define DMA1BYC 0xF003
+#define DMACMD1 0xF008
+#define DMASTS 0xF008
+#define DMASRR 0xF009
+#define DMAMSK 0xF00A
+#define DMAMOD1 0xF00B
+#define DMACLRBP 0xF00C
+#define DMACLR 0xF00D
+#define DMACLRMSK 0xF00E
+#define DMAGRPMSK 0xF00F
+#define DMA0REQL 0xF010
+#define DMA0REQH 0xF011
+#define DMA1REQL 0xF012
+#define DMA1REQH 0xF013
+#define DMABSR 0xF018
+#define DMACHR 0xF019
+#define DMAIS 0xF019
+#define DMACMD2 0xF01A
+#define DMAMOD2 0xF01B
+#define DMAIEN 0xF01C
+#define DMAOVFE 0xF01D
+#define DMACLRTC 0xF01E
+#define DMA1TARPL 0xF083
+#define DMA1TARPH 0xF085
+#define DMA0TARPH 0xF086
+#define DMA0TARPL 0xF087
+#define DMA0BYCH 0xF098
+#define DMA1BYCH 0xF099
+
+/* DMA UNIT REGISTERS -- SLOT 0 ADDRESSES */
+#define DMA0TARDOS 0x0000
+#define DMA0BYCDOS 0x0001
+#define DMA1TARDOS 0x0002
+#define DMA1BYCDOS 0x0003
+#define DMACMD1DOS 0x0008
+#define DMASTSDOS 0x0008
+#define DMASRRDOS 0x0009
+#define DMAMSKDOS 0x000A
+#define DMAMOD1DOS 0x000B
+#define DMACLRBPDOS 0x000C
+#define DMACLRDOS 0x000D
+#define DMACLRMSKDOS 0x000E
+#define DMAGRPMSKDOS 0x000F
+#define DMA1TARPLDOS 0x0083
+#define DMA0TARPLDOS 0x0087
+
+/* A20GATE AND FAST CPU RESET -- SLOT 15 ADDRESS */
+#define PORT92 0xF092
+/* A20GATE AND FAST CPU RESET -- SLOT 0 ADDRESS */
+#define PORT92DOS 0x0092
+
+/* end of include file */
diff --git a/c/src/lib/libbsp/i386/ts_386ex/start/80386ex.inc b/c/src/lib/libbsp/i386/ts_386ex/start/80386ex.inc
new file mode 100644
index 0000000000..798dda4215
--- /dev/null
+++ b/c/src/lib/libbsp/i386/ts_386ex/start/80386ex.inc
@@ -0,0 +1,252 @@
+/*
+ * Submitted by:
+ *
+ * Erik Ivanenko
+ * University of Toronto
+ * erik.ivanenko@utoronto.ca
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * $Id$
+ */
+
+/* REMAP ADDRESSING Registers */
+.set REMAPCFGH , 0x0023
+.set REMAPCFGL , 0x0022
+.set REMAPCFG , 0x0022
+/* INTERRUPT CONTROL REGISTERS -- SLOT 15 ADDRESSES */
+.set ICW1M , 0xF020
+.set ICW1S , 0xF0A0
+.set ICW2M , 0xF021
+.set ICW2S , 0xF0A1
+.set ICW3M , 0xF021
+.set ICW3S , 0xF0A1
+.set ICW4M , 0xF021
+.set ICW4S , 0xF0A1
+.set OCW1M , 0xF021
+.set OCW1S , 0xF0A1
+.set OCW2M , 0xF020
+.set OCW2S , 0xF0A0
+.set OCW3M , 0xF020
+.set OCW3S , 0xF0A0
+/* INTERRUPT CONTROL REGISTERS -- SLOT 0 ADDRESSES */
+.set ICW1MDOS , 0x0020
+.set ICW1SDOS , 0x00A0
+.set ICW2MDOS , 0x0021
+.set ICW2SDOS , 0x00A1
+.set ICW3MDOS , 0x0021
+.set ICW3SDOS , 0x00A1
+.set ICW4MDOS , 0x0021
+.set ICW4SDOS , 0x00A1
+.set OCW1MDOS , 0x0021
+.set OCW1SDOS , 0x00A1
+.set OCW2MDOS , 0x0020
+.set OCW2SDOS , 0x00A0
+.set OCW3MDOS , 0x0020
+.set OCW3SDOS , 0x00A0
+
+
+/* CONFIGURATION Registers */
+.set DMACFG , 0xF830
+.set INTCFG , 0xF832
+.set TMRCFG , 0xF834
+.set SIOCFG , 0xF836
+.set P1CFG , 0xF820
+.set P2CFG , 0xF822
+.set P3CFG , 0xF824
+.set PINCFG , 0xF826
+
+/* WATCHDOG TIMER Registers */
+.set WDTRLDH , 0xF4C0
+.set WDTRLDL , 0xF4C2
+.set WDTCNTH , 0xF4C4
+.set WDTCNTL , 0xF4C6
+.set WDTCLR , 0xF4C8
+.set WDTSTATUS , 0xF4CA
+
+/* TIMER CONTROL REGISTERS -- SLOT 15 ADDRESSES */
+.set TMR0 , 0xF040
+.set TMR1 , 0xF041
+.set TMR2 , 0xF042
+.set TMRCON , 0xF043
+/* TIMER CONTROL REGISTERS -- SLOT 0 ADDRESSES */
+.set TMR0DOS , 0x0040
+.set TMR1DOS , 0x0041
+.set TMR2DOS , 0x0042
+.set TMRCONDOS , 0x0043
+
+/* INPUT/OUTPUT PORT UNIT Registers */
+.set P1PIN , 0xF860
+.set P1LTC , 0xF862
+.set P1DIR , 0xF864
+.set P2PIN , 0xF868
+.set P2LTC , 0xF86A
+.set P2DIR , 0xF86C
+.set P3PIN , 0xF870
+.set P3LTC , 0xF872
+.set P3DIR , 0xF874
+
+/* ASYNCHRONOUS SERIAL CHANNEL 0 -- SLOT 15 ADDRESSES */
+.set RBR0 , 0xF4F8
+.set THR0 , 0xF4F8
+.set TBR0 , 0xF4F8
+.set DLL0 , 0xF4F8
+.set IER0 , 0xF4F9
+.set DLH0 , 0xF4F9
+.set IIR0 , 0xF4FA
+.set LCR0 , 0xF4FB
+.set MCR0 , 0xF4FC
+.set LSR0 , 0xF4FD
+.set MSR0 , 0xF4FE
+.set SCR0 , 0xF4FF
+/* ASYNCHRONOUS SERIAL CHANNEL 0 -- SLOT 0 ADDRESSES */
+.set RBR0DOS , 0x03F8
+.set THR0DOS , 0x03F8
+.set TBR0DOS , 0x03F8
+.set DLL0DOS , 0x03F8
+.set IER0DOS , 0x03F9
+.set DLH0DOS , 0x03F9
+.set IIR0DOS , 0x03FA
+.set LCR0DOS , 0x03FB
+.set MCR0DOS , 0x03FC
+.set LSR0DOS , 0x03FD
+.set MSR0DOS , 0x03FE
+.set SCR0DOS , 0x03FF
+
+/* ASYNCHRONOUS SERIAL CHANNEL 1 -- SLOT 15 ADDRESSES */
+.set RBR1 , 0xF8F8
+.set THR1 , 0xF8F8
+.set TBR1 , 0XF8F8
+.set DLL1 , 0xF8F8
+.set IER1 , 0xF8F9
+.set DLH1 , 0xF8F9
+.set IIR1 , 0xF8FA
+.set LCR1 , 0xF8FB
+.set MCR1 , 0xF8FC
+.set LSR1 , 0xF8FD
+.set MSR1 , 0xF8FE
+.set SCR1 , 0xF8FF
+/* ASYNCHRONOUS SERIAL CHANNEL 1 -- SLOT 0 ADDRESSES */
+.set RBR1DOS , 0x02F8
+.set THR1DOS , 0x02F8
+.set TBR1DOS , 0x02F8
+.set DLL1DOS , 0x02F8
+.set IER1DOS , 0x02F9
+.set DLH1DOS , 0x02F9
+.set IIR1DOS , 0x02FA
+.set LCR1DOS , 0x02FB
+.set MCR1DOS , 0x02FC
+.set LSR1DOS , 0x02FD
+.set MSR1DOS , 0x02FE
+.set SCR1DOS , 0x02FF
+
+/* SYNCHRONOUS SERIAL CHANNEL REGISTERS */
+.set SSIOTBUF , 0xF480
+.set SSIORBUF , 0xF482
+.set SSIOBAUD , 0xF484
+.set SSIOCON1 , 0xF486
+.set SSIOCON2 , 0xF488
+.set SSIOCTR , 0xF48A
+
+/* CHIP SELECT UNIT Registers */
+.set CS0ADL , 0xF400
+.set CS0ADH , 0xF402
+.set CS0MSKL , 0xF404
+.set CS0MSKH , 0xF406
+.set CS1ADL , 0xF408
+.set CS1ADH , 0xF40A
+.set CS1MSKL , 0xF40C
+.set CS1MSKH , 0xF40E
+.set CS2ADL , 0xF410
+.set CS2ADH , 0xF412
+.set CS2MSKL , 0xF414
+.set CS2MSKH , 0xF416
+.set CS3ADL , 0xF418
+.set CS3ADH , 0xF41A
+.set CS3MSKL , 0xF41C
+.set CS3MSKH , 0xF41E
+.set CS4ADL , 0xF420
+.set CS4ADH , 0xF422
+.set CS4MSKL , 0xF424
+.set CS4MSKH , 0xF426
+.set CS5ADL , 0xF428
+.set CS5ADH , 0xF42A
+.set CS5MSKL , 0xF42C
+.set CS5MSKH , 0xF42E
+.set CS6ADL , 0xF430
+.set CS6ADH , 0xF432
+.set CS6MSKL , 0xF434
+.set CS6MSKH , 0xF436
+.set UCSADL , 0xF438
+.set UCSADH , 0xF43A
+.set UCSMSKL , 0xF43C
+.set UCSMSKH , 0xF43E
+
+/* REFRESH CONTROL UNIT Registers */
+
+.set RFSBAD , 0xF4A0
+.set RFSCIR , 0xF4A2
+.set RFSCON , 0xF4A4
+.set RFSADD , 0xF4A6
+
+/* POWER MANAGEMENT CONTROL Registers */
+
+.set PWRCON , 0xF800
+.set CLKPRS , 0xF804
+
+/* DMA UNIT REGISTERS -- SLOT 15 ADDRESSES */
+.set DMA0TAR , 0xF000
+.set DMA0BYC , 0xF001
+.set DMA1TAR , 0xF002
+.set DMA1BYC , 0xF003
+.set DMACMD1 , 0xF008
+.set DMASTS , 0xF008
+.set DMASRR , 0xF009
+.set DMAMSK , 0xF00A
+.set DMAMOD1 , 0xF00B
+.set DMACLRBP , 0xF00C
+.set DMACLR , 0xF00D
+.set DMACLRMSK , 0xF00E
+.set DMAGRPMSK , 0xF00F
+.set DMA0REQL , 0xF010
+.set DMA0REQH , 0xF011
+.set DMA1REQL , 0xF012
+.set DMA1REQH , 0xF013
+.set DMABSR , 0xF018
+.set DMACHR , 0xF019
+.set DMAIS , 0xF019
+.set DMACMD2 , 0xF01A
+.set DMAMOD2 , 0xF01B
+.set DMAIEN , 0xF01C
+.set DMAOVFE , 0xF01D
+.set DMACLRTC , 0xF01E
+.set DMA1TARPL , 0xF083
+.set DMA1TARPH , 0xF085
+.set DMA0TARPH , 0xF086
+.set DMA0TARPL , 0xF087
+.set DMA0BYCH , 0xF098
+.set DMA1BYCH , 0xF099
+
+/* DMA UNIT REGISTERS -- SLOT 0 ADDRESSES */
+.set DMA0TARDOS , 0x0000
+.set DMA0BYCDOS , 0x0001
+.set DMA1TARDOS , 0x0002
+.set DMA1BYCDOS , 0x0003
+.set DMACMD1DOS , 0x0008
+.set DMASTSDOS , 0x0008
+.set DMASRRDOS , 0x0009
+.set DMAMSKDOS , 0x000A
+.set DMAMOD1DOS , 0x000B
+.set DMACLRBPDOS , 0x000C
+.set DMACLRDOS , 0x000D
+.set DMACLRMSKDOS , 0x000E
+.set DMAGRPMSKDOS , 0x000F
+.set DMA1TARPLDOS , 0x0083
+.set DMA0TARPLDOS , 0x0087
+
+/* A20GATE AND FAST CPU RESET -- SLOT 15 ADDRESS */
+.set PORT92 , 0xF092
+/* A20GATE AND FAST CPU RESET -- SLOT 0 ADDRESS */
+.set PORT92DOS , 0x0092
diff --git a/c/src/lib/libbsp/i386/ts_386ex/start/Makefile.in b/c/src/lib/libbsp/i386/ts_386ex/start/Makefile.in
new file mode 100644
index 0000000000..313955a579
--- /dev/null
+++ b/c/src/lib/libbsp/i386/ts_386ex/start/Makefile.in
@@ -0,0 +1,72 @@
+#
+# $Id$
+#
+
+@SET_MAKE@
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+top_builddir = ../../../../../../..
+subdir = c/src/lib/libbsp/i386/ts_386ex/start
+
+INSTALL = @INSTALL@
+
+RTEMS_ROOT = $(top_srcdir)/@RTEMS_TOPdir@
+PROJECT_ROOT = @PROJECT_ROOT@
+
+VPATH = @srcdir@
+
+RTEMS_GAS_CODE16 = @RTEMS_GAS_CODE16@
+
+PGMS=${ARCH}/start.o
+
+# C source names, if any, go here -- minus the .c
+C_PIECES=
+C_FILES=$(C_PIECES:%=%.c)
+C_O_FILES=$(C_PIECES:%=${ARCH}/%.o)
+
+H_FILES=
+
+# Assembly source names, if any, go here -- minus the .S
+S_PIECES=start
+S_FILES=$(S_PIECES:%=%.S)
+S_O_FILES=$(S_FILES:%.S=${ARCH}/%.o)
+
+SRCS=$(C_FILES) $(H_FILES) $(S_FILES)
+OBJS=$(C_O_FILES) $(S_O_FILES)
+
+include $(RTEMS_ROOT)/make/custom/$(RTEMS_BSP).cfg
+include $(RTEMS_ROOT)/make/leaf.cfg
+
+#
+# (OPTIONAL) Add local stuff here using +=
+#
+
+ifeq ($(RTEMS_GAS_CODE16),yes)
+CPPFLAGS += -DNEW_GAS
+endif
+
+CFLAGS +=
+
+LD_PATHS +=
+LD_LIBS +=
+LDFLAGS +=
+
+#
+# Add your list of files to delete here. The config files
+# already know how to delete some stuff, so you may want
+# to just run 'make clean' first to see what gets missed.
+# 'make clobber' already includes 'make clean'
+#
+
+CLEAN_ADDITIONS +=
+CLOBBER_ADDITIONS +=
+
+all: ${ARCH} $(SRCS) $(OBJS) $(PGM)
+ $(INSTALL_VARIANT) -m 555 ${PGMS} ${PROJECT_RELEASE}/lib
+
+# Install the program(s), appending _g or _p as appropriate.
+# for include files, just use $(INSTALL_CHANGE)
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ cd $(top_builddir) \
+ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
diff --git a/c/src/lib/libbsp/i386/ts_386ex/start/macros.inc b/c/src/lib/libbsp/i386/ts_386ex/start/macros.inc
new file mode 100644
index 0000000000..b3814479a2
--- /dev/null
+++ b/c/src/lib/libbsp/i386/ts_386ex/start/macros.inc
@@ -0,0 +1,115 @@
+/* macros.inc
+ *
+ * This file assists the board independent startup code
+ * by initializing the chip-select channels to
+ * reflect the proper memory configuration.
+ *
+ * NOTE: No stack has been established when this routine
+ * is invoked. It returns to start.s through ldsegs
+ *
+ * Submitted by:
+ *
+ * Erik Ivanenko
+ * University of Toronto
+ * erik.ivanenko@utoronto.ca
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * $Id$
+ */
+
+.set GDT_CODE_PTR , 0x08
+.set GDT_DATA_PTR , 0x10
+
+.set BOARD_SELECT , 0x301
+.set BOARD_DATA , 0x302
+.set BOARD_LATCH , 0x303
+
+
+#define SetExRegByte(_register,_value) \
+ movb $ ## _value, al; \
+ movw $ ## _register, dx; \
+ outb al, dx
+
+#define SetExRegWord(_register,_value) \
+ movw $ ## _value, ax; \
+ movw $ ## _register, dx ; \
+ outw ax, dx
+
+
+#define DESC2(lim_0_15, bas_0_15, bas_16_23, access, gran, bas_24_31) \
+ .word lim_0_15 ; \
+ .word bas_0_15 ; \
+ .byte bas_16_23 ; \
+ .byte access ; \
+ .byte gran ; \
+ .byte bas_24_31
+
+#define DESC3( _base, _limit) \
+.word _limit ; \
+.long _base
+
+/* THE GET_ACCESS IS CHANGED FROM 8E TO 9E */
+
+#define INTERRUPT_GATE( _vector ) \
+ .word _vector ; \
+ .word GDT_CODE_PTR ; \
+ .byte 0x0 ; \
+ .byte 0x8E ; \
+ .word 0x0
+
+#define rLOAD_INDEX( _selector, _segment_register) \
+ movl _selector , _segment_register ; \
+ addb al, ( eax )
+
+#define rLOAD_SEGMENT( _reg, _segment_register) \
+ mov _reg , _segment_register ; \
+
+/* #define rLOAD_SEGMENT( _reg, _segment_register) \
+ .code16 ; \
+ mov _reg , _segment_register ; \
+ .code32
+*/
+#define pLOAD_SEGMENT( _selector, _segment_register) \
+ movl $ ## _selector , eax ; .code16 ; \
+ mov ax, _segment_register ; .code32
+
+/* #define MOVE_WORD( _immed32, _reg ) \
+ data16 ; \
+ movl _immed32, _reg
+*/
+
+#define MOVE_WORD( _immed32, _reg ) \
+ movw _immed32, _reg
+
+/* #define MOVE_IMMED_WORD( _immed32, _reg ) \
+ data16 ; \
+ mov $ ## _immed32, _reg
+
+#define CS_OFF( _cs_symbol, _reg ) \
+ data16 ; \
+ mov _cs_symbol, _reg ; \
+ data16 ;\
+ andl $0x000ffff, _reg
+
+#define _16_NOPS \
+ nop ; \
+ nop ; \
+ nop ; \
+ nop ; \
+ nop ; \
+ nop ; \
+ nop ; \
+ nop ; \
+ nop ; \
+ nop ; \
+ nop ; \
+ nop ; \
+ nop ; \
+ nop ; \
+ nop ; \
+ nop ;
+*/
+
diff --git a/c/src/lib/libbsp/i386/ts_386ex/start/start.S b/c/src/lib/libbsp/i386/ts_386ex/start/start.S
new file mode 100644
index 0000000000..7a3c8509c1
--- /dev/null
+++ b/c/src/lib/libbsp/i386/ts_386ex/start/start.S
@@ -0,0 +1,501 @@
+/*
+ * This file is the main boot and configuration file for the TS-1325. It is
+ * solely responsible for initializing the internal register set to reflect
+ * the proper board configuration. This version is modified from the i386ex
+ * BSP startup:
+ *
+ * 1) 1 MB RAM @ 0x0100000
+ * 2) 1 MB RAM @ 0x0 but with standard DOS memory usage.
+ * 3) Timer0 used as RTEMS clock ticker, 1 msec tick rate.
+ * 4) READY# is generated by CPU
+ *
+ * The file describes the ".initial" section, which contains:
+ * 1) device configuration code
+ * 2) interrupt descriptor table
+ * 3) global descriptor table
+ * 4) and initial boot code
+ *
+ * Modified by:
+ *
+ * Tony Ambardar
+ * University of British Columbia
+ * tonya@ece.ubc.ca
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * $Id$
+ */
+
+#include "asm.h"
+#include "macros.inc"
+#include "80386ex.inc"
+
+#include "ts_1325.inc" /* controls for LED and button */
+
+/*
+ * NEW_GAS Needed for binutils 2.9.1.0.7 and higher
+ */
+
+ EXTERN (boot_card) /* exits to bspstart */
+ EXTERN (_DOS_seg_base) /* defined in startup/linkcmds */
+ EXTERN (Clock_exit)
+
+ PUBLIC (Interrupt_descriptor_table)
+ PUBLIC ( SYM(IDTR) )
+ PUBLIC (_Global_descriptor_table)
+ PUBLIC ( SYM(GDTR) )
+
+ PUBLIC( SYM(_init_i386ex) )
+
+
+ .section .initial
+
+/*
+ * Enable access to peripheral register at expanded I/O addresses
+ */
+SYM(_init_i386ex):
+ .code16
+/*
+ LED_GREEN
+ WAIT_BUTTON
+*/
+# cli Move this up for now for debug.
+ movw $0x8000 , ax
+ outb al , $REMAPCFGH
+ xchg al , ah
+ outb al , $REMAPCFGL
+ outw ax , $REMAPCFG ;
+/*
+ LED_OFF
+ WAIT_BUTTON
+*/
+/*
+ * Configure operation of the A20 Address Line
+ */
+SYM(A20):
+ movw $PORT92 , dx
+
+ inb dx , al # clear A20 port reset
+ andb $0xfe , al # b0 Fast Reset(0)=disabled,(1)=reset triggered
+ orb $0x02 , al # Bit 1 Fast A20 = 0 (always 0) else enabled.
+ outb al , dx
+/*
+ LED_YELLOW
+ WAIT_BUTTON
+*/
+SYM(Watchdog):
+ movw $WDTSTATUS , dx # address the WDT status port
+ inb dx , al # get the WDT status
+ orb $0x01 , al # set the CLKDIS bit
+ outb al , dx # disable the clock to the WDT
+/*
+ LED_GREEN
+ WAIT_BUTTON
+*/
+/*
+ * Initialize Refresh Control Unit for:
+ * Refresh Address = 0x0000
+
+ * Refresh gate between rows is 20.0 (???) uSec
+ * Using a CLK2 frequency of 50Mhz ( 25Mhz CPU )
+ * The refresh unit is enabled
+ * The refresh pin is not used.
+ *
+ * Different TS units might have different refresh intervals, so
+ * comment out. Will be set up anyway after booting to DOS.
+ */
+
+/*
+SYM(InitRCU):
+ SetExRegWord( RFSCIR , 0x1F4) # refresh interval 500
+ SetExRegWord( RFSBAD , 0x0) # base address
+ SetExRegWord( RFSADD , 0x0) # address register
+ SetExRegWord( RFSCON , 0x8000) # enable bit
+*/
+
+/*
+ LED_OFF
+ WAIT_BUTTON
+*/
+/*
+ * Initialize clock and power mgmt unit for:
+ * Clock Frequency = 50 Mhz
+ * Prescaled clock output = 1 Mhz
+ * Normal halt instructions
+ *
+ * NOTE: Hope this doesn't change the COMCLK frequency
+ */
+
+SYM(InitClk):
+ SetExRegByte( PWRCON, 0x0 )
+ SetExRegWord( CLKPRS, 0x17) # 0x13 for 1.19318 MHz. 0x17 for 1MHz.
+
+/**************************************************************
+ * Initialize the Pin Configurations
+ *************************************************************/
+/*
+ LED_YELLOW
+ WAIT_BUTTON
+*/
+/*
+ * Initialize I/O port 1 for:
+ * PIN 0 = 0, Inport for external push-button switch
+ * PIN 1 = 1, RTS0# to package pin
+ * PIN 2 = 1, DTR0# to package pin
+ * PIN 3 = 1, DSR0# to package pin
+ * PIN 4 = 0, Inport ???
+ * PIN 5 = 0, Outport (Green LED, 1 = ON)
+ * PIN 6 = 0, Outport (Red LED, 1 = OFF)
+ * PIN 7 = 0, Inport ???
+ */
+
+SYM(InitPort1):
+ SetExRegByte( P1LTC , 0xd1 )
+ SetExRegByte( P1DIR , 0x91)
+ SetExRegByte( P1CFG , 0x0e)
+/*
+ LED_GREEN
+ WAIT_BUTTON
+*/
+/*
+ * Initialize I/O port 2 for:
+ * PIN 0 = 0, Outport ???
+ * PIN 1 = 0, Outport ???
+ * PIN 2 = 0, Outport ???
+ * PIN 3 = 0, Outport ???
+ * PIN 4 = 0, Outport ???
+ * PIN 5 = 1, Int. periph, RXD0
+ * PIN 6 = 1, Int. periph, TXD0
+ * PIN 7 = 0, Outport ???
+ */
+
+SYM(InitPort2):
+ SetExRegByte( P2LTC , 0x1f )
+ SetExRegByte( P2DIR , 0x00 )
+ SetExRegByte( P2CFG , 0x60)
+/*
+ LED_OFF
+ WAIT_BUTTON
+*/
+/*
+ * Initialize I/O port 3 P3CFG
+ * PIN 0 = 1, Int. periph, TMROUT0
+ * PIN 1 = 1, Int. periph, TMROUT1
+ * PIN 2 = 1, Int. periph, INT0 (IR1)
+ * PIN 3 = 1, Int. periph, INT1 (IR5)
+ * PIN 4 = 1, Int. periph, INT2 (IR6)
+ * PIN 5 = 1, Int. periph, INT2 (IR7)
+ * PIN 6 = 0, Outport ???
+ * PIN 7 = 1, Int. periph, COMCLK used for serial I/O
+ */
+
+SYM(InitPort3):
+ SetExRegByte( P3LTC , 0x00 )
+ SetExRegByte( P3DIR , 0xbf )
+ SetExRegByte( P3CFG , 0xbf ) # can check TMROUT0
+/*
+ LED_YELLOW
+ WAIT_BUTTON
+*/
+/*
+ * Initialize Peripheral Pin Configurations:
+ * PIN 0 = 1, Select RTS1#
+ * PIN 1 = 1, Select DTR1#
+ * PIN 2 = 1, Select TXD1#
+ * PIN 3 = 1, Select CTS1#
+ * PIN 4 = 1, CS5
+ * PIN 5 = 1, Timer2 pins enabled
+ * PIN 6 = 0, Select CS6#
+ * PIN 7 = 0, Don't care
+ */
+
+SYM(InitPeriph):
+ SetExRegByte( PINCFG , 0x3f)
+/*
+ LED_GREEN
+ WAIT_BUTTON
+*/
+/*
+ * Initialize the Asynchronous Serial Ports:
+ * BIT 7 = 1, Internal SIO1 modem signals
+ * BIT 6 = 1, Internal SIO0 modem signals
+ * BIT 2 = 0, PSCLK for SSIO clock
+ * BIT 1 = 1, SERCLK for SIO1 clock
+ * BIT 0 = 1, SERCLK for SIO0 clock
+ */
+
+SYM(InitSIO):
+ SetExRegByte( SIOCFG, 0x00 ) # COMCLK -> baud-rate generator
+ # modem signals -> package pins
+ SetExRegByte( LCR0, 0x80 ) # latch DLL0, DLH0
+ SetExRegByte( DLL0, 0x01 ) # 0x0C sets to 9600 baud 0x6 = 19.2K
+ SetExRegByte( DLH0, 0x00 ) # 0x4 is 28.8K baud, 0x1 is 115K baud
+ SetExRegByte( LCR0, 0x03 ) # enable r/w buffers, IER0 accessible
+ # mode 8-n-1
+ SetExRegByte( IER0, 0x00 ) # no generated interrupts
+
+ SetExRegByte( LCR1, 0x80 ) # latch DLL0, DLH0
+ SetExRegByte( DLL1, 0x01 ) # 0x0C set to 9600 baud, 0x6 = 19.2K
+ SetExRegByte( DLH1, 0x00 ) # 0x4 is 28.8K baud
+ SetExRegByte( LCR1, 0x03 ) # enable r/w buffers, IER1 accessible
+ # reg 8-n-1
+ SetExRegByte( IER1, 0x00 ) # no generated intrrupts
+/*
+ LED_OFF
+ WAIT_BUTTON
+*/
+SYM(InitMCR):
+ SetExRegByte( MCR0, 0x03 ) # standard mode, RTS,DTR activated
+ SetExRegByte( MCR1, 0x03 ) # standard mode, RTS,DTR activated
+
+/*
+ * Initialize Timer for:
+ * BIT 7 = 1, Timer clocks disabled
+ * BIT 6 = 0, Reserved
+ * BIT 5 = 1, TMRCLK2 instead of Vcc to Gate2
+ * BIT 4 = 0, PSCLK to CLK2
+ * BIT 3 = 1, TMRCLK1 instead of Vcc to Gate1
+ * BIT 2 = 0, PSCLK to Gate1
+ * BIT 1 = 0, Vcc to Gate0
+ * BIT 0 = 0, PSCLK to Gate0
+ */
+/*
+ LED_YELLOW
+ WAIT_BUTTON
+*/
+SYM(InitTimer):
+ SetExRegByte(TMRCFG , 0x80 ) # All counters disabled, Gates 0,1
+ # and 2 are set to Vcc
+
+ SetExRegByte(TMRCON , 0x34 ) # prepare to write counter 0 LSB,MSB
+ SetExRegByte(TMR0 , 0x00 ) # sfa
+ SetExRegByte(TMR0 , 0x00 ) # sfa
+
+
+ SetExRegByte(TMRCON , 0x70 ) # mode 0 disables on Gate= Vcc
+ SetExRegByte(TMR1 , 0x00 ) # sfa
+ SetExRegByte(TMR1 , 0x00 ) # sfa
+
+ SetExRegByte(TMRCON , 0xB0 ) # mode 0 disables on gate =Vcc
+ SetExRegByte(TMR2 , 0x00 ) #
+ SetExRegByte(TMR2 , 0x00 ) #
+
+/*
+ LED_GREEN
+ WAIT_BUTTON
+*/
+/*
+ * Initialize the DMACFG register for:
+ * BIT 7 = 1 , Disable DACK#1
+ * BITs 6:4 = 100, TMROUT2 connected to DRQ1
+ * BIT 3 = 1 , Disable DACK0#
+ * BIT 2:0 = 000, Pin is connected to DRQ0
+ *
+ * NOTE: not 100% sure of this...
+ */
+
+ SetExRegByte(DMACFG , 0xC0 )
+ SetExRegByte(DMACMD1, 0x00 ) # disable both DMA channels
+ SetExRegByte(DMAMOD1, 0x40 ) # DMA0 single transer mode
+/*
+ LED_OFF
+ WAIT_BUTTON
+*/
+/*
+ * Initialize the INTCFG register for:
+ * BIT 7 = 0, 8259 cascade disabled
+ * BIT 3 = 0, SLAVE IR6 connected to Vss
+ * BIT 2 = 0, SLAVE IR5 connected to Vss
+ * BIT 1 = 0, SLAVE IR1 connected to SSIOINT
+ * BIT 0 = 0, SLAVE IR0 connected to Vss
+ *
+ * NOTE: not 100% sure of this either... Why IR5 active?
+ */
+
+SYM(InitInt):
+
+ cli # !
+/*
+ LED_YELLOW
+ WAIT_BUTTON
+*/
+ SetExRegByte(ICW1S , 0x11 ) # EDGE TRIGGERED
+ SetExRegByte(ICW2S , 0x28 ) # Slave base vector after Master
+ SetExRegByte(ICW3S , 0x02 ) # slave cascaded to IR2 on master
+ SetExRegByte(ICW4S , 0x01 ) # fully nested mode, no EOI
+
+ SetExRegByte(ICW1M , 0x11 ) # edge triggered
+ SetExRegByte(ICW2M , 0x20 ) # base vector starts at byte 32
+ SetExRegByte(ICW3M , 0x04) # internal slave cascaded from master IR2
+ SetExRegByte(ICW4M , 0x01 ) # idem
+
+ SetExRegByte(OCW1M , 0xfb ) # mask master IRQs, but not IR2 (cascade)
+ SetExRegByte(OCW1S , 0xff ) # mask all slave IRQs
+ SetExRegByte(INTCFG , 0x00 ) # slave IRs -> Vss or SSIOINT
+
+/* The i8259s_cache (IRQ mask) location is in BSS, which is zeroed later!
+ * So to initialize the cache we should do the following command after
+ * the BSS is zeroed, and in 32-bit protected mode.
+ *
+ * movw $0xFFFB, SYM(i8259s_cache)
+ *
+ */
+
+/*
+ NOTE: not sure about this so comment out...
+
+SYM(SetCS4):
+ SetExRegWord(CS4ADL , 0x702) #Configure chip select 4
+ SetExRegWord(CS4ADH , 0x00)
+ SetExRegWord(CS4MSKH, 0x03F)
+ SetExRegWord(CS4MSKL, 0xFC01)
+*/
+/*
+ LED_GREEN
+ WAIT_BUTTON
+*/
+/*****************************
+ * Load the Global Descriptor
+ * Table Register
+ ****************************/
+
+ movl $SYM(GDTR), eax
+ andl $0xFFFF, eax
+
+#ifdef NEW_GAS
+ addr32
+ data32
+#endif
+
+ lgdt (eax) # location of GDT in segment
+
+/*
+ NOTE: not sure about this either so comment out for now...
+SYM(SetUCS):
+ SetExRegWord(UCSADL, 0xC503) # values taken from TS-1325 memory
+ SetExRegWord(UCSADH, 0x000D)
+ SetExRegWord(UCSMSKH, 0x0000)
+ SetExRegWord(UCSMSKL, 0x3C01) # configure upper chip select
+*/
+/*
+ LED_OFF
+ WAIT_BUTTON
+*/
+/***************************
+ * Switch to Protected Mode
+ ***************************/
+ mov cr0, eax
+ orw $0x1, ax
+ mov eax, cr0
+
+/**************************
+ * Flush prefetch queue,
+ * and load CS selector
+ *********************/
+/*
+ LED_YELLOW
+ WAIT_BUTTON
+*/
+ ljmpl $ GDT_CODE_PTR , $ SYM(_load_segment_registers) # sets the code selector
+
+/*
+ * Load the segment registers
+ */
+SYM(_load_segment_registers):
+ .code32
+/*
+ LED_GREEN
+ WAIT_BUTTON
+*/
+ pLOAD_SEGMENT( GDT_DATA_PTR, fs)
+ pLOAD_SEGMENT( GDT_DATA_PTR, gs)
+ pLOAD_SEGMENT( GDT_DATA_PTR, ss)
+ pLOAD_SEGMENT( GDT_DATA_PTR, ds)
+ pLOAD_SEGMENT( GDT_DATA_PTR, es)
+
+/*
+ * Set up the stack
+ */
+/*
+ LED_OFF
+ WAIT_BUTTON
+*/
+SYM(lidtr):
+ lidt SYM(IDTR)
+/*
+ LED_YELLOW
+ WAIT_BUTTON
+*/
+SYM (_establish_stack):
+ movl $_ebss, eax # stack starts right after bss
+ movl $stack_origin, esp # this is the high starting address
+ movl $stack_origin, ebp
+/*
+ LED_GREEN
+ WAIT_BUTTON
+*/
+/*
+ * Zero out the BSS segment
+ */
+SYM (zero_bss):
+ cld # make direction flag count up
+ movl $ SYM (_ebss),ecx # find end of .bss
+ movl $ SYM (_bss_start),edi # edi = beginning of .bss
+ subl edi,ecx # ecx = size of .bss in bytes
+ shrl ecx # size of .bss in longs
+ shrl ecx
+ xorl eax,eax # value to clear out memory
+ repne # while ecx != 0
+ stosl # clear a long in the bss
+/*
+ * Now we can initialize the IRQ mask in i8259s_cache
+ */
+ movw $0xFFFB, SYM(i8259s_cache)
+/*
+ LED_YELLOW # Indicate ready to run
+ WAIT_BUTTON
+*/
+ LED_GREEN # Indicate RTEMS running!
+
+/*
+ * Transfer control to User's Board Support Package
+ */
+ pushl $0 # environp
+ pushl $0 # argv
+ pushl $0 # argc
+ call SYM(boot_card)
+ addl $12,esp
+
+ LED_RED # Indicate RTEMS exited
+/*
+ WAIT_BUTTON
+*/
+ cli # stops interrupts after hlt!
+ hlt # shutdown
+
+
+ .balign 4 # align tables to 4 byte boundary
+
+SYM(IDTR): DESC3( SYM(Interrupt_descriptor_table), 0x07ff );
+
+SYM(Interrupt_descriptor_table): /* Now in data section */
+ .rept 256
+ .word 0,0,0,0
+ .endr
+
+
+/*
+ * Use the first (null) entry in the the GDT as a self-pointer for the GDTR.
+ * (looks like a common trick)
+ */
+
+SYM (_Global_descriptor_table):
+SYM(GDTR): DESC3( GDTR, 0x17 ); # one less than the size
+ .word 0 # padding to DESC2 size
+SYM(GDT_CODE): DESC2(0xffff,0,0x0,0x9B,0xDF,0x00);
+SYM(GDT_DATA): DESC2(0xffff,0,0x0,0x92,0xDF,0x00); # was CF
+SYM(GDT_END):
+
+END
diff --git a/c/src/lib/libbsp/i386/ts_386ex/start/ts_1325.inc b/c/src/lib/libbsp/i386/ts_386ex/start/ts_1325.inc
new file mode 100644
index 0000000000..e10999abc0
--- /dev/null
+++ b/c/src/lib/libbsp/i386/ts_386ex/start/ts_1325.inc
@@ -0,0 +1,50 @@
+/*
+ These are just some useful macros that control the TS-1325's
+ LEDs and push-button switch. Useful for debugging.
+
+ NOTE: This *must* be 16-bit compatible code to work in start.s
+
+ Tony Ambardar
+*/
+
+ .macro LED_OFF
+ movw $P1LTC, dx
+ inb dx, al
+ orb $0b01000000, al
+ andb $0b11011111, al
+ outb al, dx
+ .endm
+
+ .macro LED_GREEN
+ movw $P1LTC, dx
+ inb dx, al
+ orb $0b01100000, al
+ outb al, dx
+ .endm
+
+ .macro LED_YELLOW
+ movw $P1LTC, dx
+ inb dx, al
+ orb $0b00100000, al
+ andb $0b10111111, al
+ outb al, dx
+ .endm
+
+ .macro LED_RED
+ movw $P1LTC, dx
+ inb dx, al
+ andb $0b10011111, al
+ outb al, dx
+ .endm
+
+ .macro WAIT_BUTTON # Wait till the button is pressed for a bit.
+ movw $P1PIN, dx # ~25-30 cycles per loop, 25MHz -> 1 sec.
+ movl $300000,ecx # "Timer" count determines how long.
+0: inb dx, al
+ andb $0b00000001,al
+ jnz 0b # Button pressed?
+ decl ecx
+ jnz 0b # CX count expired?
+ .endm
+
+