struct / union in initializer, RFE #901.
[sdcc.git] / sdcc / device / lib / ds400 / tinibios.c
blobae20c42a74bb135410c8fa83a7bc1cf940cfcc9e
1 /*-------------------------------------------------------------------------
2 tinibios.c - startup and serial routines for the DS80C400 (tested on TINIM400)
4 Copyright (C) 2003, Johan Knol <johan.knol AT iduna.nl>
6 This library is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
9 later version.
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this library; see the file COPYING. If not, write to the
18 Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
19 MA 02110-1301, USA.
21 As a special exception, if you link this library with other files,
22 some of which are compiled with SDCC, to produce an executable,
23 this library does not by itself cause the resulting executable to
24 be covered by the GNU General Public License. This exception does
25 not however invalidate any other reasons why the executable file
26 might be covered by the GNU General Public License.
27 -------------------------------------------------------------------------*/
29 #include <tinibios.h>
30 #include <ds400rom.h>
32 #include <stdio.h>
34 #define TIMED_ACCESS(sfr,value) { TA=0xaa; TA=0x55; sfr=value; }
36 unsigned char __sdcc_external_startup(void)
38 IE = 0; // Disable all interrupts.
40 PSW = 0;
42 __asm
43 ; save the 24-bit return address
44 pop ar2; msb
45 pop ar1
46 pop ar0; lsb
48 mov _ESP,#0x00; reinitialize the stack
49 mov _SP,#0x00
51 ; restore the 24-bit return address
52 push ar0; lsb
53 push ar1
54 push ar2; msb
55 __endasm;
57 // Stub: call rom_init here, then fixup IVT.
60 Serial0Init(1, 0); // baud argument ignored.
62 IE = 0x80; // Enable interrupts.
64 return 0;
67 // now the serial0 stuff
69 // just to make the code more readable
70 #define S0RBS SERIAL_0_RECEIVE_BUFFER_SIZE
72 // this is a ring buffer and can overflow at anytime!
73 static volatile unsigned char receive0Buffer[S0RBS];
74 static volatile int receive0BufferHead=0;
75 static volatile int receive0BufferTail=0;
76 // no buffering for transmit
77 static volatile char transmit0IsBusy=0;
79 static __data unsigned char serial0Buffered;
81 /* Initialize serial0.
83 Available baudrates are from 110 upto 115200 (using 16-bit timer 2)
84 If baud==0, the port is disabled.
86 If buffered!=0, characters received are buffered using an interrupt
90 #define TIMER_RELOAD (65536 - ((OSCILLATOR) / (32 * SERIAL_0_BAUD)))
92 void Serial0Init (unsigned long baud, unsigned char buffered)
94 ES0 = 0; // disable serial channel 0 interrupt
96 #if 0
97 // Need no port setup, done by boot rom.
98 baud;
99 #else
100 SCON0 = 0x5A; // 10 bit serial 0, use timer baud rate, enable receiving
101 RCAP2H = (TIMER_RELOAD >> 8) & 0xff;
102 RCAP2L = TIMER_RELOAD & 0xff;
103 T2CON = 0x30; // Enable timer 2 for serial port
104 TR2 = 1; // Set timer 2 to run
106 baud;
107 #endif
109 serial0Buffered=buffered;
111 if (buffered) {
112 installInterrupt(Serial0IrqHandler, 0x23);
113 RI_0=TI_0=0; // clear "pending" interrupts
114 ES0 = 1; // enable serial channel 0 interrupt
115 } else {
116 RI_0=0; // receive buffer empty
117 TI_0=1; // transmit buffer empty
121 void Serial0SwitchToBuffered(void)
123 IE &= ~0x80;
125 serial0Buffered = 1;
126 installInterrupt(Serial0IrqHandler, 0x23);
127 RI_0=TI_0=0; // clear "pending" interrupts
128 ES0 = 1; // enable serial channel 0 interrupt
130 IE |= 0x80;
133 void Serial0IrqHandler (void) __interrupt (4)
135 if (RI_0) {
136 receive0Buffer[receive0BufferHead]=SBUF0;
137 receive0BufferHead=(receive0BufferHead+1)&(S0RBS-1);
138 if (receive0BufferHead==receive0BufferTail) {
139 /* buffer overrun, sorry :) */
140 receive0BufferTail=(receive0BufferTail+1)&(S0RBS-1);
142 RI_0=0;
144 if (TI_0) {
145 TI_0=0;
146 transmit0IsBusy=0;
150 char Serial0CharArrived(void)
152 if (serial0Buffered) {
153 if (receive0BufferHead!=receive0BufferTail)
154 return receive0Buffer[receive0BufferTail];
155 } else {
156 if (RI_0)
157 return SBUF0;
159 return 0;
162 void Serial0PutChar (char c)
164 if (serial0Buffered) {
165 while (transmit0IsBusy)
167 transmit0IsBusy=1;
168 SBUF0=c;
169 } else {
170 while (!TI_0)
172 TI_0 = 0;
173 SBUF0=c;
177 char Serial0GetChar (void)
179 char c;
180 if (serial0Buffered) {
181 while (receive0BufferHead==receive0BufferTail)
183 c=receive0Buffer[receive0BufferTail];
184 ES0=0; // disable serial interrupts
185 receive0BufferTail=(receive0BufferTail+1)&(S0RBS-1);
186 ES0=1; // enable serial interrupts
187 } else {
188 while (!RI_0)
190 c=SBUF0;
191 RI_0=0;
193 return c;
196 void Serial0SendBreak (void)
198 P3 &= ~0x02;
199 ClockMilliSecondsDelay(2);
200 P3 |= 0x02;
203 void Serial0Flush (void)
205 ES0=0; // disable interrupts
206 receive0BufferHead=receive0BufferTail=0;
207 RI_0=0;
208 if (serial0Buffered) {
209 TI_0=0;
210 ES0=1; // enable interrupts
211 } else {
212 TI_0=1;
216 // now let's go for the clock stuff - on the DS400, we can just
217 // use the ROM's millisecond timer, running off timer 0.
219 // for now, this timer runs too fast by about 20%. We need an implementation of
220 // task_settickreload to fix this.
222 void ClockInit (void)
224 // nada, all done by DSS_rom_init
227 // we can't just use milliSeconds
228 unsigned long ClockTicks(void)
230 return task_gettimemillis_long();
233 void ClockMilliSecondsDelay(unsigned long delay)
235 unsigned long ms = task_gettimemillis_long() + delay;
237 while (ms > task_gettimemillis_long())
241 // Return the start of the XI_SEG. Really just a workaround for the
242 // fact that the linker defined symbol (s_XISEG) isn't directly accessible
243 // from C due to the lack of a leading underscore, and I'm too lazy to hack
244 // the linker.
245 static void __xdata *_xisegStart(void) __naked
247 __asm
248 mov dptr, #(s_XISEG)
250 __endasm;
253 // Return the length of the XI_SEG. Really just a workaround for the
254 // fact that the linker defined symbol (l_XISEG) isn't directly accessible
255 // from C due to the lack of a leading underscore, and I'm too lazy to hack
256 // the linker.
257 static unsigned _xisegLen(void) __naked
259 __asm
260 mov dptr, #(l_XISEG)
262 __endasm;
265 // Returns the address of the first byte available for heap memory,
266 // i.e. the first byte following the XI_SEG.
267 static void __xdata *_firstHeapByte(void)
269 unsigned char __xdata *start;
271 start = (unsigned char __xdata *) _xisegStart();
272 start += _xisegLen();
274 return (void __xdata *)start;
277 // TINIm400 specific startup.
279 // The last addressable byte of the CE0 area.
280 #define CE0_END 0xfffff
282 unsigned char romInit(unsigned char noisy, char speed)
284 void __xdata *heapStart;
285 void __xdata *heapEnd;
286 unsigned long heapLen;
287 unsigned char rc;
289 if (speed == SPEED_2X)
291 PMR = 0x82;
292 PMR = 0x92;
294 while (!(EXIF & 8))
297 PMR = 0x12;
299 else if (speed == SPEED_4X)
301 // Hangs on TINIm400!
302 PMR = 0x82;
303 PMR = 0x8a;
304 PMR = 0x9a;
306 while (!(EXIF & 8))
309 PMR = 0x1a;
312 heapStart = _firstHeapByte();
313 heapEnd = (void __xdata *)CE0_END;
315 rc = init_rom(heapStart, heapEnd);
317 if (noisy)
319 if (rc)
321 printf("error: rom_init returns %d\n", (int)rc);
322 return rc;
324 else
326 heapLen = CE0_END - (unsigned long)heapStart;
327 printf("Heap starts at %p, length %luK\n", heapStart, heapLen / 1024);
331 task_settickreload(RELOAD_14_746);
333 // Switch to interrupt driven serial I/O now that the rom is initialized.
334 Serial0SwitchToBuffered();
336 P5 &= ~4; // LED on.
338 return 0;
341 // Install an interrupt handler.
342 void installInterrupt(void (*isrPtr)(void), unsigned char offset)
344 unsigned char __xdata * vectPtr = (unsigned char __xdata *) offset;
345 unsigned long isr = (unsigned long)isrPtr;
347 *vectPtr++ = 0x02;
348 *vectPtr++ = (unsigned char)(isr >> 16);
349 *vectPtr++ = (unsigned char)(isr >> 8);
350 *vectPtr = (unsigned char)isr;