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 {
134 receive0Buffer[receive0BufferHead]=SBUF0;
135 receive0BufferHead=(receive0BufferHead+1)&(S0RBS-1);
136 if (receive0BufferHead==receive0BufferTail) {
137 /* buffer overrun, sorry :) */
138 receive0BufferTail=(receive0BufferTail+1)&(S0RBS-1);
148 char Serial0CharArrived(void) {
149 if (serial0Buffered) {
150 if (receive0BufferHead!=receive0BufferTail)
151 return receive0Buffer[receive0BufferTail];
159 void Serial0PutChar (char c)
161 if (serial0Buffered) {
162 while (transmit0IsBusy)
174 char Serial0GetChar (void)
177 if (serial0Buffered) {
178 while (receive0BufferHead==receive0BufferTail)
180 c=receive0Buffer[receive0BufferTail];
181 ES0=0; // disable serial interrupts
182 receive0BufferTail=(receive0BufferTail+1)&(S0RBS-1);
183 ES0=1; // enable serial interrupts
193 void Serial0SendBreak() {
195 ClockMilliSecondsDelay(2);
199 void Serial0Flush() {
200 ES0=0; // disable interrupts
201 receive0BufferHead=receive0BufferTail=0;
203 if (serial0Buffered) {
205 ES0=1; // enable interrupts
211 // now let's go for the clock stuff - on the DS400, we can just
212 // use the ROM's millisecond timer, running off timer 0.
214 // for now, this timer runs too fast by about 20%. We need an implementation of
215 // task_settickreload to fix this.
218 // nada, all done by DSS_rom_init
221 // we can't just use milliSeconds
222 unsigned long ClockTicks(void) {
223 return task_gettimemillis_long();
226 void ClockMilliSecondsDelay(unsigned long delay) {
227 unsigned long ms = task_gettimemillis_long() + delay;
229 while (ms > task_gettimemillis_long())
233 // Return the start of the XI_SEG. Really just a workaround for the
234 // fact that the linker defined symbol (s_XISEG) isn't directly accessible
235 // from C due to the lack of a leading underscore, and I'm too lazy to hack
237 static void xdata *_xisegStart(void) _naked
245 // Return the length of the XI_SEG. Really just a workaround for the
246 // fact that the linker defined symbol (l_XISEG) isn't directly accessible
247 // from C due to the lack of a leading underscore, and I'm too lazy to hack
249 static unsigned _xisegLen(void) _naked
257 // Returns the address of the first byte available for heap memory,
258 // i.e. the first byte following the XI_SEG.
259 static void xdata *_firstHeapByte(void)
261 unsigned char xdata *start;
263 start = (unsigned char xdata *) _xisegStart();
264 start += _xisegLen();
266 return (void xdata *)start;
269 // TINIm400 specific startup.
271 // The last addressible byte of the CE0 area.
272 #define CE0_END 0xfffff
274 unsigned char romInit(unsigned char noisy,
277 void xdata *heapStart;
279 unsigned long heapLen;
282 if (speed == SPEED_2X)
292 else if (speed == SPEED_4X)
294 // Hangs on TINIm400!
305 heapStart = _firstHeapByte();
306 heapEnd = (void xdata *)CE0_END;
308 rc = init_rom(heapStart, heapEnd);
314 printf("error: rom_init returns %d\n", (int)rc);
319 heapLen = CE0_END - (unsigned long)heapStart;
320 printf("Heap starts at %p, length %luK\n", heapStart, heapLen / 1024);
324 task_settickreload(RELOAD_14_746);
326 // Switch to interrupt driven serial I/O now that the rom is initialized.
327 Serial0SwitchToBuffered();
334 // Install an interrupt handler.
335 void installInterrupt(void (*isrPtr)(void), unsigned char offset)
337 unsigned char xdata * vectPtr = (unsigned char xdata *) offset;
338 unsigned long isr = (unsigned long)isrPtr;
341 *vectPtr++ = (unsigned char)(isr >> 16);
342 *vectPtr++ = (unsigned char)(isr >> 8);
343 *vectPtr = (unsigned char)isr;