DS80C400 support, the beginning
[fw/sdcc] / device / lib / ds400 / tinibios.c
1 /*-------------------------------------------------------------------------
2   tinibios.c - startup and serial routines for the DS80C400 (tested on TINIM400)
3   
4    Written By - Johan Knol, johan.knol@iduna.nl
5    
6    Further hacked by Kevin Vigor with invaluable assistance from Bob Heise.
7     
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
11    later version.
12    
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.
17    
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.
21    
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 -------------------------------------------------------------------------*/
26
27 #include <tinibios.h>
28
29 #define TIMED_ACCESS(sfr,value) { TA=0xaa; TA=0x55; sfr=value; }
30
31 // FIXME: Doesn't work, maybe?
32 static void _installInterrupt(void (*isrPtr)(void), unsigned char offset)
33 {
34     unsigned char xdata * vectPtr = (unsigned char xdata *) offset;
35     unsigned long isr = (unsigned long)isrPtr;
36     
37     *vectPtr++ = 0x02;
38     *vectPtr++ = (unsigned char)(isr >> 16);
39     *vectPtr++ = (unsigned char)(isr >> 8);
40     *vectPtr = (unsigned char)isr;
41 }
42
43 unsigned char _sdcc_external_startup(void)
44 {
45 #if 0    
46     int i, j;
47
48     // Do some blinking of the LED.
49     for  (j = 0; j < 10; j++)
50     {
51         P5 |= 4;
52         for (i = 0; i < 32767; i++)
53         {
54             ;
55         }
56         P5 &= ~4;
57         for (i = 0; i < 32767; i++)
58         {
59             ;
60         }       
61     }
62 #endif    
63     
64     IE = 0; // Disable all interrupts.
65     
66   _asm
67     ; save the 24-bit return address
68     pop ar2; msb
69     pop ar1
70     pop ar0; lsb
71
72
73     mov _ESP,#0x00; reinitialize the stack
74     mov _SP,#0x00
75
76     ; restore the 24-bit return address
77     push ar0; lsb
78     push ar1
79     push ar2; msb
80   _endasm;    
81     
82     // Stub: call rom_init here, then fixup IVT.
83     // 
84     
85     Serial0Init(1, 0); // baud argument ignored.
86     
87     IE = 0x80; // Enable interrupts.
88     
89     return 0;
90 }
91
92 // now the serial0 stuff
93
94 // just to make the code more readable 
95 #define S0RBS SERIAL_0_RECEIVE_BUFFER_SIZE
96
97 // this is a ring buffer and can overflow at anytime!
98 static volatile unsigned char receive0Buffer[S0RBS];
99 static volatile int receive0BufferHead=0;
100 static volatile int receive0BufferTail=0;
101 // no buffering for transmit
102 static volatile char transmit0IsBusy=0;
103
104 static data unsigned char serial0Buffered;
105
106 /* Initialize serial0.
107
108    Available baudrates are from 110 upto 115200 (using 16-bit timer 2)
109    If baud==0, the port is disabled.
110
111    If buffered!=0, characters received are buffered using an interrupt
112 */
113
114 void Serial0Init (unsigned long baud, unsigned char buffered) {
115   
116   ES0 = 0; // disable serial channel 0 interrupt
117
118   // Need no port setup, done by boot rom.
119   
120   baud;
121   
122   // hack serial ISR in, no magic support for ISR routines yet.
123   //
124   // FIXME: this doesn't work, use only non-buffered mode!
125   
126   _installInterrupt(Serial0IrqHandler, 0x23);  
127     
128   serial0Buffered=buffered;
129  
130  if (buffered) {
131     RI_0=TI_0=0; // clear "pending" interrupts
132     ES0 = 1; // enable serial channel 0 interrupt
133   } else {
134     RI_0=0; // receive buffer empty
135     TI_0=1; // transmit buffer empty
136   }
137 }
138
139 void Serial0Baud(unsigned long baud) {
140   TR2=0; // stop timer
141   baud=-((long)OSCILLATOR/(32*baud));
142   TL2=RCAP2L= baud;
143   TH2=RCAP2H= baud>>8;
144   TF2=0; // clear overflow flag
145   TR2=1; // start timer
146 }  
147
148 void Serial0IrqHandler (void) interrupt 4 {
149   P5 |= 4;
150   if (RI_0) {
151     receive0Buffer[receive0BufferHead]=SBUF0;
152     receive0BufferHead=(receive0BufferHead+1)&(S0RBS-1);
153     if (receive0BufferHead==receive0BufferTail) {
154       /* buffer overrun, sorry :) */
155       receive0BufferTail=(receive0BufferTail+1)&(S0RBS-1);
156     }
157     RI_0=0;
158   }
159   if (TI_0) {
160     TI_0=0;
161     transmit0IsBusy=0;
162   }
163 }
164
165 char Serial0CharArrived(void) {
166   if (serial0Buffered) {
167     if (receive0BufferHead!=receive0BufferTail)
168       return receive0Buffer[receive0BufferTail];
169   } else {
170     if (RI_0)
171       return SBUF0;
172   }
173   return 0;
174 }
175
176 void Serial0PutChar (char c)
177 {
178   if (serial0Buffered) {
179     while (transmit0IsBusy)
180       ;
181     transmit0IsBusy=1;
182     SBUF0=c;
183   } else {
184     while (!TI_0)
185       ;
186     SBUF0=c;
187     TI_0=0;
188   }
189 }
190
191 char Serial0GetChar (void)
192 {
193   char c;
194   if (serial0Buffered) {
195     while (receive0BufferHead==receive0BufferTail)
196       ;
197     c=receive0Buffer[receive0BufferTail];
198     ES0=0; // disable serial interrupts
199     receive0BufferTail=(receive0BufferTail+1)&(S0RBS-1);
200     ES0=1; // enable serial interrupts
201   } else {
202     while (!RI_0)
203       ;
204     c=SBUF0;
205     RI_0=0;
206   }
207   return c;
208 }
209
210 #if 0 
211 // FIXME: no ClockMilliSecondsDelay yet.
212 void Serial0SendBreak() {
213   P3 &= ~0x02;
214   ClockMilliSecondsDelay(2);
215   P3 |= 0x02;
216 }
217 #endif
218
219 void Serial0Flush() {
220   ES0=0; // disable interrupts
221   receive0BufferHead=receive0BufferTail=0;
222   RI_0=0;
223   if (serial0Buffered) {
224     TI_0=0;
225     ES0=1; // enable interrupts
226   } else {
227     TI_0=1;
228   }
229 }