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
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
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
.elf.b:
$(OBJCOPY) --output-target=binary --gap-fill=255 \
- --only-section=.data $(OBJCOPY_FLAGS) $< $*.b
-
+ $(OBJCOPY_FLAGS) $< $*.b
--- /dev/null
+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.
+
+
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 */
" 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"
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;
+}
#include "motors.h"
#include "sci.h"
#include "vend.h"
+#include "xmodem.h"
u8 last_standalone;
u8 last_switch_input;
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';
}
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;
" -------------| " CRLF
" | | | | " CRLF
" <__/ \\__>" CRLF
+"" CRLF
+" ... Where's the cheese?" CRLF
);
}
" 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);
case 'Q':
quit();
break;
+ case 'G':
+ getrom();
+ break;
default:
// shurg
unknown_command();
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). */
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 */
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) {
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 */
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 */
+ }
+}
#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_ */
--- /dev/null
+#!/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
.sect .text
rti:
jsr chime
+ jsr serial_rti
ldaa #0x40
staa 0x1025
rti
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 */
--- /dev/null
+/* 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."); */
+}
--- /dev/null
+/* 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 */