booter.c

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_TCTN];
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 }