From db71d9706715bf39fa5c5696108019bacd8181fa Mon Sep 17 00:00:00 2001 From: Bernard Blackham Date: Tue, 22 Jun 2004 19:31:32 +0000 Subject: [PATCH] xmodem support delay routine fix (fixes motors) added README general happiness --- ROM2/Makefile | 15 ++- ROM2/README | 14 +++ ROM2/helpers.c | 9 +- ROM2/main_basic.c | 64 ++++++++++- ROM2/memory.x | 1 + ROM2/sci.c | 36 +++++++ ROM2/sci.h | 5 + ROM2/src2c.pl | 17 +++ ROM2/vectors.s | 1 + ROM2/vend.h | 1 + ROM2/xmodem.c | 267 ++++++++++++++++++++++++++++++++++++++++++++++ ROM2/xmodem.h | 29 +++++ 12 files changed, 450 insertions(+), 9 deletions(-) create mode 100644 ROM2/README create mode 100644 ROM2/src2c.pl create mode 100644 ROM2/xmodem.c create mode 100644 ROM2/xmodem.h diff --git a/ROM2/Makefile b/ROM2/Makefile index 17694c0..71e8c7d 100644 --- a/ROM2/Makefile +++ b/ROM2/Makefile @@ -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 index 0000000..3bfc653 --- /dev/null +++ b/ROM2/README @@ -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. + + diff --git a/ROM2/helpers.c b/ROM2/helpers.c index ad52123..424f81c 100644 --- a/ROM2/helpers.c +++ b/ROM2/helpers.c @@ -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; +} diff --git a/ROM2/main_basic.c b/ROM2/main_basic.c index 5c35aab..cddfb12 100644 --- a/ROM2/main_basic.c +++ b/ROM2/main_basic.c @@ -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(); diff --git a/ROM2/memory.x b/ROM2/memory.x index e983e0c..6b3abc6 100644 --- a/ROM2/memory.x +++ b/ROM2/memory.x @@ -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). */ diff --git a/ROM2/sci.c b/ROM2/sci.c index d7c9f28..fe59f75 100644 --- a/ROM2/sci.c +++ b/ROM2/sci.c @@ -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 */ + } +} diff --git a/ROM2/sci.h b/ROM2/sci.h index 0db4b64..8a46d2d 100644 --- a/ROM2/sci.h +++ b/ROM2/sci.h @@ -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 index 0000000..8da9766 --- /dev/null +++ b/ROM2/src2c.pl @@ -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 <= 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 index 0000000..e119c03 --- /dev/null +++ b/ROM2/xmodem.h @@ -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 */ -- 2.20.1