00001 /* booter.c -- External RAM booter 00002 Copyright 2000, 2001, 2002 Free Software Foundation, Inc. 00003 Written by Stephane Carrez (stcarrez@nerim.fr) 00004 00005 This file is part of GTAM. 00006 00007 GTAM is free software; you can redistribute it and/or modify 00008 it under the terms of the GNU General Public License as published by 00009 the Free Software Foundation; either version 2, or (at your option) 00010 any later version. 00011 00012 GTAM is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 GNU General Public License for more details. 00016 00017 You should have received a copy of the GNU General Public License 00018 along with GTAM; see the file COPYING. If not, write to 00019 the Free Software Foundation, 59 Temple Place - Suite 330, 00020 Boston, MA 02111-1307, USA. */ 00021 00076 #include <sys/ports.h> 00077 00078 typedef void __attribute__ ((noreturn)) (* func)(); 00079 00080 static unsigned short get_char (void); 00081 static unsigned char* get_addr (void); 00082 static void restart (void); 00083 volatile int __attribute__((noreturn)) main (void); 00084 static void flush (void); 00085 void _start (void); 00086 00087 void 00088 _start() 00089 { 00090 /* Switch to 9600 baud. */ 00091 flush (); 00092 #if 0 00093 _io_ports[M6811_BAUD] = 0x30; 00094 #endif 00095 set_bus_expanded (); 00096 00097 __asm__ __volatile__ ("bra main"); 00098 /* main (); */ 00099 } 00100 00101 static void 00102 flush () 00103 { 00104 while (!(_io_ports[M6811_SCSR] & M6811_TDRE)) 00105 continue; 00106 } 00107 00108 static void 00109 put_char (unsigned char c) 00110 { 00111 flush (); 00112 _io_ports[M6811_SCDR] = c; 00113 _io_ports[M6811_SCCR2] |= M6811_TE; 00114 } 00115 00116 volatile int 00117 main () 00118 { 00119 volatile unsigned char* addr; 00120 unsigned char c; 00121 00122 while (1) 00123 { 00124 /* Print banner for synchronization. */ 00125 put_char ('\n'); 00126 put_char ('>'); 00127 00128 /* Wait for command. */ 00129 c = get_char (); 00130 00131 /* Write memory command. Command format is: 00132 00133 M<ADDR-HIGH><ADDR-LOW><SIZE>[<DATA>] 00134 00135 Address, size and data are passed in binary form. 00136 A size of 0 corresponds to 256 bytes. 00137 00138 After writing the memory, we read it back and compute 00139 a crc that is then returned. */ 00140 if (c == 'M') 00141 { 00142 unsigned char crc; 00143 unsigned char size; 00144 00145 addr = get_addr (); 00146 size = get_char (); 00147 crc = 0; 00148 do 00149 { 00150 *addr = get_char (); 00151 crc ^= *addr++; 00152 } 00153 while (--size != 0); 00154 00155 /* Report the crc in pseudo hexa. GTAM checks the crc to verify 00156 that what was written is correct. */ 00157 put_char (((crc >> 4) & 0x0F) + '0'); 00158 put_char ((crc & 0x0F) + '0'); 00159 } 00160 00161 /* Go command. Command format is: 00162 00163 G<ADDR-HIGH><ADDR-LOW> 00164 00165 We reply with a G. Depending on the program, the final \n 00166 may not be received since we don't wait for it to be sent. */ 00167 else if (c == 'G') 00168 { 00169 func handler; 00170 00171 addr = get_addr (); 00172 put_char ('G'); 00173 put_char ('\n'); 00174 flush (); 00175 00176 handler = (func) addr; 00177 handler (); 00178 } 00179 00180 /* For others, emit something to tell we are alive. */ 00181 else 00182 { 00183 put_char ('?'); 00184 } 00185 } 00186 } 00187 00188 static unsigned char* 00189 get_addr () 00190 { 00191 unsigned short c1, c2; 00192 00193 c1 = get_char (); 00194 c2 = get_char (); 00195 return (unsigned char*) (((unsigned short) c1 << 8) | ((unsigned short) c2)); 00196 } 00197 00198 static inline void 00199 restart () 00200 { 00201 volatile unsigned char* ports = &_io_ports[0]; 00202 00203 /* Wait for the transmitter to be ready. */ 00204 while (!(ports[M6811_SCSR] & M6811_TDRE)) 00205 continue; 00206 00207 /* Send a break. */ 00208 ports[M6811_SCCR2] |= M6811_SBK; 00209 00210 /* Wait some time (??? is it necessary ???). */ 00211 #if 0 00212 for (i = 1000; --i != 0;) 00213 (void) ports[M6811_TCNT]; 00214 #endif 00215 ports[M6811_SCCR2] &= ~M6811_SBK; 00216 00217 /* Go back to the main with some longjump. We can't go to _start() 00218 because it was clobbered by the ZTMP and ZREG registers. */ 00219 __asm__ __volatile__ ("lds #0x0ff"); 00220 __asm__ __volatile__ ("bra main"); 00221 } 00222 00223 static unsigned short 00224 get_char () 00225 { 00226 unsigned char c; 00227 volatile unsigned char* ports = &_io_ports[0]; 00228 00229 while (1) 00230 { 00231 c = ports[M6811_SCSR]; 00232 00233 /* If there is a read error or a break, abort everything and 00234 restart. When restarting we send a break so that the host 00235 knows we are restarting. */ 00236 if (c & M6811_FE) 00237 restart (); 00238 00239 if (c & M6811_RDRF) 00240 break; 00241 } 00242 return ports[M6811_SCDR]; 00243 }