1 /*-------------------------------------------------------------------------
2 tinibios.c - startup and serial routines for the DS80C400 (tested on TINIM400)
4 Written By - Johan Knol, johan.knol@iduna.nl
6 Further hacked by Kevin Vigor with invaluable assistance from Bob Heise.
8 This program is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 2, or (at your option) any
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 In other words, you are welcome to use, share and improve this program.
23 You are forbidden to forbid anyone else to use, share and improve
24 what you give them. Help stamp out software-hoarding!
25 -------------------------------------------------------------------------*/
32 #define TIMED_ACCESS(sfr,value) { TA=0xaa; TA=0x55; sfr=value; }
34 unsigned char _sdcc_external_startup(void)
36 IE = 0; // Disable all interrupts.
41 ; save the 24-bit return address
47 mov _ESP,#0x00; reinitialize the stack
50 ; restore the 24-bit return address
56 // Stub: call rom_init here, then fixup IVT.
59 Serial0Init(1, 0); // baud argument ignored.
61 IE = 0x80; // Enable interrupts.
66 // now the serial0 stuff
68 // just to make the code more readable
69 #define S0RBS SERIAL_0_RECEIVE_BUFFER_SIZE
71 // this is a ring buffer and can overflow at anytime!
72 static volatile unsigned char receive0Buffer[S0RBS];
73 static volatile int receive0BufferHead=0;
74 static volatile int receive0BufferTail=0;
75 // no buffering for transmit
76 static volatile char transmit0IsBusy=0;
78 static __data unsigned char serial0Buffered;
80 /* Initialize serial0.
82 Available baudrates are from 110 upto 115200 (using 16-bit timer 2)
83 If baud==0, the port is disabled.
85 If buffered!=0, characters received are buffered using an interrupt
89 #define TIMER_RELOAD (65536 - ((OSCILLATOR) / (32 * SERIAL_0_BAUD)))
91 void Serial0Init (unsigned long baud, unsigned char buffered)
93 ES0 = 0; // disable serial channel 0 interrupt
96 // Need no port setup, done by boot rom.
99 SCON0 = 0x5A; // 10 bit serial 0, use timer baud rate, enable recieving
100 RCAP2H = (TIMER_RELOAD >> 8) & 0xff;
101 RCAP2L = TIMER_RELOAD & 0xff;
102 T2CON = 0x30; // Enable timer 2 for serial port
103 TR2 = 1; // Set timer 2 to run
108 serial0Buffered=buffered;
111 installInterrupt(Serial0IrqHandler, 0x23);
112 RI_0=TI_0=0; // clear "pending" interrupts
113 ES0 = 1; // enable serial channel 0 interrupt
115 RI_0=0; // receive buffer empty
116 TI_0=1; // transmit buffer empty
120 void Serial0SwitchToBuffered(void)
125 installInterrupt(Serial0IrqHandler, 0x23);
126 RI_0=TI_0=0; // clear "pending" interrupts
127 ES0 = 1; // enable serial channel 0 interrupt
132 void Serial0IrqHandler (void) __interrupt 4
135 receive0Buffer[receive0BufferHead]=SBUF0;
136 receive0BufferHead=(receive0BufferHead+1)&(S0RBS-1);
137 if (receive0BufferHead==receive0BufferTail) {
138 /* buffer overrun, sorry :) */
139 receive0BufferTail=(receive0BufferTail+1)&(S0RBS-1);
149 char Serial0CharArrived(void)
151 if (serial0Buffered) {
152 if (receive0BufferHead!=receive0BufferTail)
153 return receive0Buffer[receive0BufferTail];
161 void Serial0PutChar (char c)
163 if (serial0Buffered) {
164 while (transmit0IsBusy)
176 char Serial0GetChar (void)
179 if (serial0Buffered) {
180 while (receive0BufferHead==receive0BufferTail)
182 c=receive0Buffer[receive0BufferTail];
183 ES0=0; // disable serial interrupts
184 receive0BufferTail=(receive0BufferTail+1)&(S0RBS-1);
185 ES0=1; // enable serial interrupts
195 void Serial0SendBreak()
198 ClockMilliSecondsDelay(2);
204 ES0=0; // disable interrupts
205 receive0BufferHead=receive0BufferTail=0;
207 if (serial0Buffered) {
209 ES0=1; // enable interrupts
215 // now let's go for the clock stuff - on the DS400, we can just
216 // use the ROM's millisecond timer, running off timer 0.
218 // for now, this timer runs too fast by about 20%. We need an implementation of
219 // task_settickreload to fix this.
223 // nada, all done by DSS_rom_init
226 // we can't just use milliSeconds
227 unsigned long ClockTicks(void)
229 return task_gettimemillis_long();
232 void ClockMilliSecondsDelay(unsigned long delay)
234 unsigned long ms = task_gettimemillis_long() + delay;
236 while (ms > task_gettimemillis_long())
240 // Return the start of the XI_SEG. Really just a workaround for the
241 // fact that the linker defined symbol (s_XISEG) isn't directly accessible
242 // from C due to the lack of a leading underscore, and I'm too lazy to hack
244 static void __xdata *_xisegStart(void) __naked
252 // Return the length of the XI_SEG. Really just a workaround for the
253 // fact that the linker defined symbol (l_XISEG) isn't directly accessible
254 // from C due to the lack of a leading underscore, and I'm too lazy to hack
256 static unsigned _xisegLen(void) __naked
264 // Returns the address of the first byte available for heap memory,
265 // i.e. the first byte following the XI_SEG.
266 static void __xdata *_firstHeapByte(void)
268 unsigned char __xdata *start;
270 start = (unsigned char __xdata *) _xisegStart();
271 start += _xisegLen();
273 return (void __xdata *)start;
276 // TINIm400 specific startup.
278 // The last addressible byte of the CE0 area.
279 #define CE0_END 0xfffff
281 unsigned char romInit(unsigned char noisy, char speed)
283 void __xdata *heapStart;
284 void __xdata *heapEnd;
285 unsigned long heapLen;
288 if (speed == SPEED_2X)
298 else if (speed == SPEED_4X)
300 // Hangs on TINIm400!
311 heapStart = _firstHeapByte();
312 heapEnd = (void __xdata *)CE0_END;
314 rc = init_rom(heapStart, heapEnd);
320 printf("error: rom_init returns %d\n", (int)rc);
325 heapLen = CE0_END - (unsigned long)heapStart;
326 printf("Heap starts at %p, length %luK\n", heapStart, heapLen / 1024);
330 task_settickreload(RELOAD_14_746);
332 // Switch to interrupt driven serial I/O now that the rom is initialized.
333 Serial0SwitchToBuffered();
340 // Install an interrupt handler.
341 void installInterrupt(void (*isrPtr)(void), unsigned char offset)
343 unsigned char __xdata * vectPtr = (unsigned char __xdata *) offset;
344 unsigned long isr = (unsigned long)isrPtr;
347 *vectPtr++ = (unsigned char)(isr >> 16);
348 *vectPtr++ = (unsigned char)(isr >> 8);
349 *vectPtr = (unsigned char)isr;