diff --git a/ROM2/Makefile b/ROM2/Makefile
index 17694c0539392854a45cfa7061aaecf12eaa7aa5..71e8c7d8281aadf5ceac4dc250cb5a4b4ae84c51 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 0000000000000000000000000000000000000000..3bfc65376de3e969678165b3c4e108284f1d3564
--- /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 ad52123b97a39a1eed528036a861948c5344c75a..424f81c31b0011c27afcc0d935540b4be04e0419 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 5c35aab32751094018ce99b0d0bcfdecbdfdc68a..cddfb12d967f79413cbf57e18cbada66b3f14145 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 e983e0c383fb7baac95bf55324a1e5a7cd6cf7c8..6b3abc6e48e38dfd122081cf6f83f4ee9bd6bd1a 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 d7c9f287df6f4c84918681b88b159855b6ddaac0..fe59f75b1b6c478a9cfaa5d5e7ebbbec1ce77e4a 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 0db4b6408f541d55c4e426aa290dff09769784c3..8a46d2d2dd587beb113c1f10d544e19cc4518b64 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 0000000000000000000000000000000000000000..8da976622a2281e0ed83b5216c5e2acf12723c22
--- /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 <<EOT;
+};
+
+const u16 _rom_src_len = $size;
+
+EOT
diff --git a/ROM2/vectors.s b/ROM2/vectors.s
index 3ffb6a68d1c5d512827ebae52b514a86ec05b9e8..04bfb72f4983dda5c5332f69c349e5eba4f698fc 100644
--- a/ROM2/vectors.s
+++ b/ROM2/vectors.s
@@ -44,6 +44,7 @@ def:
 	.sect .text
 rti:
 	jsr chime
+	jsr serial_rti
 	ldaa #0x40
 	staa 0x1025
 	rti
diff --git a/ROM2/vend.h b/ROM2/vend.h
index 460aa71169a3291e8805f19e69696185701f8f2f..7686620d675bcc313965e7779c30d20ebfb1856f 100644
--- a/ROM2/vend.h
+++ b/ROM2/vend.h
@@ -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
index 0000000000000000000000000000000000000000..7615d9bff363c51e10592ca62f9124804286563c
--- /dev/null
+++ b/ROM2/xmodem.c
@@ -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
index 0000000000000000000000000000000000000000..e119c03616e2d6dafa1b845e8ed58e989218bc52
--- /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 */