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
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,
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 -------------------------------------------------------------------------*/
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.
43 ; save the
24-bit
return address
48 mov _ESP
,#0x00; reinitialize the stack
51 ; restore the
24-bit
return address
57 // Stub: call rom_init here, then fixup IVT.
60 Serial0Init(1, 0); // baud argument ignored.
62 IE
= 0x80; // Enable interrupts.
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
97 // Need no port setup, done by boot rom.
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
109 serial0Buffered
=buffered
;
112 installInterrupt(Serial0IrqHandler
, 0x23);
113 RI_0
=TI_0
=0; // clear "pending" interrupts
114 ES0
= 1; // enable serial channel 0 interrupt
116 RI_0
=0; // receive buffer empty
117 TI_0
=1; // transmit buffer empty
121 void Serial0SwitchToBuffered(void)
126 installInterrupt(Serial0IrqHandler
, 0x23);
127 RI_0
=TI_0
=0; // clear "pending" interrupts
128 ES0
= 1; // enable serial channel 0 interrupt
133 void Serial0IrqHandler (void) __interrupt (4)
136 receive0Buffer
[receive0BufferHead
]=SBUF0
;
137 receive0BufferHead
=(receive0BufferHead
+1)&(S0RBS
-1);
138 if (receive0BufferHead
==receive0BufferTail
) {
139 /* buffer overrun, sorry :) */
140 receive0BufferTail
=(receive0BufferTail
+1)&(S0RBS
-1);
150 char Serial0CharArrived(void)
152 if (serial0Buffered
) {
153 if (receive0BufferHead
!=receive0BufferTail
)
154 return receive0Buffer
[receive0BufferTail
];
162 void Serial0PutChar (char c
)
164 if (serial0Buffered
) {
165 while (transmit0IsBusy
)
177 char Serial0GetChar (void)
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
196 void Serial0SendBreak (void)
199 ClockMilliSecondsDelay(2);
203 void Serial0Flush (void)
205 ES0
=0; // disable interrupts
206 receive0BufferHead
=receive0BufferTail
=0;
208 if (serial0Buffered
) {
210 ES0
=1; // enable interrupts
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
245 static void __xdata
*_xisegStart(void) __naked
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
257 static unsigned _xisegLen(void) __naked
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
;
289 if (speed
== SPEED_2X
)
299 else if (speed
== SPEED_4X
)
301 // Hangs on TINIm400!
312 heapStart
= _firstHeapByte();
313 heapEnd
= (void __xdata
*)CE0_END
;
315 rc
= init_rom(heapStart
, heapEnd
);
321 printf("error: rom_init returns %d\n", (int)rc
);
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();
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
;
348 *vectPtr
++ = (unsigned char)(isr
>> 16);
349 *vectPtr
++ = (unsigned char)(isr
>> 8);
350 *vectPtr
= (unsigned char)isr
;