xmodem support
authorBernard Blackham <[email protected]>
Tue, 22 Jun 2004 19:31:32 +0000 (19:31 +0000)
committerBernard Blackham <[email protected]>
Tue, 22 Jun 2004 19:31:32 +0000 (19:31 +0000)
delay routine fix (fixes motors)
added README
general happiness

12 files changed:
ROM2/Makefile
ROM2/README [new file with mode: 0644]
ROM2/helpers.c
ROM2/main_basic.c
ROM2/memory.x
ROM2/sci.c
ROM2/sci.h
ROM2/src2c.pl [new file with mode: 0644]
ROM2/vectors.s
ROM2/vend.h
ROM2/xmodem.c [new file with mode: 0644]
ROM2/xmodem.h [new file with mode: 0644]

index 17694c0..71e8c7d 100644 (file)
@@ -3,9 +3,8 @@
 OBJS = \
        motors.o keypad.o display_basic.o coinmech.o chime.o \
        helpers.o main_basic.o sci.o \
-       vectors.o start.o
+       vectors.o start.o romsrc.o xmodem.o
 INCLUDES = vend.h keypad.h chime.h asm.h display_basic.h ports.h types.h
-
 # debugging doesn't get compiled into the ROM image
 CFLAGS = -m68hc11 -mshort -Wall -O1 \
        -msoft-reg-count=0 -ffixed-z -g -fomit-frame-pointer
@@ -39,9 +38,10 @@ all: rom2.b rom2.elf rom2.s19
 
 rom2.elf: $(OBJS) memory.x
        $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBADD)
+       $(SIZE) $@
 
 clean:
-       rm -f *.o *.elf *.s19 *.b *.a
+       rm -f *.o *.elf *.s19 *.b *.a rom.tar.bz2 romsrc.c
 
 #
 # Some useful rules
@@ -52,6 +52,12 @@ dump:        rom2.elf
 size:   rom2.s19
        $(SIZE) $<
 
+rom.tar.bz2:
+       rm -f romsrc.c
+       tar cjf rom.tar.bz2 README Makefile *.c *.h *.s *.x
+
+romsrc.c: rom.tar.bz2
+       perl -w src2c.pl < $< > $@
 
 #
 # Implicit rules
@@ -67,5 +73,4 @@ size:   rom2.s19
 
 .elf.b:
        $(OBJCOPY) --output-target=binary --gap-fill=255 \
-                   --only-section=.data $(OBJCOPY_FLAGS) $< $*.b
-                  
+                   $(OBJCOPY_FLAGS) $< $*.b
diff --git a/ROM2/README b/ROM2/README
new file mode 100644 (file)
index 0000000..3bfc653
--- /dev/null
@@ -0,0 +1,14 @@
+This is the source code for the Snack Machine's new ROM at the University
+Computer Club.
+
+To build, you'll require the gcc-m68hc1x & binutils-m68hc1x packages.
+
+You can also run it in a simulator using gdb-m68hc1x. Except to do so, you'll
+need to use a local copy generated as such:
+
+sed -e 's|m68hc11eepr/reg 0xb000 512|m68hc11eepr/reg 0x4000 1  |' < /usr/bin/m68hc11-gdb > my-m68hc11-gdb
+
+This is in order to move the internal eprom out of the way in the simulator that
+would otherwise cause the simulator to fail when loading the ROM.
+
+
index ad52123..424f81c 100644 (file)
@@ -13,8 +13,6 @@ void delay(u16 ms) {
        asm volatile ("ldx %0\n" :: "m" (ms) : "x");
        asm volatile (
                "delay_loop:\n"
-               "       dex\n"                        /* 3 */
-               "       beq delay_out\n"              /* 3 */
                //"     ldd #327\n"                   /* 3 */
                "       ldd #150\n"                   /* 3 */
                "delay_inner_loop:\n" /* 15 cycles each */
@@ -23,6 +21,8 @@ void delay(u16 ms) {
                "       subd #0x0001\n"               /* 4 */
                "       bra delay_inner_loop\n"       /* 3 */
                "delay_inner_loop_end:\n"
+               "       dex\n"                        /* 3 */
+               "       beq delay_out\n"              /* 3 */
                "       bra delay_loop\n"             /* 3 */
                "delay_out:\n" ::: "x", "d");
                /*"     pulb\n"
@@ -50,3 +50,8 @@ void my_memcpy(char* dst, char* src, u8 size) {
        u8 i = 0;
        for (i = 0; i < size; i++) dst[i] = src[i];
 }
+
+void my_memset(char* dst, u8 val, u16 count) {
+       char* c;
+       for (c = dst; c < dst+count; c++) *c = val;
+}
index 5c35aab..cddfb12 100644 (file)
@@ -13,6 +13,7 @@
 #include "motors.h"
 #include "sci.h"
 #include "vend.h"
+#include "xmodem.h"
 
 u8 last_standalone;
 u8 last_switch_input;
@@ -182,7 +183,7 @@ u8 hexchar2u8(char b) {
 
 char nibble2hexchar(u8 b) {
        if (b <= 9) return b+'0';
-       if (b >= 10 && b <= 15) return b+'A';
+       if (b >= 10 && b <= 15) return b+'A'-10;
        return 'X';
 }
 
@@ -203,7 +204,7 @@ void do_chime() {
        if (sci_rx_buf[1] == '\0')
                chime_start();
        else if (sci_rx_buf[2] != '\0' && sci_rx_buf[3] == '\0')
-               chime_start(hex2u8(sci_rx_buf[1], sci_rx_buf[2]));
+               chime_for(hex2u8(sci_rx_buf[1], sci_rx_buf[2]));
        else {
                send_string("510 Unknown chime duration." CRLF);
                return;
@@ -289,6 +290,8 @@ void moo() {
 "    -------------|   " CRLF
 "        | |    | | " CRLF
 "       <__/    \\__>" CRLF
+"" CRLF
+"  ... Where's the cheese?" CRLF
        );
 }
 
@@ -304,10 +307,64 @@ void help() {
                " B[nn]         beep for a duration nn (optional)" CRLF
                " S[...]        query all internal switch states" CRLF
                " H[...]        this help screen" CRLF
+               " GETROM        download the ROM source code using xmodem" CRLF
                "Comments start with a #" CRLF
        );
 }
 
+extern const char _rom_src_data[];
+extern const u16 _rom_src_len;
+void getrom() {
+       if (!my_strncmp("ETROM", (char*)sci_rx_buf+1, 5)) {
+               unknown_command();
+               return;
+       }
+       char s[4];
+       send_string("Writing to serial port (maybe). Size is 0x");
+       send_string(u82hex(_rom_src_len >> 8));
+       send_string(u82hex(_rom_src_len & 0xff));
+       send_string(" with signature ");
+       s[0] = _rom_src_data[0];
+       s[1] = _rom_src_data[1];
+       s[2] = _rom_src_data[2];
+       s[3] = '\0';
+       send_string(s);
+       send_string(CRLF " Type YES to download via XMODEM: ");
+       msg_clr();
+       while (!sci_have_packet); /* spin */
+       if (!my_strncmp("YES", (char*)sci_rx_buf, 3)) return;
+
+       sci_init();
+       sci_doing_xmodem = 1;
+       if (!xmodem_init_xfer()) {
+               sci_doing_xmodem = 0;
+               send_string("XMODEM init failed. Nobody's listening :(" CRLF);
+               return;
+       }
+       char *p = (char*)_rom_src_data;
+       char *end = (char*)_rom_src_data+_rom_src_len;
+       bool aborted = 0;
+       while (1) {
+               if (!xmodem_send_packet((char*)p, 128)) {
+                       aborted = 1;
+                       break;
+               }
+               p += 128;
+               if (p + 128 > end) {
+                       /* send partial packet */
+                       if (!xmodem_send_packet((char*)p, end-p)) aborted = 1;
+                       break;
+               }
+       }
+
+       xmodem_finish_xfer();
+       sci_doing_xmodem = 0;
+       if (aborted)
+               send_string(CRLF "Transfer aborted." CRLF);
+       else
+               send_string(CRLF "Transfer complete." CRLF);
+}
+
 void quit() {
        if (my_strncmp("UIT", (char*)sci_rx_buf+1, 3))
                send_string("013 You can't quit you doofus." CRLF);
@@ -429,6 +486,9 @@ int main() {
                                case 'Q':
                                        quit();
                                        break;
+                               case 'G':
+                                       getrom();
+                                       break;
                                default:
                                        // shurg
                                        unknown_command();
index e983e0c..6b3abc6 100644 (file)
@@ -4,6 +4,7 @@ MEMORY
   page0 (rwx) : ORIGIN = 0x0000, LENGTH = 0x0080
   data  (rw)  : ORIGIN = 0x0080, LENGTH = 0x0080
   text  (rx)  : ORIGIN = 0x8000, LENGTH = 0x8000
+  eeprom(rwx) : ORIGIN = 0x4000, LENGTH = 0x0200
 }
 
 /* Setup the stack on the top of the data internal ram (not used).  */
index d7c9f28..fe59f75 100644 (file)
@@ -5,7 +5,9 @@ char sci_tx_buf[BUFFER_LEN];
 volatile char sci_rx_buf[BUFFER_LEN];
 volatile bool sci_have_packet;
 volatile u8 sci_rx_buf_ptr;
+volatile u8 sci_rx_buf_ptr_start;
 volatile bool sci_echo;
+bool sci_doing_xmodem;
 
 void sci_init() {
        /* assumes clock of 4.91Mhz */
@@ -19,7 +21,9 @@ void sci_init() {
 
        sci_have_packet = 0;
        sci_rx_buf_ptr = 0;
+       sci_rx_buf_ptr_start = 0;
        sci_echo = 0;
+       sci_doing_xmodem = 0;
 }
 
 void send_buffer(bool crlf) {
@@ -48,6 +52,16 @@ void send_string(char* c) {
 
 void sci_rx_int() {
        char buf = _io_ports[M6811_SCDR];
+       if (sci_doing_xmodem) {
+               if ((sci_rx_buf_ptr+1)%BUFFER_LEN == sci_rx_buf_ptr_start) {
+                       /* we drop following bytes :( */
+                       return;
+               }
+               sci_rx_buf[sci_rx_buf_ptr] = buf;
+               sci_rx_buf_ptr++;
+               sci_rx_buf_ptr %= BUFFER_LEN;
+               return;
+       }
        if (sci_echo) {
                while (!(_io_ports[M6811_SCSR] & M6811_TDRE)); /* wait for TX ready */
                _io_ports[M6811_SCDR] = buf; /* send byte */
@@ -91,3 +105,25 @@ void send_ack() {
 void send_nack() {
        send_string("?" CRLF);
 }
+
+u16 sci_timer;
+void serial_rti() { /* called every 6.6 ms */
+       if (sci_timer) sci_timer--;
+}
+
+/* for gdb compatibility */
+int serial_readchar(u8 timeout) {
+       sci_timer = timeout * 152;
+       while (sci_timer && sci_rx_buf_ptr_start == sci_rx_buf_ptr); /* spin */
+       if (sci_timer == 0) return SERIAL_TIMEOUT;
+       return sci_rx_buf[sci_rx_buf_ptr_start++];
+}
+
+void serial_write(const char *str, int len) {
+       char *c, *end;
+       end = (char*)(str + len);
+       for (c = (char*)str; c < end; c++) {
+               while (!(_io_ports[M6811_SCSR] & M6811_TDRE)); /* wait for TX ready */
+               _io_ports[M6811_SCDR] = *c; /* send byte */
+       }
+}
index 0db4b64..8a46d2d 100644 (file)
@@ -6,17 +6,22 @@
 #define BUFFER_LEN 12
 #define CRLF "\r\n"
 
+#define SERIAL_TIMEOUT -2
+
 void sci_init();
 void msg_clr();
 void send_buffer(bool crlf);
 void send_string(char* s);
 void send_ack();
 void send_nack();
+int serial_readchar(u8 timeout);
+void serial_write(const char *str, int len);
 #define wait_for_tx_free() do { } while(0)
 
 extern char sci_tx_buf[BUFFER_LEN];
 extern volatile char sci_rx_buf[BUFFER_LEN];
 extern volatile u8 sci_have_packet;
 extern volatile bool sci_echo;
+extern bool sci_doing_xmodem;
 
 #endif /* _SCI_H_ */
diff --git a/ROM2/src2c.pl b/ROM2/src2c.pl
new file mode 100644 (file)
index 0000000..8da9766
--- /dev/null
@@ -0,0 +1,17 @@
+#!/usr/bin/perl -w
+
+print "#include \"types.h\"\n";
+print "const char _rom_src_data[] = {\n\t";
+my $size = 0;
+my $a;
+while (read STDIN,$a,1) {
+       printf "0x%02x,", ord($a);
+       $size++;
+       if ($size%8 == 0) { print "\n\t"; }
+}
+print <<EOT;
+};
+
+const u16 _rom_src_len = $size;
+
+EOT
index 3ffb6a6..04bfb72 100644 (file)
@@ -44,6 +44,7 @@ def:
        .sect .text
 rti:
        jsr chime
+       jsr serial_rti
        ldaa #0x40
        staa 0x1025
        rti
index 460aa71..7686620 100644 (file)
@@ -35,6 +35,7 @@ void delay(u16 ms);
 void my_strncpy(char* dst, char* src, u8 max_size); /* for null-term strings */
 bool my_strncmp(char* a, char* b, u8 len);
 void my_memcpy(char* dst, char* src, u8 size);
+void my_memset(char* dst, u8 val, u16 count);
 
 /******** Some meaningful bits ******/
 #define PORTA_CHIME         0x10 /* chime is on when set */
diff --git a/ROM2/xmodem.c b/ROM2/xmodem.c
new file mode 100644 (file)
index 0000000..7615d9b
--- /dev/null
@@ -0,0 +1,267 @@
+/* XMODEM support for GDB, the GNU debugger.
+   Copyright 1995, 2000, 2001 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "chime.h"
+#include "sci.h"
+#include "xmodem.h"
+
+/* These definitions are for xmodem protocol. */
+
+#define SOH    0x01
+#define STX    0x02
+#define ACK    0x06
+#define NAK    0x15
+#define EOT    0x04
+#define CANCEL 0x18
+
+static int blknum;             /* XMODEM block number */
+static int crcflag;            /* Sez we are using CRC's instead of cksums */
+
+static int
+readchar (int timeout)
+{
+  int c;
+
+  c = serial_readchar (timeout);
+
+  if (c >= 0)
+    return c;
+
+  if (c == SERIAL_TIMEOUT)
+         chime_for(0xff);
+    /*error ("Timeout reading from remote system.")*/;
+
+  return 0;
+}
+
+#define CRC16 0x1021           /* Generator polynomial (X^16 + X^12 + X^5 + 1) */
+
+
+/* Call this to init the fast CRC-16 calculation table.  */
+
+static short crctab(u8 val) {
+      int i;
+      unsigned int crc;
+
+      crc = val << 8;
+
+      for (i = 0; i < 8; ++i)
+       {
+         crc <<= 1;
+
+         if (crc & 0x10000)
+           crc ^= CRC16;
+       }
+
+         return crc;
+}
+
+/* Calculate a CRC-16 for the LEN byte message pointed at by P.  */
+/* Pads with ^Z if necessary */
+
+static unsigned short
+docrc (unsigned char *p, int len)
+{
+  int len2 = len;
+  unsigned short crc = 0;
+
+  while (len-- > 0)
+    crc = (crc << 8) ^ crctab((crc >> 8) ^ *p++);
+  if (len2 < 128) {
+    len = 128-len;
+    while (len-- > 0)
+      crc = (crc << 8) ^ crctab((crc >> 8) ^ 0x1a);
+  }
+
+  return crc;
+}
+
+/* Start up the transmit process.  Reset state variables.  Wait for receiver to
+   send NAK or CRC request.  */
+
+int
+xmodem_init_xfer ()
+{
+  int c;
+  int i;
+
+  blknum = 1;
+  crcflag = 0;
+
+  for (i = 1; i <= 10; i++)
+    {
+      c = readchar (6);
+
+      switch (c)
+       {
+       case 'C':
+         crcflag = 1;
+         /* fall through */
+       case NAK:
+         return 1;
+       default:
+         chime_for(0x7f);
+         /* fprintf_unfiltered (gdb_stderr, "xmodem_init_xfer: Got unexpected character %c (0%o)\n", c, c); */
+         continue;
+       case CANCEL:            /* target aborted load */
+         /* fprintf_unfiltered (gdb_stderr, "Got a CANCEL from the target.\n"); */
+         return 0;
+       }
+    }
+  chime_for(0xff);
+  /*error ("xmodem_init_xfer:  Too many unexpected characters.");*/
+  return 0;
+}
+
+/* Take 128 bytes of data and make a packet out of it.
+
+ *      Each packet looks like this:
+ *      +-----+-------+-------+------+-----+
+ *      | SOH | Seq1. | Seq2. | data | SUM |
+ *      +-----+-------+-------+------+-----+
+ *      SOH  = 0x01
+ *      Seq1 = The sequence number.
+ *      Seq2 = The complement of the sequence number.
+ *      Data = A 128 bytes of data.
+ *      SUM  = Add the contents of the 128 bytes and use the low-order
+ *             8 bits of the result.
+ *
+ * send_xmodem_packet fills in the XMODEM fields of PACKET and sends it to the
+ * remote system.  PACKET must be XMODEM_PACKETSIZE bytes long.  The data must
+ * start 3 bytes after the beginning of the packet to leave room for the
+ * XMODEM header.  LEN is the length of the data portion of the packet (and
+ * must be <= 128 bytes).  If it is < 128 bytes, ^Z padding will be added.
+ */
+
+bool
+xmodem_send_packet (const unsigned char *packet, int len)
+{
+  int i;
+  int retries;
+  char p;
+  char s[3];
+
+  if (len > XMODEM_DATASIZE) {
+    chime_for(0xff);
+    return 0;
+  }
+
+  for (retries = 3; retries >= 0; retries--) {
+    int c;
+    /* send the packet header */
+    send_string("\x01"); /* SOH */
+    p = blknum; serial_write(&p, 1);
+    p = ~blknum; serial_write(&p, 1);
+
+    serial_write(packet, len); /* Send data bytes */
+
+    char *ptr, *end;
+    ptr = (char*)(packet+len);
+    end = (char*)(packet+128);
+    for (; ptr < end; ptr++) {
+      send_string("\x1A"); /* pad with ^Z */
+    }
+
+    /* Add ^Z padding if packet < 128 (or 1024) bytes */
+    if (crcflag) {
+      u16 crc;
+
+      crc = docrc ((unsigned char*)packet, len);
+
+      s[0] = crc >> 8;
+      s[1] = crc & 0xff;
+      s[2] = '\0';
+      send_string(s);
+    } else {
+      int sum;
+
+      sum = 0;
+      for (i = 0; i < len; i++)
+       sum += packet[i];
+      for (; i < 128; i++)
+       sum += 0x1a;
+
+      s[0] = sum;
+      s[1] = '\0';
+      send_string(s);
+    }
+
+    c = readchar (3);
+    switch (c)
+      {
+      case ACK:
+       goto out;
+      case NAK:
+       continue;
+      case CANCEL:
+       /* error ("xmodem_send_packet: Transfer aborted by receiver."); */
+       chime_for(0xff);
+       return 0;
+      default:
+       /*fprintf_unfiltered (gdb_stderr, "xmodem_send_packet: Got unexpected character %c (0%o)\n", c, c);*/
+       /* mtearle is evil */
+       chime_for(c);
+       continue;
+      }
+  }
+
+  //serial_write ("\004", 1);  /* Send an EOT */
+
+  /* error ("xmodem_send_packet:  Excessive retries."); */
+  chime_for(0xff);
+  return 0;
+out:
+  blknum++;
+  return 1;
+}
+
+/* Finish off the transfer.  Send out the EOT, and wait for an ACK.  */
+
+void
+xmodem_finish_xfer ()
+{
+  int retries;
+
+  for (retries = 10; retries >= 0; retries--)
+    {
+      int c;
+
+      serial_write ("\004", 1);        /* Send an EOT */
+
+      c = readchar (3);
+      switch (c)
+       {
+       case ACK:
+         return;
+       case NAK:
+         continue;
+       case CANCEL:
+         chime_for(0xff);
+         /* error ("xmodem_finish_xfer: Transfer aborted by receiver."); */
+       default:
+         /* fprintf_unfiltered (gdb_stderr, "xmodem_send_packet: Got unexpected character %c (0%o)\n", c, c); */
+         chime_for(c);
+         continue;
+       }
+    }
+
+  chime_for(0xff);
+  /* error ("xmodem_finish_xfer:  Excessive retries."); */
+}
diff --git a/ROM2/xmodem.h b/ROM2/xmodem.h
new file mode 100644 (file)
index 0000000..e119c03
--- /dev/null
@@ -0,0 +1,29 @@
+/* XMODEM support for GDB, the GNU debugger.
+   Copyright 1995, 2000 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+int xmodem_init_xfer ();
+bool xmodem_send_packet (const unsigned char *packet, int len);
+void xmodem_finish_xfer ();
+
+#define XMODEM_DATASIZE        128     /* The data size is ALWAYS 128 */
+#define XMODEM_1KDATASIZE 1024 /* Unless it's 1024!!! */
+#define XMODEM_PACKETSIZE 133  /* data + packet headers and crc */
+#define XMODEM_1KPACKETSIZE 1024 + 5   /* data + packet headers and crc */
+#define XMODEM_DATAOFFSET 3    /* Offset to start of actual data */

UCC git Repository :: git.ucc.asn.au