Index: firmware_legacy/usb/hid.c
===================================================================
--- firmware_legacy/usb/hid.c	(nonexistent)
+++ firmware_legacy/usb/hid.c	(revision 799)
@@ -0,0 +1,833 @@
+//#include <stdio.h>
+
+#include "usb.h"
+#include "timer.h"
+#include "hidparser.h"
+#include "events.h"
+#include "debug.h"
+#include "usbhostslave.h"
+#include "log.h"
+
+/*
+#include "printf.h"
+extern unsigned char volatile * baseaddr;
+extern int debug_pos;
+*/
+
+unsigned char kbd_led_state;  // default: all leds off
+unsigned char joysticks;      // number of detected usb joysticks
+
+//#define hid_debugf printf
+
+uint16_t bs16(uint8_t * in)
+{
+	uint16_t low = *in;
+	uint16_t high = *(in+1);
+	uint16_t res = (high<<8) | low;
+	return res;
+}
+
+uint8_t hid_get_joysticks(void) {
+  return joysticks;
+}
+
+//get HID report descriptor 
+static uint8_t hid_get_report_descr(usb_device_t *dev, uint8_t i, uint16_t size)  {
+  //  hid_debugf("%s(%x, if=%d, size=%d)", __FUNCTION__, dev->bAddress, iface, size);
+
+  uint8_t buf[size];
+  usb_hid_info_t *info = &(dev->hid_info);
+  uint8_t rcode = usb_ctrl_req( dev, HID_REQ_HIDREPORT, USB_REQUEST_GET_DESCRIPTOR, 0x00, 
+			      HID_DESCRIPTOR_REPORT, info->iface[i].iface_idx, size, buf);
+ 
+  if(!rcode) {
+    hid_debugf("HID report desc:");
+    //MWW hexdump(buf, size, 0);
+
+    // we got a report descriptor. Try to parse it
+    if(parse_report_descriptor(buf, size, &(info->iface[i].conf))) {
+      if(info->iface[i].conf.type == CONFIG_TYPE_JOYSTICK) {
+	//unsigned char * temp = baseaddr;
+	//baseaddr = (unsigned char volatile *)(40000 + atari_regbase);
+	//debug_pos=160;
+	//printf("Detected USB joystick #%d", joysticks);
+	hid_debugf("stick #%d", joysticks);
+
+	info->iface[i].device_type = HID_DEVICE_JOYSTICK;
+	info->iface[i].jindex = joysticks++;
+	//debug_pos=240;
+	//printf("assigned index #%d", info->iface[i].jindex);
+	//baseaddr = temp;
+      }
+    }
+  }
+    
+  return rcode;
+}
+
+static uint8_t hid_set_idle(usb_device_t *dev, uint8_t iface, uint8_t reportID, uint8_t duration ) {
+  //  hid_debugf("%s(%x, if=%d id=%d, dur=%d)", __FUNCTION__, dev->bAddress, iface, reportID, duration);
+
+  return( usb_ctrl_req( dev, HID_REQ_HIDOUT, HID_REQUEST_SET_IDLE, reportID, 
+		       duration, iface, 0x0000, NULL));
+}
+
+static uint8_t hid_set_protocol(usb_device_t *dev, uint8_t iface, uint8_t protocol) {
+  //  hid_debugf("%s(%x, if=%d proto=%d)", __FUNCTION__, dev->bAddress, iface, protocol);
+
+  return( usb_ctrl_req( dev, HID_REQ_HIDOUT, HID_REQUEST_SET_PROTOCOL, protocol, 
+		       0x00, iface, 0x0000, NULL));
+}
+
+static uint8_t hid_set_report(usb_device_t *dev, uint8_t iface, uint8_t report_type, uint8_t report_id, 
+			      uint16_t nbytes, uint8_t* dataptr ) {
+  //  hid_debugf("%s(%x, if=%d data=%x)", __FUNCTION__, dev->bAddress, iface, dataptr[0]);
+
+  return( usb_ctrl_req(dev, HID_REQ_HIDOUT, HID_REQUEST_SET_REPORT, report_id, 
+		       report_type, iface, nbytes, dataptr));
+}
+
+/* todo: handle parsing in chunks */
+static uint8_t usb_hid_parse_conf(usb_device_t *dev, uint8_t conf, uint16_t len) {
+  usb_hid_info_t *info = &(dev->hid_info);
+  uint8_t rcode;
+  bool isGoodInterface = false;
+
+  union buf_u {
+    usb_configuration_descriptor_t conf_desc;
+    usb_interface_descriptor_t iface_desc;
+    usb_endpoint_descriptor_t ep_desc;
+    usb_hid_descriptor_t hid_desc;
+    uint8_t raw[len];
+  } buf, *p;
+
+  // usb_interface_descriptor
+
+  if(rcode = usb_get_conf_descr(dev, len, conf, &buf.conf_desc)) 
+    return rcode;
+
+  /* scan through all descriptors */
+  p = &buf;
+  //LOG("LenX:%d\n", p->conf_desc.bLength);
+  while(len > 0) {
+    hid_debugf("L%02d %02d %02d ",len, p->conf_desc.bLength, p->conf_desc.bDescriptorType);
+
+    switch(p->conf_desc.bDescriptorType) {
+    case USB_DESCRIPTOR_CONFIGURATION:
+      hid_debugf("conf descriptor size %d", p->conf_desc.bLength);
+      // we already had this, so we simply ignore it
+      break;
+
+    case USB_DESCRIPTOR_INTERFACE:
+      isGoodInterface = false;
+      hid_debugf("iface descriptor size %d class %d", p->iface_desc.bLength, p->iface_desc.bInterfaceClass);
+
+      /* check the interface descriptors for supported class */
+
+      // only HID interfaces are supported
+      if(p->iface_desc.bInterfaceClass == USB_CLASS_HID) {
+	hid_debugf("iface is HID");
+	//	puts("iface is HID");
+
+	if(info->bNumIfaces < MAX_IFACES) {
+	  // ok, let's use this interface
+	  isGoodInterface = true;
+
+	  info->iface[info->bNumIfaces].iface_idx = p->iface_desc.bInterfaceNumber;
+	  info->iface[info->bNumIfaces].has_boot_mode = false;
+	  info->iface[info->bNumIfaces].is_5200daptor = false;
+	  info->iface[info->bNumIfaces].is_MCC = 0;
+	  info->iface[info->bNumIfaces].key_state = 0;
+	  info->iface[info->bNumIfaces].device_type = HID_DEVICE_UNKNOWN;
+	  info->iface[info->bNumIfaces].conf.type = CONFIG_TYPE_NONE;
+
+	  if(p->iface_desc.bInterfaceSubClass == HID_BOOT_INTF_SUBCLASS) {
+	    hid_debugf("Iface %d is Boot sub class", info->bNumIfaces);
+	    info->iface[info->bNumIfaces].has_boot_mode = true;
+	  }
+	  
+	  hid_debugf("HID protocol is ");
+	  switch(p->iface_desc.bInterfaceProtocol) {
+	  case HID_PROTOCOL_NONE:
+	    hid_debugf("NONE");
+	    break;
+	    
+	  case HID_PROTOCOL_KEYBOARD:
+	    hid_debugf("KEYBOARD");
+	    info->iface[info->bNumIfaces].device_type = HID_DEVICE_KEYBOARD;
+	    break;
+	    
+	  case HID_PROTOCOL_MOUSE:
+	    hid_debugf("MOUSE");
+	    info->iface[info->bNumIfaces].device_type = HID_DEVICE_MOUSE;
+	    break;
+	    
+	  default:
+	    hid_debugf("%d", p->iface_desc.bInterfaceProtocol);
+	    break;
+	  }
+	}
+      }
+      break;
+
+    case USB_DESCRIPTOR_ENDPOINT:
+      //      hid_debugf("endpoint descriptor size %d", p->ep_desc.bLength);
+
+      if(isGoodInterface) {
+
+	// only interrupt in endpoints are supported
+	if ((p->ep_desc.bmAttributes & 0x03) == 3 && (p->ep_desc.bEndpointAddress & 0x80) == 0x80) {
+	  hid_debugf("ep %d, ival = %dms", 
+		  p->ep_desc.bEndpointAddress & 0x0F, p->ep_desc.bInterval);
+
+	  // Fill in the endpoint info structure
+	  uint8_t epidx = info->bNumIfaces;
+	  info->iface[epidx].interval = p->ep_desc.bInterval;
+	  info->iface[epidx].ep.epAddr	 = (p->ep_desc.bEndpointAddress & 0x0F);
+	  info->iface[epidx].ep.maxPktSize = p->ep_desc.wMaxPacketSize[0];
+	  info->iface[epidx].ep.epAttribs	 = 0;
+	  info->iface[epidx].ep.bmNakPower = USB_NAK_NOWAIT;
+	  info->bNumIfaces++;
+	}
+      }
+      break;
+
+    case HID_DESCRIPTOR_HID:
+      hid_debugf("hid desc size %d type %x", p->ep_desc.bLength, p->hid_desc.bDescrType);
+
+      if(isGoodInterface) {
+	// we need a report descriptor
+	if(p->hid_desc.bDescrType == HID_DESCRIPTOR_REPORT) {
+	  uint16_t len = p->hid_desc.wDescriptorLength[0] + 
+	    256 * p->hid_desc.wDescriptorLength[1];
+	  hid_debugf(" -> report desc size = %d", len);
+	  
+	  info->iface[info->bNumIfaces].report_desc_size = len;
+	}
+      }
+      break;
+
+    default:
+      hid_debugf("unsupd desc type %d size %d", p->raw[1], p->raw[0]);
+    }
+
+    // advance to next descriptor
+   //LOG("Len:%d\n", p->conf_desc.bLength);
+   //timer_delay_msec(1000);
+    len -= p->conf_desc.bLength;
+    p = (union buf_u*)(p->raw + p->conf_desc.bLength);
+  }
+  
+  if(len != 0) {
+    hid_debugf("Config underrun: %d", len);
+    return USB_ERROR_CONFIGURAION_SIZE_MISMATCH;
+  }
+
+  return 0;
+}
+
+static uint8_t usb_hid_init(usb_device_t *dev) {
+  hid_debugf("%s(%x)", __FUNCTION__, dev->bAddress);
+
+  uint8_t rcode;
+  uint8_t i;
+  uint16_t vid, pid;
+
+  kbd_led_state = 0;  // default: all leds off
+
+  usb_hid_info_t *info = &(dev->hid_info);
+  
+  union {
+    usb_device_descriptor_t dev_desc;
+    usb_configuration_descriptor_t conf_desc;
+  } buf;
+
+  // reset status
+  info->bPollEnable = false;
+  info->bNumIfaces = 0;
+
+  for(i=0;i<MAX_IFACES;i++) {
+    info->iface[i].qNextPollTime = 0;
+    info->iface[i].ep.epAddr	 = i;
+    info->iface[i].ep.maxPktSize = 8;
+    info->iface[i].ep.epAttribs	 = 0;
+    info->iface[i].ep.bmNakPower = USB_NAK_MAX_POWER;
+  }
+
+  // try to re-read full device descriptor from newly assigned address
+  if(rcode = usb_get_dev_descr( dev, sizeof(usb_device_descriptor_t), &buf.dev_desc ))
+    return rcode;
+
+  // save vid/pid for automatic hack later
+  vid = bs16(&buf.dev_desc.idVendorL);
+  pid = bs16(&buf.dev_desc.idProductL);
+
+  uint8_t num_of_conf = buf.dev_desc.bNumConfigurations;
+  hid_debugf("number of configurations: %d", num_of_conf);
+
+  for(i=0; i<num_of_conf; i++) {
+    if(rcode = usb_get_conf_descr(dev, sizeof(usb_configuration_descriptor_t), i, &buf.conf_desc)) 
+      return rcode;
+    
+    uint16_t wTotalLength = bs16(&buf.conf_desc.wTotalLengthL);
+    hid_debugf("conf desc %d size %d", i, wTotalLength);
+    LOG("conf descriptor %d has total size %d", i, wTotalLength);
+
+    // parse directly if it already fitted completely into the buffer
+    usb_hid_parse_conf(dev, i, wTotalLength);
+  }
+
+  hid_debugf("here:%d vid:%x pid:%x",info->bNumIfaces,vid,pid);
+
+  // check if we found valid hid interfaces
+  if(!info->bNumIfaces) {
+    hid_debugf("no hid ifaces found");
+
+    if((vid == 0x45e) && (pid == 0x028e)) {
+      hid_debugf("hackn Torid\n");
+      info->bNumIfaces = 1;
+      info->iface[0].iface_idx = 0;
+      info->iface[0].has_boot_mode = false;
+      info->iface[0].is_5200daptor = false;
+      info->iface[0].is_MCC = 3;
+      info->iface[0].key_state = 0;
+      info->iface[0].device_type = HID_DEVICE_JOYSTICK;
+      info->iface[0].conf.type = CONFIG_TYPE_JOYSTICK;
+      info->iface[0].jindex = joysticks++;
+      info->iface[0].interval = 1;
+      info->iface[0].ep.epAddr	 = 1;
+      info->iface[0].ep.maxPktSize = 14;
+      info->iface[0].ep.epAttribs	 = 0;
+      info->iface[0].ep.bmNakPower = USB_NAK_NOWAIT;
+
+      /*info->iface[0].conf.joystick.button[0].byte_offset = 2;
+      info->iface[0].conf.joystick.button[0].bitmask;
+      info->iface[0].conf.joystick.axis[0].size;
+      info->iface[0].conf.joystick.axis[0].byte_offset;
+      info->iface[0].conf.joystick.axis[0].logical.min;
+      info->iface[0].conf.joystick.axis[0].logical.max;
+      */
+
+      // joystick pos is expected to be an axis... it isn't...
+      // might be easier to directly create jmap for torid...
+    }
+    else
+    {
+      return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
+    }
+  }
+
+  // Set Configuration Value
+  rcode = usb_set_conf(dev, buf.conf_desc.bConfigurationValue);
+
+  // process all supported interfaces
+  for(i=0; i<info->bNumIfaces; i++) {
+    // no boot mode, try to parse HID report descriptor
+    if(!info->iface[i].has_boot_mode && !info->iface[i].is_MCC) {
+ 
+      hid_debugf("DESC %x ", info->iface[i].report_desc_size);
+      rcode = hid_get_report_descr(dev, i, info->iface[i].report_desc_size);
+      if(rcode) return rcode;
+
+      hid_debugf("TYPE%02x ", info->iface[i].device_type);
+      if(info->iface[i].device_type == CONFIG_TYPE_JOYSTICK) {
+	char k;
+        
+	iprintf("Report: type = %d, id = %d, size = %d\n", 
+		info->iface[i].conf.type,
+		info->iface[i].conf.report_id,
+		info->iface[i].conf.report_size);
+	
+	for(k=0;k<2;k++)
+	  iprintf("Axis%d: %d@%d %d->%d\n", k, 
+		  info->iface[i].conf.joystick.axis[k].size,
+		  info->iface[i].conf.joystick.axis[k].byte_offset,
+		  info->iface[i].conf.joystick.axis[k].logical.min,
+		  info->iface[i].conf.joystick.axis[k].logical.max);
+	
+	for(k=0;k<24;k++)
+	  iprintf("Button%d: @%d/%d\n", k,
+		  info->iface[i].conf.joystick.button[k].byte_offset,
+		  info->iface[i].conf.joystick.button[k].bitmask);
+      }
+      
+      
+      // use fixed setup for known interfaces 
+      if((vid == 0x0079) && (pid == 0x0011) && (i==0)) {
+	iprintf("hacking cheap NES pad\n");
+        
+        // fixed setup for nes gamepad
+        info->iface[0].conf.joystick.button[0].byte_offset = 5;
+        info->iface[0].conf.joystick.button[0].bitmask = 32;
+        info->iface[0].conf.joystick.button[1].byte_offset = 5;
+        info->iface[0].conf.joystick.button[1].bitmask = 64;
+        info->iface[0].conf.joystick.button[2].byte_offset = 6;
+        info->iface[0].conf.joystick.button[2].bitmask = 16;
+        info->iface[0].conf.joystick.button[3].byte_offset = 6;
+        info->iface[0].conf.joystick.button[3].bitmask = 32;
+      }
+
+      if((vid == 0x04d8) && (pid == 0xf6ec) && (i==0)) {
+	iprintf("hacking 5200daptor\n");
+        
+	info->iface[0].conf.joystick.button[2].byte_offset = 4;
+	info->iface[0].conf.joystick.button[2].bitmask = 0x40;    // "Reset"
+	info->iface[0].conf.joystick.button[3].byte_offset = 4;
+	info->iface[0].conf.joystick.button[3].bitmask = 0x10;    // "Start"
+
+	info->iface[0].is_5200daptor = true;
+      }
+
+      if((vid == 0x0079) && (pid == 0x0006) && (i==0)) {
+	iprintf("MCC classic\n");
+
+	info->iface[0].is_MCC = 1;
+      }
+      if((vid == 0x1a34) && (pid == 0x0809) && (i==0)) {
+	iprintf("MCC Xeox\n");
+
+	info->iface[0].is_MCC = 2;
+      }
+    }
+
+    rcode = hid_set_idle(dev, info->iface[i].iface_idx, 0, 0);
+    // MWW if (rcode && rcode != hrSTALL)
+    //printf("RCODE:%02x ",rcode);
+    if (rcode && rcode != OHS900_STATMASK_STALL_RXED)
+      return rcode;
+
+    //printf("BM ");
+    // enable boot mode
+    if(info->iface[i].has_boot_mode)
+    {
+      //printf("BM ");
+      hid_set_protocol(dev, info->iface[i].iface_idx, HID_BOOT_PROTOCOL);
+    }
+  }
+  
+  iprintf("HID configured\n");
+
+  // update leds
+  for(i=0;i<MAX_IFACES;i++)
+    if(dev->hid_info.iface[i].device_type == HID_DEVICE_KEYBOARD)
+    {
+//      printf("LEDS ");
+      uint8_t res = hid_set_report(dev, dev->hid_info.iface[i].iface_idx, 2, 0, 1, &kbd_led_state);
+//      printf("LEDS res:%02x ", res);
+    }
+
+  info->bPollEnable = true;
+  return 0;
+}
+
+static uint8_t usb_hid_release(usb_device_t *dev) {
+  usb_hid_info_t *info = &(dev->hid_info);
+
+  iprintf("%s\n",__FUNCTION__);
+
+  uint8_t i;
+  // check if a joystick is released
+  for(i=0;i<info->bNumIfaces;i++) {
+    if(info->iface[i].device_type == HID_DEVICE_JOYSTICK) {
+      uint8_t c_jindex = info->iface[i].jindex;
+      hid_debugf("rel joystick #%d, renum", c_jindex);
+
+      event_digital_joystick(c_jindex, 0);
+      event_analog_joystick(c_jindex, 0,0);
+
+      // walk through all devices and search for sticks with a higher id
+
+      // search for all joystick interfaces on all hid devices
+      usb_device_t *dev = usb_get_devices();
+      uint8_t j;
+      for(j=0;j<USB_NUMDEVICES;j++) {
+	if(dev[j].bAddress && (dev[j].class == &usb_hid_class)) {
+	  // search for joystick interfaces
+	  uint8_t k;
+	  for(k=0;k<MAX_IFACES;k++) {
+	    if(dev[j].hid_info.iface[k].device_type == HID_DEVICE_JOYSTICK) {
+	      if(dev[j].hid_info.iface[k].jindex > c_jindex) {
+		hid_debugf("dec jindex of dev #%d from %d to %d", j, 
+			dev[j].hid_info.iface[k].jindex, dev[j].hid_info.iface[k].jindex-1);
+
+		dev[j].hid_info.iface[k].jindex--;
+	      }
+	    }
+	  }
+	}
+      }
+      // one less joystick in the system ...
+      joysticks--;
+    }
+  }
+
+  return 0;
+}
+
+#ifdef FIRMWARE_5200
+// special 5200daptor button processing
+static void handle_5200daptor(usb_hid_iface_info_t *iface, uint8_t *buf) {
+
+  // list of buttons that are reported as keys
+  static const struct {
+    uint8_t byte_offset;   // offset of the byte within the report which the button bit is in
+    uint8_t mask;          // bitmask of the button bit
+    uint8_t key_code[2];   // usb keycodes to be sent for joystick 0 and joystick 1
+  } button_map[] = {
+    { 4, 0x10, 0x3a, 0x3d }, /* START -> f1/f4 */
+    { 4, 0x20, 0x3b, 0x3e }, /* PAUSE -> f2/f5 */
+    { 4, 0x40, 0x3c, 0x3f }, /* RESET -> f3/f6 */
+    { 5, 0x01, 0x1e, 0x21 }, /*     1 ->  1/4  */
+    { 5, 0x02, 0x1f, 0x22 }, /*     2 ->  2/5  */
+    { 5, 0x04, 0x20, 0x23 }, /*     3 ->  3/6  */
+    { 5, 0x08, 0x14, 0x15 }, /*     4 ->  q/r  */
+    { 5, 0x10, 0x1a, 0x17 }, /*     5 ->  w/t  */
+    { 5, 0x20, 0x08, 0x1c }, /*     6 ->  e/y  */
+    { 5, 0x40, 0x04, 0x09 }, /*     7 ->  a/f  */
+    { 5, 0x80, 0x16, 0x0a }, /*     8 ->  s/g  */
+    { 6, 0x01, 0x07, 0x0b }, /*     9 ->  d/h  */
+    { 6, 0x02, 0x1d, 0x19 }, /*     * ->  z/v  */
+    { 6, 0x04, 0x1b, 0x05 }, /*     0 ->  x/b  */
+    { 6, 0x08, 0x06, 0x11 }, /*     # ->  c/n  */
+    { 0, 0x00, 0x00, 0x00 }  /* ----  end ---- */
+  };
+
+  // keyboard events are only generated for the first
+  // two joysticks in the system
+  if(iface->jindex > 1) return;
+
+  // build map of pressed keys
+  uint8_t i;
+  uint16_t keys = 0;
+  for(i=0;button_map[i].mask;i++) 
+    if(buf[button_map[i].byte_offset] & button_map[i].mask)
+      keys |= (1<<i);
+
+  // check if keys have changed
+  if(iface->key_state != keys) {
+    uint8_t buf[6] = { 0,0,0,0,0,0 };
+    uint8_t p = 0;
+
+    // report up to 6 pressed keys
+    for(i=0;(i<16)&&(p<6);i++) 
+      if(keys & (1<<i))
+	buf[p++] = button_map[i].key_code[iface->jindex];
+
+    //    iprintf("5200: %d %d %d %d %d %d\n", buf[0],buf[1],buf[2],buf[3],buf[4],buf[5]);
+
+    // generate key events
+    event_keyboard(0x00, buf);
+
+    // save current state of keys
+    iface->key_state = keys;
+  }
+}
+#endif
+
+// special MCC button processing
+static void handle_MCC(usb_hid_iface_info_t *iface, uint32_t * jmap_ptr, uint8_t type) {
+
+/*
+[start or left&right shoulder2] - start
+[select or left&right shoulder1] - select
+[select] - option
+[3] - reset
+[2] - cold start
+[1] - quick select
+[4] - settings
+
+MY MAPPING
+[select] - select
+[start] - start
+[L1|R1|3] - fire!
+[L2|R2|4] - option
+[L2&R2] - reboot
+[L1&R2] - reset
+[1] - settings
+[2] - disk menu
+*/
+/*
+    { 4, 0x41, }, * START -> f8 [1]*
+    { 5, 0x41, }, * START -> f8 [2]*
+    { 6, 0x42, }, * PAUSE -> f9 [3]*
+    { 7, 0x43, }, * RESET -> f10 [4]*
+    { 8, 0x1e, }, *     1 ->  1/4  SH L1*
+    { 9, 0x1f, }, *     2 ->  2/5  SH R1*
+    { 10, 0x20 }, *     3 ->  3/6 SH L2 *
+    { 11, 0x14 }, *     4 ->  q/r  SH R2*
+    { 12, 0x1a }, *     5 ->  w/t  SELECT*
+    { 13, 0x08 }, *     6 ->  e/y  START*
+    { 14, 0x04 }, *     7 ->  a/f  STICK CLICK LEFT*
+    { 15, 0x16 }, *     8 ->  s/g  STICK CLICK RIGHT*
+*/
+
+uint32_t jmap = *jmap_ptr;
+*jmap_ptr&=0xf;
+
+  if (type == 2)
+  {
+    uint32_t mask = 0;
+    if (jmap&0x40) mask ^= 0xc0;
+    if (jmap&0x80) mask ^= 0x90;
+    if (jmap&0x10) mask ^= 0x50;
+    jmap ^= mask;
+//x(left)=40 (old 80)
+//y(up)=80 (old 10)
+//a(down)=10 (old 40)
+  }
+
+  static const struct {
+    uint8_t bit1;           // bit of the button bit (1<<bit)
+    uint8_t bit2;           // bit of the button bit (1<<bit)
+    uint8_t key_code;      // usb keycodes to be sent for all joysticks
+    uint8_t button_bit;  
+  } button_map[] = {
+#ifndef FIRMWARE_5200
+    { 13, 13, 0x3f, 0 }, /* start -> f6 */
+    { 12, 12, 0x40, 0 }, /* select -> f7 */
+    { 10, 10, 0x41, 0 }, /* l2 -> f8 */
+    { 11, 11, 0x41, 0 }, /* r2 -> f8 */
+    { 7, 7, 0x41, 0 }, /* 4 -> f8 */
+    { 10, 11, 0x43, 0 }, /* l2&r2 -> f10 */
+    { 8, 11, 0x42, 0 }, /* l1&r2 -> f9 */
+    { 6, 6, 0x00, 4 }, /* 3 -> fire */
+#endif
+#ifdef FIRMWARE_5200
+    { 13, 13, 0x3a, 0 }, /* start -> f1 (start) */
+    { 12, 12, 0x3b, 0 }, /* select -> f2 (pause) */
+    { 10, 10, 0x00, 5 }, /* l2 -> fire2 */
+    { 11, 11, 0x00, 5 }, /* r2 -> fire2 */
+    { 6, 6, 0x00, 5 }, /* 3 -> fire2 */
+    { 7, 7, 0x00, 4 }, /* 4 -> fire */
+#endif
+    { 4, 4, 0x45, 0 }, /* 1 -> f12 */
+    { 5, 5, 0x44, 0 }, /* 2 -> f11 */
+    { 14, 15, 0x29, 0 }, /* both sticks  -> esc */
+    { 8, 8, 0x00, 4 }, /* l1 -> fire */
+    { 9, 9, 0x00, 4 }, /* r1 -> fire */
+    { 10, 15, 0x43, 0 }, /* l2& rstick click -> f10 */
+    { 9, 15, 0x42, 0 }, /* l1& rstick click -> f9 */
+    { 0, 0, 0x00, 0 }  /* ----  end ---- */
+  };
+
+  uint8_t buf[6] = { 0,0,0,0,0,0 };
+  uint8_t p = 0;
+
+  // report up to 6 pressed keys
+  // modify jmap buttons
+  int i;
+  for(i=0;button_map[i].bit1;i++) 
+  {
+    uint32_t mask = 0;
+    mask |= 1<<button_map[i].bit1;
+    mask |= 1<<button_map[i].bit2;
+
+    if((jmap & mask) == mask)
+    {
+      if (p<6 && button_map[i].key_code)
+      {
+          buf[p++] = button_map[i].key_code;
+      }
+
+      if (button_map[i].button_bit)
+      {
+          *jmap_ptr |= 1<<button_map[i].button_bit;
+      }
+    }
+  }
+  // generate key events
+  event_keyboard(0x00, buf);
+}
+
+static uint8_t usb_hid_poll(usb_device_t *dev) {
+  usb_hid_info_t *info = &(dev->hid_info);
+  int8_t i;
+
+  if (!info->bPollEnable)
+    return 0;
+  
+  for(i=0;i<info->bNumIfaces;i++) {
+    usb_hid_iface_info_t *iface = info->iface+i;
+    
+    if(iface->device_type != HID_DEVICE_UNKNOWN) {
+
+      if (iface->qNextPollTime <= timer_get_msec()) {
+	//      hid_debugf("poll %d...", iface->ep.epAddr);
+      
+	uint16_t read = iface->ep.maxPktSize;
+	uint8_t buf[iface->ep.maxPktSize];
+        //hid_debugf("bytes:%d ep:%x",read,iface->ep);
+	uint8_t rcode = 
+	  usb_in_transfer(dev, &(iface->ep), &read, buf);
+	
+	if (rcode) {
+	  // MWW if (rcode != hrNAK)
+	  if (rcode != OHS900_STATMASK_NAK_RXED)
+	    hid_debugf("%s() error: %d", __FUNCTION__, rcode);
+	} else {
+	  
+	  // successfully received some bytes
+	  if(iface->has_boot_mode) {
+	    if(iface->device_type == HID_DEVICE_MOUSE) {
+	      // boot mouse needs at least three bytes
+	      if(read >= 3) {
+		// forward all three bytes to the user_io layer
+		event_mouse(buf[0], buf[1], buf[2]);
+	      }
+	    }
+	    
+	    if(iface->device_type == HID_DEVICE_KEYBOARD) {
+	      // boot kbd needs at least eight bytes
+	      if(read >= 8) {
+		event_keyboard(buf[0], buf+2);
+	      }
+	    }
+	  }
+	  
+	  if(iface->device_type == HID_DEVICE_JOYSTICK) {
+	    hid_config_t *conf = &iface->conf;
+            //hid_debugf("JOY");
+	    if(iface->is_MCC==3 || read >= conf->report_size) {
+	      uint32_t jmap = 0;
+	      uint16_t a[2];
+	      uint8_t idx, i;
+	      
+	      // hid_debugf("Joystick data:"); hexdump(buf, read, 0);
+
+	      // two axes ...
+              if(iface->is_MCC==3)
+	      {
+                /*14 bytes (0-13)
+                Left trigger: Byte 4: 0 (not pressed) to ff (pressed) - analogue
+                Right trigger: Byte 5: 0 (not pressed) to ff (pressed) - analogue
+                Left button: Byte 3: bit 0 (1=pressed)
+                Right button: Byte 3: bit 1 (2=pressed)
+                A button: Byte 3: bit 4 (0x10=pressed)
+                B button: Byte 3: bit 5 (0x20=pressed)
+                X button: Byte 3: bit 6 (0x40=pressed)
+                Y button: Byte 3: bit 7 (0x80=pressed)
+                Joy up: Byte 2: bit 0 (1=pressed)
+                Joy down: Byte 2: bit 1 (2=pressed)
+                Joy left: Byte 2: bit 2 (4=pressed)
+                Joy right: Byte 2: bit 3 (8=pressed)
+                Start: Byte 2: bit 4 (0x10=pressed)
+                Select: Byte 2: bit 5 (0x20=pressed)
+                Left hat LR: Byte 7: 0x80 - 0x7f (analogue - 2s comp left =-ve) 
+                Left hat UD: Byte 9: 0x80 - 0x7f (analogue - 2s comp down=-ve) 
+                Right hat LR: Byte b: 0x80 - 0x7f (analogue - 2s comp left =-ve) 
+                Right hat UD: Byte d: 0x80 - 0x7f (analogue - 2s comp down=-ve) 
+                left hat button: byte 2: bit 6 (0x40=pressed)
+                right hat button: byte 2: bit 7 (0x80=pressed)*/
+
+		if (buf[0]==00 && buf[1]==0x14)
+		{
+			if (buf[2]&1) jmap |= JOY_UP;
+			if (buf[2]&2) jmap |= JOY_DOWN;
+			if (buf[2]&4) jmap |= JOY_LEFT;
+			if (buf[2]&8) jmap |= JOY_RIGHT;
+			if (buf[3]&0x80) jmap |= 1<<4; //1
+			if (buf[3]&0x20) jmap |= 1<<5;  //2
+			if (buf[3]&0x10) jmap |= 1<<6;  //3
+			if (buf[3]&0x40) jmap |= 1<<7;  //4
+			if (buf[3]&1) jmap |= 1<<8; //l1
+			if (buf[3]&2) jmap |= 1<<9;  //r1
+			if (buf[4]&0x80) jmap |= 1<<10;  //l2
+			if (buf[5]&0x80) jmap |= 1<<11;  //r2
+			if (buf[2]&0x20) jmap |= 1<<12; //select
+			if (buf[2]&0x10) jmap |= 1<<13;  //start
+			if (buf[2]&0x40) jmap |= 1<<14;  //lstick click
+			if (buf[2]&0x80) jmap |= 1<<15;  //rstick click
+
+			int8_t x = (char)buf[7];
+			int8_t y = (char)buf[9];
+
+			a[0] = 128+x;
+			a[1] = 127-y;
+		}
+		else
+		{
+			jmap = 0;
+			a[0] = 128;
+			a[1] = 128;
+		}
+
+		//for (i=0;i!=14;++i)
+		//{
+		//	hid_debugf("%02x",buf[i]);
+		//}
+            	//hid_debugf("=jmap:%x",jmap);
+	      }
+              else
+	      {
+	        for(i=0;i<2;i++) {
+	          a[i] = buf[conf->joystick.axis[i].byte_offset];
+	          if(conf->joystick.axis[i].size == 16)
+	            a[i] += (buf[conf->joystick.axis[i].byte_offset+1])<<8;
+
+	          // scale to 0 -> 255 range. 99% of the joysticks already deliver that
+	          if((conf->joystick.axis[i].logical.min != 0) ||
+	             (conf->joystick.axis[i].logical.max != 255)) {
+	            a[i] = ((a[i] - conf->joystick.axis[i].logical.min) * 255)/
+	              (conf->joystick.axis[i].logical.max - 
+	               conf->joystick.axis[i].logical.min);
+	          }
+	        }
+  	      
+  	        //	      iprintf("JOY X:%d Y:%d\n", a[0], a[1]);
+  	      
+  	        // ... and twenty-four buttons
+  	        for(i=0;i<24;i++)
+  	 	  if(buf[conf->joystick.button[i].byte_offset] & 
+  	  	     conf->joystick.button[i].bitmask) jmap |= (JOY_BTN1<<i);
+              }
+
+  	      if(a[0] <  64) jmap |= JOY_LEFT;
+  	      if(a[0] > 192) jmap |= JOY_RIGHT;
+  	      if(a[1] <  64) jmap |= JOY_UP;
+  	      if(a[1] > 192) jmap |= JOY_DOWN;
+	      
+	      //	      iprintf("JOY D:%d\n", jmap);
+
+	      idx = iface->jindex;
+	      
+	      // check if joystick state has changed
+	      if(jmap != iface->jmap) {
+
+		//unsigned char * temp = baseaddr;
+		//baseaddr = (unsigned char volatile *)(screen_address + atari_regbase);
+		//debug_pos=80;
+		//printf("jmap %d(%d) changed to %x\n", idx, iface->jindex,jmap);
+		//baseaddr = temp;
+		//	      iprintf("jmap %d changed to %x\n", idx, jmap);
+		iface->jmap = jmap;
+
+                // do special MCC treatment
+                if(iface->is_MCC)
+                    handle_MCC(iface, &jmap, iface->is_MCC);
+		
+		// and feed into joystick input system
+		event_digital_joystick(idx, jmap);
+	      }
+	      
+	      // also send analog values
+	      event_analog_joystick(idx, a[0]-128, a[1]-128);
+
+	      // do special 5200daptor treatment
+#ifdef FIRMWARE_5200
+	      if(iface->is_5200daptor)
+		handle_5200daptor(iface, buf);
+#endif
+	    }
+	  }
+	}
+	iface->qNextPollTime += iface->interval;   // poll at requested rate
+      }
+    }
+  }
+
+  return 0;
+}
+
+const usb_device_class_config_t usb_hid_class = {
+  usb_hid_init, usb_hid_release, usb_hid_poll };  
+
Index: firmware_legacy/usb/events.h
===================================================================
--- firmware_legacy/usb/events.h	(nonexistent)
+++ firmware_legacy/usb/events.h	(revision 799)
@@ -0,0 +1,160 @@
+//#include "printf.h"
+#include "regs.h"
+
+#include "keycodes.h"
+
+extern int debug_pos;
+
+uint8_t kbbuf[6];
+uint32_t jmaps[4];
+
+int8_t analogx[4];
+int8_t analogy[4];
+
+void event_keyboard(uint8_t mod, uint8_t buf[])
+{
+	//printf("Event keyboard:%d\n", mod);
+	/*int changed = 0;
+
+	if (lastmod!=i)
+	{
+		lastmod = i;
+		changed = 1;
+	}
+	int j;
+        for (j=0;j!=8;++j)
+	{
+		//printf("Event keyboard:%d = %x\n", j, buf[j]);
+		if (buf[j] != kbbuf[j])
+		{
+			changed = 1;
+			kbbuf[j] = buf[j];
+		}
+	}*/
+
+  /* usb modifer bits: 
+        0     1     2    3    4     5     6    7
+      LCTRL LSHIFT LALT LGUI RCTRL RSHIFT RALT RGUI
+  */
+
+	// Convert changes into a serial of release/press notifications
+	int i=0;
+	for(i=0;i!=8;++i)
+	{
+		int bit = 1<<i;
+		uint32_t pressed = !!(bit&mod);
+		uint32_t ps2_key = ps2_modifier[i];
+		*zpu_out4 = (pressed<<16)|ps2_key;
+	}
+	
+	// unpress old keys that are no longer pressed
+	for (i=0;i!=6;++i)
+	{
+		if (kbbuf[i]==MISS) continue;
+
+		uint32_t oldkey = usb2ps2[kbbuf[i]];
+		int j=0;
+		int found = 0;
+		for (j=0;j!=6;++j)
+		{
+			uint32_t newkey = usb2ps2[buf[i]];
+			if (oldkey==newkey) {found=1;break;}
+		}
+
+		if (!found)
+		{
+			*zpu_out4 = oldkey; // unpress
+		}
+	}
+
+	// press/hold new keys
+	for (i=0;i!=6;++i)
+	{
+		if (buf[i]==MISS) continue;
+
+		uint32_t newkey = usb2ps2[buf[i]];
+
+		// press new one
+		*zpu_out4 = (1<<16)|newkey;
+	}
+
+	for (i=0;i!=6;++i)
+	{
+		kbbuf[i] = buf[i]; // store
+	}
+
+/*	if (changed)
+	{
+		debug_pos = 120;
+		printf("KB:");
+		printf("%02x ",kbi);
+		for (j=0;j!=8;++j)
+		{
+			printf("%04x ",usb2ps2[kbbuf[j]]);
+		}
+
+		// lctrl:1, lshift:2, lalt:4, lwin:8, rctrl:10, rshift:20, altgr:40
+		uint32_t mod = kbi;
+		uint32_t key1 = usb2ps2[kbbuf[0]];
+		//uint32_t key2 = usb2ps2[kbbuf[1]];
+		//uint32_t key3 = usb2ps2[kbbuf[2]];
+
+		uint32_t res = (key3<<24) | (key2<<16) || (key1<<8) || mod;
+		*zpu_out4 = res;
+	}*/
+}
+void event_mouse(uint8_t a, uint8_t b, uint8_t c)
+{
+	//printf("Event mouse:%d %d %d\n",a,b,c);
+}
+void event_digital_joystick(uint8_t idx, uint32_t jmap)
+{
+	//printf("Event joystick:%d %x\n", idx,jmap);
+	/*if (jmaps[idx] != jmap)
+	{
+		jmaps[idx] = jmap;
+		debug_pos = 200 + idx*40;
+		printf("JOY:%d:%08x ",idx,jmap);
+	}*/
+	idx = idx&1;
+	if (idx == 0)
+	{
+		*zpu_out2 = jmap;
+	}
+	if (idx == 1)
+	{
+		*zpu_out3 = jmap;
+	}
+}
+void event_analog_joystick(uint8_t idx, int8_t x, int8_t y)
+{
+	//printf("Event analog joystick:%d %d %d\n", idx,x,y);
+	idx = idx&1;
+	if (analogx[idx]!=x || analogy[idx]!=y)
+	{
+		analogx[idx] = x;
+		analogy[idx] = y;
+		//debug_pos = 360 + idx*40;
+		//printf("AJOY:%d:%d:%d ", idx,x,y);
+		
+		uint32_t x0 = (uint8_t)analogx[0];
+		uint32_t y0 = (uint8_t)analogy[0];
+		uint32_t x1 = (uint8_t)analogx[1];
+		uint32_t y1 = (uint8_t)analogy[1];
+
+		uint32_t comb = (y1<<24)|(x1<<16)|(y0<<8) |x0;
+		*zpu_out5 = comb;
+	}
+}
+
+#define JOY_RIGHT       0x01
+#define JOY_LEFT        0x02
+#define JOY_DOWN        0x04
+#define JOY_UP          0x08
+#define JOY_BTN1        0x10
+#define JOY_BTN2        0x20
+#define JOY_BTN3        0x40
+#define JOY_BTN4        0x80
+#define JOY_MOVE        (JOY_RIGHT|JOY_LEFT|JOY_UP|JOY_DOWN)
+
+
Index: firmware_legacy/mif_file_stuff/rom_prologue.vhd
===================================================================
--- firmware_legacy/mif_file_stuff/rom_prologue.vhd	(nonexistent)
+++ firmware_legacy/mif_file_stuff/rom_prologue.vhd	(revision 799)
@@ -0,0 +1,10 @@
+DEPTH = 8192; % Memory depth and width are required % 
+ % DEPTH is the number of addresses % 
+WIDTH = 32; % WIDTH is the number of bits of data per word % 
+% DEPTH and WIDTH should be entered as decimal numbers % 
+ADDRESS_RADIX = HEX; % Address and value radixes are required % 
+DATA_RADIX = HEX; % Enter BIN, DEC, HEX, OCT, or UNS; unless % 
+ % otherwise specified, radixes = HEX % 
+-- Specify values for addresses, which can be single address or range 
+CONTENT 
+BEGIN 
Index: firmware_legacy/mif_file_stuff/zpuromgen
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: firmware_legacy/mif_file_stuff/zpuromgen
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: firmware_legacy/fat/pff_file.c
===================================================================
--- firmware_legacy/fat/pff_file.c	(nonexistent)
+++ firmware_legacy/fat/pff_file.c	(revision 799)
@@ -0,0 +1,456 @@
+#include "pff_file.h"
+
+#include "pff.h"
+#include "utils.h"
+#include "diskio.h"
+#include "simplefile.h"
+//#include "printf.h"
+
+struct SimpleFile * openfile;
+
+void * dir_cache;
+int dir_cache_size;
+
+FATFS fatfs;
+DIR dir;
+FILINFO filinfo;
+
+int write_pending;
+
+#define translateStatus(res) (res == FR_OK ? SimpleFile_OK: SimpleFile_FAIL)
+#define translateDStatus(res) (res == RES_OK ? SimpleFile_OK: SimpleFile_FAIL)
+
+/*
+enum SimpleFileStatus translateStatus(FRESULT res)
+{
+	return res == FR_OK ? SimpleFile_OK: SimpleFile_FAIL;
+}
+
+enum SimpleFileStatus translateDStatus(DSTATUS res)
+{
+	return res == RES_OK ? SimpleFile_OK: SimpleFile_FAIL;
+}*/
+
+char const * file_of(char const * path)
+{
+	char const * start = path + strlen(path);
+	while (start!=path)
+	{
+		--start;
+		if (*start == '/')
+		{
+			++start;
+			break;
+		}
+	}
+	return start;
+}
+
+void dir_of(char * dir, char const * path)
+{
+	char const * end = file_of(path);
+	if (end != path) 
+	{
+		int len = end-path;
+		while (len--)
+		{
+			*dir++ = *path++;
+		}
+		--dir;
+	}
+
+	*dir = '\0';
+	return;
+}
+
+char const * file_name(struct SimpleFile * file)
+{
+	return file_of(&file->path[0]);
+}
+
+char const * file_path(struct SimpleFile * file)
+{
+	return &file->path[0];
+}
+
+void file_init(struct SimpleFile * file)
+{
+	file->path[0] = '\0';
+	file->is_readonly = 1;
+	file->size = 0;
+}
+
+void file_check_open(struct SimpleFile * file)
+{
+	if (openfile!=file)
+	{
+		file_write_flush();
+
+		pf_open(&file->path[0]);
+		openfile = file;
+	}
+}
+
+enum SimpleFileStatus file_read(struct SimpleFile * file, void * buffer, int bytes, int * bytesread)
+{
+	UINT bytesread_word;
+	FRESULT res;
+
+	file_write_flush();
+	file_check_open(file);
+
+	res = pf_read(buffer, bytes, &bytesread_word);
+	*bytesread = bytesread_word;
+
+	return translateStatus(res);
+}
+
+enum SimpleFileStatus file_write(struct SimpleFile * file, void * buffer, int bytes, int * byteswritten)
+{
+	UINT byteswritten_word;
+	FRESULT res =  FR_OK;
+
+	//printf("went\n");
+	if (file->is_readonly) return SimpleFile_FAIL;
+
+	file_check_open(file);
+
+	int rem = bytes;
+	while (rem>0)
+	{
+		int sector = fatfs.fptr>>9;
+		int pos = fatfs.fptr&0x1ff;
+
+		int bytes_this_cycle = rem;
+		if (bytes_this_cycle>(512-pos))
+			bytes_this_cycle = 512-pos;
+
+		//printf("file_write:%d/%d - %d/%d\n",sector,pos,bytes_this_cycle,bytes);
+
+		if (sector != write_pending)
+		{
+			file_write_flush();
+		}
+
+		if (write_pending <0)
+		{
+			// read the sector into our 512 byte buffer...
+			pf_lseek(sector<<9);
+			int fptr = fatfs.fptr;
+
+			char temp_buffer[1];
+			pf_read(&temp_buffer[0], 1, &byteswritten_word);
+
+			//printf("Writing initial pos:%d\n",pos);
+
+			// seek to the initial pos
+			fatfs.fptr = fptr + pos;
+
+			write_pending = sector;
+		}
+
+		res = disk_writep(buffer, pos, bytes_this_cycle);
+
+		fatfs.fptr += bytes_this_cycle;
+		rem-=bytes_this_cycle;
+		buffer+=bytes_this_cycle;
+	}
+	*byteswritten = bytes;
+
+	//printf("wend\n");
+	return translateStatus(res);
+}
+
+enum SimpleFileStatus file_write_flush()
+{
+	if (write_pending >= 0)
+	{
+		//printf("wflush\n");
+		disk_writeflush();
+		write_pending = -1;
+	}
+	return SimpleFile_OK;
+}
+
+enum SimpleFileStatus file_seek(struct SimpleFile * file, int offsetFromStart)
+{
+	FRESULT res;
+
+	int location = offsetFromStart>>9;
+	if (write_pending >=0 && write_pending != offsetFromStart)
+	{
+		//printf("flush on seek\n");
+		file_write_flush();
+	}
+
+	file_check_open(file);
+
+	res = pf_lseek(offsetFromStart);
+	return translateStatus(res);
+}
+
+int file_size(struct SimpleFile * file)
+{
+	return file->size;
+}
+
+int file_readonly(struct SimpleFile * file)
+{
+	return file->is_readonly;
+}
+
+int file_struct_size()
+{
+	return sizeof(struct SimpleFile);
+}
+
+enum SimpleFileStatus file_open_name_in_dir(struct SimpleDirEntry * entry, char const * filename, struct SimpleFile * file)
+{
+	file_write_flush();
+
+	while (entry)
+	{
+		//printf("%s ",entry->filename_ptr);
+		if (0==stricmp(filename,entry->filename_ptr))
+		{
+			return file_open_dir(entry, file);
+		}
+		entry = entry->next;
+	}
+
+	return SimpleFile_FAIL;
+}
+
+enum SimpleFileStatus file_open_name(char const * path, struct SimpleFile * file)
+{
+	char dirname[MAX_DIR_LENGTH];
+	char const * filename = file_of(path);
+	dir_of(&dirname[0], path);
+
+	file_write_flush();
+
+	//printf("filename:%s dirname:%s ", filename,&dirname[0]);
+
+	struct SimpleDirEntry * entry = dir_entries(&dirname[0]);
+	return file_open_name_in_dir(entry,filename, file);
+}
+
+enum SimpleFileStatus file_open_dir(struct SimpleDirEntry * dir, struct SimpleFile * file)
+{
+	FRESULT res;
+
+	strcpy(&file->path[0],dir->path);
+	file->is_readonly = dir->is_readonly;
+	file->size = dir->size;
+
+	file_write_flush();
+
+	res = pf_open(&file->path[0]);
+	openfile = file;
+
+	return translateStatus(res);
+}
+
+enum SimpleFileStatus dir_init(void * mem, int space)
+{
+	FRESULT fres;
+	DSTATUS res;
+
+	write_pending = -1;
+
+	//printf("dir_init\n");
+
+	dir_cache = mem;
+	dir_cache_size = space;
+
+	//printf("disk_init go\n");
+	res = disk_initialize();
+	//printf("disk_init done\n");
+	if (res!=RES_OK) return translateDStatus(res);
+
+	//printf("pf_mount\n");
+	fres = pf_mount(&fatfs);
+	//printf("pf_mount done\n");
+
+	return translateStatus(fres);
+}
+
+// Read entire dir into memory (i.e. give it a decent chunk of sdram)
+struct SimpleDirEntry * dir_entries(char const * dirPath)
+{
+	return dir_entries_filtered(dirPath,0);
+}
+
+int dircmp(struct SimpleDirEntry * a, struct SimpleDirEntry * b)
+{
+	if (a->is_subdir==b->is_subdir)
+		return strcmp(a->lfn,b->lfn);
+	else
+		return a->is_subdir<b->is_subdir;
+}
+
+void sort_ll(struct SimpleDirEntry * h)
+{
+//struct SimpleDirEntry
+//{
+//	char path[MAX_PATH_LENGTH];
+//	char * filename_ptr;
+//	int size;
+//	int is_subdir;
+//	struct SimpleDirEntry * next; // as linked list - want to allow sorting...
+//};
+
+	struct SimpleDirEntry * p,*temp,*prev;
+	int i,j,n,sorted=0;
+	temp=h;
+	prev=0;
+	for(n=0;temp!=0;temp=temp->next) n++;
+
+	for(i=0;i<n-1 && !sorted;i++){
+		p=h;sorted=1;
+		prev=0;
+		for(j=0;j<n-(i+1);j++){
+	//		printf("p->issubdir:%d(%s) p->next->issubdir:%d(%s)",p->is_subdir,p->path,p->next->is_subdir,p->next->path);
+
+			if(dircmp(p,p->next)>0) {
+	//			printf("SWITCH!\n");
+				struct SimpleDirEntry * a = p;
+				struct SimpleDirEntry * b = p->next;
+				a->next=b->next;
+				b->next=a;
+				if (prev)
+					prev->next=b;
+				p=b;
+
+				sorted=0;
+			}
+			prev=p;
+			p=p->next;
+		}
+	}
+
+	//temp=h;
+	//for(n=0;temp!=0;temp=temp->next) printf("POST:%s\n",temp->path);
+}
+
+struct SimpleDirEntry * dir_entries_filtered(char const * dirPath,int(* filter)(struct SimpleDirEntry *))
+{
+	int room = dir_cache_size/sizeof(struct SimpleDirEntry);
+
+	file_write_flush();
+
+	//printf("opendir ");
+	if (FR_OK != pf_opendir(&dir,dirPath))
+	{
+		//printf("FAIL ");
+		return 0;
+	}
+	//printf("OK ");
+
+	struct SimpleDirEntry * prev = (struct SimpleDirEntry *)dir_cache;
+	strcpy(prev->path,"..");
+	strcpy(prev->lfn,"..");
+	prev->filename_ptr = prev->path;
+	prev->size = 0;
+	prev->is_subdir = 1;
+	prev->is_readonly = 1;
+	prev->next = 0;
+	--room;
+
+	//int count=0;
+	struct SimpleDirEntry * entry = prev + 1;
+	while (room && FR_OK == pf_readdir(&dir,&filinfo) && filinfo.fname[0]!='\0')
+	{
+		char * ptr;
+
+		if (filinfo.fattrib & AM_SYS)
+		{
+			continue;
+		}
+		if (filinfo.fattrib & AM_HID)
+		{
+			continue;
+		}
+
+		//printf("next %x %d ",entry,room);
+
+		entry->is_subdir = (filinfo.fattrib & AM_DIR) ? 1 : 0;
+		entry->is_readonly = (filinfo.fattrib & AM_RDO) ? 1 : 0;
+
+		//printf("%s ",filinfo.fname);
+
+		strcpy(&entry->path[0],dirPath);
+		ptr = &entry->path[0];
+		ptr += strlen(&entry->path[0]);
+		*ptr++ = '/';
+		entry->filename_ptr = ptr;
+		strcpy(ptr,filinfo.fname);
+		entry->size = filinfo.fsize;
+
+		//printf("LFN:%s\n",&filinfo.lfname[0]);
+		strcpy(&entry->lfn[0],&filinfo.lfname[0]);
+
+		//int count;
+		//printf("%d %s %s\n",count++, filinfo.fname, filinfo.lfname);
+
+
+		if (filter && !filter(entry))
+		{
+			continue;
+		}
+
+		entry->next = 0;
+
+		if (prev)
+			prev->next = entry;
+		prev = entry;
+		entry++;
+		room--;
+
+		//printf("n %d %d %x ",filinfo.fsize, entry->size, entry->next);
+	}
+
+	//printf("dir_entries done ");
+
+	/*struct SimpleDirEntry * begin = (struct SimpleDirEntry *) dir_cache;
+	int count = 0;
+	while (begin)
+	{
+		printf("%d %s\n",count++, begin->path);
+		begin = begin->next;
+	}*/
+
+	if (filter)
+	{
+		sort_ll((struct SimpleDirEntry *) dir_cache);
+	}
+	return (struct SimpleDirEntry *) dir_cache;
+}
+
+char const * dir_path(struct SimpleDirEntry * entry)
+{
+	return &entry->path[0];
+}
+
+char const * dir_filename(struct SimpleDirEntry * entry)
+{
+	//return entry->filename_ptr;
+	return &entry->lfn[0];
+}
+
+int dir_filesize(struct SimpleDirEntry * entry)
+{
+	return entry->size;
+}
+
+struct SimpleDirEntry * dir_next(struct SimpleDirEntry * entry)
+{
+	return entry->next;
+}
+
+int dir_is_subdir(struct SimpleDirEntry * entry)
+{
+	return entry->is_subdir;
+}
+
+
Index: firmware_legacy/fat/pff.h
===================================================================
--- firmware_legacy/fat/pff.h	(nonexistent)
+++ firmware_legacy/fat/pff.h	(revision 799)
@@ -0,0 +1,160 @@
+/*---------------------------------------------------------------------------/
+/  Petit FatFs - FAT file system module include file  R0.03   (C)ChaN, 2014
+/----------------------------------------------------------------------------/
+/ Petit FatFs module is an open source software to implement FAT file system to
+/ small embedded systems. This is a free software and is opened for education,
+/ research and commercial developments under license policy of following trems.
+/
+/  Copyright (C) 2014, ChaN, all right reserved.
+/
+/ * The Petit FatFs module is a free software and there is NO WARRANTY.
+/ * No restriction on use. You can use, modify and redistribute it for
+/   personal, non-profit or commercial use UNDER YOUR RESPONSIBILITY.
+/ * Redistributions of source code must retain the above copyright notice.
+/
+/----------------------------------------------------------------------------*/
+
+#ifndef _PFATFS
+#define _PFATFS	4004	/* Revision ID */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "integer.h"
+#include "pffconf.h"
+
+#if _PFATFS != _PFFCONF
+#error Wrong configuration file (pffconf.h).
+#endif
+
+#if _FS_FAT32
+#define	CLUST	DWORD
+#else
+#define	CLUST	WORD
+#endif
+
+
+/* File system object structure */
+
+typedef struct {
+	BYTE	fs_type;	/* FAT sub type */
+	BYTE	flag;		/* File status flags */
+	BYTE	csize;		/* Number of sectors per cluster */
+	BYTE	pad1;
+	WORD	n_rootdir;	/* Number of root directory entries (0 on FAT32) */
+	CLUST	n_fatent;	/* Number of FAT entries (= number of clusters + 2) */
+	DWORD	fatbase;	/* FAT start sector */
+	DWORD	dirbase;	/* Root directory start sector (Cluster# on FAT32) */
+	DWORD	database;	/* Data start sector */
+	DWORD	fptr;		/* File R/W pointer */
+	DWORD	fsize;		/* File size */
+	CLUST	org_clust;	/* File start cluster */
+	CLUST	curr_clust;	/* File current cluster */
+	DWORD	dsect;		/* File current data sector */
+} FATFS;
+
+
+
+/* Directory object structure */
+
+typedef struct {
+	WORD	index;		/* Current read/write index number */
+	BYTE*	fn;			/* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */
+	CLUST	sclust;		/* Table start cluster (0:Static table) */
+	CLUST	clust;		/* Current cluster */
+	DWORD	sect;		/* Current sector */
+} DIR;
+
+
+
+/* File status structure */
+
+typedef struct {
+	DWORD	fsize;		/* File size */
+	WORD	fdate;		/* Last modified date */
+	WORD	ftime;		/* Last modified time */
+	BYTE	fattrib;	/* Attribute */
+	char	fname[13];	/* File name */
+	char	lfname[256];	/* File name */
+} FILINFO;
+
+
+
+/* File function return code (FRESULT) */
+
+typedef enum {
+	FR_OK = 0,			/* 0 */
+	FR_DISK_ERR,		/* 1 */
+	FR_NOT_READY,		/* 2 */
+	FR_NO_FILE,			/* 3 */
+	FR_NOT_OPENED,		/* 4 */
+	FR_NOT_ENABLED,		/* 5 */
+	FR_NO_FILESYSTEM	/* 6 */
+} FRESULT;
+
+
+
+/*--------------------------------------------------------------*/
+/* Petit FatFs module application interface                     */
+
+FRESULT pf_mount (FATFS* fs);								/* Mount/Unmount a logical drive */
+FRESULT pf_open (const char* path);							/* Open a file */
+FRESULT pf_read (void* buff, UINT btr, UINT* br);			/* Read data from the open file */
+FRESULT pf_write (const void* buff, UINT btw, UINT* bw);	/* Write data to the open file */
+FRESULT pf_lseek (DWORD ofs);								/* Move file pointer of the open file */
+FRESULT pf_opendir (DIR* dj, const char* path);				/* Open a directory */
+FRESULT pf_readdir (DIR* dj, FILINFO* fno);					/* Read a directory item from the open directory */
+
+
+
+/*--------------------------------------------------------------*/
+/* Flags and offset address                                     */
+
+/* File status flag (FATFS.flag) */
+
+#define	FA_OPENED	0x01
+#define	FA_WPRT		0x02
+#define	FA__WIP		0x40
+
+
+/* FAT sub type (FATFS.fs_type) */
+
+#define FS_FAT12	1
+#define FS_FAT16	2
+#define FS_FAT32	3
+
+
+/* File attribute bits for directory entry */
+
+#define	AM_RDO	0x01	/* Read only */
+#define	AM_HID	0x02	/* Hidden */
+#define	AM_SYS	0x04	/* System */
+#define	AM_VOL	0x08	/* Volume label */
+#define AM_LFN	0x0F	/* LFN entry */
+#define AM_DIR	0x10	/* Directory */
+#define AM_ARC	0x20	/* Archive */
+#define AM_MASK	0x3F	/* Mask of defined bits */
+
+
+/*--------------------------------*/
+/* Multi-byte word access macros  */
+
+#if _WORD_ACCESS == 1	/* Enable word access to the FAT structure */
+#define	LD_WORD(ptr)		(WORD)(*(WORD*)(BYTE*)(ptr))
+#define	LD_DWORD(ptr)		(DWORD)(*(DWORD*)(BYTE*)(ptr))
+#define	ST_WORD(ptr,val)	*(WORD*)(BYTE*)(ptr)=(WORD)(val)
+#define	ST_DWORD(ptr,val)	*(DWORD*)(BYTE*)(ptr)=(DWORD)(val)
+#else					/* Use byte-by-byte access to the FAT structure */
+#define	LD_WORD(ptr)		(WORD)(((WORD)*((BYTE*)(ptr)+1)<<8)|(WORD)*(BYTE*)(ptr))
+#define	LD_DWORD(ptr)		(DWORD)(((DWORD)*((BYTE*)(ptr)+3)<<24)|((DWORD)*((BYTE*)(ptr)+2)<<16)|((WORD)*((BYTE*)(ptr)+1)<<8)|*(BYTE*)(ptr))
+#define	ST_WORD(ptr,val)	*(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8)
+#define	ST_DWORD(ptr,val)	*(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8); *((BYTE*)(ptr)+2)=(BYTE)((DWORD)(val)>>16); *((BYTE*)(ptr)+3)=(BYTE)((DWORD)(val)>>24)
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PFATFS */
Index: firmware_legacy/fat/pff_file.h
===================================================================
--- firmware_legacy/fat/pff_file.h	(nonexistent)
+++ firmware_legacy/fat/pff_file.h	(revision 799)
@@ -0,0 +1,28 @@
+#pragma once
+
+#include "simplefile.h"
+#include "simpledir.h"
+
+#define MAX_DIR_LENGTH (9*5+1)
+#define MAX_FILE_LENGTH (8+3+1+1)
+#define MAX_PATH_LENGTH (9*5 + 8+3+1 + 1)
+
+// Do not access these directly... They vary by architecture, just the simplefile/simpledir interface is the same
+struct SimpleFile
+{
+	char path[MAX_PATH_LENGTH];
+	int is_readonly;
+	int size;
+};
+
+struct SimpleDirEntry
+{
+	char path[MAX_PATH_LENGTH];
+	char * filename_ptr;
+	char lfn[256];
+	int size;
+	int is_subdir;
+	int is_readonly;
+	struct SimpleDirEntry * next; // as linked list - want to allow sorting...
+};
+
Index: firmware_legacy/regs.h
===================================================================
--- firmware_legacy/regs.h	(nonexistent)
+++ firmware_legacy/regs.h	(revision 799)
@@ -0,0 +1,102 @@
+#ifndef regs_h
+#define regs_h
+#include "memory.h"
+
+static const int screen_address = 11328;
+
+#define zpu_in1 ((int volatile *)(0*4+zpu_regbase))
+#define zpu_in2 ((int volatile *)(1*4+zpu_regbase))
+#define zpu_in3 ((int volatile *)(2*4+zpu_regbase))
+#define zpu_in4 ((int volatile *)(3*4+zpu_regbase))
+
+#define zpu_out1 ((int volatile *)(4*4+zpu_regbase))
+#define zpu_out2 ((int volatile *)(5*4+zpu_regbase))
+#define zpu_out3 ((int volatile *)(6*4+zpu_regbase))
+#define zpu_out4 ((int volatile *)(7*4+zpu_regbase))
+#define zpu_out5 ((int volatile *)(14*4+zpu_regbase))
+#define zpu_out6 ((int volatile *)(15*4+zpu_regbase))
+
+#define zpu_pause ((int volatile *)(8*4+zpu_regbase))
+#define zpu_timer ((int volatile *)(8*4+zpu_regbase))
+
+#define zpu_spi_data ((int volatile *)(9*4+zpu_regbase))
+#define zpu_spi_state ((int volatile *)(10*4+zpu_regbase))
+
+#define zpu_sio ((int volatile *)(11*4+zpu_regbase))
+
+#define zpu_board ((int volatile *)(12*4+zpu_regbase))
+
+#define zpu_spi_dma ((int volatile *)(13*4+zpu_regbase))
+
+#define zpu_pokey_audf0 ((unsigned char volatile *)(0x0*4+pokey_regbase))
+#define zpu_pokey_audc0 ((unsigned char volatile *)(0x1*4+pokey_regbase))
+#define zpu_pokey_audf1 ((unsigned char volatile *)(0x2*4+pokey_regbase))
+#define zpu_pokey_audc1 ((unsigned char volatile *)(0x3*4+pokey_regbase))
+#define zpu_pokey_audf2 ((unsigned char volatile *)(0x4*4+pokey_regbase))
+#define zpu_pokey_audc2 ((unsigned char volatile *)(0x5*4+pokey_regbase))
+#define zpu_pokey_audf3 ((unsigned char volatile *)(0x6*4+pokey_regbase))
+#define zpu_pokey_audc3 ((unsigned char volatile *)(0x7*4+pokey_regbase))
+
+#define zpu_pokey_audctl ((unsigned char volatile *)(0x8*4+pokey_regbase))
+
+#define zpu_pokey_skrest ((unsigned char volatile *)(0xa*4+pokey_regbase))
+#define zpu_pokey_serout ((unsigned char volatile *)(0xd*4+pokey_regbase))
+#define zpu_pokey_irqen ((unsigned char volatile *)(0xe*4+pokey_regbase))
+#define zpu_pokey_skctl ((unsigned char volatile *)(0xf*4+pokey_regbase))
+
+#define zpu_siocommand_ready ((unsigned char volatile *)(0x15*4+pokey_regbase))
+#define zpu_siocommand_data ((unsigned char volatile *)(0x10*4+pokey_regbase))
+
+#define atari_nmien ((unsigned char volatile *)(0xd40e + atari_regbase))
+#define atari_dlistl ((unsigned char volatile *)(0xd402 + atari_regbase))
+#define atari_dlisth ((unsigned char volatile *)(0xd403 + atari_regbase))
+
+#define atari_porta ((unsigned char volatile *)(0xd300 + atari_regbase))
+#define atari_portb ((unsigned char volatile *)(0xd301 + atari_regbase))
+#define atari_chbase ((unsigned char volatile *)(0xd409 + atari_regbase))
+#define atari_chactl ((unsigned char volatile *)(0xd401 + atari_regbase))
+#define atari_dmactl ((unsigned char volatile *)(0xd400 + atari_regbase))
+
+#ifdef FIRMWARE_5200
+// 5200: GTIA and POKEY are on different addresses
+#define atari_colbk ((unsigned char volatile *)(0xc01a + atari_regbase))
+#define atari_colpf1 ((unsigned char volatile *)(0xc017 + atari_regbase))
+#define atari_colpf2 ((unsigned char volatile *)(0xc018 + atari_regbase))
+#define atari_colpf3 ((unsigned char volatile *)(0xc019 + atari_regbase))
+#define atari_colpf0 ((unsigned char volatile *)(0xc016 + atari_regbase))
+#define atari_prior ((unsigned char volatile *)(0xc01b + atari_regbase))
+#define atari_consol ((unsigned char volatile *)(0xc01f + atari_regbase))
+#define atari_trig0 ((unsigned char volatile *)(0xc010 + atari_regbase))
+#define atari_trig1 ((unsigned char volatile *)(0xc011 + atari_regbase))
+#define atari_trig2 ((unsigned char volatile *)(0xc012 + atari_regbase))
+#define atari_trig3 ((unsigned char volatile *)(0xc013 + atari_regbase))
+
+#define atari_skctl ((unsigned char volatile *)(0xe80f + atari_regbase))
+#define atari_kbcode ((unsigned char volatile *)(0xe809 + atari_regbase))
+#define atari_random ((unsigned char volatile *)(0xe80a + atari_regbase))
+#define atari_pot0 ((unsigned char volatile *)(0xe800 + atari_regbase))
+#define atari_pot1 ((unsigned char volatile *)(0xe801 + atari_regbase))
+#define atari_pot2 ((unsigned char volatile *)(0xe802 + atari_regbase))
+#define atari_pot3 ((unsigned char volatile *)(0xe803 + atari_regbase))
+#define atari_potgo ((unsigned char volatile *)(0xe80b + atari_regbase))
+#define atari_allpot ((unsigned char volatile *)(0xe808 + atari_regbase))
+
+#else
+
+#define atari_colbk ((unsigned char volatile *)(0xd01a + atari_regbase))
+#define atari_colpf1 ((unsigned char volatile *)(0xd017 + atari_regbase))
+#define atari_colpf2 ((unsigned char volatile *)(0xd018 + atari_regbase))
+#define atari_colpf3 ((unsigned char volatile *)(0xd019 + atari_regbase))
+#define atari_colpf0 ((unsigned char volatile *)(0xd016 + atari_regbase))
+#define atari_prior ((unsigned char volatile *)(0xd01b + atari_regbase))
+
+#define atari_skctl ((unsigned char volatile *)(0xd20f + atari_regbase))
+#define atari_kbcode ((unsigned char volatile *)(0xd209 + atari_regbase))
+#define atari_random ((unsigned char volatile *)(0xd20a + atari_regbase))
+
+#define atari_trig0 ((unsigned char volatile *)(0xd010 + atari_regbase))
+#define atari_trig1 ((unsigned char volatile *)(0xd011 + atari_regbase))
+
+#endif
+
+#endif // regs_h
Index: firmware_legacy/papilioduo/memory.h
===================================================================
--- firmware_legacy/papilioduo/memory.h	(nonexistent)
+++ firmware_legacy/papilioduo/memory.h	(revision 799)
@@ -0,0 +1,40 @@
+#ifndef MEMORY_H
+#define MEMORY_H
+
+//512k memory map
+//(up to 320k atari mem)
+//----
+//64k (base)
+//64-127  (64k)= freeze backup
+//128-223 (96k)= carts 
+//160-223 (64k)= dir cache
+//224-255 (32k)= os rom/ram
+//256 (ext)
+
+#define SRAM_BASE ((void*) 0x200000)
+#define SDRAM_BASE ((void*) 0x800000)
+
+// Memory usage...
+// 0x20000-0x37FFF (0x820000 in zpu space) = carts - 96k
+// 0x28000-0x37FFF (0x820000 in zpu space) = directory cache - 64k
+// 0x10000-0x1FFFF (0x810000 in zpu space) = freeze backup - 64k
+// 0x38000-0x3FFFF (0x838000 in zpu space) = os rom/basic rom - 32k
+
+#define INIT_MEM
+
+#define DIR_INIT_MEM (SDRAM_BASE + 0x28000)
+#define DIR_INIT_MEMSIZE 65536
+#define FREEZE_MEM (SDRAM_BASE + 0x10000)
+
+#define CARTRIDGE_MEM (SDRAM_BASE + 0x20000) // Share with dir cache, long carts will be wired by dir listing
+
+// offset in SDRAM area
+#define ROM_OFS 0x38000
+
+
+#define atari_regbase  ((void*) 0x10000)
+#define atari_regmirror  ((void*) 0x20000)
+#define zpu_regbase ((void*) 0x40000)
+#define pokey_regbase ((void*) 0x40400)
+
+#endif
Index: firmware_legacy/fat/diskio.h
===================================================================
--- firmware_legacy/fat/diskio.h	(nonexistent)
+++ firmware_legacy/fat/diskio.h	(revision 799)
@@ -0,0 +1,42 @@
+/*-----------------------------------------------------------------------
+/  PFF - Low level disk interface modlue include file    (C)ChaN, 2009
+/-----------------------------------------------------------------------*/
+
+#ifndef _DISKIO
+
+#include "integer.h"
+
+
+/* Status of Disk Functions */
+typedef BYTE	DSTATUS;
+
+
+/* Results of Disk Functions */
+typedef enum {
+	RES_OK = 0,		/* 0: Function succeeded */
+	RES_ERROR,		/* 1: Disk error */
+	RES_NOTRDY,		/* 2: Not ready */
+	RES_PARERR		/* 3: Invalid parameter */
+} DRESULT;
+
+
+/*---------------------------------------*/
+/* Prototypes for disk control functions */
+
+DSTATUS disk_initialize (void);
+DRESULT disk_readp (BYTE*, DWORD, WORD, WORD);
+DRESULT disk_writep (const BYTE* buff, DWORD sofs, DWORD count);
+void disk_writeflush();
+
+#define STA_NOINIT		0x01	/* Drive not initialized */
+#define STA_NODISK		0x02	/* No medium in the drive */
+
+/* Card type flags (CardType) */
+#define CT_MMC				0x01	/* MMC ver 3 */
+#define CT_SD1				0x02	/* SD ver 1 */
+#define CT_SD2				0x04	/* SD ver 2 */
+#define CT_SDC				(CT_SD1|CT_SD2)	/* SD */
+#define CT_BLOCK			0x08	/* Block addressing */
+
+#define _DISKIO
+#endif
Index: firmware_legacy/pokey/uart.c
===================================================================
--- firmware_legacy/pokey/uart.c	(nonexistent)
+++ firmware_legacy/pokey/uart.c	(revision 799)
@@ -0,0 +1,108 @@
+#include "uart.h"
+
+#include "regs.h"
+
+void actions();
+
+int USART_Data_Needed()
+{
+	int needed = 0==(0x10&(*zpu_pokey_irqen));
+	if (needed)
+	{
+		*zpu_pokey_irqen = 0x28;
+		*zpu_pokey_irqen = 0x38;
+	}
+	return needed;
+}
+
+int USART_Data_Ready()
+{
+	int ready = 0==(0x20&(*zpu_pokey_irqen));
+	if (ready)
+	{
+		*zpu_pokey_irqen = 0x18;
+		*zpu_pokey_irqen = 0x38;
+	}
+	return ready;
+}
+
+void USART_Init( u08 value )
+{
+	// value is pokey div + 6
+	*zpu_pokey_skctl = 0;
+	wait_us(10);
+	USART_Receive_Mode(); // turn of reset and listen to commands
+	*zpu_pokey_audctl = 0x78; // linked channels, fast clocked
+	*zpu_pokey_audf1 = 0x00;
+	*zpu_pokey_audf0 = value-6;
+	*zpu_pokey_audf3 = 0x00;
+	*zpu_pokey_audf2 = value-6;
+
+	*zpu_pokey_irqen = 0x00;
+	*zpu_pokey_irqen = 0x38;
+}
+
+void USART_Transmit_Byte( unsigned char data )
+{
+	*zpu_pokey_serout = data;
+
+	// wait until next byte is needed 
+	while (!USART_Data_Needed());
+}
+unsigned char USART_Receive_Byte( void )
+{
+	// wait for data
+	while (!USART_Data_Ready())
+	{
+		actions();
+	}
+
+	u08 res = *zpu_pokey_serout; //serin at same address
+	return res;
+}
+
+void USART_Transmit_Mode()
+{
+	*zpu_pokey_skctl = 0x23; // 010 for transmission
+	*zpu_pokey_skrest = 0xff;
+	*zpu_pokey_irqen = 0x28; // clear data needed
+	*zpu_pokey_irqen = 0x38;
+}
+
+void USART_Receive_Mode()
+{
+	*zpu_pokey_skctl = 0x13; // 001 for receiving
+	*zpu_pokey_skrest = 0xff;
+}
+
+int USART_Framing_Error()
+{
+	if (0x80&(*zpu_pokey_skctl))
+	{
+		return 0;
+	}
+	else
+	{
+		return 1;
+	}
+}
+
+void USART_Wait_Transmit_Complete()
+{
+	while (1)
+	{
+		int ready = 0==(0x08&(*zpu_pokey_irqen));
+		if (ready)
+		{
+			*zpu_pokey_irqen = 0x30;
+			*zpu_pokey_irqen = 0x38;
+			return;
+		}
+	}
+}
+
+int USART_Command_Line()
+{
+	return (1&(*zpu_sio));
+}
+
Index: firmware_legacy/linux/memory.h
===================================================================
--- firmware_legacy/linux/memory.h	(nonexistent)
+++ firmware_legacy/linux/memory.h	(revision 799)
@@ -0,0 +1,33 @@
+#ifndef MEMORY_H
+#define MEMORY_H
+
+extern void* SDRAM_BASE;
+extern void* SRAM_BASE;
+extern void* CARTRIDGE_MEM;
+extern void* FREEZER_RAM_MEM;
+extern void* FREEZER_ROM_MEM;
+
+#define HAVE_FREEZER_ROM_MEM 1
+
+#define INIT_MEM
+
+// Memory usage...
+// 0x410000-0x44FFFF (0xc10000 in zpu space) = directory cache - 256k
+// 0x450000-0x46FFFF (0xc50000 in zpu space) = freeze backup
+// 0x700000-0x77FFFF (0xf00000 in zpu space) = os rom/basic rom
+
+#define DIR_INIT_MEM (SDRAM_BASE + 0x410000)
+#define DIR_INIT_MEMSIZE 262144
+#define FREEZE_MEM (SDRAM_BASE + 0x450000)
+
+// offset into SDRAM
+#define ROM_OFS 0x700000
+
+extern void* atari_regbase;
+extern void* atari_regmirror;
+extern void* zpu_regbase;
+extern void* pokey_regbase;
+
+void init_memory(void);
+
+#endif
Index: firmware_legacy/usb/usb.c
===================================================================
--- firmware_legacy/usb/usb.c	(nonexistent)
+++ firmware_legacy/usb/usb.c	(revision 799)
@@ -0,0 +1,834 @@
+//#include <stdio.h>
+
+#include "timer.h"
+#include "usb.h"
+#include "usbhostslave.h"
+#include "debug.h"
+#include "memory.h"
+#include "printf.h"
+#include "log.h"
+
+extern unsigned char joysticks;      // number of detected usb joysticks
+usb_device_t devices[USB_NUMDEVICES];
+
+/*#define tokSETUP  0x10  // HS=0, ISO=0, OUTNIN=0, SETUP=1
+#define tokIN     0x00  // HS=0, ISO=0, OUTNIN=0, SETUP=0
+#define tokOUT    0x20  // HS=0, ISO=0, OUTNIN=1, SETUP=0
+#define tokINHS   0x80  // HS=1, ISO=0, OUTNIN=0, SETUP=0
+#define tokOUTHS  0xA0  // HS=1, ISO=0, OUTNIN=1, SETUP=0 
+#define tokISOIN  0x40  // HS=0, ISO=1, OUTNIN=0, SETUP=0
+#define tokISOOUT 0x60  // HS=0, ISO=1, OUTNIN=1, SETUP=0
+*/
+
+typedef enum {tokSETUP,tokIN,tokOUT,tokINHS,tokOUTHS,tokISOIN,tokISOOUT} TOKEN;
+
+static uint8_t outType;
+static uint8_t controlAdj;
+static uint8_t lineControlAdj;
+
+#ifdef LINUX_BUILD
+#define USBHOSTSLAVE_READ(ADDR) usbhostslave_read(ADDR)
+#define USBHOSTSLAVE_WRITE(ADDR,VALUE) usbhostslave_write(ADDR,VALUE)
+#else
+#define USBHOSTSLAVE_READ(ADDR) usbhostslave[ADDR]
+#define USBHOSTSLAVE_WRITE(ADDR,VALUE) usbhostslave[ADDR] = VALUE
+#endif
+
+void usb_reset_state() {
+  iprintf("%s\n",__FUNCTION__);
+}
+
+usb_device_t *usb_get_devices() {
+  return devices;
+}
+
+void usb_init(struct usb_host * host, int portnumber) {
+  iprintf("%s\n",__FUNCTION__);
+
+  joysticks = 0;
+
+  // MWW max3421e_init();   // init underlaying hardware layer
+
+  if (portnumber == 0)
+  {
+      host->addr = zpu_regbase + 0x800;
+  }
+  if (portnumber == 1)
+  {
+      host->addr = zpu_regbase + 0xc00;
+  }
+  usbhostslave = host->addr;
+  host->poll = 0;
+  host->delay = 0;
+
+  USBHOSTSLAVE_WRITE(OHS900_HOSTSLAVECTLREG, OHS900_HSCTLREG_RESET_CORE);
+  timer_delay_msec(1);
+  USBHOSTSLAVE_WRITE(OHS900_TXLINECTLREG, 0);
+  USBHOSTSLAVE_WRITE(OHS900_HOSTSLAVECTLREG, OHS900_HS_CTL_INIT);
+  USBHOSTSLAVE_WRITE(OHS900_SOFENREG, 0);
+  USBHOSTSLAVE_WRITE(OHS900_IRQ_ENABLE, 0);
+
+  host->usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE; 
+
+  outType = 0;
+  controlAdj = 0;
+  lineControlAdj = 0;
+
+  uint8_t i;
+  for(i=0;i<USB_NUMDEVICES;i++)
+    devices[i].bAddress = 0;
+
+  usb_reset_state();
+}
+
+uint8_t usb_set_address(usb_device_t *dev, ep_t *ep, 
+			uint16_t *nak_limit) {
+  //  printf("  %s(addr=%x, ep=%d)\n", __FUNCTION__, addr, ep);
+  *nak_limit = (1UL << ( ( ep->bmNakPower > USB_NAK_MAX_POWER ) ? 
+			 USB_NAK_MAX_POWER : ep->bmNakPower) ) - 1;
+  
+  /*
+    printf("\nAddress: %x\n", addr);
+    printf(" EP: %d\n", ep);
+    printf(" NAK Power: %d\n",(*ppep)->bmNakPower);
+    printf(" NAK Limit: %d\n", nak_limit);
+  */
+  
+  USBHOSTSLAVE_WRITE(OHS900_TXADDRREG, dev->bAddress);
+
+  /* MWW (sets address and messes with mode - I plan to change mode on connect only...)
+  max3421e_write_u08( MAX3421E_PERADDR, dev->bAddress); // set peripheral address
+  uint8_t mode = max3421e_read_u08( MAX3421E_MODE );
+  
+  // Set bmLOWSPEED and bmHUBPRE in case of low-speed device, 
+  // reset them otherwise
+  max3421e_write_u08( MAX3421E_MODE, 
+		      (dev->lowspeed) ? mode |   MAX3421E_LOWSPEED | bmHubPre : 
+		                      mode & ~(MAX3421E_HUBPRE | MAX3421E_LOWSPEED)); 
+  */
+
+  controlAdj = 0;
+  lineControlAdj = 0;
+  if (dev->parent) // via hub
+  {
+    controlAdj = dev->lowspeed ? OHS900_HCTLMASK_PREAMBLE_EN : 0;
+    lineControlAdj = dev->lowspeed ? 0 : OHS900_TXLCTL_MASK_FS_RATE; 
+    lineControlAdj |= OHS900_TXLCTL_MASK_FS_POL; // hub always full speed polarity
+  }
+  else // direct
+  {
+    lineControlAdj = dev->lowspeed ? OHS900_TXLCTL_MASK_LSPD : OHS900_TXLCTL_MASK_FSPD;
+  }
+  
+  return 0;
+}
+
+/* dispatch usb packet. Assumes peripheral address is set and relevant */
+/* buffer is loaded/empty */
+/* If NAK, tries to re-send up to nak_limit times  */
+/* If nak_limit == 0, do not count NAKs, exit after timeout */
+/* If bus timeout, re-sends up to USB_RETRY_LIMIT times */
+/* return codes 0x00-0x0f are HRSLT (0x00 being success), 0xff means timeout */
+uint8_t usb_dispatchPktWithData( TOKEN token, uint8_t ep, uint16_t nak_limit, uint8_t * data, uint16_t bytes_tosend, uint8_t * sndToggle) {
+ //   printf("  %s(token=%x, ep=%d, nak_limit=%d tosend:%d)\n", 
+ // 	  __FUNCTION__, token, ep, nak_limit, bytes_tosend);
+  iprintf("SEND%02d ", bytes_tosend);
+  unsigned long timeout = timer_get_msec() + USB_XFER_TIMEOUT;
+  uint8_t tmpdata;   
+  uint8_t rcode = 0x00;
+  uint8_t retry_count = 0;
+  uint16_t nak_count = 0;
+	
+  while( timeout > timer_get_msec() )  {
+    //MWW max3421e_write_u08( MAX3421E_HXFR, ( token|ep )); //launch the transfer
+    USBHOSTSLAVE_WRITE(OHS900_TXENDPREG, ep);
+    uint8_t control = OHS900_HCTLMASK_TRANS_REQ|controlAdj;
+    uint8_t line_control = 0;
+    uint8_t load_fifo = 0;
+    uint8_t wait_for_sof = OHS900_HCTLMASK_SOF_SYNC;
+    uint8_t expect_ack = 0;
+    switch (token)
+    {
+    case tokSETUP:
+        USBHOSTSLAVE_WRITE(OHS900_TXTRANSTYPEREG, OHS900_SETUP);
+	iprintf("S ");
+	load_fifo = 1;
+        expect_ack = 1;
+        break;
+    case tokIN:
+        USBHOSTSLAVE_WRITE(OHS900_TXTRANSTYPEREG, OHS900_IN);
+	iprintf("I ");
+        break;
+    case tokOUT:
+        USBHOSTSLAVE_WRITE(OHS900_TXTRANSTYPEREG, *sndToggle ? OHS900_OUT_DATA1 : OHS900_OUT_DATA0);
+	iprintf(*sndToggle ? "Data1 ":"Data0 ");
+	load_fifo = 1;
+        expect_ack = 1;
+        break;
+    case tokINHS:
+        USBHOSTSLAVE_WRITE(OHS900_TXTRANSTYPEREG, OHS900_IN);
+	iprintf("HI ");
+	//wait_for_sof = 0;
+        break;
+    case tokOUTHS:
+        USBHOSTSLAVE_WRITE(OHS900_TXTRANSTYPEREG, OHS900_OUT_DATA1);
+	iprintf("HO ");
+	load_fifo = 1;
+	//wait_for_sof = 0;
+        expect_ack = 1;
+        break;
+    case tokISOIN:
+        USBHOSTSLAVE_WRITE(OHS900_TXTRANSTYPEREG, OHS900_IN);
+        control |= OHS900_HCTLMASK_ISO_EN;
+        break;
+    case tokISOOUT:
+        USBHOSTSLAVE_WRITE(OHS900_TXTRANSTYPEREG, *sndToggle ? OHS900_OUT_DATA1 : OHS900_OUT_DATA0);
+      	*sndToggle = !*sndToggle; // No acks, toggle each time
+	load_fifo = 1;
+        control |= OHS900_HCTLMASK_ISO_EN;
+        break;
+    }
+
+    line_control |= lineControlAdj;
+
+    USBHOSTSLAVE_WRITE(OHS900_TXFIFOCONTROLREG, OHS900_FIFO_FORCE_EMPTY);
+    USBHOSTSLAVE_WRITE(OHS900_RXFIFOCONTROLREG, OHS900_FIFO_FORCE_EMPTY);
+
+    if (load_fifo && data)
+    {
+  
+      //filling output FIFO
+      //MWW max3421e_write( MAX3421E_SNDFIFO, bytes_tosend, data );
+      uint16_t toSend = bytes_tosend;
+      uint8_t * dataToSend = data;
+      iprintf("FIFO:");
+      while (toSend--)
+      {
+	iprintf("%02x", *dataToSend);
+        USBHOSTSLAVE_WRITE(OHS900_HOST_TXFIFO_DATA, *dataToSend++);
+      }
+	iprintf(" ");
+      
+      //set number of bytes
+      //MWW max3421e_write_u08( MAX3421E_SNDBC, bytes_tosend );
+    }
+
+	{
+	    rcode = USBHOSTSLAVE_READ(OHS900_HRXSTATREG);
+	   // printf("Pre transfer rcode:%02x line:%02x ctrl:%02x", rcode, line_control, control);
+	}
+
+    USBHOSTSLAVE_WRITE(OHS900_TXLINECTLREG, line_control);
+    //USBHOSTSLAVE_WRITE(OHS900_HOST_TX_CTLREG, control|wait_for_sof);
+    USBHOSTSLAVE_WRITE(OHS900_HOST_TX_CTLREG, control);
+
+    rcode = USB_ERROR_TRANSFER_TIMEOUT;   
+    
+    // wait for transfer completion
+	//printf("Wait:%x %x ", timer_get_msec(), timeout);
+    while( timer_get_msec() < timeout )	{
+      //tmpdata = max3421e_read_u08( MAX3421E_HIRQ );
+      // MWW
+      tmpdata = USBHOSTSLAVE_READ(OHS900_IRQ_STATUS);
+
+      if( tmpdata & OHS900_INTMASK_TRANS_DONE ) {
+	//clear the interrupt
+	//max3421e_write_u08( MAX3421E_HIRQ, MAX3421E_HXFRDNIRQ );
+	// MWW
+	USBHOSTSLAVE_WRITE(OHS900_IRQ_STATUS, OHS900_INTMASK_TRANS_DONE);
+	rcode = 0x00;
+
+	iprintf("OK ");
+	break;
+      }
+    }
+
+    if( rcode != 0x00 )                 //exit if timeout
+	{
+		iprintf("TMOUT ");
+      return( rcode );
+	}
+
+    //analyze transfer result
+    //rcode = ( max3421e_read_u08( MAX3421E_HRSL ) & 0x0f );
+    //rcode = 0x00;
+    rcode = USBHOSTSLAVE_READ(OHS900_HRXSTATREG);
+        
+    iprintf("R%02x ", rcode);
+    rcode &= ~OHS900_STATMASK_DATA_SEQ;
+
+    if (!expect_ack && rcode == 0x00)
+    {
+        iprintf("EMPTY! ");
+        //rcode = USB_ERROR_TRANSFER_TIMEOUT;   
+        return rcode;
+    }
+
+    if (rcode&OHS900_STATMASK_ACK_RXED)
+    {
+        //set toggle value
+        // MWW: max3421e_write_u08(MAX3421E_HCTL, 
+        //    (pep->bmSndToggle) ? MAX3421E_SNDTOG1 : MAX3421E_SNDTOG0 );
+        *sndToggle = !*sndToggle; // Toggled on ack
+        iprintf("ACK ");
+        break;
+    }
+    else if (rcode&OHS900_STATMASK_NAK_RXED)
+    {
+      nak_count++;
+      if( nak_limit && ( nak_count == nak_limit ))
+	return( rcode );
+    }
+    else if (rcode&OHS900_STATMASK_RX_TMOUT)
+    {
+      retry_count++;
+      iprintf("Retry ");
+      if( retry_count == USB_RETRY_LIMIT )
+	return( rcode );
+    }
+    else if (rcode&(OHS900_STATMASK_CRC_ERROR|OHS900_STATMASK_BS_ERROR|OHS900_STATMASK_STALL_RXED))
+    {
+      return( rcode );
+    }
+  }
+
+  return( rcode&~(OHS900_STATMASK_ACK_RXED));
+}
+
+uint8_t usb_dispatchPkt( uint8_t token, uint8_t ep, uint16_t nak_limit)
+{
+  uint8_t dummy = 0;
+  return usb_dispatchPktWithData(token,ep,nak_limit,0,0,&dummy);
+}
+
+uint8_t usb_InTransfer(ep_t *pep, uint16_t nak_limit, 
+		       uint16_t *nbytesptr, uint8_t* data) {
+  uint8_t rcode = 0;
+  uint8_t pktsize;
+  uint8_t stat;
+  
+  uint16_t	nbytes		= *nbytesptr;
+  uint8_t	maxpktsize	= pep->maxPktSize; 
+
+  *nbytesptr = 0;
+  // set toggle value
+  // MWW max3421e_write_u08( MAX3421E_HCTL, 
+  //	      (pep->bmRcvToggle) ? MAX3421E_RCVTOG1 : MAX3421E_RCVTOG0 );
+  // MWW: TODO on receipt looks like hardware takes cart of DATA0/DATA1? Perhaps I'm meant to check DATA_SEQUENCE_BIT...
+  
+  // use a 'return' to exit this loop
+  while( 1 ) { 
+    //IN packet to EP-'endpoint'. Function takes care of NAKS.
+    rcode = usb_dispatchPkt( tokIN, pep->epAddr, nak_limit );
+      
+    //should be 0, indicating ACK. Else return error code.
+    if( rcode )
+      return( rcode );
+    
+    /* check for RCVDAVIRQ and generate error if not present */ 
+    /* the only case when absense of RCVDAVIRQ makes sense is when */
+    /* toggle error occured. Need to add handling for that */
+  // MWW if(( max3421e_read_u08( MAX3421E_HIRQ ) & MAX3421E_RCVDAVIRQ ) == 0 ) 
+  //    return ( 0xf0 );                            //receive error
+    stat = USBHOSTSLAVE_READ(OHS900_HRXSTATREG);
+    iprintf("rcv %02d stat %02d ", pep->bmRcvToggle, stat);
+    if (pep->bmRcvToggle != (!!(stat&OHS900_STATMASK_DATA_SEQ))) // Check data0/data1
+    {
+        iprintf("DATA WRONG! rcv %02d stat %02d ", pep->bmRcvToggle, stat);
+        return (0xf0);
+    }
+    
+    // MWW pktsize = max3421e_read_u08( MAX3421E_RCVBC ); // number of received bytes
+    pktsize = USBHOSTSLAVE_READ(OHS900_RXFIFOCNTLSBREG);
+    iprintf("rd %02d ", pktsize);
+        
+    int16_t mem_left = (int16_t)nbytes - *((int16_t*)nbytesptr);
+
+    if (mem_left < 0)
+      mem_left = 0;
+
+    //MWW data = max3421e_read(MAX3421E_RCVFIFO, 
+    //		 ((pktsize > mem_left) ? mem_left : pktsize), data );
+    int16_t toRead = (pktsize > mem_left) ? mem_left : pktsize;
+    iprintf("rd2 %02d ",toRead);
+    LOG("DATA:%x:%d\n",data,toRead);
+    while (toRead--)
+    {
+      uint8_t val = USBHOSTSLAVE_READ(OHS900_HOST_RXFIFO_DATA);
+      iprintf ("%02x", val);
+      *data++ = val;
+    }
+    iprintf(" ");
+
+    // Clear the IRQ & free the buffer
+    //MWW - already done? max3421e_write_u08( MAX3421E_HIRQ, MAX3421E_RCVDAVIRQ );
+    *nbytesptr += pktsize;							
+    // add this packet's byte count to total transfer length
+    /* The transfer is complete under two conditions:           */
+    /* 1. The device sent a short packet (L.T. maxPacketSize)   */
+    /* 2. 'nbytes' have been transferred.                       */
+
+    pep->bmRcvToggle = (!(stat&OHS900_STATMASK_DATA_SEQ)); // expect other way next time
+
+    // have we transferred 'nbytes' bytes?
+    if (( pktsize < maxpktsize ) || (*nbytesptr >= nbytes )) {     
+      // Save toggle value
+      //MWW pep->bmRcvToggle = (( max3421e_read_u08( MAX3421E_HRSL ) & 
+	//		    MAX3421E_RCVTOGRD )) ? 1 : 0;
+      
+      return 0;
+    }
+  }
+}
+
+/* IN transfer to arbitrary endpoint. Assumes PERADDR is set. Handles multiple packets */
+/* if necessary. Transfers 'nbytes' bytes. Keep sending INs and writes data to memory area */
+/* pointed by 'data' */
+/* rcode 0 if no errors. rcode 01-0f is relayed from dispatchPkt(). Rcode f0 means RCVDAVIRQ error, */
+/* fe USB xfer timeout */
+uint8_t usb_in_transfer( usb_device_t *dev, ep_t *ep, uint16_t *nbytesptr, uint8_t* data) {
+  uint16_t nak_limit = 0;
+
+  uint8_t rcode = usb_set_address(dev, ep, &nak_limit);
+  if (rcode) return rcode;
+
+  return usb_InTransfer(ep, nak_limit, nbytesptr, data);
+}
+
+uint8_t usb_OutTransfer(ep_t *pep, uint16_t nak_limit, 
+			uint16_t nbytes, uint8_t *data) {
+  //  printf("%s(%d)\n", __FUNCTION__, nbytes);
+
+  uint8_t rcode = 0;
+  uint16_t bytes_tosend;
+  uint16_t bytes_left = nbytes;
+  
+  uint8_t maxpktsize = pep->maxPktSize; 
+ 
+  if (maxpktsize < 1 || maxpktsize > 64)
+    return USB_ERROR_INVALID_MAX_PKT_SIZE;
+ 
+  //unsigned long timeout = timer_get_msec() + USB_XFER_TIMEOUT;
+  
+  while( bytes_left ) {
+    bytes_tosend = ( bytes_left >= maxpktsize ) ? maxpktsize : bytes_left;
+
+    uint8_t sndToggle = pep->bmSndToggle;
+    rcode = usb_dispatchPktWithData( tokOUT, pep->epAddr, nak_limit, data, bytes_tosend, &sndToggle );
+    pep->bmSndToggle = sndToggle!=0;
+    if (rcode)
+    {
+       return(rcode);
+    }
+
+/*    MWW (this was custom due to bug in chip I think) // dispatch packet
+    max3421e_write_u08( MAX3421E_HXFR, ( tokOUT | pep->epAddr ));
+
+    //wait for the completion IRQ
+    while(!(max3421e_read_u08( MAX3421E_HIRQ ) & MAX3421E_HXFRDNIRQ ));
+    max3421e_write_u08( MAX3421E_HIRQ, MAX3421E_HXFRDNIRQ );    //clear IRQ
+    rcode = max3421e_read_u08( MAX3421E_HRSL ) & 0x0f;
+    
+    while( rcode && ( timeout > timer_get_msec())) {
+      switch( rcode ) {
+      case hrNAK:
+	nak_count ++;
+	if( nak_limit && ( nak_count == nak_limit )) 
+	  return( rcode );
+	break;
+      case hrTIMEOUT:
+	retry_count ++;
+	if( retry_count == USB_RETRY_LIMIT ) 
+	  return( rcode );
+	break;
+      default:
+	return( rcode );
+      }
+      
+      // process NAK according to Host out NAK bug 
+      max3421e_write_u08( MAX3421E_SNDBC, 0 );
+      max3421e_write_u08( MAX3421E_SNDFIFO, *data );
+      max3421e_write_u08( MAX3421E_SNDBC, bytes_tosend );
+
+      // dispatch packet
+      max3421e_write_u08( MAX3421E_HXFR, ( tokOUT | pep->epAddr ));
+
+      // wait for the completion IRQ
+      while(!(max3421e_read_u08( MAX3421E_HIRQ ) & MAX3421E_HXFRDNIRQ ));
+      max3421e_write_u08( MAX3421E_HIRQ, MAX3421E_HXFRDNIRQ );      // clear IRQ
+      rcode = ( max3421e_read_u08( MAX3421E_HRSL ) & 0x0f );
+    }//while( rcode && .... */
+    bytes_left -= bytes_tosend;
+    data += bytes_tosend;
+  }//while( bytes_left...
+
+  //update toggle
+  // MWW: pep->bmSndToggle = ( max3421e_read_u08( MAX3421E_HRSL ) & MAX3421E_SNDTOGRD ) ? 1 : 0;
+
+  return (rcode);    //should be 0 in all cases
+}
+
+/* OUT transfer to arbitrary endpoint. Handles multiple packets if necessary. Transfers 'nbytes' bytes. */
+/* Handles NAK bug per Maxim Application Note 4000 for single buffer transfer   */
+/* rcode 0 if no errors. rcode 01-0f is relayed from HRSL                       */
+uint8_t usb_out_transfer(usb_device_t *dev, ep_t *ep, uint16_t nbytes, uint8_t* data ) {
+  uint16_t nak_limit = 0;
+
+  uint8_t rcode = usb_set_address(dev, ep, &nak_limit);
+  if (rcode) return rcode;
+
+  return usb_OutTransfer(ep, nak_limit, nbytes, data);
+}
+
+/* Control transfer. Sets address, endpoint, fills control packet */
+/* with necessary data, dispatches control packet, and initiates */
+/* bulk IN transfer, depending on request. Actual requests are defined */
+/* as inlines                   */
+/* return codes:                */
+/* 00       =   success         */
+/* 01-0f    =   non-zero HRSLT  */
+
+uint8_t usb_ctrl_req(usb_device_t *dev, uint8_t bmReqType, 
+		    uint8_t bRequest, uint8_t wValLo, uint8_t wValHi, 
+		    uint16_t wInd, uint16_t nbytes, uint8_t* dataptr) {
+//    printf("%s(addr=%x, len=%d, ptr=%p)\n", __FUNCTION__,
+//  	  dev->bAddress, nbytes, dataptr);
+iprintf("C%02X %02X %02x ",dev->bAddress,bRequest, nbytes);
+  bool direction = false;     //request direction, IN or OUT
+  uint8_t rcode;   
+  setup_pkt_t setup_pkt;
+  uint16_t	nak_limit;
+  
+  rcode = usb_set_address(dev, &(dev->ep0), &nak_limit);
+  if (rcode)
+  {
+    iprintf("set_address failed ");
+    return rcode;
+  }
+  
+  direction = (( bmReqType & 0x80 ) > 0);
+
+  /* fill in setup packet */
+  setup_pkt.ReqType_u.bmRequestType	= bmReqType;
+  setup_pkt.bRequest			= bRequest;
+  setup_pkt.wValueL		= wValLo;
+  setup_pkt.wValueH		= wValHi;
+  setup_pkt.wIndexL			= wInd&0xFF;
+  setup_pkt.wIndexH			= wInd>>8;
+  setup_pkt.wLengthL			= nbytes&0xFF;
+  setup_pkt.wLengthH			= nbytes>>8;
+  
+  // transfer to setup packet FIFO
+  /* MWW max3421e_write(MAX3421E_SUDFIFO, sizeof(setup_pkt_t), (uint8_t*)&setup_pkt );
+  
+  rcode = usb_dispatchPkt( tokSETUP, 0, nak_limit );     //dispatch packet
+  */
+  uint8_t dummy = 0;
+  rcode = usb_dispatchPktWithData( tokSETUP, 0, nak_limit, (uint8_t*)&setup_pkt,  sizeof(setup_pkt_t), &dummy);
+  if( rcode )		//return HRSLT if not zero
+  {
+    iprintf("setup failed:%02x ",rcode);
+    return( rcode );
+  }
+  
+  // data stage, if present
+  if( dataptr != NULL )	{
+    if( direction ) { //IN transfer
+      dev->ep0.bmRcvToggle = 1;
+      rcode = usb_InTransfer( &(dev->ep0), nak_limit, &nbytes, dataptr );
+    } else { //OUT transfer
+      dev->ep0.bmSndToggle = 1;
+      rcode = usb_OutTransfer( &(dev->ep0), nak_limit, nbytes, dataptr );
+    }    
+
+    //return error
+    if( rcode )	
+    {
+      iprintf("setupd failed:%02x ",rcode);
+      return( rcode );
+    }
+  }
+
+  // Status stage
+  // GET if direction
+  rcode = usb_dispatchPkt( (direction) ? tokOUTHS : tokINHS, 0, nak_limit );
+  if (rcode)
+  {
+      iprintf("status failed:%02x ",rcode);
+  }
+  return rcode;
+}
+
+// list of supported device classes
+static const usb_device_class_config_t *class_list[]= {
+  &usb_hub_class,
+  &usb_hid_class,
+  NULL
+};
+
+uint8_t usb_configure(uint8_t parent, uint8_t port, bool lowspeed) {
+  uint8_t rcode = 0;
+  iprintf("%s(par=%x prt=%d speed=%d)\n", __FUNCTION__, parent, port, lowspeed);
+
+  // find an empty device entry
+  uint8_t i;
+  for(i=0; i<USB_NUMDEVICES && devices[i].bAddress; i++);
+
+  if(i < USB_NUMDEVICES) {
+    iprintf("using entry %d\n", i);
+
+    usb_device_t *d = devices+i;
+
+    // setup generic info
+    d->bAddress = 0;
+    d->parent = parent;
+    d->lowspeed = lowspeed;
+    d->port = port;
+    d->class = NULL;
+    d->host_addr = usbhostslave;
+
+    // setup endpoint 0
+    d->ep0.epAddr	= 0;
+    d->ep0.maxPktSize	= 8;
+    d->ep0.epAttribs	= 0;
+    d->ep0.bmNakPower	= USB_NAK_MAX_POWER;
+
+    // --- enumerate device ---
+
+    // Assign new address to the device
+    // (address is simply the number of the free slot + 1)
+    iprintf("Set addr %x\n", i+1);
+    rcode = usb_set_addr(d, i+1);
+    if(rcode) {
+      iprintf("failed to assign address:%x\n", rcode);
+      return rcode;
+    }
+
+    // try to connect device to one of the supported classes
+    uint8_t c;
+    for(c=0;class_list[c];c++) {
+      iprintf("trying to init class %d\n", c);
+      rcode = class_list[c]->init(d);
+
+      if (!rcode) {
+	d->class = class_list[c];
+
+	iprintf(" -> accepted :-)\n");
+	// ok, device accepted by class
+
+	return 0;
+      }
+  
+      iprintf(" -> not accepted :-(\n");
+    }
+  } else
+  {
+    iprintf("no more free entries\n");
+  }
+
+  iprintf("unsupported device\n");
+  return 0;
+}
+
+void usb_poll(struct usb_host * host) {
+  bool lowspeed = false;
+
+  usbhostslave = host->addr;
+
+  // max poll 1ms
+  if(timer_get_msec() > host->poll) {
+    host->poll = timer_get_msec()+1;
+
+    // poll underlaying hardware layer
+    //MWW tmpdata = max3421e_poll();
+    uint8_t conState = USBHOSTSLAVE_READ(OHS900_RXCONNSTATEREG);
+    switch(conState)
+    {
+    case OHS900_DISCONNECT_STATE:
+      if(( host->usb_task_state & USB_STATE_MASK ) != USB_STATE_DETACHED ) 
+        host->usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE;
+      break;
+    case OHS900_LS_CONN_STATE:
+      lowspeed = true;
+      // intentional fall-through ...
+    case OHS900_FS_CONN_STATE:
+      if(( host->usb_task_state & USB_STATE_MASK ) == USB_STATE_DETACHED ) {
+        host->delay = timer_get_msec() + USB_SETTLE_DELAY;
+        host->usb_task_state = USB_ATTACHED_SUBSTATE_SETTLE;
+      }
+      break;
+    }
+  
+    /* modify USB task state if Vbus changed */
+  /*  switch( tmpdata )  {
+  
+      // illegal state
+    case MAX3421E_STATE_SE1:   
+      host->usb_task_state = USB_DETACHED_SUBSTATE_ILLEGAL;
+      lowspeed = false;
+      break;
+  
+      // disconnected
+    case MAX3421E_STATE_SE0:
+      if(( host->usb_task_state & USB_STATE_MASK ) != USB_STATE_DETACHED ) 
+        host->usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE;
+      lowspeed = false;
+      break;
+  
+      // attached
+    case MAX3421E_STATE_LSHOST:
+      lowspeed = true;
+      // intentional fall-through ...
+  
+    case MAX3421E_STATE_FSHOST:
+      if(( host->usb_task_state & USB_STATE_MASK ) == USB_STATE_DETACHED ) {
+        delay = timer_get_msec() + USB_SETTLE_DELAY;
+        host->usb_task_state = USB_ATTACHED_SUBSTATE_SETTLE;
+      }
+      break;
+    }*/
+
+    // poll all configured devices
+    uint8_t i;
+    LOG("Poll\n");
+    //printf("Poll\n");
+    for (i=0; i<USB_NUMDEVICES; i++)
+      if(devices[i].bAddress && devices[i].class && devices[i].class->poll && devices[i].host_addr == usbhostslave)
+	devices[i].class->poll(devices+i);
+	// MWW (rcode unused error) rcode = devices[i].class->poll(dev+i);
+    
+    switch( host->usb_task_state ) {
+    case USB_DETACHED_SUBSTATE_INITIALIZE:
+      usb_reset_state();
+      
+      // just remove everything ...
+      for (i=0; i<USB_NUMDEVICES; i++) {
+	if(devices[i].bAddress && devices[i].class && devices[i].host_addr == usbhostslave) {
+	  devices[i].class->release(devices+i);
+	  // MWW (rcode unused error) rcode = devices[i].class->release(devices+i);
+	  devices[i].bAddress = 0;
+	}
+      }
+    
+      host->usb_task_state = USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE;
+      break;
+      
+    case USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE:
+    case USB_DETACHED_SUBSTATE_ILLEGAL:
+      break;
+      
+    case USB_ATTACHED_SUBSTATE_SETTLE:              //settle time for just attached device            
+      if( host->delay < timer_get_msec() ) 
+	host->usb_task_state = USB_ATTACHED_SUBSTATE_RESET_DEVICE;
+      break;
+      
+    case USB_ATTACHED_SUBSTATE_RESET_DEVICE:
+      // MWW max3421e_write_u08( MAX3421E_HCTL, MAX3421E_BUSRST );	             // issue bus reset
+      USBHOSTSLAVE_WRITE(OHS900_SOFENREG, 0);
+      USBHOSTSLAVE_WRITE(OHS900_TXLINECTLREG, OHS900_TXLCTL_MASK_SE0);
+      host->usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE;
+      host->delay = timer_get_msec() + 50; // send reset for 50msec
+      break;
+      
+    case USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE:
+      if( host->delay < timer_get_msec() )
+      {
+        USBHOSTSLAVE_WRITE(OHS900_SOFENREG, OHS900_MASK_SOF_ENA);
+        USBHOSTSLAVE_WRITE(OHS900_TXLINECTLREG, OHS900_TXLCTL_MASK_NORMAL);
+        USBHOSTSLAVE_WRITE(OHS900_IRQ_STATUS, OHS900_INTMASK_SOFINTR);
+  
+        /*if(( !max3421e_read_u08( MAX3421E_HCTL ) & MAX3421E_BUSRST ) ) {
+  	tmpdata = max3421e_read_u08( MAX3421E_MODE ) | MAX3421E_SOFKAENAB;   // start SOF generation
+  	max3421e_write_u08( MAX3421E_MODE, tmpdata );
+        }*/
+        host->delay = timer_get_msec() + 20;                           //20ms wait after reset per USB spec
+        host->usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_SOF;
+      }
+      break;
+      
+    case USB_ATTACHED_SUBSTATE_WAIT_SOF:  //todo: change check order
+      // MWW if( max3421e_read_u08( MAX3421E_HIRQ ) & MAX3421E_FRAMEIRQ ) { //when first SOF received we can continue
+      if (USBHOSTSLAVE_READ(OHS900_IRQ_STATUS)&OHS900_INTMASK_SOFINTR)
+      {
+        USBHOSTSLAVE_WRITE(OHS900_IRQ_STATUS, OHS900_INTMASK_SOFINTR);
+	if( host->delay < timer_get_msec() ) //20ms passed
+	  host->usb_task_state = USB_STATE_CONFIGURING;
+      }
+      break;
+      
+    case USB_STATE_CONFIGURING:
+      // configure root device
+      usb_configure(0, 0, lowspeed);
+      host->usb_task_state = USB_STATE_RUNNING;
+    break;
+    
+    case USB_STATE_RUNNING:
+      break;
+    }
+  }
+
+  if (USBHOSTSLAVE_READ(OHS900_IRQ_STATUS)&OHS900_INTMASK_SOFINTR)
+  {
+    USBHOSTSLAVE_WRITE(OHS900_IRQ_STATUS, OHS900_INTMASK_SOFINTR);
+  }
+
+}
+
+uint8_t usb_release_device(uint8_t parent, uint8_t port) {
+  iprintf("%s(parent=%x, port=%d\n", __FUNCTION__, parent, port);
+
+
+  int i;
+  for(i=0; i<USB_NUMDEVICES; i++) {
+    if(devices[i].bAddress && devices[i].parent == parent && devices[i].port == port && devices[i].host_addr == usbhostslave) {
+      iprintf("  -> device with address %x\n", devices[i].bAddress);
+
+      // check if this is a hub (parent of some other device)
+      // and release its kids first
+      uint8_t j;
+      for(j=0; j<USB_NUMDEVICES; j++) {
+	if(devices[j].parent == devices[i].bAddress && devices[j].host_addr == devices[i].host_addr)
+	  usb_release_device(devices[j].parent, devices[j].port);
+      }
+      
+      uint8_t rcode = 0;
+      if(devices[i].class)
+	rcode = devices[i].class->release(devices+i);
+
+      devices[i].bAddress = 0;
+      return rcode;	
+    }
+  }
+
+  // this should never happen ...
+  return 0;
+}
+
+uint8_t usb_get_dev_descr( usb_device_t *dev, uint16_t nbytes, usb_device_descriptor_t* p )  {
+  return( usb_ctrl_req( dev, USB_REQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 
+	       0x00, USB_DESCRIPTOR_DEVICE, 0x0000, nbytes, (uint8_t*)p));
+}
+
+//get configuration descriptor  
+uint8_t usb_get_conf_descr( usb_device_t *dev, uint16_t nbytes, 
+			    uint8_t conf, usb_configuration_descriptor_t* p )  {
+  LOG("GET_CONF:%x\n",p);
+  return( usb_ctrl_req( dev, USB_REQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 
+	       conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, nbytes, (uint8_t*)p));
+}
+
+uint8_t usb_set_addr( usb_device_t *dev, uint8_t newaddr )  {
+  iprintf("%s(%x)\n", __FUNCTION__, newaddr);
+  
+  uint8_t rcode = usb_ctrl_req( dev, USB_REQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 
+				0x00, 0x0000, 0x0000, NULL);
+  if(!rcode) dev->bAddress = newaddr;
+  return rcode;
+}
+
+//set configuration
+uint8_t usb_set_conf( usb_device_t *dev, uint8_t conf_value )  {
+  return( usb_ctrl_req( dev, USB_REQ_SET, USB_REQUEST_SET_CONFIGURATION,
+			conf_value, 0x00, 0x0000, 0x0000, NULL));
+}
+
Index: firmware_legacy/usb/hub.c
===================================================================
--- firmware_legacy/usb/hub.c	(nonexistent)
+++ firmware_legacy/usb/hub.c	(revision 799)
@@ -0,0 +1,300 @@
+//#include <stdio.h>
+
+#include "usb.h"
+#include "timer.h"
+#include "debug.h"
+
+//#include "printf.h"
+
+uint16_t bs16(uint8_t * in);
+
+uint32_t bs32(uint8_t * in)
+{
+	uint32_t a = *in;
+	uint32_t b = *(in+1);
+	uint32_t c = *(in+2);
+	uint32_t d = *(in+3);
+	uint32_t res = (d<<24) | (c<<16) | (b<<8) | a;
+	return res;
+}
+
+static uint8_t usb_hub_clear_hub_feature(usb_device_t *dev, uint8_t fid )  {
+  return( usb_ctrl_req( dev, USB_HUB_REQ_CLEAR_HUB_FEATURE, 
+       USB_REQUEST_CLEAR_FEATURE, fid, 0, 0, 0, NULL));
+}
+
+// Clear Port Feature
+static uint8_t usb_hub_clear_port_feature(usb_device_t *dev, uint8_t fid, uint8_t port, uint8_t sel )  {
+  return( usb_ctrl_req( dev , USB_HUB_REQ_CLEAR_PORT_FEATURE, 
+       USB_REQUEST_CLEAR_FEATURE, fid, 0, ((0x0000|port)|(sel<<8)), 0, NULL));
+}
+// Get Hub Descriptor
+static uint8_t usb_hub_get_hub_descriptor(usb_device_t *dev, uint8_t index, 
+					  uint16_t nbytes, usb_hub_descriptor_t *dataptr )  {
+  return( usb_ctrl_req( dev, USB_HUB_REQ_GET_HUB_DESCRIPTOR, 
+			USB_REQUEST_GET_DESCRIPTOR, index, 0x29, 0, nbytes, (uint8_t*)dataptr));
+}
+
+// Set Port Feature
+static uint8_t usb_hub_set_port_feature(usb_device_t *dev, uint8_t fid, uint8_t port, uint8_t sel ) {
+  return( usb_ctrl_req( dev, USB_HUB_REQ_SET_PORT_FEATURE, 
+       USB_REQUEST_SET_FEATURE, fid, 0, (((0x0000|sel)<<8)|port), 0, NULL));
+}
+
+// Get Port Status
+static uint8_t usb_hub_get_port_status(usb_device_t *dev, uint8_t port, uint16_t nbytes, uint8_t* dataptr )  {
+  uint8_t res = ( usb_ctrl_req( dev, USB_HUB_REQ_GET_PORT_STATUS, 
+       USB_REQUEST_GET_STATUS, 0, 0, port, nbytes, dataptr));
+
+  hub_debugf("portstat:%d bytes:%d res:%02x ",port,nbytes,res);
+  return res;
+}
+
+static uint8_t usb_hub_init(usb_device_t *dev) {
+  hub_debugf("%s()\n", __FUNCTION__);
+
+  uint8_t rcode;
+  uint8_t i;
+
+  usb_hub_info_t *info = &(dev->hub_info);
+
+  union {
+    usb_device_descriptor_t dev_desc;
+    usb_configuration_descriptor_t conf_desc;
+    usb_hub_descriptor_t hub_desc;
+  } buf;
+
+  // reset status
+  info->bNbrPorts = 0; 
+  info->qNextPollTime = 0;
+  info->bPollEnable = false;
+
+  info->ep.epAddr	= 1;
+  info->ep.maxPktSize	= 8;  //kludge
+  info->ep.epAttribs     = 0;
+  info->ep.bmNakPower	= USB_NAK_NOWAIT;
+
+  rcode = usb_get_dev_descr( dev, 8, &buf.dev_desc );
+  if( rcode ) {
+    hub_debugf("failed to get device descriptor 1\n");
+    return rcode;
+  }
+  
+  // Extract device class from device descriptor
+  // If device class is not a hub return
+  if (buf.dev_desc.bDeviceClass != USB_CLASS_HUB) {
+    hub_debugf("not a hub!\n");    
+    return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
+  }
+
+  // try to re-read full device descriptor from newly assigned address
+  if(rcode = usb_get_dev_descr( dev, sizeof(usb_device_descriptor_t), &buf.dev_desc )) {
+    hub_debugf("failed to get device descriptor 2\n");
+    return rcode;
+  }
+ 
+  // Get hub descriptor
+  rcode = usb_hub_get_hub_descriptor(dev, 0, 8, &buf.hub_desc);
+    
+  if (rcode) {
+    hub_debugf("failed to get hub descriptor\n");
+    return rcode;
+  }
+  
+  // Save number of ports for future use
+  info->bNbrPorts = buf.hub_desc.bNbrPorts;
+  hub_debugf("ports:%d ",buf.hub_desc.bNbrPorts); // MWW
+    
+  // Read configuration Descriptor in Order To Obtain Proper Configuration Value
+  rcode = usb_get_conf_descr(dev, sizeof(usb_configuration_descriptor_t), 0, &buf.conf_desc);
+  if (rcode) {
+    hub_debugf("failed to read configuration descriptor\n");
+    return rcode;
+  }
+
+  // Set Configuration Value
+  rcode = usb_set_conf(dev, buf.conf_desc.bConfigurationValue);
+  if (rcode) {
+    hub_debugf("failed to set configuration to %d\n", buf.conf_desc.bConfigurationValue);
+    return rcode;
+  }
+    
+  // Power on all ports
+  for (i=1; i<=info->bNbrPorts; i++)
+  {
+    rcode = usb_hub_set_port_feature(dev, HUB_FEATURE_PORT_POWER, i, 0);	// HubPortPowerOn(i);
+    hub_debugf("PWR:%d:%02x ",i,rcode);
+  }
+    
+  hub_debugf("HUB pollingOn "); // MWW
+  info->bPollEnable = true;
+
+  return 0;
+}
+
+static uint8_t usb_hub_release(usb_device_t *dev) {
+  hub_debugf("%s\n",__FUNCTION__);
+
+  return 0;
+}
+
+static void usb_hub_show_port_status(uint8_t port, uint16_t status, uint16_t changed) {
+  hub_debugf("Status of port %d:\n", port);
+
+  if(status & USB_HUB_PORT_STATUS_PORT_CONNECTION)    hub_debugf(" connected\n");
+  if(status & USB_HUB_PORT_STATUS_PORT_ENABLE)        hub_debugf(" enabled\n");
+  if(status & USB_HUB_PORT_STATUS_PORT_SUSPEND)       hub_debugf(" suspended\n");
+  if(status & USB_HUB_PORT_STATUS_PORT_OVER_CURRENT)  hub_debugf(" over current\n");
+  if(status & USB_HUB_PORT_STATUS_PORT_RESET)         hub_debugf(" reset\n");
+  if(status & USB_HUB_PORT_STATUS_PORT_POWER)         hub_debugf(" powered\n");
+  if(status & USB_HUB_PORT_STATUS_PORT_LOW_SPEED)     hub_debugf(" low speed\n");
+  if(status & USB_HUB_PORT_STATUS_PORT_HIGH_SPEED)    hub_debugf(" high speed\n");
+  if(status & USB_HUB_PORT_STATUS_PORT_TEST)          hub_debugf(" test\n");
+  if(status & USB_HUB_PORT_STATUS_PORT_INDICATOR)     hub_debugf(" indicator\n");
+
+  hub_debugf("Changes on port %d:\n", port);
+  if(changed & USB_HUB_PORT_STATUS_PORT_CONNECTION)   hub_debugf(" connected\n");
+  if(changed & USB_HUB_PORT_STATUS_PORT_ENABLE)       hub_debugf(" enabled\n");
+  if(changed & USB_HUB_PORT_STATUS_PORT_SUSPEND)      hub_debugf(" suspended\n");
+  if(changed & USB_HUB_PORT_STATUS_PORT_OVER_CURRENT) hub_debugf(" over current\n");
+  if(changed & USB_HUB_PORT_STATUS_PORT_RESET)        hub_debugf(" reset\n");
+}
+
+static uint8_t usb_hub_port_status_change(usb_device_t *dev, uint8_t port, hub_event_t evt) {
+  usb_hub_info_t *info = &(dev->hub_info);
+
+  hub_debugf("status change on port %d, 0x%x\n", port, bs32(&evt.bmEventLL));
+  usb_hub_show_port_status(port, bs16(&evt.bmStatusL), bs16(&evt.bmChangeL));
+
+  static bool bResetInitiated = false;
+
+  switch (bs32(&evt.bmEventLL)) {
+    // Device connected event
+  case USB_HUB_PORT_EVENT_CONNECT:
+  case USB_HUB_PORT_EVENT_LS_CONNECT:
+    hub_debugf(" dev %x: port %d connect!\n", dev->bAddress, port);
+
+    if (bResetInitiated) {
+      hub_debugf("reset already in progress\n");
+      return 0;
+    }
+
+    //    timer_delay_msec(100);
+
+    hub_debugf("resetting port %d\n", port);
+    usb_hub_clear_port_feature(dev, HUB_FEATURE_C_PORT_ENABLE, port, 0);
+    usb_hub_clear_port_feature(dev, HUB_FEATURE_C_PORT_CONNECTION, port, 0);
+    usb_hub_set_port_feature(dev, HUB_FEATURE_PORT_RESET, port, 0);	
+    bResetInitiated = true;
+    return HUB_ERROR_PORT_HAS_BEEN_RESET;
+    
+    // Device disconnected event
+  case USB_HUB_PORT_EVENT_DISCONNECT:
+    hub_debugf(" port %d disconnect!\n", port);
+
+    usb_hub_clear_port_feature(dev, HUB_FEATURE_C_PORT_ENABLE, port, 0);
+    usb_hub_clear_port_feature(dev, HUB_FEATURE_C_PORT_CONNECTION, port, 0);
+    bResetInitiated = false;
+
+    usb_release_device(dev->bAddress, port);
+
+    return 0;
+    
+    // Reset complete event
+  case USB_HUB_PORT_EVENT_RESET_COMPLETE:
+  case USB_HUB_PORT_EVENT_LS_RESET_COMPLETE:
+    hub_debugf(" port %d reset complete!\n", port);
+    usb_hub_clear_port_feature(dev, HUB_FEATURE_C_PORT_RESET, port, 0);
+    usb_hub_clear_port_feature(dev, HUB_FEATURE_C_PORT_CONNECTION, port, 0);
+    
+    usb_configure(dev->bAddress, port, 
+	  (bs16(&evt.bmStatusL) & USB_HUB_PORT_STATUS_PORT_LOW_SPEED)!=0 );
+
+    bResetInitiated = false;
+    break;
+  }
+
+  return 0;
+}
+
+static uint8_t usb_hub_check_hub_status(usb_device_t *dev, uint8_t ports) {
+  usb_hub_info_t *info = &(dev->hub_info);
+
+  uint8_t	rcode;
+  uint8_t	buf[8];
+  uint16_t	read = 1;
+
+  //hub_debugf("%s(addr=%x)\n", __FUNCTION__, dev->bAddress);
+
+  rcode = usb_in_transfer(dev, &(info->ep), &read, buf);
+  if(rcode)
+  {
+    //hub_debugf("RC:%02x ",rcode);
+    return rcode;
+  }
+
+  uint8_t port, mask;
+  for(port=1,mask=0x02; port<8; mask<<=1, port++) {
+    if (buf[0] & mask) {
+      hub_event_t evt;
+      evt.bmEventLL = evt.bmEventLL2 = evt.bmEventLL3 = evt.bmEventLL4 = 0;
+
+      rcode = usb_hub_get_port_status(dev, port, sizeof(evt.evtBuff), evt.evtBuff);
+      if (rcode)
+	continue;
+
+      rcode = usb_hub_port_status_change(dev, port, evt);
+      
+      if (rcode == HUB_ERROR_PORT_HAS_BEEN_RESET)
+	return 0;
+      
+      if (rcode)
+	return rcode;
+    }
+  } // for
+  
+  for (port=1; port<=ports; port++) {
+    hub_event_t	evt;
+    evt.bmEventLL = evt.bmEventLL2 = evt.bmEventLL3 = evt.bmEventLL4 = 0;
+    
+    rcode = usb_hub_get_port_status(dev, port, 4, evt.evtBuff);
+    if (rcode)
+      continue;
+    
+    if ((bs16(&evt.bmStatusL) & USB_HUB_PORT_STATE_CHECK_DISABLED) != USB_HUB_PORT_STATE_DISABLED)
+      continue;
+    
+    // Emulate connection event for the port
+    evt.bmChangeL |= 0xff&(USB_HUB_PORT_STATUS_PORT_CONNECTION);
+    evt.bmChangeH |= (USB_HUB_PORT_STATUS_PORT_CONNECTION)>>8;
+    
+    rcode = usb_hub_port_status_change(dev, port, evt);
+    if (rcode == HUB_ERROR_PORT_HAS_BEEN_RESET)
+      return 0;
+    
+    if (rcode)
+      return rcode;
+  }
+  return 0;
+}
+
+static uint8_t usb_hub_poll(usb_device_t *dev) {
+  usb_hub_info_t *info = &(dev->hub_info);
+
+  uint8_t rcode = 0;
+
+  if (!info->bPollEnable)
+    return 0;
+  
+  if (info->qNextPollTime <= timer_get_msec()) {
+    rcode = usb_hub_check_hub_status(dev, info->bNbrPorts);
+    //info->qNextPollTime = timer_get_msec() + 100;   // poll 10 times a second 
+    info->qNextPollTime = timer_get_msec() + 2000;   // poll every 2 seconds
+  }
+
+  return rcode;
+}
+
+const usb_device_class_config_t usb_hub_class = {
+  usb_hub_init, usb_hub_release, usb_hub_poll };  
+
Index: firmware_legacy/usb/debug.c
===================================================================
--- firmware_legacy/usb/debug.c	(nonexistent)
+++ firmware_legacy/usb/debug.c	(revision 799)
@@ -0,0 +1,64 @@
+#include "debug.h"
+
+#include "stdarg.h"
+#include "simplefile.h"
+
+#include "printf/printf.h"
+
+struct SimpleFile * usb_file;
+int usb_location;
+
+void usb_log_init(struct SimpleFile * file)
+{
+	if (SimpleFile_OK == file_open_name("/usb.log", file) && (file_size(file)>=65536 && file_readonly(file)==0))
+	{
+		char buffer[256];
+		memset8(&buffer,0,256);
+
+		file_seek(file,0);
+
+		int i;
+		for (i=0;i!=1024;++i)
+		{
+			int byteswritten = 0;
+			file_write(file,(void *)buffer,sizeof(buffer),&byteswritten);
+		}
+
+		file_seek(file,0);
+		usb_location = 0;
+		usb_file = file;
+	}
+	else
+		usb_file = 0;
+}
+
+static void putcp(void* p,char c)
+	{
+	*(*((char**)p))++ = c;
+	}
+
+void usb_log(char *fmt, ...)
+{
+	va_list va;
+	va_start(va,fmt);
+
+	if (usb_file)
+	{
+	        char buffer[256];
+		char * ptr = &buffer[0];
+		tfp_format(&ptr,putcp,fmt,va);
+		putcp(&ptr,0);
+
+		file_seek(usb_file,usb_location);
+
+		int byteswritten = 0;
+		file_write(usb_file,(void *)buffer,strlen(buffer),&byteswritten);
+		usb_location +=byteswritten;
+
+		file_write(usb_file,(void *)"\n",strlen("\n"),&byteswritten);
+		usb_location +=byteswritten;
+	}
+
+	va_end(va);
+}
+
Index: firmware_legacy/usb/debug.h
===================================================================
--- firmware_legacy/usb/debug.h	(nonexistent)
+++ firmware_legacy/usb/debug.h	(revision 799)
@@ -0,0 +1,15 @@
+#define hid_debugf(IN, ...) {};
+#define hidp_debugf(IN, ...) {};
+#define hub_debugf(IN, ...) {};
+#define iprintf(IN, ...) {};
+
+extern struct SimpleFile * usb_file;
+
+void usb_log_init(struct SimpleFile * file);
+
+void usb_log(char * format, ...);
+
+//#define hid_debugf usb_log
+//#define hidp_debugf usb_log
+//#define iprintf usb_log
+
Index: firmware_legacy/usb/hid.h
===================================================================
--- firmware_legacy/usb/hid.h	(nonexistent)
+++ firmware_legacy/usb/hid.h	(revision 799)
@@ -0,0 +1,95 @@
+#ifndef HID_H
+#define HID_H
+
+//#include <stdbool.h>
+//#include <inttypes.h>
+#include <common/integer.h>
+#include "hidparser.h"
+
+#define HID_LED_NUM_LOCK    0x01
+#define HID_LED_CAPS_LOCK   0x02
+#define HID_LED_SCROLL_LOCK 0x04
+
+/* HID constants. Not part of chapter 9 */
+/* Class-Specific Requests */
+#define HID_REQUEST_GET_REPORT      0x01
+#define HID_REQUEST_GET_IDLE        0x02
+#define HID_REQUEST_GET_PROTOCOL    0x03
+#define HID_REQUEST_SET_REPORT      0x09
+#define HID_REQUEST_SET_IDLE        0x0A
+#define HID_REQUEST_SET_PROTOCOL    0x0B
+
+#define HID_DESCRIPTOR_HID		0x21
+#define HID_DESCRIPTOR_REPORT		0x22
+#define HID_DESRIPTOR_PHY		0x23
+
+/* Protocol Selection */
+#define HID_BOOT_PROTOCOL                       0x00
+#define HID_RPT_PROTOCOL                        0x01
+
+/* HID Interface Class SubClass Codes */
+#define HID_BOOT_INTF_SUBCLASS          0x01
+
+#define HID_PROTOCOL_NONE           0x00
+#define HID_PROTOCOL_KEYBOARD       0x01
+#define HID_PROTOCOL_MOUSE          0x02
+
+#define HID_REQ_HIDREPORT     USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_INTERFACE
+#define HID_REQ_HIDOUT        USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
+
+#define MAX_IFACES  2  // max supported interfaces per device. 2 to support kbd/mouse combos
+
+#define HID_DEVICE_UNKNOWN  0
+#define HID_DEVICE_MOUSE    1
+#define HID_DEVICE_KEYBOARD 2
+#define HID_DEVICE_JOYSTICK 3
+
+typedef struct {
+  ep_t ep;    // interrupt endpoint info structure
+
+  uint8_t iface_idx;
+  uint16_t report_desc_size;
+
+  uint8_t device_type;
+  uint8_t has_boot_mode;     // device supports boot mode
+  uint8_t is_5200daptor;     // device is a 5200daptor with special key handling
+  uint8_t is_MCC;            // device is an MCC controller with special key handling
+  uint16_t key_state;        // needed to detect key state changes in 5200daptor
+  
+  // additional info extracted from the report descriptor
+  // (currently only used for joysticks) 
+  uint32_t jmap;           // last reported joystick state
+  uint8_t jindex;         // joystick index
+  hid_config_t conf;
+
+  uint8_t interval;
+  uint32_t qNextPollTime;     // next poll time
+
+} usb_hid_iface_info_t;
+
+typedef struct {
+  bool	   bPollEnable;	      // poll enable flag
+  uint8_t  bNumIfaces;
+
+  usb_hid_iface_info_t iface[MAX_IFACES];
+} usb_hid_info_t;
+
+/* HID descriptor */
+typedef struct  {
+  uint8_t         bLength;
+  uint8_t         bDescriptorType;
+  uint8_t        bcdHIDL;                         // HID class specification release
+  uint8_t        bcdHIDH;                         // HID class specification release
+  uint8_t         bCountryCode;
+  uint8_t         bNumDescriptors;                // Number of additional class specific descriptors
+  uint8_t         bDescrType;                     // Type of class descriptor
+  uint8_t         wDescriptorLength[2];           // Total size of the Report descriptor
+} __attribute__((packed)) usb_hid_descriptor_t;
+
+// interface to usb core
+extern const usb_device_class_config_t usb_hid_class;
+
+void hid_set_kbd_led(unsigned char led, bool on);
+uint8_t hid_get_joysticks(void);
+
+#endif // HID_H
Index: firmware_legacy/usb/hidparser.c
===================================================================
--- firmware_legacy/usb/hidparser.c	(nonexistent)
+++ firmware_legacy/usb/hidparser.c	(revision 799)
@@ -0,0 +1,445 @@
+// http://www.frank-zhao.com/cache/hid_tutorial_1.php
+
+//#include <inttypes.h>
+//#include <stdbool.h>
+//#include <stdio.h>
+
+#include "hidparser.h"
+#include "debug.h"
+//#include "printf.h"
+//#include <stdio.h>
+
+#if 0
+#define hidp_extreme_debugf(...) hidp_debugf(__VA_ARGS__)
+#else
+#define hidp_extreme_debugf(...)
+#endif
+
+//#define hidp_debugf printf
+
+typedef struct {
+  uint8_t bSize: 2;
+  uint8_t bType: 2;
+  uint8_t bTag: 4;
+} __attribute__((packed)) item_t;
+
+// flags for joystick components required
+#define JOYSTICK_REQ_AXIS_X  0x01
+#define JOYSTICK_REQ_AXIS_Y  0x02
+#define JOYSTICK_REQ_BTN_0   0x04
+#define JOYSTICK_COMPLETE    (JOYSTICK_REQ_AXIS_X | JOYSTICK_REQ_AXIS_Y | JOYSTICK_REQ_BTN_0)
+
+#define USAGE_PAGE_GENERIC_DESKTOP  1
+#define USAGE_PAGE_SIMULATION       2
+#define USAGE_PAGE_VR               3
+#define USAGE_PAGE_SPORT            4
+#define USAGE_PAGE_GAMING           5
+#define USAGE_PAGE_GENERIC_DEVICE   6
+#define USAGE_PAGE_KEYBOARD         7
+#define USAGE_PAGE_LEDS             8
+#define USAGE_PAGE_BUTTON           9
+#define USAGE_PAGE_ORDINAL         10
+#define USAGE_PAGE_TELEPHONY       11
+#define USAGE_PAGE_CONSUMER        12
+
+
+#define USAGE_POINTER   1
+#define USAGE_MOUSE     2
+#define USAGE_JOYSTICK  4
+#define USAGE_GAMEPAD   5
+#define USAGE_KEYBOARD  6
+#define USAGE_KEYPAD    7
+#define USAGE_MULTIAXIS 8
+
+#define USAGE_X       48
+#define USAGE_Y       49
+#define USAGE_Z       50
+#define USAGE_WHEEL   56
+
+bool parse_report_descriptor(uint8_t *rep, uint16_t rep_size, hid_config_t *conf) {
+  int8_t app_collection = 0;
+  int8_t phys_log_collection = 0;
+  uint8_t skip_collection = 0;
+  int8_t generic_desktop = -1;   // depth at which first gen_desk was found
+  uint8_t collection_depth = 0;
+
+  uint8_t i;
+
+  // 
+  uint8_t report_size, report_count;
+  uint16_t bit_count = 0, usage_count = 0;
+  uint16_t logical_minimum=0, logical_maximum=0;
+
+  // mask used to check of all required components have been found, so
+  // that e.g. both axes and the button of a joystick are ready to be used
+  uint8_t setup_complete = 0;
+
+  /*printf("PARSE:");
+  int j = 0;
+  for (j=0; j!=rep_size; ++j)
+  {
+    printf("%02x",rep[j]);
+  }
+  printf(" ");*/
+
+  // joystick/mouse components
+  int8_t axis[2]; // MWW = { -1, -1}; (this instantiates memcpy!)
+  axis[0] = -1;
+  axis[1] = -1;
+  uint8_t btns = 0;
+
+  conf->type = CONFIG_TYPE_NONE;
+
+  while(rep_size) {
+    // extract short item
+/*    uint8_t tag = ((item_t*)rep)->bTag;
+    uint8_t type = ((item_t*)rep)->bType;
+    uint8_t size = ((item_t*)rep)->bSize;*/
+/*typedef struct {
+  uint8_t bSize: 2;
+  uint8_t bType: 2;
+  uint8_t bTag: 4;
+} __attribute__((packed)) item_t;*/
+    // MWW - bitfields are not working
+    uint8_t tag = (rep[0]&0xf0)>>4;
+    uint8_t type = (rep[0]&0x0c)>>2;
+    uint8_t size = rep[0]&0x03;
+//    printf("WTF:%02x %02x %02x %02x\n",rep[0],tag,type,size);
+
+    rep++;
+    rep_size--;   // one byte consumed
+    
+    uint32_t value = 0;
+    if(size) {      // size 1/2/3
+      value = *rep++;
+      rep_size--;
+    }
+
+    if(size > 1) {  // size 2/3
+      value = (value & 0xff) + ((uint32_t)(*rep++)<<8);
+      rep_size--;
+    }
+
+    if(size > 2) {  // size 3
+      value &= 0xffff;
+      value |= ((uint32_t)(*rep++)<<16);
+      value |= ((uint32_t)(*rep++)<<24);
+      rep_size-=2;
+    }
+
+    //    hidp_extreme_debugf("Value = %d (%u)\n", value, value);
+    
+    // we are currently skipping an unknown/unsupported collection) 
+    if(skip_collection) {
+      if(!type) {  // main item
+	// any new collection increases the depth of collections to skip
+	if(tag == 10) {
+	  skip_collection++;
+	  collection_depth++;
+	}
+
+	// any end collection decreases it
+	if(tag == 12) {
+	  skip_collection--;
+	  collection_depth--;
+
+	  // leaving the depth the generic desktop was valid for
+	  if(generic_desktop > collection_depth)
+	    generic_desktop = -1;
+	}
+      }
+
+      
+    } else {
+      //      hidp_extreme_debugf("-> Item tag=%d type=%d size=%d\n", tag, type, size);
+
+      switch(type) {
+      case 0:
+	// main item
+	
+	switch(tag) {
+	case 8:
+	  // 
+	  if(btns) {
+	    if(conf->type == CONFIG_TYPE_JOYSTICK) {
+	      // scan for up to 24 buttons
+	      char b;
+	      for(b=0;b<24;b++) {
+		if(report_count > b) {
+		  uint16_t this_bit = bit_count+b;
+
+		  hidp_debugf("BUTTON%d @ %d (byte %d, mask %d)\n", b, 
+			      this_bit, this_bit/8, 1 << (this_bit%8));
+
+		  conf->joystick.button[b].byte_offset = this_bit/8;
+		  conf->joystick.button[b].bitmask = 1 << (this_bit%8);
+		}
+	      }
+
+	      // we found at least one button which is all we want to accept this as a valid 
+	      // joystick
+	      setup_complete |= JOYSTICK_REQ_BTN_0;
+	    }
+	  }
+
+	  // 
+	  char c;
+	  for(c=0;c<2;c++) {
+	    if(axis[c] >= 0) {
+	      uint16_t cnt = bit_count + report_size * axis[c];
+	      hidp_debugf("  (%c-AXIS @ %d (byte %d))\n", 'X'+c,
+		     cnt, cnt/8);
+
+	      // only 8/16 bit axes at byte boundaries are supported for
+	      // joysticks
+	      if((conf->type == CONFIG_TYPE_JOYSTICK) &&
+		 ((report_size == 8) || (report_size == 16)) && ((cnt&7) == 0)) {
+		// save in joystick config
+		conf->joystick.axis[c].byte_offset = cnt/8;
+		conf->joystick.axis[c].size = report_size;
+		conf->joystick.axis[c].logical.min = logical_minimum;
+		conf->joystick.axis[c].logical.max = logical_maximum;
+		conf->joystick.axis[c].size = report_size;
+		if(c==0) setup_complete |= JOYSTICK_REQ_AXIS_X;
+		if(c==1) setup_complete |= JOYSTICK_REQ_AXIS_Y;
+	      }
+
+	      if((report_size != 8) && (report_size != 16))
+		hidp_debugf("Unsupported report size %d\n", report_size);
+
+	      if((cnt&7) != 0) 
+		hidp_debugf("Unsupported bit offset %d\n", cnt&7);
+	    }
+	  }
+	  
+	  hidp_extreme_debugf("INPUT(%d)\n", value);
+
+	  // reset for next inputs
+	  bit_count += report_count * report_size;
+	  usage_count = 0;
+	  btns = 0;
+	  axis[0] = axis[1] = -1;
+	  break;
+
+	case 9:
+	  hidp_extreme_debugf("OUTPUT(%d)\n", value);
+	  break;
+
+	case 11:
+	  hidp_extreme_debugf("FEATURE(%d)\n", value);
+	  break;
+
+	case 10:
+	  hidp_extreme_debugf("COLLECTION(%d)\n", value);
+	  collection_depth++;
+	  usage_count = 0;
+
+	  if(value == 1) {	   // app collection
+	    hidp_extreme_debugf("  -> application\n");
+	    app_collection++;
+	  } else if(value == 0) {  // physical collection
+	    hidp_extreme_debugf("  -> physical\n");
+	    phys_log_collection++;
+	  } else if(value == 2) {  // logical collection
+	    hidp_extreme_debugf("  -> logical\n");
+	    phys_log_collection++;
+	  } else {
+	    hidp_extreme_debugf("skipping unsupported collection\n");
+	    skip_collection++;
+	  }
+	  break;
+	  
+	case 12:
+	  hidp_extreme_debugf("END_COLLECTION(%d)\n", value);
+	  collection_depth--;
+
+	  // leaving the depth the generic desktop was valid for
+	  if(generic_desktop > collection_depth)
+	    generic_desktop = -1;
+
+	  if(phys_log_collection) {
+	    hidp_extreme_debugf("  -> phys/log end\n");
+	    phys_log_collection--;
+	  } else if(app_collection) {
+	    hidp_extreme_debugf("  -> app end\n");
+	    app_collection--;
+	  } else {
+	    hidp_debugf(" -> unexpected\n");
+	    return false;
+	  }
+	  break;
+
+	default:
+	  hidp_debugf("unexpected main item %d\n", tag);
+	  return false;
+	  break;
+	}
+	break;
+	
+      case 1:
+	// global item
+	switch(tag) {
+	case 0:
+	  hidp_extreme_debugf("USAGE_PAGE(%d/0x%x)\n", value, value);
+
+	  if(value == USAGE_PAGE_KEYBOARD) {
+	    hidp_extreme_debugf(" -> Keyboard\n");
+	  } else if(value == USAGE_PAGE_GAMING) {
+	    hidp_extreme_debugf(" -> Game device\n");
+	  } else if(value == USAGE_PAGE_LEDS) {
+	    hidp_extreme_debugf(" -> LEDs\n");
+	  } else if(value == USAGE_PAGE_CONSUMER) {
+	    hidp_extreme_debugf(" -> Consumer\n");
+	  } else if(value == USAGE_PAGE_BUTTON) {
+	    hidp_extreme_debugf(" -> Buttons\n");
+	    btns = 1;
+	  } else if(value == USAGE_PAGE_GENERIC_DESKTOP) {
+	    hidp_extreme_debugf(" -> Generic Desktop\n");
+
+	    if(generic_desktop < 0)
+	      generic_desktop = collection_depth;
+	  } else
+	    hidp_extreme_debugf(" -> UNSUPPORTED USAGE_PAGE\n");
+
+	  break;
+	  
+	case 1:
+	  hidp_extreme_debugf("LOGICAL_MINIMUM(%d/%d)\n", value, (int8_t)value);
+	  logical_minimum = value;
+	  break;
+	  
+	case 2:
+	  hidp_extreme_debugf("LOGICAL_MAXIMUM(%d)\n", value);
+	  logical_maximum = value;
+	  break;
+
+	case 3:
+	  hidp_extreme_debugf("PHYSICAL_MINIMUM(%d/%d)\n", value, (int8_t)value);
+	  break;
+	  
+	case 4:
+	  hidp_extreme_debugf("PHYSICAL_MAXIMUM(%d)\n", value);
+	  break;
+
+	case 5:
+	  hidp_extreme_debugf("UNIT_EXPONENT(%d)\n", value);
+	  break;
+
+	case 6:
+	  hidp_extreme_debugf("UNIT(%d)\n", value);
+	  break;
+
+	case 7:
+	  hidp_extreme_debugf("REPORT_SIZE(%d)\n", value);
+	  report_size = value;
+	  break;
+
+	case 8:
+	  hidp_extreme_debugf("REPORT_ID(%d)\n", value);
+	  conf->report_id = value;
+	  break;
+
+	case 9:
+	  hidp_extreme_debugf("REPORT_COUNT(%d)\n", value);
+	  report_count = value;
+	  break;
+	  
+	default:
+	  hidp_debugf("unexpected global item %d\n", tag);
+	  return false;
+	  break;
+	}
+	break;
+	
+      case 2:
+	// local item
+	switch(tag) {
+	case 0:
+	  // we only support mice, keyboards and joysticks
+	  hidp_extreme_debugf("USAGE(%d/0x%x)\n", value, value);
+
+	  if( !collection_depth && (value == USAGE_KEYBOARD)) {
+	    // usage(keyboard) is always allowed
+	    hidp_debugf(" -> Keyboard\n");
+	    conf->type = CONFIG_TYPE_KEYBOARD;
+	  } else if(!collection_depth && (value == USAGE_MOUSE)) {
+	    // usage(mouse) is always allowed
+	    hidp_debugf(" -> Mouse\n");
+	    conf->type = CONFIG_TYPE_MOUSE;
+	  } else if(!collection_depth && 
+		    ((value == USAGE_GAMEPAD) || (value == USAGE_JOYSTICK))) {
+	    hidp_extreme_debugf(" -> Gamepad/Joystick\n");
+	    hidp_debugf("Gamepad/Joystick usage found\n");
+	    conf->type = CONFIG_TYPE_JOYSTICK;
+	  } else if(value == USAGE_POINTER && app_collection) {
+	    // usage(pointer) is allowed within the application collection
+
+	    hidp_debugf(" -> Pointer\n");
+
+	  } else if((value == USAGE_X || value == USAGE_Y) && app_collection) {
+	    // usage(x) and usage(y) are allowed within the app collection
+	    hidp_extreme_debugf(" -> axis usage\n");
+
+	    // we support x and y axis on joysticks
+	    if(conf->type == CONFIG_TYPE_JOYSTICK) {
+	      if(value == USAGE_X) {
+		hidp_extreme_debugf("JOYSTICK: found x axis @ %d\n", usage_count);
+		axis[0] = usage_count;
+	      }
+	      if(value == USAGE_Y) {
+		hidp_extreme_debugf("JOYSTICK: found y axis @ %d\n", usage_count);
+		axis[1] = usage_count;
+	      }
+	    }
+	  } else {
+	    hidp_extreme_debugf(" -> UNSUPPORTED USAGE\n");
+	    //	    return false;
+	  }
+
+	  usage_count++;
+	  break;
+	  
+	case 1:
+	  hidp_extreme_debugf("USAGE_MINIMUM(%d)\n", value);
+	  usage_count -= (value-1);
+	  break;
+	  
+	case 2:
+	  hidp_extreme_debugf("USAGE_MAXIMUM(%d)\n", value);
+	  usage_count += value;
+	  break;
+	  
+	default:
+	  hidp_extreme_debugf("unexpected local item %d\n", tag);
+	  //	  return false;
+	  break;
+	}
+	break;
+	
+      default:
+	// reserved
+	hidp_extreme_debugf("unexpected resreved item %d\n", tag);
+	//	return false;
+	break;
+      }
+    }
+  }
+
+  hidp_debugf("total bit count: %d (%d bytes, %d bits)\n", 
+	 bit_count, bit_count/8, bit_count%8);
+
+  conf->report_size = bit_count/8;
+
+  // check if something useful was detected
+  if(conf->type == CONFIG_TYPE_JOYSTICK) {
+    if(setup_complete == JOYSTICK_COMPLETE) {
+      hidp_debugf("Joystick ok\n");
+      return true;
+    }
+
+    hidp_debugf("Ignoring incomplete joystick %x\n", setup_complete);
+  } else
+    hidp_debugf("No joystick\n");
+
+  return false;
+}
Index: firmware_legacy/usb/hidparser.h
===================================================================
--- firmware_legacy/usb/hidparser.h	(nonexistent)
+++ firmware_legacy/usb/hidparser.h	(revision 799)
@@ -0,0 +1,42 @@
+#ifndef HIDPARSER_H
+#define HIDPARSER_H
+
+#include <common/integer.h>
+
+#define CONFIG_TYPE_NONE     0
+#define CONFIG_TYPE_MOUSE    1
+#define CONFIG_TYPE_KEYBOARD 2
+#define CONFIG_TYPE_JOYSTICK 3
+
+// currently only joysticks are supported
+typedef struct {
+  uint8_t type: 2;             // CONFIG_TYPE_...
+  uint8_t report_id;
+  uint8_t report_size;
+
+  union {
+    struct {
+      struct {
+	uint8_t byte_offset;
+	uint8_t size;          // 8 or 16 bits supported
+	struct {
+/*	  uint8_t minl;
+	  uint8_t minh;
+	  uint8_t maxl;
+	  uint8_t maxh;*/
+	  uint16_t min;
+	  uint16_t max;
+	} logical;
+      } axis[2];               // x and y axis
+
+      struct {
+	uint8_t byte_offset;
+	uint8_t bitmask;
+      } button[24];             // 24 buttons
+    } joystick;
+  };
+} hid_config_t;
+
+bool parse_report_descriptor(uint8_t *rep, uint16_t rep_size, hid_config_t *conf);
+
+#endif // HIDPARSER_H
Index: firmware_legacy/usb/hub.h
===================================================================
--- firmware_legacy/usb/hub.h	(nonexistent)
+++ firmware_legacy/usb/hub.h	(revision 799)
@@ -0,0 +1,117 @@
+#ifndef HUB_H
+#define HUB_H
+
+//#include <stdbool.h>
+//#include <inttypes.h>
+#include <common/integer.h>
+
+typedef struct {
+  uint8_t  bNbrPorts;	    // number of ports
+  uint32_t qNextPollTime;   // next poll time
+  bool	   bPollEnable;	    // poll enable flag
+  ep_t ep;	            // interrupt endpoint info structure
+} usb_hub_info_t;
+
+// Hub Requests
+#define USB_HUB_REQ_CLEAR_HUB_FEATURE		USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE
+#define USB_HUB_REQ_CLEAR_PORT_FEATURE	USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
+#define USB_HUB_REQ_CLEAR_TT_BUFFER		USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
+#define USB_HUB_REQ_GET_HUB_DESCRIPTOR	USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE
+#define USB_HUB_REQ_GET_HUB_STATUS		USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE
+#define USB_HUB_REQ_GET_PORT_STATUS		USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
+#define USB_HUB_REQ_RESET_TT			USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
+#define USB_HUB_REQ_SET_HUB_DESCRIPTOR	USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE
+#define USB_HUB_REQ_SET_HUB_FEATURE		USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE
+#define USB_HUB_REQ_SET_PORT_FEATURE		USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
+#define USB_HUB_REQ_GET_TT_STATE		USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
+#define USB_HUB_REQ_STOP_TT			USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_OTHER
+
+// Hub Features
+#define HUB_FEATURE_C_HUB_LOCAL_POWER	0
+#define HUB_FEATURE_C_HUB_OVER_CURRENT	1
+
+#define HUB_FEATURE_PORT_CONNECTION	0
+#define HUB_FEATURE_PORT_ENABLE		1
+#define HUB_FEATURE_PORT_SUSPEND	2
+#define HUB_FEATURE_PORT_OVER_CURRENT	3
+#define HUB_FEATURE_PORT_RESET		4
+#define HUB_FEATURE_PORT_POWER		8
+#define HUB_FEATURE_PORT_LOW_SPEED	9
+#define HUB_FEATURE_C_PORT_CONNECTION	16
+#define HUB_FEATURE_C_PORT_ENABLE	17
+#define HUB_FEATURE_C_PORT_SUSPEND	18
+#define HUB_FEATURE_C_PORT_OVER_CURRENT	19
+#define HUB_FEATURE_C_PORT_RESET	20
+#define HUB_FEATURE_PORT_TEST		21
+#define HUB_FEATURE_PORT_INDICATOR	22
+
+// Additional Error Codes
+#define HUB_ERROR_PORT_HAS_BEEN_RESET			0xb1
+
+// Hub Port Status Bitmasks 
+#define USB_HUB_PORT_STATUS_PORT_CONNECTION		0x0001
+#define USB_HUB_PORT_STATUS_PORT_ENABLE			0x0002
+#define USB_HUB_PORT_STATUS_PORT_SUSPEND			0x0004
+#define USB_HUB_PORT_STATUS_PORT_OVER_CURRENT		0x0008
+#define USB_HUB_PORT_STATUS_PORT_RESET			0x0010
+#define USB_HUB_PORT_STATUS_PORT_POWER			0x0100
+#define USB_HUB_PORT_STATUS_PORT_LOW_SPEED		0x0200
+#define USB_HUB_PORT_STATUS_PORT_HIGH_SPEED		0x0400
+#define USB_HUB_PORT_STATUS_PORT_TEST			0x0800
+#define USB_HUB_PORT_STATUS_PORT_INDICATOR		0x1000
+
+// Bit mask to check for DISABLED state in HubEvent::bmStatus field 
+#define USB_HUB_PORT_STATE_CHECK_DISABLED	(USB_HUB_PORT_STATUS_PORT_POWER | USB_HUB_PORT_STATUS_PORT_ENABLE | USB_HUB_PORT_STATUS_PORT_CONNECTION | USB_HUB_PORT_STATUS_PORT_SUSPEND)
+
+// Hub Port States
+#define USB_HUB_PORT_STATE_DISABLED		(USB_HUB_PORT_STATUS_PORT_POWER | USB_HUB_PORT_STATUS_PORT_CONNECTION)
+
+// Hub Port Events
+#define USB_HUB_PORT_EVENT_CONNECT		(((0UL | USB_HUB_PORT_STATUS_PORT_CONNECTION)	<< 16) | USB_HUB_PORT_STATUS_PORT_POWER | USB_HUB_PORT_STATUS_PORT_CONNECTION)
+#define USB_HUB_PORT_EVENT_DISCONNECT		(((0UL | USB_HUB_PORT_STATUS_PORT_CONNECTION)	<< 16) | USB_HUB_PORT_STATUS_PORT_POWER)
+#define USB_HUB_PORT_EVENT_RESET_COMPLETE	(((0UL | USB_HUB_PORT_STATUS_PORT_RESET) << 16) | USB_HUB_PORT_STATUS_PORT_POWER | USB_HUB_PORT_STATUS_PORT_ENABLE | USB_HUB_PORT_STATUS_PORT_CONNECTION)
+
+#define USB_HUB_PORT_EVENT_LS_CONNECT		(((0UL | USB_HUB_PORT_STATUS_PORT_CONNECTION)	<< 16) | USB_HUB_PORT_STATUS_PORT_POWER | USB_HUB_PORT_STATUS_PORT_CONNECTION | USB_HUB_PORT_STATUS_PORT_LOW_SPEED)
+#define USB_HUB_PORT_EVENT_LS_RESET_COMPLETE	(((0UL | USB_HUB_PORT_STATUS_PORT_RESET)		<< 16) | USB_HUB_PORT_STATUS_PORT_POWER | USB_HUB_PORT_STATUS_PORT_ENABLE | USB_HUB_PORT_STATUS_PORT_CONNECTION | USB_HUB_PORT_STATUS_PORT_LOW_SPEED)
+#define USB_HUB_PORT_EVENT_LS_PORT_ENABLED	(((0UL | USB_HUB_PORT_STATUS_PORT_CONNECTION | USB_HUB_PORT_STATUS_PORT_ENABLE) << 16) | USB_HUB_PORT_STATUS_PORT_POWER | USB_HUB_PORT_STATUS_PORT_ENABLE | USB_HUB_PORT_STATUS_PORT_CONNECTION | USB_HUB_PORT_STATUS_PORT_LOW_SPEED)
+
+typedef struct {
+  uint8_t bDescLength;		// descriptor length
+  uint8_t bDescriptorType;	// descriptor type
+  uint8_t bNbrPorts;		// number of ports a hub equiped with
+  
+ /* struct {
+    uint16_t LogPwrSwitchMode	     : 2;
+    uint16_t CompoundDevice	     : 1;
+    uint16_t OverCurrentProtectMode  : 2;
+    uint16_t TTThinkTime	     : 2;
+    uint16_t PortIndicatorsSupported : 1;
+    uint16_t Reserved		     : 8;
+  } __attribute__((packed));*/
+  uint8_t bCharacteristicsL;
+  uint8_t bCharacteristicsH;
+  
+  uint8_t bPwrOn2PwrGood;
+  uint8_t bHubContrCurrent;
+} __attribute__((packed)) usb_hub_descriptor_t;
+
+typedef struct {
+  union {
+    struct {
+      uint8_t bmStatusL;	// port status bits
+      uint8_t bmStatusH;	// port status bits
+      uint8_t bmChangeL;	// port status change bits
+      uint8_t bmChangeH;	// port status change bits
+    } __attribute__((packed));
+    uint8_t bmEventLL;
+    uint8_t bmEventLL2;
+    uint8_t bmEventLL3;
+    uint8_t bmEventLL4;
+    uint8_t  evtBuff[4];
+  } __attribute__((packed));
+}__attribute__((packed)) hub_event_t;
+
+// interface to usb core
+extern const usb_device_class_config_t usb_hub_class;
+
+#endif // HUB_H
Index: firmware_legacy/usb/keycodes.h
===================================================================
--- firmware_legacy/usb/keycodes.h	(nonexistent)
+++ firmware_legacy/usb/keycodes.h	(revision 799)
@@ -0,0 +1,139 @@
+// http://wiki.amigaos.net/index.php/Keymap_Library
+// http://www.win.tue.nl/~aeb/linux/kbd/scancodes-14.html
+
+#define MISS  0xff
+#define KEYCODE_MAX (0x6f)
+
+// The original minimig had the keyboard connected to the FPGA. Thus all key events (even for OSD)
+// came from the FPGA core. The MIST has the keyboard attached to the arm controller. To be compatible
+// with the minimig core all keys (incl. OSD!) are forwarded to the FPGA and the OSD keys are returned.
+// These keys are tagged with the "OSD" flag
+// The atari/mist core does not forwards keys through the FPGA but queues them inside the arm controller.
+// These keys are tagged with the "OSD_LOC" flag. The keycodes itself used are identical between OSD
+// and OSD_LOC
+
+#define OSD               0x0100     // to be used by OSD, not the core itself
+#define OSD_LOC           0x0200     // OSD key not forwarded to core, but queued in arm controller
+#define CAPS_LOCK_TOGGLE  0x0400     // caps lock toggle behaviour
+#define NUM_LOCK_TOGGLE   0x0800
+#define EXT               0x1000     // extended PS/2 keycode
+
+const unsigned short ps2_modifier[] = 
+      { 0x14, 0x12, 0x11, EXT|0x1f, EXT|0x14, 0x59, EXT|0x11, EXT|0x27 };
+
+// keycode translation table for ps2 emulation
+const unsigned short usb2ps2[] = {
+  MISS,  // 00: NoEvent
+  MISS,  // 01: Overrun Error
+  MISS,  // 02: POST fail
+  MISS,  // 03: ErrorUndefined
+  0x1c,  // 04: a
+  0x32,  // 05: b
+  0x21,  // 06: c
+  0x23,  // 07: d
+  0x24,  // 08: e
+  0x2b,  // 09: f
+  0x34,  // 0a: g
+  0x33,  // 0b: h
+  0x43,  // 0c: i
+  0x3b,  // 0d: j
+  0x42,  // 0e: k
+  0x4b,  // 0f: l
+  0x3a,  // 10: m
+  0x31,  // 11: n
+  0x44,  // 12: o
+  0x4d,  // 13: p
+  0x15,  // 14: q
+  0x2d,  // 15: r
+  0x1b,  // 16: s
+  0x2c,  // 17: t
+  0x3c,  // 18: u
+  0x2a,  // 19: v
+  0x1d,  // 1a: w
+  0x22,  // 1b: x
+  0x35,  // 1c: y
+  0x1a,  // 1d: z
+  0x16,  // 1e: 1
+  0x1e,  // 1f: 2
+  0x26,  // 20: 3
+  0x25,  // 21: 4
+  0x2e,  // 22: 5
+  0x36,  // 23: 6
+  0x3d,  // 24: 7
+  0x3e,  // 25: 8
+  0x46,  // 26: 9
+  0x45,  // 27: 0
+  0x5a,  // 28: Return
+  0x76,  // 29: Escape
+  0x66,  // 2a: Backspace
+  0x0d,  // 2b: Tab
+  0x29,  // 2c: Space
+  0x4e,  // 2d: -
+  0x55,  // 2e: =
+  0x54,  // 2f: [
+  0x5b,  // 30: ]
+  0x5d,  // 31: backslash
+  0x5d,  // 32: Europe 1
+  0x4c,  // 33: ; 
+  0x52,  // 34: '
+  0x0e,  // 35: `
+  0x41,  // 36: ,
+  0x49,  // 37: .
+  0x4a,  // 38: /
+  0x58,  // 39: Caps Lock
+  0x05,  // 3a: F1
+  0x06,  // 3b: F2
+  0x04,  // 3c: F3
+  0x0c,  // 3d: F4
+  0x03,  // 3e: F5
+  0x0b,  // 3f: F6
+  0x83,  // 40: F7
+  0x0a,  // 41: F8
+  0x01,  // 42: F9
+  0x09,  // 43: F10
+  0x78,  // 44: F11
+  OSD_LOC | 0x07,  // 45: F12 (OSD)
+  EXT | 0x7c, // 46: Print Screen
+  NUM_LOCK_TOGGLE,  // 47: Scroll Lock
+  0x77,  // 48: Pause (special key handled inside user_io)
+  EXT | 0x70, // 49: Insert
+  EXT | 0x6c, // 4a: Home
+  EXT | 0x7d, // 4b: Page Up
+  EXT | 0x71, // 4c: Delete
+  EXT | 0x69, // 4d: End
+  EXT | 0x7a, // 4e: Page Down
+  EXT | 0x74, // 4f: Right Arrow
+  EXT | 0x6b, // 50: Left Arrow
+  EXT | 0x72, // 51: Down Arrow
+  EXT | 0x75, // 52: Up Arrow
+  NUM_LOCK_TOGGLE,  // 53: Num Lock
+  EXT | 0x4a, // 54: KP /
+  0x7c,  // 55: KP *
+  0x7b,  // 56: KP -
+  0x79,  // 57: KP +
+  EXT | 0x5a, // 58: KP Enter
+  0x69,  // 59: KP 1
+  0x72,  // 5a: KP 2
+  0x7a,  // 5b: KP 3
+  0x6b,  // 5c: KP 4
+  0x73,  // 5d: KP 5
+  0x74,  // 5e: KP 6
+  0x6c,  // 5f: KP 7
+  0x75,  // 60: KP 8
+  0x7d,  // 61: KP 9
+  0x70,  // 62: KP 0
+  0x71,  // 63: KP .
+  0x61,  // 64: Europe 2
+  EXT | 0x2f, // 65: App
+  EXT | 0x37, // 66: Power
+  0x0f,  // 67: KP =
+  0x08,  // 68: F13
+  0x10,  // 69: F14
+  0x18,  // 6a: F15
+  0x20,  // 6b: F16
+  0x28,  // 6c: F17
+  0x30,  // 6d: F18
+  0x38,  // 6e: F19
+  0x40   // 6f: F20
+};
+
Index: firmware_legacy/usb/timer.c
===================================================================
--- firmware_legacy/usb/timer.c	(nonexistent)
+++ firmware_legacy/usb/timer.c	(revision 799)
@@ -0,0 +1,29 @@
+#include "timer.h"
+#include "regs.h"
+
+// this is a 32 bit counter which overflows after 2^32 milliseconds
+// -> after 46 days
+
+void wait_us(int unsigned num);
+
+void timer_init() {
+}
+
+#ifdef LINUX_BUILD
+#include <sys/time.h>
+msec_t timer_get_msec() {
+	struct timeval x;
+	gettimeofday(&x,0);
+	return (x.tv_sec*1000+(x.tv_usec/1000));
+}
+#else
+msec_t timer_get_msec() {
+	int res = *zpu_timer;
+	return res;
+}
+#endif
+
+void timer_delay_msec(msec_t t) {
+	int y = t;
+	wait_us(y*1000);
+}
Index: firmware_legacy/usb/usb.h
===================================================================
--- firmware_legacy/usb/usb.h	(nonexistent)
+++ firmware_legacy/usb/usb.h	(revision 799)
@@ -0,0 +1,260 @@
+#ifndef USB_H
+#define USB_H
+
+//#include <inttypes.h>
+//#include <stdbool.h>
+
+#include "common/integer.h"
+#include "timer.h"
+
+/* NAK powers. To save space in endpoint data structure, amount of retries */
+/* before giving up and returning 0x4 is stored in bmNakPower as a power of 2.*/
+/* The actual nak_limit is then calculated as nak_limit = ( 2^bmNakPower - 1) */
+#define USB_NAK_MAX_POWER 16	//NAK binary order maximum value
+#define USB_NAK_DEFAULT	  14	//default 16K-1 NAKs before giving up
+#define USB_NAK_NOWAIT	  1	//Single NAK stops transfer
+#define USB_NAK_NONAK	  0	//Do not count NAKs, stop retrying after USB Timeout
+
+typedef struct {
+  uint8_t epAddr;	// Endpoint address 
+  uint8_t maxPktSize;	// Maximum packet size
+  
+  union {
+    uint8_t epAttribs;
+    
+    struct {
+      // Send toggle, when zero bmSNDTOG0, bmSNDTOG1 otherwise
+      uint8_t bmSndToggle: 1;
+      // Send toggle, when zero bmRCVTOG0, bmRCVTOG1 otherwise
+      uint8_t bmRcvToggle: 1;
+      // Binary order for NAK_LIMIT value
+      uint8_t bmNakPower:  6;
+    };
+  };
+} ep_t;
+
+#define USB_NUMDEVICES 16      // number of supported USB devices
+
+/* Common setup data constant combinations  */
+#define USB_REQ_GET_DESCR     USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE     //get descriptor request type
+#define USB_REQ_SET           USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE     //set request type for all but 'set feature' and 'set interface'
+#define USB_REQ_CL_GET_INTF   USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE     //get interface request type
+
+#define USB_SETTLE_DELAY 200   // settle delay in milliseconds
+#define USB_XFER_TIMEOUT 5000  // USB transfer timeout in milliseconds, per section 9.2.6.1 of USB 2.0 spec
+#define USB_RETRY_LIMIT	3      // retry limit for a transfer
+
+/* USB state machine states */
+#define USB_STATE_MASK                                      0xf0
+
+#define USB_STATE_DETACHED                                  0x10
+#define USB_DETACHED_SUBSTATE_INITIALIZE                    0x11        
+#define USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE               0x12
+#define USB_DETACHED_SUBSTATE_ILLEGAL                       0x13
+#define USB_ATTACHED_SUBSTATE_SETTLE                        0x20
+#define USB_ATTACHED_SUBSTATE_RESET_DEVICE                  0x30    
+#define USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE           0x40
+#define USB_ATTACHED_SUBSTATE_WAIT_SOF                      0x50
+#define USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE    0x60
+#define USB_STATE_ADDRESSING                                0x70
+#define USB_STATE_CONFIGURING                               0x80
+#define USB_STATE_RUNNING                                   0x90
+
+/* USB Setup Packet Structure   */
+typedef struct {
+  union {                          // offset   description
+    uint8_t bmRequestType;         //   0      Bit-map of request type
+    struct {
+      uint8_t    recipient:  5;    //          Recipient of the request
+      uint8_t    type:       2;    //          Type of request
+      uint8_t    direction:  1;    //          Direction of data X-fer
+    } __attribute__((packed));
+  } __attribute__((packed)) ReqType_u;
+  uint8_t    bRequest;		   //   1      Request
+  uint8_t    wValueL;
+  uint8_t    wValueH;
+  uint8_t    wIndexL;              //   4      Depends on bRequest
+  uint8_t    wIndexH;              //   5      Depends on bRequest
+  uint8_t    wLengthL;             //   6      Depends on bRequest
+  uint8_t    wLengthH;             //   7      Depends on bRequest
+} __attribute__((packed)) setup_pkt_t;
+
+// Additional Error Codes
+#define USB_ERROR_INVALID_MAX_PKT_SIZE			    0xDA
+#define USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED           0xDB
+#define USB_ERROR_CONFIGURAION_SIZE_MISMATCH                0xDC
+#define USB_ERROR_TRANSFER_TIMEOUT			    0xFF
+
+struct usb_device_entry;
+
+typedef struct {
+  uint8_t (*init)(struct usb_device_entry *);
+  uint8_t (*release)(struct usb_device_entry *);
+  uint8_t (*poll)(struct usb_device_entry *);
+} usb_device_class_config_t;
+
+#include "hub.h"
+#include "hid.h"
+
+// entry used for list of connected devices
+typedef struct usb_device_entry {
+  const usb_device_class_config_t *class;  // pointer to class hadlers
+  ep_t ep0;                            // information about endpoint 0
+  uint8_t bAddress;	                   // device address
+  uint8_t parent;                          // parent device address
+  uint8_t port;
+  bool lowspeed;
+  char volatile * host_addr;
+
+  union {
+    usb_hub_info_t hub_info;
+    usb_hid_info_t hid_info;
+  };
+} usb_device_t;
+
+struct usb_host
+{
+	uint8_t usb_task_state;
+        unsigned char * addr;
+        msec_t poll;
+        msec_t delay;
+};
+
+#define USB_CLASS_USE_CLASS_INFO          0x00    // Use Class Info in the Interface Descriptors
+#define USB_CLASS_AUDIO                   0x01    // Audio
+#define USB_CLASS_COM_AND_CDC_CTRL        0x02    // Communications and CDC Control
+#define USB_CLASS_HID                     0x03    // HID
+#define USB_CLASS_PHYSICAL                0x05    // Physical
+#define USB_CLASS_IMAGE                   0x06    // Image
+#define USB_CLASS_PRINTER                 0x07    // Printer
+#define USB_CLASS_MASS_STORAGE            0x08    // Mass Storage
+#define USB_CLASS_HUB                     0x09    // Hub
+#define USB_CLASS_CDC_DATA                0x0a    // CDC-Data
+#define USB_CLASS_SMART_CARD              0x0b    // Smart-Card
+#define USB_CLASS_CONTENT_SECURITY        0x0d    // Content Security
+#define USB_CLASS_VIDEO                   0x0e    // Video
+#define USB_CLASS_PERSONAL_HEALTH         0x0f    // Personal Healthcare
+#define USB_CLASS_DIAGNOSTIC_DEVICE       0xdc    // Diagnostic Device
+#define USB_CLASS_WIRELESS_CTRL           0xe0    // Wireless Controller
+#define USB_CLASS_MISC                    0xef    // Miscellaneous
+#define USB_CLASS_APP_SPECIFIC            0xfe    // Application Specific
+#define USB_CLASS_VENDOR_SPECIFIC         0xff    // Vendor Specific
+
+/*******************************************************************************/
+/***                                                                         ***/
+/***                       USB chapter 9 structures                          ***/
+/***                                                                         ***/
+/*******************************************************************************/
+
+/* Device descriptor structure */
+typedef struct {
+  uint8_t  bLength;            // Length of this descriptor.
+  uint8_t  bDescriptorType;    // DEVICE descriptor type (USB_DESCRIPTOR_DEVICE).
+  uint8_t bcdUSBL;	       // USB Spec Release Number (BCD).
+  uint8_t bcdUSBH;	       // USB Spec Release Number (BCD).
+  uint8_t  bDeviceClass;       // Class code (assigned by the USB-IF). 0xFF-Vendor specific.
+  uint8_t  bDeviceSubClass;    // Subclass code (assigned by the USB-IF).
+  uint8_t  bDeviceProtocol;    // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific.
+  uint8_t  bMaxPacketSize0;    // Maximum packet size for endpoint 0.
+  uint8_t idVendorL;	       // Vendor ID (assigned by the USB-IF).
+  uint8_t idVendorH;	       // Vendor ID (assigned by the USB-IF).
+  uint8_t idProductL;	       // Product ID (assigned by the manufacturer).
+  uint8_t idProductH;	       // Product ID (assigned by the manufacturer).
+  uint8_t bcdDeviceL;	       // Device release number (BCD).
+  uint8_t bcdDeviceH;	       // Device release number (BCD).
+  uint8_t  iManufacturer;      // Index of String Descriptor describing the manufacturer.
+  uint8_t  iProduct;           // Index of String Descriptor describing the product.
+  uint8_t  iSerialNumber;      // Index of String Descriptor with the device's serial number.
+  uint8_t  bNumConfigurations; // Number of possible configurations.
+} __attribute__((packed)) usb_device_descriptor_t;
+
+/* Configuration descriptor structure */
+typedef struct {
+  uint8_t bLength;             // Length of this descriptor.
+  uint8_t bDescriptorType;     // CONFIGURATION descriptor type (USB_DESCRIPTOR_CONFIGURATION).
+  uint8_t wTotalLengthL;       // Total length of all descriptors for this configuration.
+  uint8_t wTotalLengthH;       // Total length of all descriptors for this configuration.
+  uint8_t bNumInterfaces;      // Number of interfaces in this configuration.
+  uint8_t bConfigurationValue; // Value of this configuration (1 based).
+  uint8_t iConfiguration;      // Index of String Descriptor describing the configuration.
+  uint8_t bmAttributes;        // Configuration characteristics.
+  uint8_t bMaxPower;           // Maximum power consumed by this configuration.
+} __attribute__((packed)) usb_configuration_descriptor_t;
+
+/* Interface descriptor structure */
+typedef struct {
+  uint8_t bLength;               // Length of this descriptor.
+  uint8_t bDescriptorType;       // INTERFACE descriptor type (USB_DESCRIPTOR_INTERFACE).
+  uint8_t bInterfaceNumber;      // Number of this interface (0 based).
+  uint8_t bAlternateSetting;     // Value of this alternate interface setting.
+  uint8_t bNumEndpoints;         // Number of endpoints in this interface.
+  uint8_t bInterfaceClass;       // Class code (assigned by the USB-IF).  0xFF-Vendor specific.
+  uint8_t bInterfaceSubClass;    // Subclass code (assigned by the USB-IF).
+  uint8_t bInterfaceProtocol;    // Protocol code (assigned by the USB-IF).  0xFF-Vendor specific.
+  uint8_t iInterface;            // Index of String Descriptor describing the interface.
+} __attribute__((packed)) usb_interface_descriptor_t;
+
+/* Endpoint descriptor structure */
+typedef struct {
+  uint8_t bLength;               // Length of this descriptor.
+  uint8_t bDescriptorType;       // ENDPOINT descriptor type (USB_DESCRIPTOR_ENDPOINT).
+  uint8_t bEndpointAddress;      // Endpoint address. Bit 7 indicates direction (0=OUT, 1=IN).
+  uint8_t bmAttributes;          // Endpoint transfer type.
+  uint8_t wMaxPacketSize[2];     // Maximum packet size.
+  uint8_t bInterval;             // Polling interval in frames.
+} __attribute__((packed)) usb_endpoint_descriptor_t;
+
+/* Standard Device Requests */
+#define USB_REQUEST_GET_STATUS                  0       // Standard Device Request - GET STATUS
+#define USB_REQUEST_CLEAR_FEATURE               1       // Standard Device Request - CLEAR FEATURE
+#define USB_REQUEST_SET_FEATURE                 3       // Standard Device Request - SET FEATURE
+#define USB_REQUEST_SET_ADDRESS                 5       // Standard Device Request - SET ADDRESS
+#define USB_REQUEST_GET_DESCRIPTOR              6       // Standard Device Request - GET DESCRIPTOR
+#define USB_REQUEST_SET_DESCRIPTOR              7       // Standard Device Request - SET DESCRIPTOR
+#define USB_REQUEST_GET_CONFIGURATION           8       // Standard Device Request - GET CONFIGURATION
+#define USB_REQUEST_SET_CONFIGURATION           9       // Standard Device Request - SET CONFIGURATION
+#define USB_REQUEST_GET_INTERFACE               10      // Standard Device Request - GET INTERFACE
+#define USB_REQUEST_SET_INTERFACE               11      // Standard Device Request - SET INTERFACE
+#define USB_REQUEST_SYNCH_FRAME                 12      // Standard Device Request - SYNCH FRAME
+
+#define USB_FEATURE_ENDPOINT_HALT               0       // CLEAR/SET FEATURE - Endpoint Halt
+#define USB_FEATURE_DEVICE_REMOTE_WAKEUP        1       // CLEAR/SET FEATURE - Device remote wake-up
+#define USB_FEATURE_TEST_MODE                   2       // CLEAR/SET FEATURE - Test mode
+
+/* Setup Data Constants */
+#define USB_SETUP_HOST_TO_DEVICE                0x00    // Device Request bmRequestType transfer direction - host to device transfer
+#define USB_SETUP_DEVICE_TO_HOST                0x80    // Device Request bmRequestType transfer direction - device to host transfer
+#define USB_SETUP_TYPE_STANDARD                 0x00    // Device Request bmRequestType type - standard
+#define USB_SETUP_TYPE_CLASS                    0x20    // Device Request bmRequestType type - class
+#define USB_SETUP_TYPE_VENDOR                   0x40    // Device Request bmRequestType type - vendor
+#define USB_SETUP_RECIPIENT_DEVICE              0x00    // Device Request bmRequestType recipient - device
+#define USB_SETUP_RECIPIENT_INTERFACE           0x01    // Device Request bmRequestType recipient - interface
+#define USB_SETUP_RECIPIENT_ENDPOINT            0x02    // Device Request bmRequestType recipient - endpoint
+#define USB_SETUP_RECIPIENT_OTHER               0x03    // Device Request bmRequestType recipient - other
+
+/* USB descriptors  */
+#define USB_DESCRIPTOR_DEVICE           0x01    // bDescriptorType for a Device Descriptor.
+#define USB_DESCRIPTOR_CONFIGURATION    0x02    // bDescriptorType for a Configuration Descriptor.
+#define USB_DESCRIPTOR_STRING           0x03    // bDescriptorType for a String Descriptor.
+#define USB_DESCRIPTOR_INTERFACE        0x04    // bDescriptorType for an Interface Descriptor.
+#define USB_DESCRIPTOR_ENDPOINT         0x05    // bDescriptorType for an Endpoint Descriptor.
+#define USB_DESCRIPTOR_DEVICE_QUALIFIER 0x06    // bDescriptorType for a Device Qualifier.
+#define USB_DESCRIPTOR_OTHER_SPEED      0x07    // bDescriptorType for a Other Speed Configuration.
+#define USB_DESCRIPTOR_INTERFACE_POWER  0x08    // bDescriptorType for Interface Power.
+
+void usb_init(struct usb_host * host, int portnumber);
+void usb_poll(struct usb_host * host);
+
+uint8_t usb_set_addr( usb_device_t *, uint8_t );
+uint8_t usb_ctrl_req( usb_device_t *, uint8_t bmReqType, 
+		      uint8_t bRequest, uint8_t wValLo, uint8_t wValHi, 
+		      uint16_t wInd, uint16_t nbytes, uint8_t* dataptr);
+uint8_t usb_get_dev_descr( usb_device_t *, uint16_t nbytes, usb_device_descriptor_t* dataptr );
+uint8_t usb_get_conf_descr( usb_device_t *, uint16_t nbytes, uint8_t conf, usb_configuration_descriptor_t* dataptr );
+uint8_t usb_set_conf( usb_device_t *dev, uint8_t conf_value );
+uint8_t usb_in_transfer( usb_device_t *, ep_t *ep, uint16_t *nbytesptr, uint8_t* data);
+uint8_t usb_out_transfer( usb_device_t *, ep_t *ep, uint16_t nbytes, uint8_t* data );
+uint8_t usb_release_device(uint8_t parent, uint8_t port);
+usb_device_t *usb_get_devices();
+
+#endif // USB_H
Index: firmware_legacy/usb/usbhostslave.h
===================================================================
--- firmware_legacy/usb/usbhostslave.h	(nonexistent)
+++ firmware_legacy/usb/usbhostslave.h	(revision 799)
@@ -0,0 +1,113 @@
+/*
+ * OHS900 register declarations and HCD data structures
+ *
+ * Copyright (C) 2005 Steve Fielding
+ * Copyright (C) 2004 Psion Teklogix
+ * Copyright (C) 2004 David Brownell
+ */
+
+// ----------------------- FIXME using direct memory access
+// base address of OHS900 MWW TODO!!!
+//#define OHS900_BASE 0x80900c00
+
+char volatile * usbhostslave;
+
+/*
+ * OHS900 has transfer registers, and control registers.  In host/master
+ * mode one set of registers is used; in peripheral/slave mode, another.
+ */
+
+
+/* TRANSFER REGISTERS
+ */
+#define OHS900_HOST_TX_CTLREG	(4*0x00) 
+#	define OHS900_HCTLMASK_TRANS_REQ		0x01 
+#	define OHS900_HCTLMASK_SOF_SYNC		0x02 
+#	define OHS900_HCTLMASK_PREAMBLE_EN	0x04 
+#	define OHS900_HCTLMASK_ISO_EN		0x08 
+
+
+#define OHS900_HRXSTATREG	(4*0x0a)	/* read */ 
+#	define OHS900_STATMASK_CRC_ERROR		0x01 
+#	define OHS900_STATMASK_BS_ERROR		0x02 
+#	define OHS900_STATMASK_RX_OVF		0x04 
+#	define OHS900_STATMASK_RX_TMOUT		0x08 
+#	define OHS900_STATMASK_NAK_RXED		0x10 
+#	define OHS900_STATMASK_STALL_RXED	0x20 
+#	define OHS900_STATMASK_ACK_RXED		0x40 
+#	define OHS900_STATMASK_DATA_SEQ		0x80 
+
+#define OHS900_TXTRANSTYPEREG		(4*0x01)	/* write */ 
+#	define	OHS900_SETUP	0x00 
+#	define	OHS900_IN	0x01 
+#	define	OHS900_OUT_DATA0	0x02 
+#	define	OHS900_OUT_DATA1	0x03 
+
+#define OHS900_TXADDRREG	(4*0x04)
+#define OHS900_TXENDPREG	(4*0x05)
+
+/* CONTROL REGISTERS:  
+ */
+#define OHS900_SOFENREG		(4*0x03 )
+#	define OHS900_MASK_SOF_ENA	0x01 
+
+#define OHS900_TXLINECTLREG (4*0x02)
+#	define OHS900_TXLCTL_MASK_FORCE	0x4 
+#	define OHS900_TXLCTL_MASK_LINE_CTRL_BITS 0x7
+#		define OHS900_TXLCTL_MASK_NORMAL	0x00 
+#		define OHS900_TXLCTL_MASK_SE0	0x04	
+#		define OHS900_TXLCTL_MASK_FS_J	0x06    
+#		define OHS900_TXLCTL_MASK_FS_K	0x05	
+#	define OHS900_TXLCTL_MASK_LSPD	0x00 
+#	define OHS900_TXLCTL_MASK_FSPD	0x18 
+#	define OHS900_TXLCTL_MASK_FS_POL	0x08 
+#	define OHS900_TXLCTL_MASK_FS_RATE 0x10 
+
+
+#define OHS900_IRQ_ENABLE	(4*0x09)             
+#	define OHS900_INTMASK_TRANS_DONE	0x01   
+#	define OHS900_INTMASK_SOFINTR	0x08   
+#	define OHS900_INTMASK_INSRMV	0x04   	
+#	define OHS900_INTMASK_RESUME_DET	0x02   
+		  
+#define OHS900_RXCONNSTATEREG (4*0x0e)
+#define   OHS900_DISCONNECT_STATE 0x00
+#define   OHS900_LS_CONN_STATE 0x01
+#define   OHS900_FS_CONN_STATE 0x02
+
+#define OHS900_SLAVE_ADDRESS		(4*0x54)
+
+
+
+#define OHS900_IRQ_STATUS	(4*0x08)	/* write to ack */ 
+#define OHS900_HWREVREG		(4*0xe1)	/* read */ 
+
+#define OHS900_SOFTMRREG		(4*0x0F) 
+
+
+
+#define OHS900_HOSTSLAVECTLREG 			(4*0xe0)
+#	define OHS900_HSCTLREG_HOST_EN_MASK	0x01 
+#	define OHS900_HSCTLREG_RESET_CORE	0x02 
+
+
+
+#define OHS900_HS_CTL_INIT OHS900_HSCTLREG_HOST_EN_MASK 
+
+/* 64-byte FIFO control and status
+ */
+#define H_MAXPACKET	64		/* bytes in fifos */
+
+#define OHS900_HOST_TXFIFO_DATA	(4*0x30) 
+#define OHS900_TXFIFOCNTMSBREG	(4*0x32) 
+#define OHS900_TXFIFOCNTLSBREG	(4*0x33)
+#define OHS900_TXFIFOCONTROLREG	(4*0x34)
+#define OHS900_HOST_RXFIFO_DATA	(4*0x20) 
+#define OHS900_RXFIFOCNTMSBREG	(4*0x22) 
+#define OHS900_RXFIFOCNTLSBREG	(4*0x23)
+#define OHS900_RXFIFOCONTROLREG	(4*0x24)
+#define		OHS900_FIFO_FORCE_EMPTY 0x01
+
+
+#define OHS900_IO_EXTENT (4*0x100)
+
Index: firmware_legacy/usb/LICENSE
===================================================================
--- firmware_legacy/usb/LICENSE	(nonexistent)
+++ firmware_legacy/usb/LICENSE	(revision 799)
@@ -0,0 +1 @@
+This part is GPL - in fact this whole firmware should be - just need to check a few things from other contributors...
Index: firmware_legacy/usb/timer.h
===================================================================
--- firmware_legacy/usb/timer.h	(nonexistent)
+++ firmware_legacy/usb/timer.h	(revision 799)
@@ -0,0 +1,14 @@
+// interface between USB timer and minimig timer
+
+#ifndef TIMER_H
+#define TIMER_H
+
+//#include <inttypes.h>
+#include <common/integer.h>
+typedef uint32_t msec_t;
+
+void timer_init();
+msec_t timer_get_msec();
+void timer_delay_msec(msec_t t);
+
+#endif // TIMER_H
Index: firmware_legacy/usb/mii.h
===================================================================
--- firmware_legacy/usb/mii.h	(nonexistent)
+++ firmware_legacy/usb/mii.h	(revision 799)
@@ -0,0 +1,65 @@
+#ifndef MII_H
+#define MII_H
+
+/* Generic MII registers. */
+#define MII_BMCR                0x00    /* Basic mode control register */
+#define MII_BMSR                0x01    /* Basic mode status register  */
+#define MII_PHYSID1             0x02    /* PHYS ID 1                   */
+#define MII_PHYSID2             0x03    /* PHYS ID 2                   */
+#define MII_ADVERTISE           0x04    /* Advertisement control reg   */
+
+/* Basic mode control register. */
+#define BMCR_RESV               0x003f  /* Unused...                   */
+#define BMCR_SPEED1000          0x0040  /* MSB of Speed (1000)         */
+#define BMCR_CTST               0x0080  /* Collision test              */
+#define BMCR_FULLDPLX           0x0100  /* Full duplex                 */
+#define BMCR_ANRESTART          0x0200  /* Auto negotiation restart    */
+#define BMCR_ISOLATE            0x0400  /* Disconnect DP83840 from MII */
+#define BMCR_PDOWN              0x0800  /* Powerdown the DP83840       */
+#define BMCR_ANENABLE           0x1000  /* Enable auto negotiation     */
+#define BMCR_SPEED100           0x2000  /* Select 100Mbps              */
+#define BMCR_LOOPBACK           0x4000  /* TXD loopback bits           */
+#define BMCR_RESET              0x8000  /* Reset the DP83840           */
+
+/* Basic mode status register. */
+#define BMSR_ERCAP              0x0001  /* Ext-reg capability          */
+#define BMSR_JCD                0x0002  /* Jabber detected             */
+#define BMSR_LSTATUS            0x0004  /* Link status                 */
+#define BMSR_ANEGCAPABLE        0x0008  /* Able to do auto-negotiation */
+#define BMSR_RFAULT             0x0010  /* Remote fault detected       */
+#define BMSR_ANEGCOMPLETE       0x0020  /* Auto-negotiation complete   */
+#define BMSR_RESV               0x00c0  /* Unused...                   */
+#define BMSR_ESTATEN            0x0100  /* Extended Status in R15 */
+#define BMSR_100HALF2           0x0200  /* Can do 100BASE-T2 HDX */
+#define BMSR_100FULL2           0x0400  /* Can do 100BASE-T2 FDX */
+#define BMSR_10HALF             0x0800  /* Can do 10mbps, half-duplex  */
+#define BMSR_10FULL             0x1000  /* Can do 10mbps, full-duplex  */
+#define BMSR_100HALF            0x2000  /* Can do 100mbps, half-duplex */
+#define BMSR_100FULL            0x4000  /* Can do 100mbps, full-duplex */
+#define BMSR_100BASE4           0x8000  /* Can do 100mbps, 4k packets  */
+
+/* Advertisement control register. */
+#define ADVERTISE_SLCT          0x001f  /* Selector bits               */
+#define ADVERTISE_CSMA          0x0001  /* Only selector supported     */
+#define ADVERTISE_10HALF        0x0020  /* Try for 10mbps half-duplex  */
+#define ADVERTISE_1000XFULL     0x0020  /* Try for 1000BASE-X full-duplex */
+#define ADVERTISE_10FULL        0x0040  /* Try for 10mbps full-duplex  */
+#define ADVERTISE_1000XHALF     0x0040  /* Try for 1000BASE-X half-duplex */
+#define ADVERTISE_100HALF       0x0080  /* Try for 100mbps half-duplex */
+#define ADVERTISE_1000XPAUSE    0x0080  /* Try for 1000BASE-X pause    */
+#define ADVERTISE_100FULL       0x0100  /* Try for 100mbps full-duplex */
+#define ADVERTISE_1000XPSE_ASYM 0x0100  /* Try for 1000BASE-X asym pause */
+#define ADVERTISE_100BASE4      0x0200  /* Try for 100mbps 4k packets  */
+#define ADVERTISE_PAUSE_CAP     0x0400  /* Try for pause               */
+#define ADVERTISE_PAUSE_ASYM    0x0800  /* Try for asymetric pause     */
+#define ADVERTISE_RESV          0x1000  /* Unused...                   */
+#define ADVERTISE_RFAULT        0x2000  /* Say we can detect faults    */
+#define ADVERTISE_LPACK         0x4000  /* Ack link partners response  */
+#define ADVERTISE_NPAGE         0x8000  /* Next page bit               */
+
+#define ADVERTISE_FULL (ADVERTISE_100FULL | ADVERTISE_10FULL | \
+                        ADVERTISE_CSMA)
+#define ADVERTISE_ALL (ADVERTISE_10HALF | ADVERTISE_10FULL | \
+                       ADVERTISE_100HALF | ADVERTISE_100FULL)
+
+#endif // MII_H
Index: firmware_legacy/atari_drive_emulator.c
===================================================================
--- firmware_legacy/atari_drive_emulator.c	(nonexistent)
+++ firmware_legacy/atari_drive_emulator.c	(revision 799)
@@ -0,0 +1,863 @@
+#include "atari_drive_emulator.h"
+#include "fileutils.h"
+
+#include "uart.h"
+#include "regs.h"
+#include "pause.h"
+#include "simplefile.h"
+#include "hexdump.h"
+
+//#include "printf.h"
+//#include <stdio.h>
+#include "integer.h"
+
+extern int debug_pos; // ARG!
+extern unsigned char volatile * baseaddr;
+
+#define send_ACK()	USART_Transmit_Byte('A');
+#define send_NACK()	USART_Transmit_Byte('N');
+#define send_CMPL()	USART_Transmit_Byte('C');
+#define send_ERR()	USART_Transmit_Byte('E');
+
+/* BiboDos needs at least 50us delay before ACK */
+#define DELAY_T2_MIN wait_us(100);
+
+/* the QMEG OS needs at least 300usec delay between ACK and complete */
+#define DELAY_T5_MIN wait_us(300);
+
+/* QMEG OS 3 needs a delay of 150usec between complete and data */
+#define DELAY_T3_PERIPH wait_us(150);
+
+#define speedslow 0x28
+#define speedfast turbo_div
+int turbo_drive;
+int turbo_div;
+
+#define XEX_SECTOR_SIZE 128
+
+#define MAX_DRIVES 4
+
+struct SimpleFile * drives[MAX_DRIVES];
+unsigned char drive_info[MAX_DRIVES];
+enum DriveInfo {DI_XD=0,DI_SD=1,DI_MD=2,DI_DD=3,DI_BITS=3,DI_RO=4};
+
+//#ifdef SOCKIT
+//double when()
+//{
+//	struct timeval tv;
+//	gettimeofday(&tv,0);
+//	double now = tv.tv_sec;
+//	now += tv.tv_usec/1e6;
+//	return now;
+//}
+//#endif
+
+struct ATRHeader
+{
+	u16 wMagic;
+	u16 wPars;
+	u16 wSecSize;
+	u08 btParsHigh;
+	u32 dwCRC;
+	u32 dwUNUSED;
+	u08 btFlags;
+} __attribute__((packed));
+struct ATRHeader atr_header;
+int offset;
+int xex_loader;
+int xex_size;
+
+int speed;
+
+int badcommandcount;
+int commandcount;
+int opendrive;
+
+int readonly;
+
+unsigned char atari_sector_buffer[256];
+
+unsigned char get_checksum(unsigned char* buffer, int len);
+
+#define    TWOBYTESTOWORD(ptr,val)           (*((u08*)(ptr)) = val&0xff);(*(1+(u08*)(ptr)) = (val>>8)&0xff);
+
+void processCommand();
+void USART_Send_cmpl_and_atari_sector_buffer_and_check_sum(unsigned short len);
+void clearAtariSectorBuffer()
+{
+	int i=256;
+	while (--i)
+		atari_sector_buffer[i] = 0;
+}
+
+uint8_t boot_xex_loader[179] = {
+	0x72,0x02,0x5f,0x07,0xf8,0x07,0xa9,0x00,0x8d,0x04,0x03,0x8d,0x44,0x02,0xa9,0x07,
+	0x8d,0x05,0x03,0xa9,0x70,0x8d,0x0a,0x03,0xa9,0x01,0x8d,0x0b,0x03,0x85,0x09,0x60,
+	0x7d,0x8a,0x48,0x20,0x53,0xe4,0x88,0xd0,0xfa,0x68,0xaa,0x8c,0x8e,0x07,0xad,0x7d,
+	0x07,0xee,0x8e,0x07,0x60,0xa9,0x93,0x8d,0xe2,0x02,0xa9,0x07,0x8d,0xe3,0x02,0xa2,
+	0x02,0x20,0xda,0x07,0x95,0x43,0x20,0xda,0x07,0x95,0x44,0x35,0x43,0xc9,0xff,0xf0,
+	0xf0,0xca,0xca,0x10,0xec,0x30,0x06,0xe6,0x45,0xd0,0x02,0xe6,0x46,0x20,0xda,0x07,
+	0xa2,0x01,0x81,0x44,0xb5,0x45,0xd5,0x43,0xd0,0xed,0xca,0x10,0xf7,0x20,0xd2,0x07,
+	0x4c,0x94,0x07,0xa9,0x03,0x8d,0x0f,0xd2,0x6c,0xe2,0x02,0xad,0x8e,0x07,0xcd,0x7f,
+	0x07,0xd0,0xab,0xee,0x0a,0x03,0xd0,0x03,0xee,0x0b,0x03,0xad,0x7d,0x07,0x0d,0x7e,
+	0x07,0xd0,0x8e,0x20,0xd2,0x07,0x6c,0xe0,0x02,0x20,0xda,0x07,0x8d,0xe0,0x02,0x20,
+	0xda,0x07,0x8d,0xe1,0x02,0x2d,0xe0,0x02,0xc9,0xff,0xf0,0xed,0xa9,0x00,0x8d,0x8e,
+	0x07,0xf0,0x82 };
+//  relokacni tabulka neni potreba, meni se vsechny hodnoty 0x07
+//  (melo by byt PRESNE 20 vyskytu! pokud je jich vic, pak bacha!!!)
+
+void byteswap(WORD * inw)
+{
+#ifndef LITTLE_ENDIAN
+	unsigned char * in = (unsigned char *)inw;
+	unsigned char temp = in[0];
+	in[0] = in[1];
+	in[1] = temp;
+#endif
+}
+
+struct command
+{
+	u08 deviceId;
+	u08 command;
+	u08 aux1;
+	u08 aux2;
+	u08 chksum;
+} __attribute__((packed));
+
+static void switch_speed()
+{
+	if (speed == speedslow)
+	{
+		speed = speedfast;
+	}
+	else
+	{
+		speed = speedslow;
+	}
+	USART_Init(speed+6);
+}
+
+void getCommand(struct command * cmd)
+{
+	int expchk;
+	int i;
+	unsigned char cmdstat;
+	while (1)
+	{
+		while (0 == USART_Command_Line())
+		{
+			actions();
+			wait_us(3);
+		}
+		USART_Init(speed+6);
+		*zpu_siocommand_ready = 1; // clear
+
+		do {
+			actions();
+			wait_us(3);
+			cmdstat = *zpu_siocommand_ready;
+		} while (0 == cmdstat);
+
+		if (cmdstat & 0x40) {
+			// state machine is stopped, just (re-)start it
+			continue;
+		}
+		if ((cmdstat & 0x80) || USART_Framing_Error()) {
+			// state machine reported error or we got a framing error:
+			// switch speed and retry
+			switch_speed();
+			continue;
+		}
+		for (i=0;i!=5;++i)
+			((unsigned char *)cmd)[i] = zpu_siocommand_data[i<<2];
+
+		atari_sector_buffer[0] = cmd->deviceId;
+		atari_sector_buffer[1] = cmd->command;
+		atari_sector_buffer[2] = cmd->aux1;
+		atari_sector_buffer[3] = cmd->aux2;
+		expchk = get_checksum(&atari_sector_buffer[0],4);
+
+		if (expchk==cmd->chksum) {
+			// got a command frame
+			break;
+		} else {
+			// just an invalid checksum, switch speed anyways
+			switch_speed();
+		}
+	}
+
+	DELAY_T2_MIN;
+}
+
+// Called whenever file changed
+void set_drive_status(int driveNumber, struct SimpleFile * file)
+{
+	int read = 0;
+	int xfd = 0;
+	unsigned char info = 0;
+
+	drives[driveNumber] = 0;
+	drive_info[driveNumber] = 0;
+
+	if (!file) return;
+
+	//printf("WTF:%d %x\n",driveNumber, file);
+
+	// Read header
+	read = 0;
+	file_seek(file,0);
+	file_read(file,(unsigned char *)&atr_header, 16, &read);
+	if (read!=16)
+	{
+		//printf("Could not read header\n");
+		return; //while(1);
+	}
+	byteswap(&atr_header.wMagic);
+	byteswap(&atr_header.wPars);
+	byteswap(&atr_header.wSecSize);
+	/*printf("\nHeader:");
+	printf("%d",atr_header.wMagic);
+	plotnext(toatarichar(' '));
+	printf("%d",atr_header.wPars);
+	plotnext(toatarichar(' '));
+	printf("%d",atr_header.wSecSize);
+	plotnext(toatarichar(' '));
+	printf("%d",atr_header.btParsHigh);
+	plotnext(toatarichar(' '));
+	printf("%d",atr_header.dwCRC);
+	printf("\n");
+	*/
+
+	xex_loader = 0;
+	xfd = compare_ext(file_name(file),"XFD");
+
+	if (xfd == 1)
+	{
+		//printf("XFD ");
+		// build a fake atr header
+		offset = 0;
+		atr_header.wMagic = 0x296;
+		atr_header.wPars = file_size(file)/16;
+		atr_header.wSecSize = 0x80;
+		atr_header.btFlags |= file_readonly(file);
+	}
+	else if (atr_header.wMagic == 0xFFFF) // XEX
+	{
+		int i;
+		//printf("XEX ");
+		offset = -256;
+		xex_loader = 1;
+		atr_header.wMagic = 0xffff;
+		xex_size = file_size(file);
+		atr_header.wPars = xex_size/16;
+		atr_header.wSecSize = XEX_SECTOR_SIZE;
+		atr_header.btFlags = 1;
+	}
+	else if (atr_header.wMagic == 0x296) // ATR
+	{
+		//printf("ATR ");
+		offset = 16;
+		atr_header.btFlags |= file_readonly(file);
+	}
+	else
+	{
+		//printf("Unknown file type");
+		return;
+	}
+
+	if (atr_header.btFlags&1)
+	{
+		info |= DI_RO;
+	}
+
+	if (atr_header.wSecSize == 0x80)
+	{
+		if (atr_header.wPars>(720*128/16))
+			info |= DI_MD;
+		else
+			info |= DI_SD;
+	}
+	else if (atr_header.wSecSize == 0x100)
+	{
+		info |= DI_DD;
+	}
+	else if (atr_header.wSecSize < 0x100)
+	{
+		info |= DI_XD;
+	}
+	else
+	{
+		//printf("BAD sector size");
+		return;
+	}	
+	//printf("%d",atr_header.wPars);
+	//printf("0\n");
+
+	drives[driveNumber] = file;
+	drive_info[driveNumber] = info;
+	//printf("appears valid\n");
+}
+
+struct SimpleFile * get_drive_status(int driveNumber)
+{
+	return drives[driveNumber];
+}
+
+void init_drive_emulator()
+{
+	int i;
+
+	set_turbo_drive(1);
+
+	commandcount = 0;
+	badcommandcount = 0;
+	opendrive = -1;
+	speed = speedslow;
+	USART_Init(speed+6);
+	for (i=0; i!=MAX_DRIVES; ++i)
+	{
+		drives[i] = 0;
+	}
+}
+
+void run_drive_emulator()
+{
+	while (1)
+	{
+		processCommand();
+	}
+}
+
+/////////////////////////
+
+void processCommand()
+{
+	struct command command;
+
+	getCommand(&command);
+
+	++commandcount;
+	/*FIXME if (commandcount==4 && (4==(4&(*zpu_switches))))
+	{
+		//printf("Paused\n");
+		pause_6502(1);
+		while(1);
+	}*/
+	/*if (badcommandcount==8)
+	{
+		//printf("Stuck?\n");
+		pause_6502(1);
+		while(1);
+	}*/
+
+	if (command.deviceId >= 0x31 && command.deviceId <= 0x34)
+	{
+		int sent = 0;
+		int drive = 0;
+		struct SimpleFile * file = 0;
+
+		drive = (command.deviceId&0xf) -1;
+	//	printf("Drive:");
+	//	printf("%x %d",command.deviceId,drive);
+		if (drive!=opendrive)
+		{
+			if (drive<MAX_DRIVES && drive>=0)
+			{
+				opendrive = drive;
+				set_drive_status(drive, drives[drive]);
+				//printf("HERE!:%d\n",drive);
+			}
+		}
+
+		if (drive<0 || !drives[drive])
+		{
+			//USART_Transmit_Mode();
+			//send_NACK();
+			//USART_Wait_Transmit_Complete();
+			//wait_us(100); // Wait for transmission to complete - Pokey bug, gets stuck active...
+			//USART_Receive_Mode();
+
+			//printf("Drive not present:%d %x", drive, drives[drive]);
+			return;
+		}
+
+		file = drives[opendrive];
+
+		switch (command.command)
+		{
+		case 0x3f:
+			{
+			//printf("Speed:");
+			int sector = ((int)command.aux1) + (((int)command.aux2)<<8);
+			USART_Transmit_Mode();
+			send_ACK();
+			clearAtariSectorBuffer();
+			atari_sector_buffer[0] = speedfast;
+			hexdump_pure(atari_sector_buffer,1);
+			USART_Send_cmpl_and_atari_sector_buffer_and_check_sum(1);
+			sent = 1;
+	if (sector == 0)
+	{
+		speed = speedfast;
+		//printf("SPDF");
+		//printf("%d",speed);
+	}
+	else
+	{
+		speed = speedslow;
+		//printf("SPDS");
+		//printf("%d",speed);
+	}
+			}
+		case 0x53:
+			{
+			unsigned char status;
+			//printf("Stat:");
+			USART_Transmit_Mode();
+			send_ACK();
+			clearAtariSectorBuffer();
+
+			status = 0x10; // Motor on;
+			if (atr_header.btFlags&1)
+			{
+				status |= 0x08; // write protected; // no write support yet...
+			}
+			if (atr_header.wSecSize == 0x80) // normal sector size
+			{
+				if (atr_header.wPars>(720*128/16))
+				{
+					status |= 0x80; // medium density - or a strange one...
+				}
+			}
+			else
+			{
+				status |= 0x20; // 256 byte sectors
+			}
+			atari_sector_buffer[0] = status;
+			atari_sector_buffer[1] = 0xff;
+			atari_sector_buffer[2] = 0xe0;
+			atari_sector_buffer[3] = 0x0;
+			hexdump_pure(atari_sector_buffer,4); // Somehow with this...
+			USART_Send_cmpl_and_atari_sector_buffer_and_check_sum(4);
+			sent = 1;
+			//printf("%d",atari_sector_buffer[0]); // and this... The wrong checksum is sent!!
+			//printf(":done\n");
+			}
+			break;
+		default:
+			// TODO
+			//USART_Transmit_Mode();
+			//send_NACK();
+			//USART_Wait_Transmit_Complete();
+			//USART_Receive_Mode();
+			break;
+		case 0x50: // write
+		case 0x57: // write with verify
+			{
+			//debug_pos = 0;
+
+			int sector = ((int)command.aux1) + (((int)command.aux2)<<8);
+			int sectorSize = 0;
+			int location =0;
+
+			USART_Transmit_Mode();
+			if (file_readonly(file))
+			{
+				send_NACK();
+				USART_Wait_Transmit_Complete();
+				USART_Receive_Mode();
+				return;
+			}
+			//printf("%f:WACK\n",when());
+			send_ACK();
+			USART_Wait_Transmit_Complete();
+			USART_Receive_Mode();
+	
+			location = offset;
+			if (sector>3)
+			{
+				sector-=4;
+				location += 128*3;
+				location += sector*atr_header.wSecSize;
+				sectorSize = atr_header.wSecSize;
+			}
+			else
+			{
+				location += 128*(sector-1);
+				sectorSize = 128;
+			}
+
+			// Receive the data
+			//printf("%f:Getting data\n",when());
+			int i;
+			for (i=0;i!=sectorSize;++i)
+			{
+				unsigned char temp = USART_Receive_Byte();
+				atari_sector_buffer[i] = temp;
+				//printf("%02x",temp);
+			}
+			unsigned char checksum = USART_Receive_Byte();
+			//hexdump_pure(atari_sector_buffer,sectorSize); // Somehow with this...
+			unsigned char expchk = get_checksum(&atari_sector_buffer[0],sectorSize);
+			//printf("DATA:%d:",sectorSize);
+			//printf("%f:CHK:%02x EXP:%02x %s\n", when(), checksum, expchk, checksum!=expchk ? "BAD" : "");
+			//printf(" %d",atari_sector_buffer[0]); // and this... The wrong checksum is sent!!
+			//printf(":done\n");
+			if (checksum==expchk)
+			{
+				//DELAY_T2_MIN
+				wait_us(20);
+				USART_Transmit_Mode();
+				//printf("%f:WACK data\n",when());
+				send_ACK();
+				USART_Wait_Transmit_Complete();
+
+				//printf("%d",location);
+				//printf("\n");
+				file_seek(file,location);
+				int written = 0;
+				file_write(file,&atari_sector_buffer[0], sectorSize, &written);
+
+				int ok = 0;
+
+				if (command.command == 0x57)
+				{
+					unsigned char buffer[256];
+					int read;
+					file_seek(file,location);
+					file_read(file,buffer,sectorSize,&read);
+
+					ok = 1;
+					for (i=0;i!=sectorSize;++i)
+					{
+						if (buffer[i] != atari_sector_buffer[i]) ok = 0;
+					}
+				}
+				else
+					ok = 1;
+
+				DELAY_T5_MIN;
+				if (ok)
+				{
+					//printf("%f:CMPL\n",when());
+					send_CMPL();
+				}
+				else
+				{
+					//printf("%f:NACK(verify failed)\n",when());
+					send_NACK();
+				}
+
+				USART_Wait_Transmit_Complete();
+				USART_Receive_Mode();
+			}
+			else
+			{
+				//printf("%f:NACK(bad checksum)\n",when());
+				send_NACK();
+
+				USART_Wait_Transmit_Complete();
+				USART_Receive_Mode();
+			}
+
+			//debug_pos = -1;
+			}
+
+			break;
+		case 0x52: // read
+			{
+			int sector = ((int)command.aux1) + (((int)command.aux2)<<8);
+
+			int sectorSize = 0;
+			int read = 0;
+			int location =0;
+
+			DELAY_T2_MIN
+			USART_Transmit_Mode();
+			//printf("%f:ACK\n",when());
+			if (sector == 0)
+			{
+				send_NACK();
+				break;
+			}
+			send_ACK();
+			//printf("Sector:");
+			//printf("%d",sector);
+			//printf(":");
+			if(xex_loader)         //n_sector>0 && //==0 se overuje hned na zacatku
+			{
+				//sektory xex bootloaderu, tj. 1 nebo 2
+				u08 i,b;
+				u08 *spt, *dpt;
+				int file_sectors;
+
+				//file_sectors se pouzije pro sektory $168 i $169 (optimalizace)
+				//zarovnano nahoru, tj. =(size+124)/125
+				file_sectors = ((xex_size+(u32)(XEX_SECTOR_SIZE-3-1))/((u32)XEX_SECTOR_SIZE-3));
+
+				//printf("XEX ");
+
+				if (sector<=2)
+				{
+					//printf("boot ");
+
+					spt= &boot_xex_loader[(u16)(sector-1)*((u16)XEX_SECTOR_SIZE)];
+					dpt= atari_sector_buffer;
+					i=XEX_SECTOR_SIZE;
+					do
+					{
+						b=*spt++;
+						//relokace bootloaderu z $0700 na jine misto
+						//TODO if (b==0x07) b+=bootloader_relocation;
+						*dpt++=b;
+						i--;
+					} while(i);
+				}
+				else
+				if(sector==0x168)
+				{
+					//printf("numtobuffer ");
+					//vrati pocet sektoru diskety
+					//byty 1,2
+					goto set_number_of_sectors_to_buffer_1_2;
+				}
+				else
+				if(sector==0x169)
+				{
+					//printf("name ");
+					//fatGetDirEntry(FileInfo.vDisk.file_index,5,0);
+					//fatGetDirEntry(FileInfo.vDisk.file_index,0); //ale musi to posunout o 5 bajtu doprava
+		
+					{
+						u08 i,j;
+						for(i=j=0;i<8+3;i++)
+						{
+							/*if( ((xex_name[i]>='A' && xex_name[i]<='Z') ||
+								(xex_name[i]>='0' && xex_name[i]<='9')) )
+							{
+							  //znak je pouzitelny na Atari
+							  atari_sector_buffer[j]=xex_name[i];
+							  j++;
+							}*/
+							if ( (i==7) || (i==8+2) )
+							{
+								for(;j<=i;j++) atari_sector_buffer[j]=' ';
+							}
+						}
+						//posune nazev z 0-10 na 5-15 (0-4 budou systemova adresarova data)
+						//musi pozpatku
+						for(i=15;i>=5;i--) atari_sector_buffer[i]=atari_sector_buffer[i-5];
+						//a pak uklidi cely zbytek tohoto sektoru
+						for(i=5+8+3;i<XEX_SECTOR_SIZE;i++)
+							atari_sector_buffer[i]=0x00;
+					}
+
+					//teprve ted muze pridat prvnich 5 bytu na zacatek nulte adresarove polozky (pred nazev)
+					//atari_sector_buffer[0]=0x42;							//0
+					//jestlize soubor zasahuje do sektoru cislo 1024 a vic,
+					//status souboru je $46 misto standardniho $42
+					atari_sector_buffer[0]=(file_sectors>(0x400-0x171))? 0x46 : 0x42; //0
+
+					TWOBYTESTOWORD(atari_sector_buffer+3,0x0171);			//3,4
+set_number_of_sectors_to_buffer_1_2:
+					TWOBYTESTOWORD(atari_sector_buffer+1,file_sectors);		//1,2
+				}
+				else
+				if(sector>=0x171)
+				{
+					//printf("data ");
+					file_seek(file,((u32)sector-0x171)*((u32)XEX_SECTOR_SIZE-3));
+					file_read(file,&atari_sector_buffer[0], XEX_SECTOR_SIZE-3, &read);
+
+					if(read<(XEX_SECTOR_SIZE-3))
+						sector=0; //je to posledni sektor
+					else
+						sector++; //ukazatel na dalsi
+
+					atari_sector_buffer[XEX_SECTOR_SIZE-3]=((sector)>>8); //nejdriv HB !!!
+					atari_sector_buffer[XEX_SECTOR_SIZE-2]=((sector)&0xff); //pak DB!!! (je to HB,DB)
+					atari_sector_buffer[XEX_SECTOR_SIZE-1]=read;
+				}
+				//printf(" sending\n");
+
+				sectorSize = XEX_SECTOR_SIZE;
+			}
+			else
+			{
+				location = offset;
+				if (sector>3)
+				{
+					sector-=4;
+					location += 128*3;
+					location += sector*atr_header.wSecSize;
+					sectorSize = atr_header.wSecSize;
+				}
+				else
+				{
+					location += 128*(sector-1);
+					sectorSize = 128;
+				}
+				//printf("%d",location);
+				//printf("\n");
+				//printf("%f:Read\n",when());
+				file_seek(file,location);
+				file_read(file,&atari_sector_buffer[0], sectorSize, &read);
+				//printf("%f:Read done\n",when());
+			}
+
+			//topofscreen();
+			//hexdump_pure(atari_sector_buffer,sectorSize);
+			//printf("Sending\n");
+			USART_Send_cmpl_and_atari_sector_buffer_and_check_sum(sectorSize);
+			sent = 1;
+
+			//pause_6502(1);
+			//hexdump_pure(0x10000+0x400,128);
+			unsigned char chksumreceive = 0; //get_checksum(0x10000+0x400, sectorSize);
+			//printf(" receive:");
+			//printf("%d",chksumreceive);
+			//printf("\n");
+			//pause_6502(1);
+			//while(1);
+			}
+			
+			break;
+		}
+
+		//wait_us(100); // Wait for transmission to complete - Pokey bug, gets stuck active...
+
+		if (sent)
+			USART_Wait_Transmit_Complete();
+		USART_Receive_Mode();
+	}
+	else
+	{
+		++badcommandcount;
+	}
+}
+	
+unsigned char get_checksum(unsigned char* buffer, int len)
+{
+	u16 i;
+	u08 sumo,sum;
+	sum=sumo=0;
+	for(i=0;i<len;i++)
+	{
+		sum+=buffer[i];
+		if(sum<sumo) sum++;
+		sumo = sum;
+
+		//printf("c:%02x:",sumo);
+	}
+	return sum;
+}
+
+void USART_Send_Buffer(unsigned char *buff, u16 len)
+{
+	while(len>0) { USART_Transmit_Byte(*buff++); len--; }
+}
+
+void USART_Send_cmpl_and_atari_sector_buffer_and_check_sum(unsigned short len)
+{
+	u08 check_sum;
+	//printf("(send:");
+	//printf("%d",len);
+
+	DELAY_T5_MIN;
+	//printf("%f:CMPL\n",when());
+	send_CMPL();
+
+	// Hias: changed to 100us so that Qmeg3 works again with the
+	// new bit-banging transmission code
+	DELAY_T3_PERIPH;
+
+	check_sum = 0;
+	//printf("%f:SendBuffer\n",when());
+	USART_Send_Buffer(atari_sector_buffer,len);
+	// tx_checksum is updated by bit-banging USART_Transmit_Byte,
+	// so we can skip separate calculation
+	check_sum = get_checksum(atari_sector_buffer,len);
+	USART_Transmit_Byte(check_sum);
+	//printf("%f:Done\n",when());
+	//hexdump_pure(atari_sector_buffer,len);
+	/*printf(":chk:");
+	printf("%d",check_sum);
+	printf(")");*/
+}
+
+void describe_disk(int driveNumber, char * buffer)
+{
+	if (drives[driveNumber]==0)
+	{
+		buffer[0] = 'N';
+		buffer[1] = 'O';
+		buffer[2] = 'N';
+		buffer[3] = 'E';
+		buffer[4] = '\0';
+		return;
+	}
+//enum DriveInfo {DI_XD=0,DI_SD=1,DI_MD=2,DI_DD=3,DI_BITS=3,DI_RO=4};
+	unsigned char info = drive_info[driveNumber];
+	buffer[0] = 'R';
+	buffer[1] = info&DI_RO ? 'O' : 'W';
+	buffer[2] = ' ';
+	unsigned char density;
+	switch (info&3)
+	{
+	case DI_XD:
+		density = 'X';
+		break;
+	case DI_SD:
+		density = 'S';
+		break;
+	case DI_MD:
+		density = 'M';
+		break;
+	case DI_DD:
+		density = 'D';
+		break;
+	}
+	buffer[3] = density;
+	buffer[4] = 'D';
+	buffer[5] = '\0';
+}
+
+void set_turbo_drive(int pos)
+{
+	turbo_drive = pos;
+	static int turbodivs[] = 
+	{
+		0x28,
+		0x6,
+		0x5,
+		0x4,
+		0x3,
+		0x2,
+		0x1,
+		0x0
+	};
+	turbo_div = turbodivs[turbo_drive];
+}
+
+int get_turbo_drive()
+{
+	return turbo_drive;
+}
+
+char const * get_turbo_drive_str()
+{
+	static char const * turbostr[] = 
+	{
+		"Standard",
+		"Fast(6)",
+		"Fast(5)",
+		"Fast(4)",
+		"Fast(3)",
+		"Fast(2)",
+		"Fast(1)",
+		"Fast(0)"
+	};
+	return turbostr[turbo_drive];
+}
+
Index: firmware_legacy/5200/mainmenu.c
===================================================================
--- firmware_legacy/5200/mainmenu.c	(nonexistent)
+++ firmware_legacy/5200/mainmenu.c	(revision 799)
@@ -0,0 +1,422 @@
+static const int main_ram_size=16384;
+#include "main.h" //!!!
+
+unsigned char freezer_rom_present = 0;
+
+void actions();
+
+#ifdef USB
+#include "usb.h"
+#endif
+
+void loadosrom()
+{
+	int j=0;
+	if (file_size(files[5]) == 0x0800)
+	{
+		int i=0;
+		unsigned char * src = (unsigned char *)(ROM_OFS + 0x4000 + SDRAM_BASE);
+		unsigned char * dest1 = (unsigned char *)(ROM_OFS + 0x4800 + SDRAM_BASE);
+		loadromfile(files[5],0x0800, ROM_OFS + 0x4000);
+
+		for (i=0; i!=0x800; ++i)
+		{
+			dest1[i] = src[i];
+		}
+	}
+}
+
+#ifdef USB
+struct usb_host usb_porta;
+#endif
+#ifdef USB2
+struct usb_host usb_portb;
+#endif
+
+void mainmenu()
+{
+#ifdef USB
+	usb_init(&usb_porta,0);
+#endif
+#ifdef USB2
+	usb_init(&usb_portb,1);
+#endif
+	memset8(SRAM_BASE+0x4000, 0, 32768);
+	memset32(SDRAM_BASE+0x4000, 0, 32768/4);
+
+	if (SimpleFile_OK == dir_init((void *)DIR_INIT_MEM, DIR_INIT_MEMSIZE))
+	{
+		#ifdef USB
+			usb_log_init(files[7]);
+		#endif
+		struct SimpleDirEntry * entries = dir_entries(ROM_DIR);
+
+		if (SimpleFile_OK == file_open_name_in_dir(entries, "5200.rom", files[5]))
+		{
+			loadosrom();
+		}
+	}
+	else
+	{
+		//printf("DIR init failed\n");
+	}
+	reboot(1);
+	for (;;) actions();
+}
+
+char const * get_ram()
+{
+	return "16K";
+}
+
+void load_cartridge(int type)
+{
+	switch(type)
+	{
+	case 4: //32k
+		loadromfile(files[4],0x8000,0x004000);
+		break;
+	case 6: // 16k two chip
+		{
+			unsigned char * src = (unsigned char *)(0x4000 + SDRAM_BASE);
+			unsigned char * dest1 = (unsigned char *)(0x6000 + SDRAM_BASE);
+			unsigned char * src2 = (unsigned char *)(0x8000 + SDRAM_BASE);
+			unsigned char * dest2 = (unsigned char *)(0xa000+ SDRAM_BASE);
+			int i = 0;
+			//*atari_colbk = 0x68;
+			//wait_us(5000000);
+
+			loadromfile(files[4],0x2000,0x004000);
+			loadromfile(files[4],0x2000,0x008000);
+	
+			for (i=0; i!=0x2000; ++i)
+			{
+				dest1[i] = src[i];
+				dest2[i] = src2[i];
+			}
+		}
+		break;
+	case 16: // 16k one chip
+		{
+			loadromfile(files[4],0x4000,0x008000);
+			unsigned char * src = (unsigned char *)(0x8000 + SDRAM_BASE);
+			unsigned char * dest1 = (unsigned char *)(0x4000 + SDRAM_BASE);
+			int i = 0;
+			for (i=0; i!=0x4000; ++i)
+			{
+				dest1[i] = src[i];
+			}
+		}
+		break;
+	case 19: // 8k
+		{
+			//*atari_colbk = 0x58;
+			//wait_us(4000000);
+			loadromfile(files[4],0x2000,0x004000);
+			unsigned char * src = (unsigned char *)(0x4000 + SDRAM_BASE);
+			unsigned char * dest1 = (unsigned char *)(0x6000 + SDRAM_BASE);
+			unsigned char * dest2 = (unsigned char *)(0x8000 + SDRAM_BASE);
+			unsigned char * dest3 = (unsigned char *)(0xa000 + SDRAM_BASE);
+			int i = 0;
+			for (i=0; i!=0x2000; ++i)
+			{
+				dest1[i] = src[i];
+				dest2[i] = src[i];
+				dest3[i] = src[i];
+			}
+		}
+		break;
+	case 20: // 4k
+		{
+			//*atari_colbk = 0x58;
+			//wait_us(4000000);
+			loadromfile(files[4],0x1000,0x004000);
+			unsigned char * src = (unsigned char *)(0x4000 + SDRAM_BASE);
+			unsigned char * dest1 = (unsigned char *)(0x5000 + SDRAM_BASE);
+			unsigned char * dest2 = (unsigned char *)(0x6000 + SDRAM_BASE);
+			unsigned char * dest3 = (unsigned char *)(0x7000 + SDRAM_BASE);
+			unsigned char * dest4 = (unsigned char *)(0x8000 + SDRAM_BASE);
+			unsigned char * dest5 = (unsigned char *)(0x9000 + SDRAM_BASE);
+			unsigned char * dest6 = (unsigned char *)(0xa000 + SDRAM_BASE);
+			unsigned char * dest7 = (unsigned char *)(0xb000 + SDRAM_BASE);
+			int i = 0;
+			for (i=0; i!=0x1000; ++i)
+			{
+				dest1[i] = src[i];
+				dest2[i] = src[i];
+				dest3[i] = src[i];
+				dest4[i] = src[i];
+				dest5[i] = src[i];
+				dest6[i] = src[i];
+				dest7[i] = src[i];
+			}
+		}
+		break;
+	default:
+		{
+			clearscreen();
+			debug_pos = 0;
+			debug_adjust = 0;
+			printf("Unknown type of cartridge!");
+			wait_us(3000000);
+		}
+		break;
+	}
+}
+
+int filter_5200(struct SimpleDirEntry * entry)
+{
+	if (dir_is_subdir(entry)) return 1;
+	char const * f = dir_filename(entry);
+	int res = (compare_ext(f,"A52") || compare_ext(f,"CAR") || compare_ext(f,"BIN"));
+	//printf("filter_disks:%s:%d\n",f,res);
+	return res;
+}
+
+void select_cartridge()
+{
+	filter = filter_5200; // .a52, .car and .bin
+	file_selector(files[4]);
+
+	// work out the type
+	char const * name = file_name(files[4]);
+	int type = -1;
+	if (compare_ext(name,"CAR"))
+	{
+		char header[16];
+		int read = 0;
+		file_read(files[4],&header,16,&read);
+		type = header[7];
+	}
+	else
+	{
+		int size = file_size(files[4]);
+
+		if (size == 32768) type = 4;
+		if (size == 16384) // uff!
+		{
+			struct joystick_status joy;
+			joy.x_ = joy.y_ = joy.fire_ = joy.escape_ = 0;
+
+			clearscreen();
+			debug_pos = 0;
+			debug_adjust = 0;
+			printf("16k cart type");
+			debug_pos = 80;
+			printf("Left for one chip");
+			debug_pos = 120;
+			printf("Right for two chip");
+
+			while(type <0)
+			{
+				joystick_wait(&joy,WAIT_QUIET);
+				joystick_wait(&joy,WAIT_EITHER);
+
+				if (joy.x_<0) type = 16;
+				if (joy.x_>0) type = 6;
+			}
+		}
+		
+		if (size == 8192) type = 19;
+		if (size == 4096) type = 20;
+	}
+
+	load_cartridge(type);
+}
+
+int settings()
+{
+	struct joystick_status joy;
+	joy.x_ = joy.y_ = joy.fire_ = joy.escape_ = 0;
+
+	int row = 0;
+
+	int done = 0;
+	for (;!done;)
+	{
+		// Render
+		clearscreen();
+		debug_pos = 0;
+		debug_adjust = 0;
+		printf("Se");
+		debug_adjust = 128;
+		printf("ttings");
+		debug_pos = 80;
+		debug_adjust = row==0 ? 128 : 0;
+		printf("Turbo:%dx", get_turbo_6502());
+		debug_pos = 120;
+		debug_adjust = row==1 ? 128 : 0;
+		printf("Ram:%s", get_ram());
+		debug_pos = 160;
+		debug_adjust = row==2 ? 128 : 0;
+		{
+			printf("Rom:%s", file_name(files[5]));
+		}
+		int i;
+
+		debug_pos = 200;
+		debug_adjust = row==3 ? 128 : 0;
+		printf("Cart:%s", file_name(files[4]) ? file_name(files[4]) : "NONE");
+
+#ifdef USBSETTINGS
+		debug_pos = 240;
+		debug_adjust = row==4 ? 128 : 0;
+		printf("Rotate USB joysticks");
+
+		debug_pos = 320;
+		debug_adjust = row==5 ? 128 : 0;
+		printf("Exit");
+
+		debug_adjust = 0;
+
+		usb_devices(400);
+#else
+		debug_pos = 240;
+		debug_adjust = row==4 ? 128 : 0;
+		printf("Exit");
+#endif
+
+/*
+while (1)
+{
+	*atari_consol = 4;
+	*atari_potgo = 0xff;
+
+	wait_us(1000000/25);
+
+	unsigned char pot0 = *atari_pot0;
+	unsigned char pot1 = *atari_pot1;
+		debug_pos = 320;
+		printf("                         ");
+		debug_pos = 320;
+		printf("pot0:%d pot1:%d",pot0,pot1);
+}*/
+
+		// Slow it down a bit
+		wait_us(100000);
+
+		// move
+		joystick_wait(&joy,WAIT_QUIET);
+		joystick_wait(&joy,WAIT_EITHER);
+		if (joy.escape_) break;
+
+		row+=joy.y_;
+		if (row<0) row = 0;
+#ifdef USBSETTINGS
+		if (row>5) row = 5;
+#else
+		if (row>4) row = 4;
+#endif
+		switch (row)
+		{
+		case 0:
+			{
+				int turbo = get_turbo_6502();
+				if (joy.x_==1) turbo<<=1;
+				if (joy.x_==-1) turbo>>=1;
+				if (turbo>16) turbo = 16;
+				if (turbo<1) turbo = 1;
+				set_turbo_6502(turbo);
+			}
+			break;
+		case 1:
+			{
+				int ram_select = get_ram_select();
+				ram_select+=joy.x_;
+				if (ram_select<0) ram_select = 0;
+				if (ram_select>7) ram_select = 7;
+				set_ram_select(ram_select);
+			}
+			break;
+		case 2:
+			{
+				if (joy.x_ || joy.fire_)
+				{
+					fil_type = fil_type_rom;
+					filter = filter_specified;
+					file_selector(files[5]);
+					loadosrom();
+				}
+			}
+			break;
+		case 3:
+			{
+				if (joy.fire_)
+				{
+					select_cartridge();
+					return 1;
+				}
+			}
+			break;
+#ifdef USBSETTINGS
+		case 4:
+			if (joy.fire_)
+			{
+				rotate_usb_sticks();
+			}
+			break;
+		case 5:
+			if (joy.fire_)
+			{
+				done = 1;
+			}
+			break;
+#else
+		case 4:
+			if (joy.fire_)
+			{
+				done = 1;
+			}
+			break;
+#endif
+		}
+	}
+
+	return 0;
+}
+
+void actions()
+{
+#ifdef LINUX_BUILD
+	check_keys();
+#endif
+#ifdef USB
+	usb_poll(&usb_porta);
+#endif
+#ifdef USB2
+	usb_poll(&usb_portb);
+#endif
+	// Show some activity!
+	//*atari_colbk = *atari_random;
+	
+	// Hot keys
+	if (get_hotkey_softboot())
+	{
+		reboot(0);	
+	}
+	else if (get_hotkey_coldboot())
+	{
+		reboot(1);	
+	}
+	else if (get_hotkey_settings())
+	{
+		set_pause_6502(1);
+		freeze();
+		debug_pos = 0;	
+		int do_reboot = settings();
+		debug_pos = -1;
+		restore();
+		if (do_reboot)
+			reboot(1);
+		else
+			set_pause_6502(0);
+	}
+	else if (get_hotkey_fileselect())
+	{
+		set_pause_6502(1);
+		freeze();
+		select_cartridge();
+		restore();
+		reboot(1);
+	}
+}
Index: firmware_legacy/5200/freeze.c
===================================================================
--- firmware_legacy/5200/freeze.c	(nonexistent)
+++ firmware_legacy/5200/freeze.c	(revision 799)
@@ -0,0 +1,127 @@
+#include "freeze.h"
+
+#include "regs.h"
+#include "memory.h"
+
+unsigned char store_portb;
+unsigned volatile char * store_mem;
+unsigned volatile char * custom_mirror;
+unsigned volatile char * atari_base;
+
+void freeze_init(void * memory)
+{
+	store_mem = (unsigned volatile char *)memory;
+
+	custom_mirror = (unsigned volatile char *)atari_regmirror;
+	atari_base = (unsigned volatile char *)atari_regbase;
+}
+
+void freeze()
+{
+	int i;
+	// store custom chips
+	//store_portb = *atari_portb;
+	{
+		//gtia
+		for (i=0xc000; i!=0xc020; i++)
+		{
+			store_mem[i] = custom_mirror[i];
+			atari_base[i] = 0;
+		}
+		//pokey1/2
+		for (i=0xe800; i!=0xe810; i++)
+		{
+			store_mem[i] = custom_mirror[i];
+			atari_base[i] = 0;
+		}
+		//antic
+		for (i=0xd400; i!=0xd410; i++)
+		{
+			store_mem[i] = custom_mirror[i];
+			atari_base[i] = 0;
+		}
+	}
+
+	//*atari_portb = 0xff;
+
+	// Copy 16k ram to sdram
+	// Atari screen memory...
+	for (i=0x0; i!=0x4000; ++i)
+	{
+		store_mem[i] = atari_base[i];
+	}
+
+	//Clear, except dl (first 0x40 bytes)
+	clearscreen();
+
+	// Put custom chips in a safe state
+	// write a display list at 0600
+	unsigned char dl[] = {
+		0x70,
+		0x70,
+		0x47,0x40,0x2c,
+		0x70,
+		0x42,0x68,0x2c,
+		0x2,0x2,0x2,0x2,0x2,
+		0x2,0x2,0x2,0x2,0x2,
+		0x2,0x2,0x2,0x2,0x2,
+		0x2,0x2,0x2,0x2,0x2,
+		0x2,0x2,
+		0x41,0x00,0x06
+	};
+	int j = 0;
+	for (i=0x0600; j!=sizeof(dl); ++i,++j)
+	{
+		atari_base[i] = dl[j];
+	}
+
+	// point antic at my display list
+	*atari_dlisth = 0x06;
+	*atari_dlistl = 0x00;
+
+	*atari_colbk = 0x00;
+	*atari_colpf0 = 0x2f;
+	*atari_colpf1 = 0x3f;
+	*atari_colpf2 = 0x00;
+	*atari_colpf3 = 0x1f;
+	*atari_prior = 0x00;
+	*atari_chbase = 0xf8;
+	*atari_dmactl = 0x22;
+	*atari_skctl = 0x2;
+	*atari_chactl = 0x2;
+	*atari_consol = 4;
+	*atari_potgo = 0xff;
+}
+
+void restore()
+{
+	int i;
+
+	// Restore memory
+	for (i=0x0; i!=0x4000; ++i)
+	{
+		atari_base[i] = store_mem[i];
+	}
+
+	// Restore custom chips
+	{
+		//gtia
+		for (i=0xc000; i!=0xc020; i++)
+		{
+			atari_base[i] = store_mem[i];
+		}
+		//pokey1/2
+		for (i=0xe800; i!=0xe810; i++)
+		{
+			atari_base[i] = store_mem[i];
+		}
+		//antic
+		for (i=0xd400; i!=0xd410; i++)
+		{
+			atari_base[i] = store_mem[i];
+		}
+	}
+
+	//*atari_portb = store_portb;
+}
+
Index: firmware_legacy/5200/joystick.c
===================================================================
--- firmware_legacy/5200/joystick.c	(nonexistent)
+++ firmware_legacy/5200/joystick.c	(revision 799)
@@ -0,0 +1,132 @@
+#include "joystick.h"
+
+#include "regs.h"
+
+//#include <stdio.h>
+//#include <printf.h>
+//extern int debug_pos;
+
+#ifdef USB
+#include "usb.h"
+#endif
+
+#ifdef USB
+extern struct usb_host usb_porta;
+#endif
+#ifdef USB2
+extern struct usb_host usb_portb;
+#endif
+
+unsigned char pot0;
+unsigned char pot1;
+unsigned char pot2;
+unsigned char pot3;
+void joystick_poll(struct joystick_status * status)
+{
+	status->x_ = 0;
+	status->y_ = 0;
+	status->fire_ = 0;
+
+#ifdef USB
+	usb_poll(&usb_porta);
+#endif
+#ifdef USB2
+	usb_poll(&usb_portb);
+#endif
+
+	int controls = get_controls();
+
+	int read = 0;
+	if (0==*atari_allpot)
+	{
+		pot0 = *atari_pot0;
+		pot1 = *atari_pot1;
+		pot2 = *atari_pot2;
+		pot3 = *atari_pot3;
+		*atari_potgo = 0xff;
+		read = 1;
+	}
+
+	unsigned char kbcode = *atari_kbcode;
+	kbcode &= 0x1e;
+
+	unsigned char key_held = *atari_skctl;
+	if ((key_held&0x4) != 0)
+	{
+		kbcode = 0x0;
+	}
+
+	//debug_pos = 400;
+	//printf("%02x %02x %02x %02x\n",pot0,pot1,*atari_allpot,read);
+
+	status->y_ = (0x8==(kbcode&0x18)) -((unsigned int)(0x18==(kbcode&0x18)));
+	status->x_ = (0x2==(kbcode&0x6)) -((unsigned int)(0x6==(kbcode&0x6)));
+
+	if (pot0>170) status->x_ =1;
+	if (pot0<60) status->x_ =-1;
+	if (pot1>170) status->y_ =1;
+	if (pot1<60) status->y_ =-1;
+	if (pot2>170) status->x_ =1;
+	if (pot2<60) status->x_ =-1;
+	if (pot3>170) status->y_ =1;
+	if (pot3<60) status->y_ =-1;
+
+	status->fire_ = (kbcode==0x14) || (!(1&*atari_trig0&*atari_trig1&*atari_trig2&*atari_trig3));
+
+	if (controls!=0)
+	{
+		status->y_ = !!(controls&0x2) -((unsigned int)!!(controls&0x1));
+		status->x_ = !!(controls&0x8) -((unsigned int)!!(controls&0x4));
+		status->fire_ = !!(controls&0x10);
+		status->escape_ = !!(controls&0x20);
+	}
+
+	//if (porta != 0xff)
+	//printf("%02x %x %x %x\n",porta,status->x_,status->y_,status->fire_);
+/*
+	if (0==(porta&0x2)) // down
+	{
+		status->y_ =1;
+	}
+	else if (0==(porta&0x1)) // up
+	{
+		status->y_ =-1;
+	}
+	if (0==(porta&0x8)) // right
+	{
+		status->x_ = 1;
+	}
+	else if (0==(porta&0x4)) // left
+	{
+		status->x_ = -1;
+	}
+	if (0==(1&*atari_trig0)) // fire
+	{
+		status->fire_ = 1;
+	}
+*/
+}
+
+void joystick_wait(struct joystick_status * status, enum JoyWait waitFor)
+{
+	while (1)
+	{
+		joystick_poll(status);
+		switch (waitFor)
+		{
+		case WAIT_QUIET:
+			if (status->x_ == 0 && status->y_ == 0 && status->fire_ == 0) return;
+			break;
+		case WAIT_FIRE:
+			if (status->fire_ == 1 || status->escape_==1) return;
+			break;
+		case WAIT_EITHER:
+			if (status->fire_ == 1) return;
+			// fall through
+		case WAIT_MOVE:
+			if (status->x_ !=0 || status->y_ != 0 || status->escape_==1) return;
+			break;
+		}
+	}
+}
+
Index: firmware_legacy/a800/mainmenu.c
===================================================================
--- firmware_legacy/a800/mainmenu.c	(nonexistent)
+++ firmware_legacy/a800/mainmenu.c	(revision 799)
@@ -0,0 +1,495 @@
+static const int main_ram_size=65536;
+#include "main.h" //!!!
+#include "atari_drive_emulator.h"
+#include "log.h"
+#include "utils.h"
+
+unsigned char freezer_rom_present;
+
+void loadosrom()
+{
+	if (file_size(files[5]) == 0x4000)
+	{
+		loadromfile(files[5],0x4000, ROM_OFS + 0x4000);
+	}
+	else if (file_size(files[5]) ==0x2800)
+	{
+		loadromfile(files[5],0x2800, ROM_OFS + 0x5800);
+	}
+}
+
+#ifdef USB
+struct usb_host usb_porta;
+#endif
+#ifdef USB2
+struct usb_host usb_portb;
+#endif
+
+/*
+void test_ram()
+{
+	int i;
+	unsigned char volatile * addr = DIR_INIT_MEM;
+	int k;
+	for (k=0;k<DIR_INIT_MEMSIZE;++k)
+	{
+		addr[k] = k&0xff;
+	}
+	int ok = 1;
+	for (k=0;k<DIR_INIT_MEMSIZE;++k)
+	{
+		unsigned char val = addr[k];
+		if (val != (k&0xff))
+		{
+			ok = 0;
+		}
+	}
+
+	int j =0;
+	if (ok)
+	{
+		while(1)
+		{
+			++j;
+			if (j&1)
+				*atari_colbk = 0xc8;
+			else
+				*atari_colbk = 0x00;
+		}
+	}
+	else
+	{
+		while(1)
+		{
+			++j;
+			if (j&1)
+				*atari_colbk = 0x38;
+			else
+				*atari_colbk = 0x00;
+		}
+	}
+}
+*/
+
+void mainmenu()
+{
+#ifdef USB
+	usb_init(&usb_porta,0);
+#endif
+#ifdef USB2
+	usb_init(&usb_portb,1);
+#endif
+	freezer_rom_present = 0;
+	if (SimpleFile_OK == dir_init((void *)DIR_INIT_MEM, DIR_INIT_MEMSIZE))
+	{
+		#ifdef USB
+			usb_log_init(files[7]);
+		#endif
+
+		//test_ram();
+
+		init_drive_emulator();
+		
+		struct SimpleDirEntry * entries = dir_entries(ROM_DIR);
+		
+		//loadrom_indir(entries,"atarixl.rom",0x4000, (void *)0x704000);
+
+		/*loadrom_indir(entries,"xlhias.rom",0x4000, (void *)0x708000);
+		loadrom_indir(entries,"ultimon.rom",0x4000, (void *)0x70c000);
+		loadrom_indir(entries,"osbhias.rom",0x4000, (void *)0x710000);
+		loadrom_indir(entries,"osborig.rom",0x2800, (void *)0x715800);
+		loadrom_indir(entries,"osaorig.rom",0x2800, (void *)0x719800);*/
+
+		loadrom_indir(entries,"ataribas.rom",0x2000,ROM_OFS);
+		if (SimpleFile_OK == file_open_name_in_dir(entries, "atarixl.rom", files[5]))
+		{
+			loadosrom();
+		}
+
+#ifdef HAVE_FREEZER_ROM_MEM
+		if (SimpleFile_OK == file_open_name_in_dir(entries, "freezer.rom", files[6]))
+		{
+			enum SimpleFileStatus ok;
+			int len;
+			ok = file_read(files[6], FREEZER_ROM_MEM, 0x10000, &len);
+			if (ok == SimpleFile_OK && len == 0x10000) {
+				LOG("freezer rom loaded\n");
+				freezer_rom_present = 1;
+			} else {
+				LOG("loading freezer rom failed\n");
+				freezer_rom_present = 0;
+			}
+		} else {
+			LOG("freezer.rom not found\n");
+		}
+#endif
+		set_freezer_enable(freezer_rom_present);
+
+		//ROM = xlorig.rom,0x4000, (void *)0x704000
+		//ROM = xlhias.rom,0x4000, (void *)0x708000
+		//ROM = ultimon.rom,0x4000, (void *)0x70c000
+		//ROM = osbhias.rom,0x4000, (void *)0x710000
+		//ROM = osborig.rom,0x2800, (void *)0x715800
+		//ROM = osaorig.rom,0x2800, (void *)0x719800
+		//
+		//ROM = ataribas.rom,0x2000,(void *)0x700000
+
+		//--SDRAM_BASIC_ROM_ADDR <= "111"&"000000"   &"00000000000000";
+		//--SDRAM_OS_ROM_ADDR    <= "111"&rom_select &"00000000000000";
+		reboot(1);
+		run_drive_emulator();
+	}
+	else
+	{
+		//printf("DIR init failed\n");
+	}
+	reboot(1);
+	for (;;) actions(1);
+}
+
+char const * get_ram()
+{
+	static char const * ram[] = 
+	{
+		"64K",
+		"128K",
+		"320K(Compy)",
+		"320K(Rambo)",
+		"576K(Compy)",
+		"576K(Rambo)",
+		"1MB",
+		"4MB"
+	};
+	return ram[get_ram_select()];
+	/*switch(get_ram_select())
+	{
+	case 0:
+		return "64K";
+	case 1:
+		return "128K";
+	case 2:
+		return "320K(Compy)";
+	case 3:
+		return "320K(Rambo)";
+	case 4:
+		return "576K(Compy)";
+	case 5:
+		return "576K(Rambo)";
+	case 6:
+		return "1MB";
+	case 7:
+		return "4MB";
+	}*/
+}
+
+
+int settings()
+{
+	struct joystick_status joy;
+	joy.x_ = joy.y_ = joy.fire_ = joy.escape_ = 0;
+
+	int row = 0;
+
+	int done = 0;
+	for (;!done;)
+	{
+		// Render
+		clearscreen();
+		debug_pos = 0;
+		debug_adjust = 0;
+		printf("Se");
+		debug_adjust = 128;
+		printf("ttings");
+		debug_pos = 80;
+		debug_adjust = row==0 ? 128 : 0;
+		printf("CPU Turbo:%dx", get_turbo_6502());
+		debug_pos = 120;
+		debug_adjust = row==1 ? 128 : 0;
+		printf("Drive Turbo:%s", get_turbo_drive_str());
+		debug_pos = 160;
+		debug_adjust = row==2 ? 128 : 0;
+		printf("Ram:%s", get_ram());
+		debug_pos = 200;
+		debug_adjust = row==3 ? 128 : 0;
+		{
+			printf("Rom:%s", file_name(files[5]));
+		}
+		debug_pos = 280;
+		int i;
+		for (i=1;i!=5;++i)
+		{
+			int temp = debug_pos;
+			debug_adjust = row==i+3 ? 128 : 0;
+			char buffer[20];
+			describe_disk(i-1,&buffer[0]);
+			printf("Drive %d:%s %s", i, file_name(files[i-1]), &buffer[0]);
+			debug_pos = temp+40;
+		}
+
+		debug_pos = 440;
+		debug_adjust = row==8 ? 128 : 0;
+		printf("Cart: %s", get_cart_select() ? file_name(files[4]) : "NONE");
+
+/*		debug_pos = 520;
+		debug_adjust = row==9 ? 128 : 0;
+		printf("Load memory");
+
+		debug_pos = 560;
+		debug_adjust = row==10 ? 128 : 0;
+		printf("Save memory (for debugging)");*/
+
+
+#ifdef USBSETTINGS
+		debug_pos = 480;
+		debug_adjust = row==9 ? 128 : 0;
+		printf("Rotate USB joysticks");
+
+		debug_pos = 560;
+		debug_adjust = row==10 ? 128 : 0;
+		printf("Exit");
+
+		debug_adjust = 0;
+
+		usb_devices(640);
+#else
+		debug_pos = 520;
+		debug_adjust = row==9 ? 128 : 0;
+		printf("Exit");
+#endif
+
+		// Slow it down a bit
+		wait_us(100000);
+
+		// move
+		joystick_wait(&joy,WAIT_QUIET);
+		joystick_wait(&joy,WAIT_EITHER);
+		if (joy.escape_) break;
+
+		row+=joy.y_;
+		if (row<0) row = 0;
+#ifdef USBSETTINGS
+		if (row>10) row = 10;
+#else
+		if (row>9) row = 9;
+#endif
+		switch (row)
+		{
+		case 0:
+			{
+				int turbo = get_turbo_6502();
+				if (joy.x_==1) turbo<<=1;
+				if (joy.x_==-1) turbo>>=1;
+				if (turbo>16) turbo = 16;
+				if (turbo<1) turbo = 1;
+				set_turbo_6502(turbo);
+			}
+			break;
+		case 1:
+			{
+				int turbo = get_turbo_drive();
+				turbo+=joy.x_;
+				if (turbo<0) turbo = 0;
+				if (turbo>7) turbo = 7;
+				set_turbo_drive(turbo);
+			}
+			break;
+		case 2:
+			{
+				int ram_select = get_ram_select();
+				ram_select+=joy.x_;
+				if (ram_select<0) ram_select = 0;
+				if (ram_select>MAX_RAM_SELECT) ram_select = MAX_RAM_SELECT;
+				set_ram_select(ram_select);
+			}
+			break;
+		case 3:
+			{
+				if (joy.x_ || joy.fire_)
+				{
+					fil_type = fil_type_rom;
+					filter = filter_specified;
+					file_selector(files[5]);
+					loadosrom();
+				}
+			}
+			break;
+		case 4:
+		case 5:
+		case 6:
+		case 7:
+			{
+				if (joy.x_>0)
+				{
+					// Choose new disk
+					filter = filter_disks;
+					file_selector(files[row-4]);
+					set_drive_status(row-4,files[row-4]);
+				}
+				else if(joy.x_<0)
+				{
+					// Remove disk
+					file_init(files[row-4]);
+					set_drive_status(row-4,0);
+				}
+				else if (joy.fire_)
+				{
+					{
+						// Swap files
+						struct SimpleFile * temp = files[row-4];
+						files[row-4] = files[0];
+						files[0] = temp;
+					}
+
+					{
+						// Swap disks
+						struct SimpleFile * temp = get_drive_status(row-4);
+						set_drive_status(row-4, get_drive_status(0));
+						set_drive_status(0,temp);
+					}
+				}
+			}
+			break;
+		case 8:
+			{
+				if (joy.x_>0) {
+					fil_type = fil_type_car;
+					filter = filter_specified;
+					file_selector(files[4]);
+					unsigned char mode = load_car(files[4]);
+					set_cart_select(mode);
+					if (mode) {
+						return 1;
+					}
+				}
+				else if (joy.x_<0) {
+					file_init(files[4]);
+					set_cart_select(0);
+				}
+			}
+			break;
+/*		case 9:
+		case 10:
+			{
+				if (joy.fire_)
+				{
+					fil_type = fil_type_mem;
+					filter = filter_specified;
+					file_selector(files[6]);
+					if (row == 9)
+					{
+						freeze_load(files[6]);
+					}
+					else if (row == 10)
+					{
+						freeze_save(files[6]);
+					}
+				}
+			}
+			break;*/
+#ifdef USBSETTINGS
+		case 9:
+			if (joy.fire_)
+			{
+				rotate_usb_sticks();
+			}
+			break;
+		case 10:
+			if (joy.fire_)
+			{
+				done = 1;
+			}
+			break;
+#else
+		case 9:
+			if (joy.fire_)
+			{
+				done = 1;
+			}
+			break;
+#endif
+		}
+	}
+
+	return 0;
+}
+
+void actions()
+{
+#ifdef LINUX_BUILD
+	check_keys();
+#endif
+#ifdef USB
+	usb_poll(&usb_porta);
+#endif
+#ifdef USB2
+	usb_poll(&usb_portb);
+#endif
+
+	// Show some activity!
+	//*atari_colbk = *atari_random;
+	
+	// Hot keys
+	if (get_hotkey_softboot())
+	{
+		reboot(0);	
+	}
+	else if (get_hotkey_coldboot())
+	{
+		reboot(1);	
+	}
+	else if (get_hotkey_settings())
+	{
+		set_pause_6502(1);
+		set_freezer_enable(0);
+		freeze();
+		debug_pos = 0;	
+		int do_reboot = settings();
+		debug_pos = -1;
+		restore();
+		if (do_reboot)
+			reboot(1);
+		else {
+			set_freezer_enable(freezer_rom_present);
+			set_pause_6502(0);
+		}
+	}
+	else if (get_hotkey_fileselect())
+	{
+/*#ifdef USB
+		set_pause_6502(1);
+		set_freezer_enable(0);
+		freeze();
+
+		debug_pos = 0;	
+		printf("Hello USB");
+		debug_pos = 80;
+		usb_init();
+		while (1)
+		{
+			usb_poll();
+			if (debug_pos>1000)
+			{
+				debug_pos = 80;
+			}
+		}
+
+		debug_pos = -1;
+		restore();
+		set_freezer_enable(freezer_rom_present);
+		set_pause_6502(0);
+#else*/
+		set_pause_6502(1);
+		set_freezer_enable(0);
+		freeze();
+		filter = filter_disks;
+		file_selector(files[0]);
+		debug_pos = -1;
+		restore();
+		set_drive_status(0,files[0]);
+		reboot(1);
+	}
+}
+
+
+
+
Index: firmware_legacy/a800/joystick.c
===================================================================
--- firmware_legacy/a800/joystick.c	(nonexistent)
+++ firmware_legacy/a800/joystick.c	(revision 799)
@@ -0,0 +1,98 @@
+#include "joystick.h"
+
+#include "regs.h"
+//#include "io.h"
+
+//#include <stdio.h>
+
+#ifdef USB
+#include "usb.h"
+#endif
+
+#ifdef USB
+extern struct usb_host usb_porta;
+#endif
+#ifdef USB2
+extern struct usb_host usb_portb;
+#endif
+
+void joystick_poll(struct joystick_status * status)
+{
+	status->x_ = 0;
+	status->y_ = 0;
+	status->fire_ = 0;
+	status->escape_ = 0;
+
+#ifdef USB
+	usb_poll(&usb_porta);
+#endif
+#ifdef USB2
+	usb_poll(&usb_portb);
+#endif
+
+	unsigned char porta = *atari_porta;
+	porta = (porta>>4) & (porta);
+
+	int controls = get_controls();
+
+	status->y_ = !(porta&0x2) -((unsigned int)!(porta&0x1));
+	status->x_ = !(porta&0x8) -((unsigned int)!(porta&0x4));
+	status->fire_ = !(1&*atari_trig0&*atari_trig1);
+
+	if (controls!=0)
+	{
+		status->y_ = !!(controls&0x2) -((unsigned int)!!(controls&0x1));
+		status->x_ = !!(controls&0x8) -((unsigned int)!!(controls&0x4));
+		status->fire_ = !!(controls&0x10);
+		status->escape_ = !!(controls&0x20);
+	}
+
+	//if (porta != 0xff)
+	//printf("%02x %x %x %x\n",porta,status->x_,status->y_,status->fire_);
+/*
+	if (0==(porta&0x2)) // down
+	{
+		status->y_ =1;
+	}
+	else if (0==(porta&0x1)) // up
+	{
+		status->y_ =-1;
+	}
+	if (0==(porta&0x8)) // right
+	{
+		status->x_ = 1;
+	}
+	else if (0==(porta&0x4)) // left
+	{
+		status->x_ = -1;
+	}
+	if (0==(1&*atari_trig0)) // fire
+	{
+		status->fire_ = 1;
+	}
+*/
+}
+
+void joystick_wait(struct joystick_status * status, enum JoyWait waitFor)
+{
+	while (1)
+	{
+		joystick_poll(status);
+		switch (waitFor)
+		{
+		case WAIT_QUIET:
+			if (status->x_ == 0 && status->y_ == 0 && status->fire_ == 0) return;
+			break;
+		case WAIT_FIRE:
+			if (status->fire_ == 1 || status->escape_==1) return;
+			break;
+		case WAIT_EITHER:
+			if (status->fire_ == 1) return;
+			// fall through
+		case WAIT_MOVE:
+			if (status->x_ !=0 || status->y_ != 0 || status->escape_==1) return;
+			break;
+		}
+	}
+}
+
Index: firmware_legacy/a800/freeze.c
===================================================================
--- firmware_legacy/a800/freeze.c	(nonexistent)
+++ firmware_legacy/a800/freeze.c	(revision 799)
@@ -0,0 +1,140 @@
+#include "freeze.h"
+
+#include "regs.h"
+#include "memory.h"
+
+unsigned volatile char * store_mem;
+unsigned volatile char * custom_mirror;
+unsigned volatile char * atari_base;
+
+// TODO - almost the same as 5200 one
+// skctl, chbase and lack of portb to merge into one file...
+
+void memset8(void * address, int value, int length);
+
+// Moving this outside function removes gcc pulling in memcpy
+unsigned char dl[] = {
+	0x70,
+	0x70,
+	0x47,0x40,0x2c,
+	0x70,
+	0x42,0x68,0x2c,
+	0x2,0x2,0x2,0x2,0x2,
+	0x2,0x2,0x2,0x2,0x2,
+	0x2,0x2,0x2,0x2,0x2,
+	0x2,0x2,0x2,0x2,0x2,
+	0x2,0x2,
+	0x41,0x00,0x06
+};
+
+void freeze_init(void * memory)
+{
+	store_mem = (unsigned volatile char *)memory;
+
+	custom_mirror = (unsigned volatile char *)atari_regmirror;
+	atari_base = (unsigned volatile char *)atari_regbase;
+}
+
+void memcp8(char const volatile * from, char volatile * to, int offset, int len)
+{
+	from+=offset;
+	to+=offset;
+	while (len--)
+		*to++ = *from++;
+}
+
+void freeze()
+{
+	int i;
+	// store custom chips
+	store_mem[0xd300] = *atari_portb;
+	{
+		//backup last value written to custom chip regs
+		//gtia
+		memcp8(custom_mirror,store_mem,0xd000,0x20);
+		//pokey1/2
+		memcp8(custom_mirror,store_mem,0xd200,0x20);
+		//antic
+		memcp8(custom_mirror,store_mem,0xd400,0x10);
+
+		// Write 0 to custom chip regs
+		memset8(atari_base+0xd000,0,0x20);
+		memset8(atari_base+0xd200,0,0x20);
+		memset8(atari_base+0xd400,0,0x10);
+	}
+
+	*atari_portb = 0xff;
+
+	// Copy 64k ram to sdram
+	// Atari screen memory...
+	memcp8(atari_base,store_mem,0,0xd000);
+	memcp8(atari_base,store_mem,0xd800,0x2800);
+
+	//Clear, except dl (first 0x40 bytes)
+	clearscreen();
+
+	// Put custom chips in a safe state
+	// write a display list at 0600
+	memcp8(dl,atari_base+0x600,0,sizeof(dl));
+
+	// point antic at my display list
+	*atari_dlisth = 0x06;
+	*atari_dlistl = 0x00;
+
+	*atari_colbk = 0x00;
+	*atari_colpf0 = 0x2f;
+	*atari_colpf1 = 0x3f;
+	*atari_colpf2 = 0x00;
+	*atari_colpf3 = 0x1f;
+	*atari_prior = 0x00;
+	*atari_chbase = 0xe0;
+	*atari_dmactl = 0x22;
+	*atari_skctl = 0x3;
+	*atari_chactl = 0x2;
+}
+
+void restore()
+{
+	// Restore memory
+	memcp8(store_mem,atari_base,0,0xd000);
+	memcp8(store_mem,atari_base,0xd800,0x2800);
+
+	// Restore custom chips
+	{
+		// gtia
+		memcp8(store_mem,atari_base,0xd000,0x20);
+		// pokey
+		memcp8(store_mem,atari_base,0xd200,0x20);
+		// antic
+		memcp8(store_mem,atari_base,0xd400,0x10);
+	}
+
+	*atari_portb = store_mem[0xd300];
+}
+
+void freeze_save(struct SimpleFile * file)
+{
+	if (file_size(file)>=65536 && file_readonly(file)==0)
+	{
+		int byteswritten = 0;
+		file_write(file,(void *)store_mem,65536,&byteswritten);
+		file_write_flush();
+	}
+}
+void freeze_load(struct SimpleFile * file)
+{
+	if (file_size(file)>=65536)
+	{
+		int bytesread = 0;
+		file_read(file,(void *)store_mem,65536,&bytesread);
+	}
+}
+
+
+/*
+enum SimpleFileStatus file_read(struct SimpleFile * file, void * buffer, int bytes, int * bytesread);
+
+enum SimpleFileStatus file_write(struct SimpleFile * file, void * buffer, int bytes, int * byteswritten);
+enum SimpleFileStatus file_write_flush();
+*/
+
Index: firmware_legacy/main.h
===================================================================
--- firmware_legacy/main.h	(nonexistent)
+++ firmware_legacy/main.h	(revision 799)
@@ -0,0 +1,378 @@
+#include <alloca.h>
+#include <sys/types.h>
+#include "integer.h"
+#include "regs.h"
+#include "pause.h"
+#include "printf.h"
+#include "joystick.h"
+#include "freeze.h"
+
+#include "simpledir.h"
+#include "simplefile.h"
+#include "fileselector.h"
+#include "cartridge.h"
+
+#ifdef LINUX_BUILD
+#include "curses_screen.h"
+#define after_set_reg_hook() display_out_regs()
+#else
+#define after_set_reg_hook() do { } while(0)
+#endif
+
+#ifdef USB
+#include "usb.h"
+#include "usb/debug.h"
+#define USBSETTINGS
+#endif
+
+#include "memory.h"
+
+extern char ROM_DIR[];
+extern unsigned char freezer_rom_present;
+
+void mainmenu();
+
+// TODO - needs serious cleanup!
+
+// FUNCTIONS in here
+// i) pff init - NOT USED EVERYWHERE
+// ii) file selector - kind of crap, no fine scrolling - NOT USED EVERYWHERE
+// iii) cold reset atari (clears base ram...)
+// iv) start atari (begins paused)
+// v) freeze/resume atari - NOT USED EVERYWHERE!
+// vi) menu for various options - NOT USED EVERYWHERE!
+// vii) pause - TODO - base this on pokey clock...
+
+// standard ZPU IN/OUT use...
+// OUT1 - 6502 settings (pause,reset,speed)
+// pause_n: bit 0 
+// reset_n: bit 1
+// turbo: bit 2-4: meaning... 0=1.79Mhz,1=3.58MHz,2=7.16MHz,3=14.32MHz,4=28.64MHz,5=57.28MHz,etc.
+// ram_select: bit 5-7: 
+//   		RAM_SELECT : in std_logic_vector(2 downto 0); -- 64K,128K,320KB Compy, 320KB Rambo, 576K Compy, 576K Rambo, 1088K, 4MB
+
+#define BIT_REG(op,mask,shift,name,reg) \
+int get_ ## name() \
+{ \
+	int val = *reg; \
+	return op((val>>shift)&mask); \
+} \
+void set_ ## name(int param) \
+{ \
+	int val = *reg; \
+	 \
+	val = (val&~(mask<<shift)); \
+	val |= op(param)<<shift; \
+	 \
+	*reg = val; \
+	after_set_reg_hook(); \
+}
+
+#define BIT_REG_RO(op,mask,shift,name,reg) \
+int get_ ## name() \
+{ \
+	int val = *reg; \
+	return op((val>>shift)&mask); \
+}
+
+BIT_REG(,0x1,0,pause_6502,zpu_out1)
+BIT_REG(,0x1,1,reset_6502,zpu_out1)
+BIT_REG(,0x3f,2,turbo_6502,zpu_out1)
+BIT_REG(,0x7,8,ram_select,zpu_out1)
+//BIT_REG(,0x3f,11,rom_select,zpu_out1)
+BIT_REG(,0x3f,17,cart_select,zpu_out1)
+// reserve 2 bits for extending cart_select
+BIT_REG(,0x01,25,freezer_enable,zpu_out1)
+
+BIT_REG_RO(,0x1,8,hotkey_softboot,zpu_in1)
+BIT_REG_RO(,0x1,9,hotkey_coldboot,zpu_in1)
+BIT_REG_RO(,0x1,10,hotkey_fileselect,zpu_in1)
+BIT_REG_RO(,0x1,11,hotkey_settings,zpu_in1)
+
+BIT_REG_RO(,0x3f,12,controls,zpu_in1) // (esc)FLRDU
+
+
+void
+wait_us(int unsigned num)
+{
+	// pause counter runs at pokey frequency - should be 1.79MHz
+	int unsigned cycles = (num*230)>>7;
+	*zpu_pause = cycles;
+#ifdef LINUX_BUILD
+	usleep(num);
+#endif
+#ifdef SOCKIT
+	usleep(num);
+#endif
+}
+
+void memset8(void * address, int value, int length)
+{
+	char * mem = address;
+	while (length--)
+		*mem++=value;
+}
+
+void memset32(void * address, int value, int length)
+{
+	int * mem = address;
+	while (length--)
+		*mem++=value;
+}
+
+void clear_main_ram()
+{
+	memset8(SRAM_BASE, 0, main_ram_size); // SRAM, if present (TODO)
+	memset32(SDRAM_BASE, 0, main_ram_size/4);
+}
+
+void
+reboot(int cold)
+{
+	set_pause_6502(1);
+	if (cold)
+	{
+		set_freezer_enable(0);
+		clear_main_ram();
+		set_freezer_enable(freezer_rom_present);
+	}
+	set_reset_6502(1);
+	// Do nothing in here - this resets the memory controller!
+	set_reset_6502(0);
+	set_pause_6502(0);
+}
+
+unsigned char toatarichar(int val)
+{
+	int inv = val>=128;
+	if (inv)
+	{
+		val-=128;
+	}
+	if (val>='A' && val<='Z')
+	{
+		val+=-'A'+33;
+	}
+	else if (val>='a' && val<='z')
+	{
+		val+=-'a'+33+64;
+	}
+	else if (val>='0' && val<='9')
+	{
+		val+=-'0'+16;	
+	}
+	else if (val>=32 && val<=47)
+	{
+		val+=-32;
+	}
+	else if (val == ':')
+	{
+		val = 26;
+	}
+	else
+	{
+		val = 0;
+	}
+	if (inv)
+	{
+		val+=128;
+	}
+	return val;
+}
+
+int debug_pos;
+int debug_adjust;
+unsigned char volatile * baseaddr;
+
+#ifdef LINUX_BUILD
+void char_out(void* p, char c)
+{
+	// get rid of unused parameter p warning
+	(void)(p);
+	int x, y;
+	x = debug_pos % 40;
+	y = debug_pos / 40;
+	display_char(x, y, c, debug_adjust == 128);
+	debug_pos++;
+}
+
+#else
+void clearscreen()
+{
+	unsigned volatile char * screen;
+	for (screen=(unsigned volatile char *)(screen_address+atari_regbase); screen!=(unsigned volatile char *)(atari_regbase+screen_address+1024); ++screen)
+		*screen = 0x00;
+}
+
+void char_out ( void* p, char c)
+{
+	unsigned char val = toatarichar(c);
+	if (debug_pos>=0)
+	{
+		*(baseaddr+debug_pos) = val|debug_adjust;
+		++debug_pos;
+	}
+}
+#endif
+
+#define NUM_FILES 8
+struct SimpleFile * files[NUM_FILES];
+
+void loadromfile(struct SimpleFile * file, int size, size_t ram_address)
+{
+	void* absolute_ram_address = SDRAM_BASE + ram_address;
+	int read = 0;
+	file_read(file, absolute_ram_address, size, &read);
+}
+
+void loadrom(char const * path, int size, size_t ram_address)
+{
+	if (SimpleFile_OK == file_open_name(path, files[5]))
+	{
+		loadromfile(files[5], size, ram_address);
+	}
+}
+
+void loadrom_indir(struct SimpleDirEntry * entries, char const * filename, int size, size_t ram_address)
+{
+	if (SimpleFile_OK == file_open_name_in_dir(entries, filename, files[5]))
+	{
+		loadromfile(files[5], size, ram_address);
+	}
+}
+
+#ifdef LINUX_BUILD
+int zpu_main(void)
+#else
+int main(void)
+#endif
+{
+	INIT_MEM
+
+	fil_type_rom = "ROM";
+	fil_type_bin = "BIN";
+	fil_type_car = "CAR";
+	fil_type_mem = "MEM";
+
+	int i;
+	for (i=0; i!=NUM_FILES; ++i)
+	{
+		files[i] = (struct SimpleFile *)alloca(file_struct_size());
+		file_init(files[i]);
+	}
+
+	freeze_init((void*)FREEZE_MEM); // 128k
+
+	debug_pos = -1;
+	debug_adjust = 0;
+	baseaddr = (unsigned char volatile *)(screen_address + atari_regbase);
+	set_pause_6502(1);
+	set_reset_6502(1);
+	set_reset_6502(0);
+	set_turbo_6502(1);
+	set_ram_select(2);
+	set_cart_select(0);
+	set_freezer_enable(0);
+
+	init_printf(0, char_out);
+
+	mainmenu();
+	return 0;
+}
+
+#ifdef USBSETTINGS
+void rotate_usb_sticks()
+{
+	int max_jindex = hid_get_joysticks()-1;
+	if (max_jindex == 0) // If only one stick connected allow it to be 0 or 1
+	{
+		max_jindex = 1;
+	}
+
+	int i;
+
+	usb_device_t * devices = usb_get_devices();
+	for (i=0;i!=USB_NUMDEVICES;++i)	
+	{
+		usb_device_t *dev  = devices + i;
+		if (dev->bAddress)
+		{
+			if (dev->class == &usb_hid_class)
+			{
+				int j=0;
+				for (j=0;j!=dev->hid_info.bNumIfaces;++j)
+				{
+					int type = dev->hid_info.iface[j].device_type;
+					if (type == HID_DEVICE_JOYSTICK)
+					{
+						int jindex = dev->hid_info.iface[j].jindex;
+						event_digital_joystick(jindex, 0);
+						event_analog_joystick(jindex, 0,0);
+
+						jindex++;
+						if (jindex > max_jindex)
+							jindex = 0;
+						
+						dev->hid_info.iface[j].jindex = jindex;
+					}
+				}
+			}
+		}
+	}
+}
+
+void usb_devices(int debugPos)
+{
+	usb_device_t *devices = usb_get_devices();
+	int nextDebugPos = debugPos;
+	int i=0;
+	int j=0;
+	for (i=0;i!=USB_NUMDEVICES;++i)	
+	{
+		debug_pos = nextDebugPos;
+		usb_device_t *dev  = devices + i;
+		if (dev->bAddress)
+		{
+			if (dev->class == &usb_hub_class)
+			{
+				//printf("%x.Hub. %d ports. poll=%d",dev->bAddress,dev->hub_info.bNbrPorts, dev->hub_info.bPollEnable);
+				printf("%x.Hub. %d ports",dev->bAddress,dev->hub_info.bNbrPorts);
+			}
+			else if (dev->class == &usb_hid_class)
+			{
+				//printf("%x.HID. %d ifaces. poll=%d",dev->bAddress,dev->hid_info.bNumIfaces,dev->hid_info.bPollEnable);
+				printf("%x.HID",dev->bAddress);
+				int adjPos = 0;
+				for (j=0;j!=dev->hid_info.bNumIfaces;++j)
+				{
+					//usb_device_descriptor_t desc;
+					int type = dev->hid_info.iface[j].device_type;
+					if (adjPos && (type == HID_DEVICE_MOUSE || type == HID_DEVICE_KEYBOARD || type == HID_DEVICE_JOYSTICK))
+					{
+						nextDebugPos = nextDebugPos+40;
+						debug_pos = nextDebugPos;
+					}
+					if (type == HID_DEVICE_MOUSE)
+						printf(" Mouse");
+					else if (type == HID_DEVICE_KEYBOARD)
+						printf(" Keyboard");
+					else if (type == HID_DEVICE_JOYSTICK)
+					{
+						printf(" Joystick:%d",dev->hid_info.iface[j].jindex+1);
+					}
+					else
+						continue;
+
+					adjPos = 1;
+
+					/*int rcode = usb_get_dev_descr( dev, 12, &desc );
+					if( !rcode ) {
+						printf(" V:%02x%02x P:%02x%02x C:%02x",desc.idVendorH,desc.idVendorL,desc.idProductH,desc.idProductL,desc.bDeviceClass);
+					}*/
+				}
+			}
+		}
+		nextDebugPos = nextDebugPos+40;
+	}
+}
+#endif
Index: firmware_legacy/mif_file_stuff/rom_epilogue.vhd
===================================================================
--- firmware_legacy/mif_file_stuff/rom_epilogue.vhd	(nonexistent)
+++ firmware_legacy/mif_file_stuff/rom_epilogue.vhd	(revision 799)
@@ -0,0 +1 @@
+END; 
Index: firmware_legacy/mif_file_stuff/zpuromgen.c
===================================================================
--- firmware_legacy/mif_file_stuff/zpuromgen.c	(nonexistent)
+++ firmware_legacy/mif_file_stuff/zpuromgen.c	(revision 799)
@@ -0,0 +1,59 @@
+// zpuromgen.c
+//
+// Program to turn a binary file into a VHDL lookup table.
+//   by Adam Pierce
+//   29-Feb-2008
+//
+// This software is free to use by anyone for any purpose.
+//
+
+#include <unistd.h>
+#include <stdio.h>
+
+typedef unsigned char BYTE;
+
+main(int argc, char **argv)
+{
+       BYTE    opcode[4];
+       int     fd;
+       int     addr = 0;
+       ssize_t s;
+
+// Check the user has given us an input file.
+       if(argc < 2)
+       {
+               printf("Usage: %s <binary_file>\n\n", argv[0]);
+               return 1;
+       }
+
+// Open the input file.
+       fd = open(argv[1], 0);
+       if(fd == -1)
+       {
+               perror("File Open");
+               return 2;
+       }
+
+       while(1)
+       {
+       // Read 32 bits.
+               s = read(fd, opcode, 4);
+               if(s == -1)
+               {
+                       perror("File read");
+                       return 3;
+               }
+
+               if(s == 0)
+                       break; // End of file.
+
+       // Output to STDOUT.
+               printf("%04x : %02x%02x%02x%02x;\n",
+                      addr++, opcode[0], opcode[1],
+                      opcode[2], opcode[3]);
+       }
+
+       close(fd);
+       return 0;
+}
+
Index: firmware_legacy/fat/pff.c
===================================================================
--- firmware_legacy/fat/pff.c	(nonexistent)
+++ firmware_legacy/fat/pff.c	(revision 799)
@@ -0,0 +1,1141 @@
+/*----------------------------------------------------------------------------/
+/  Petit FatFs - FAT file system module  R0.03                (C)ChaN, 2014
+/-----------------------------------------------------------------------------/
+/ Petit FatFs module is a generic FAT file system module for small embedded
+/ systems. This is a free software that opened for education, research and
+/ commercial developments under license policy of following trems.
+/
+/  Copyright (C) 2014, ChaN, all right reserved.
+/
+/ * The Petit FatFs module is a free software and there is NO WARRANTY.
+/ * No restriction on use. You can use, modify and redistribute it for
+/   personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY.
+/ * Redistributions of source code must retain the above copyright notice.
+/
+/-----------------------------------------------------------------------------/
+/ Jun 15,'09  R0.01a  First release.
+/
+/ Dec 14,'09  R0.02   Added multiple code page support.
+/                     Added write funciton.
+/                     Changed stream read mode interface.
+/ Dec 07,'10  R0.02a  Added some configuration options.
+/                     Fixed fails to open objects with DBCS character.
+
+/ Jun 10,'14  R0.03   Separated out configuration options to pffconf.h.
+/                     Added _USE_LCC option.
+/                     Added _FS_FAT16 option.
+/----------------------------------------------------------------------------*/
+
+#include "pff.h"		/* Petit FatFs configurations and declarations */
+#include "diskio.h"		/* Declarations of low level disk I/O functions */
+//#include "printf.h"
+
+
+
+/*--------------------------------------------------------------------------
+
+   Module Private Definitions
+
+---------------------------------------------------------------------------*/
+
+
+#if _PFATFS != 4004	/* Revision ID */
+#error Wrong include file (pff.h).
+#endif
+
+#if _FS_FAT32
+#if !_FS_FAT16 && !_FS_FAT12
+#define _FS_32ONLY 1
+#else
+#define _FS_32ONLY 0
+#endif
+#else
+#if !_FS_FAT16 && !_FS_FAT12
+#error Wrong _FS_FATxx setting.
+#endif
+#define _FS_32ONLY 0
+#endif
+
+#define ABORT(err)	{fs->flag = 0; return err;}
+
+
+
+/*--------------------------------------------------------*/
+/* DBCS code ranges and SBCS extend char conversion table */
+/*--------------------------------------------------------*/
+
+#if _CODE_PAGE == 932	/* Japanese Shift-JIS */
+#define _DF1S	0x81	/* DBC 1st byte range 1 start */
+#define _DF1E	0x9F	/* DBC 1st byte range 1 end */
+#define _DF2S	0xE0	/* DBC 1st byte range 2 start */
+#define _DF2E	0xFC	/* DBC 1st byte range 2 end */
+#define _DS1S	0x40	/* DBC 2nd byte range 1 start */
+#define _DS1E	0x7E	/* DBC 2nd byte range 1 end */
+#define _DS2S	0x80	/* DBC 2nd byte range 2 start */
+#define _DS2E	0xFC	/* DBC 2nd byte range 2 end */
+
+#elif _CODE_PAGE == 936	/* Simplified Chinese GBK */
+#define _DF1S	0x81
+#define _DF1E	0xFE
+#define _DS1S	0x40
+#define _DS1E	0x7E
+#define _DS2S	0x80
+#define _DS2E	0xFE
+
+#elif _CODE_PAGE == 949	/* Korean */
+#define _DF1S	0x81
+#define _DF1E	0xFE
+#define _DS1S	0x41
+#define _DS1E	0x5A
+#define _DS2S	0x61
+#define _DS2E	0x7A
+#define _DS3S	0x81
+#define _DS3E	0xFE
+
+#elif _CODE_PAGE == 950	/* Traditional Chinese Big5 */
+#define _DF1S	0x81
+#define _DF1E	0xFE
+#define _DS1S	0x40
+#define _DS1E	0x7E
+#define _DS2S	0xA1
+#define _DS2E	0xFE
+
+#elif _CODE_PAGE == 437	/* U.S. (OEM) */
+#define _EXCVT {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F,0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+				0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+				0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 720	/* Arabic (OEM) */
+#define _EXCVT {0x80,0x81,0x45,0x41,0x84,0x41,0x86,0x43,0x45,0x45,0x45,0x49,0x49,0x8D,0x8E,0x8F,0x90,0x92,0x92,0x93,0x94,0x95,0x49,0x49,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+				0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+				0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 737	/* Greek (OEM) */
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x92,0x92,0x93,0x94,0x95,0x96,0x97,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, \
+				0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0xAA,0x92,0x93,0x94,0x95,0x96,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+				0x97,0xEA,0xEB,0xEC,0xE4,0xED,0xEE,0xE7,0xE8,0xF1,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 775	/* Baltic (OEM) */
+#define _EXCVT {0x80,0x9A,0x91,0xA0,0x8E,0x95,0x8F,0x80,0xAD,0xED,0x8A,0x8A,0xA1,0x8D,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0x95,0x96,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \
+				0xA0,0xA1,0xE0,0xA3,0xA3,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xA5,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+				0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE3,0xE8,0xE8,0xEA,0xEA,0xEE,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 850	/* Multilingual Latin 1 (OEM) */
+#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0xDE,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x59,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \
+				0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+				0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE7,0xE9,0xEA,0xEB,0xED,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 852	/* Latin 2 (OEM) */
+#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xDE,0x8F,0x80,0x9D,0xD3,0x8A,0x8A,0xD7,0x8D,0x8E,0x8F,0x90,0x91,0x91,0xE2,0x99,0x95,0x95,0x97,0x97,0x99,0x9A,0x9B,0x9B,0x9D,0x9E,0x9F, \
+				0xB5,0xD6,0xE0,0xE9,0xA4,0xA4,0xA6,0xA6,0xA8,0xA8,0xAA,0x8D,0xAC,0xB8,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBD,0xBF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC6,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD2,0xD3,0xD2,0xD5,0xD6,0xD7,0xB7,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+				0xE0,0xE1,0xE2,0xE3,0xE3,0xD5,0xE6,0xE6,0xE8,0xE9,0xE8,0xEB,0xED,0xED,0xDD,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xEB,0xFC,0xFC,0xFE,0xFF}
+
+#elif _CODE_PAGE == 855	/* Cyrillic (OEM) */
+#define _EXCVT {0x81,0x81,0x83,0x83,0x85,0x85,0x87,0x87,0x89,0x89,0x8B,0x8B,0x8D,0x8D,0x8F,0x8F,0x91,0x91,0x93,0x93,0x95,0x95,0x97,0x97,0x99,0x99,0x9B,0x9B,0x9D,0x9D,0x9F,0x9F, \
+				0xA1,0xA1,0xA3,0xA3,0xA5,0xA5,0xA7,0xA7,0xA9,0xA9,0xAB,0xAB,0xAD,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB6,0xB6,0xB8,0xB8,0xB9,0xBA,0xBB,0xBC,0xBE,0xBE,0xBF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD3,0xD3,0xD5,0xD5,0xD7,0xD7,0xDD,0xD9,0xDA,0xDB,0xDC,0xDD,0xE0,0xDF, \
+				0xE0,0xE2,0xE2,0xE4,0xE4,0xE6,0xE6,0xE8,0xE8,0xEA,0xEA,0xEC,0xEC,0xEE,0xEE,0xEF,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 857	/* Turkish (OEM) */
+#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0x98,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x98,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9E, \
+				0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA6,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+				0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xDE,0x59,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 858	/* Multilingual Latin 1 + Euro (OEM) */
+#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0xDE,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x59,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \
+				0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+				0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE7,0xE9,0xEA,0xEB,0xED,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 862	/* Hebrew (OEM) */
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+				0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+				0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 866	/* Russian (OEM) */
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+				0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+				0x90,0x91,0x92,0x93,0x9d,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 874	/* Thai (OEM, Windows) */
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+				0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+				0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 1250 /* Central Europe (Windows) */
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x8D,0x8E,0x8F, \
+				0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xA3,0xB4,0xB5,0xB6,0xB7,0xB8,0xA5,0xAA,0xBB,0xBC,0xBD,0xBC,0xAF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xFF}
+
+#elif _CODE_PAGE == 1251 /* Cyrillic (Windows) */
+#define _EXCVT {0x80,0x81,0x82,0x82,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x80,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x8D,0x8E,0x8F, \
+				0xA0,0xA2,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB2,0xA5,0xB5,0xB6,0xB7,0xA8,0xB9,0xAA,0xBB,0xA3,0xBD,0xBD,0xAF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF}
+
+#elif _CODE_PAGE == 1252 /* Latin 1 (Windows) */
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0xAd,0x9B,0x8C,0x9D,0xAE,0x9F, \
+				0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x9F}
+
+#elif _CODE_PAGE == 1253 /* Greek (Windows) */
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+				0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xA2,0xB8,0xB9,0xBA, \
+				0xE0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xF2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xFB,0xBC,0xFD,0xBF,0xFF}
+
+#elif _CODE_PAGE == 1254 /* Turkish (Windows) */
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x9D,0x9E,0x9F, \
+				0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x9F}
+
+#elif _CODE_PAGE == 1255 /* Hebrew (Windows) */
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+				0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+				0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 1256 /* Arabic (Windows) */
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x8C,0x9D,0x9E,0x9F, \
+				0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+				0x41,0xE1,0x41,0xE3,0xE4,0xE5,0xE6,0x43,0x45,0x45,0x45,0x45,0xEC,0xED,0x49,0x49,0xF0,0xF1,0xF2,0xF3,0x4F,0xF5,0xF6,0xF7,0xF8,0x55,0xFA,0x55,0x55,0xFD,0xFE,0xFF}
+
+#elif _CODE_PAGE == 1257 /* Baltic (Windows) */
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+				0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xA8,0xB9,0xAA,0xBB,0xBC,0xBD,0xBE,0xAF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xFF}
+
+#elif _CODE_PAGE == 1258 /* Vietnam (OEM, Windows) */
+#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0xAC,0x9D,0x9E,0x9F, \
+				0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+				0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xEC,0xCD,0xCE,0xCF,0xD0,0xD1,0xF2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xFE,0x9F}
+
+#else
+#error Unknown code page.
+
+#endif
+
+
+
+/* Character code support macros */
+
+#define IsUpper(c)	(((c)>='A')&&((c)<='Z'))
+#define IsLower(c)	(((c)>='a')&&((c)<='z'))
+
+#ifndef _EXCVT	/* DBCS configuration */
+
+#ifdef _DF2S	/* Two 1st byte areas */
+#define IsDBCS1(c)	(((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) || ((BYTE)(c) >= _DF2S && (BYTE)(c) <= _DF2E))
+#else			/* One 1st byte area */
+#define IsDBCS1(c)	((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E)
+#endif
+
+#ifdef _DS3S	/* Three 2nd byte areas */
+#define IsDBCS2(c)	(((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E) || ((BYTE)(c) >= _DS3S && (BYTE)(c) <= _DS3E))
+#else			/* Two 2nd byte areas */
+#define IsDBCS2(c)	(((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E))
+#endif
+
+#else			/* SBCS configuration */
+
+#define IsDBCS1(c)	0
+#define IsDBCS2(c)	0
+
+#endif /* _EXCVT */
+
+
+/* FatFs refers the members in the FAT structures with byte offset instead
+/ of structure member because there are incompatibility of the packing option
+/ between various compilers. */
+
+#define BS_jmpBoot			0
+#define BS_OEMName			3
+#define BPB_BytsPerSec		11
+#define BPB_SecPerClus		13
+#define BPB_RsvdSecCnt		14
+#define BPB_NumFATs			16
+#define BPB_RootEntCnt		17
+#define BPB_TotSec16		19
+#define BPB_Media			21
+#define BPB_FATSz16			22
+#define BPB_SecPerTrk		24
+#define BPB_NumHeads		26
+#define BPB_HiddSec			28
+#define BPB_TotSec32		32
+#define BS_55AA				510
+
+#define BS_DrvNum			36
+#define BS_BootSig			38
+#define BS_VolID			39
+#define BS_VolLab			43
+#define BS_FilSysType		54
+
+#define BPB_FATSz32			36
+#define BPB_ExtFlags		40
+#define BPB_FSVer			42
+#define BPB_RootClus		44
+#define BPB_FSInfo			48
+#define BPB_BkBootSec		50
+#define BS_DrvNum32			64
+#define BS_BootSig32		66
+#define BS_VolID32			67
+#define BS_VolLab32			71
+#define BS_FilSysType32		82
+
+#define MBR_Table			446
+
+#define	DIR_Name			0
+#define	DIR_Attr			11
+#define	DIR_NTres			12
+#define	DIR_CrtTime			14
+#define	DIR_CrtDate			16
+#define	DIR_FstClusHI		20
+#define	DIR_WrtTime			22
+#define	DIR_WrtDate			24
+#define	DIR_FstClusLO		26
+#define	DIR_FileSize		28
+
+
+
+/*--------------------------------------------------------------------------
+
+   Private Functions
+
+---------------------------------------------------------------------------*/
+
+
+static
+FATFS *FatFs;	/* Pointer to the file system object (logical drive) */
+
+
+/* Fill memory */
+static
+void mem_set (void* dst, int val, int cnt) {
+	char *d = (char*)dst;
+	while (cnt--) *d++ = (char)val;
+}
+
+/* Compare memory to memory */
+static
+int mem_cmp (const void* dst, const void* src, int cnt) {
+	const char *d = (const char *)dst, *s = (const char *)src;
+	int r = 0;
+	while (cnt-- && (r = *d++ - *s++) == 0) ;
+	return r;
+}
+
+
+
+/*-----------------------------------------------------------------------*/
+/* FAT access - Read value of a FAT entry                                */
+/*-----------------------------------------------------------------------*/
+
+static
+CLUST get_fat (	/* 1:IO error, Else:Cluster status */
+	CLUST clst	/* Cluster# to get the link information */
+)
+{
+	BYTE buf[4];
+	FATFS *fs = FatFs;
+
+	if (clst < 2 || clst >= fs->n_fatent)	/* Range check */
+		return 1;
+
+	switch (fs->fs_type) {
+#if _FS_FAT12
+	case FS_FAT12 : {
+		UINT wc, bc, ofs;
+
+		bc = (UINT)clst; bc += bc / 2;
+		ofs = bc % 512; bc /= 512;
+		if (ofs != 511) {
+			if (disk_readp(buf, fs->fatbase + bc, ofs, 2)) break;
+		} else {
+			if (disk_readp(buf, fs->fatbase + bc, 511, 1)) break;
+			if (disk_readp(buf+1, fs->fatbase + bc + 1, 0, 1)) break;
+		}
+		wc = LD_WORD(buf);
+		return (clst & 1) ? (wc >> 4) : (wc & 0xFFF);
+	}
+#endif
+#if _FS_FAT16
+	case FS_FAT16 :
+		if (disk_readp(buf, fs->fatbase + clst / 256, ((UINT)clst % 256) * 2, 2)) break;
+		return LD_WORD(buf);
+#endif
+#if _FS_FAT32
+	case FS_FAT32 :
+		if (disk_readp(buf, fs->fatbase + clst / 128, ((UINT)clst % 128) * 4, 4)) break;
+		return LD_DWORD(buf) & 0x0FFFFFFF;
+#endif
+	}
+
+	return 1;	/* An error occured at the disk I/O layer */
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Get sector# from cluster# / Get cluster field from directory entry    */
+/*-----------------------------------------------------------------------*/
+
+static
+DWORD clust2sect (	/* !=0: Sector number, 0: Failed - invalid cluster# */
+	CLUST clst		/* Cluster# to be converted */
+)
+{
+	FATFS *fs = FatFs;
+
+
+	clst -= 2;
+	if (clst >= (fs->n_fatent - 2)) return 0;		/* Invalid cluster# */
+	return (DWORD)clst * fs->csize + fs->database;
+}
+
+
+static
+CLUST get_clust (
+	BYTE* dir		/* Pointer to directory entry */
+)
+{
+	FATFS *fs = FatFs;
+	CLUST clst = 0;
+
+
+	if (_FS_32ONLY || (_FS_FAT32 && fs->fs_type == FS_FAT32)) {
+		clst = LD_WORD(dir+DIR_FstClusHI);
+		clst <<= 16;
+	}
+	clst |= LD_WORD(dir+DIR_FstClusLO);
+
+	return clst;
+}
+
+
+/*-----------------------------------------------------------------------*/
+/* Directory handling - Rewind directory index                           */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT dir_rewind (
+	DIR *dj			/* Pointer to directory object */
+)
+{
+	CLUST clst;
+	FATFS *fs = FatFs;
+
+
+	dj->index = 0;
+	clst = dj->sclust;
+	if (clst == 1 || clst >= fs->n_fatent)	/* Check start cluster range */
+		return FR_DISK_ERR;
+	if (_FS_FAT32 && !clst && (_FS_32ONLY || fs->fs_type == FS_FAT32))	/* Replace cluster# 0 with root cluster# if in FAT32 */
+		clst = (CLUST)fs->dirbase;
+	dj->clust = clst;						/* Current cluster */
+	dj->sect = (_FS_32ONLY || clst) ? clust2sect(clst) : fs->dirbase;	/* Current sector */
+
+	return FR_OK;	/* Seek succeeded */
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Directory handling - Move directory index next                        */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT dir_next2 (	/* FR_OK:Succeeded, FR_NO_FILE:End of table */
+	DIR *dj			/* Pointer to directory object */
+)
+{
+	CLUST clst;
+	WORD i;
+	FATFS *fs = FatFs;
+
+
+	i = dj->index + 1;
+	if (!i || !dj->sect)	/* Report EOT when index has reached 65535 */
+		return FR_NO_FILE;
+
+	if (!(i % 16)) {		/* Sector changed? */
+		dj->sect++;			/* Next sector */
+
+		if (dj->clust == 0) {	/* Static table */
+			if (i >= fs->n_rootdir)	/* Report EOT when end of table */
+				return FR_NO_FILE;
+		}
+		else {					/* Dynamic table */
+			if (((i / 16) & (fs->csize - 1)) == 0) {	/* Cluster changed? */
+				clst = get_fat(dj->clust);		/* Get next cluster */
+				if (clst <= 1) return FR_DISK_ERR;
+				if (clst >= fs->n_fatent)		/* When it reached end of dynamic table */
+					return FR_NO_FILE;			/* Report EOT */
+				dj->clust = clst;				/* Initialize data for new cluster */
+				dj->sect = clust2sect(clst);
+			}
+		}
+	}
+
+	dj->index = i;
+
+	return FR_OK;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Directory handling - Find an object in the directory                  */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT dir_find (
+	DIR *dj,		/* Pointer to the directory object linked to the file name */
+	BYTE *dir		/* 32-byte working buffer */
+)
+{
+	FRESULT res;
+	BYTE c;
+
+
+	res = dir_rewind(dj);			/* Rewind directory object */
+	if (res != FR_OK) return res;
+
+	do {
+		res = disk_readp(dir, dj->sect, (dj->index % 16) * 32, 32)	/* Read an entry */
+			? FR_DISK_ERR : FR_OK;
+		if (res != FR_OK) break;
+		c = dir[DIR_Name];	/* First character */
+		if (c == 0) { res = FR_NO_FILE; break; }	/* Reached to end of table */
+		if (!(dir[DIR_Attr] & AM_VOL) && !mem_cmp(dir, dj->fn, 11)) /* Is it a valid entry? */
+			break;
+		res = dir_next2(dj);					/* Next entry */
+	} while (res == FR_OK);
+
+	return res;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Read an object from the directory                                     */
+/*-----------------------------------------------------------------------*/
+#if _USE_DIR
+static
+FRESULT dir_read (
+	DIR *dj,		/* Pointer to the directory object to store read object name */
+	BYTE *dir,		/* 32-byte working buffer */
+	char *lfn_buffer        /* 256-byte lfn buffer */
+)
+{
+	FRESULT res;
+	BYTE a, c;
+
+	int lfn = 0;
+	char *lfn_pos = &lfn_buffer[255];
+	lfn_buffer[255] = '\0';
+
+	res = FR_NO_FILE;
+	while (dj->sect) {
+		res = disk_readp(dir, dj->sect, (dj->index % 16) * 32, 32)	/* Read an entry */
+			? FR_DISK_ERR : FR_OK;
+		if (res != FR_OK) break;
+		c = dir[DIR_Name];
+		if (c == 0) { res = FR_NO_FILE; break; }	/* Reached to end of table */
+		a = dir[DIR_Attr] & AM_MASK;
+
+	//	printf("LFN2:%x:%x:%x:%x\n",a&AM_LFN==AM_LFN,dir[0],dir[0x1a],dir[0x1c]);
+		if (a&AM_LFN == AM_LFN && ((dir[0]&0xbf) < 16) && dir[0x1a]==0) // && dir[0x1c]!=0)
+		{
+			lfn_pos-=13;
+			char * ptr = lfn_pos;
+			int i;
+			for (i=1;i!=32;i+=2)
+			{
+				if (i==0xb) i=0xe;
+				if (i==0x1a) i=0x1c;
+				char b1 = dir[i];
+				char b2 = dir[i+1];
+				if (b2==0) *ptr++ = b1; else *ptr++ = '_';
+			}
+			//printf("LFN seq:%d %c%c%c%c%c%c%c%c%c%c%c%c%c \n",dir[0],dir[1],dir[3],dir[5],dir[7],dir[9],dir[14],dir[16],dir[18],dir[20],dir[22],dir[24],dir[28],dir[30]);
+			lfn = 1;
+		}
+
+
+		if (c != 0xE5 && c != '.' && !(a & AM_VOL))	/* Is it a valid entry? */
+			break;
+		res = dir_next2(dj);			/* Next entry */
+		if (res != FR_OK) break;
+	}
+
+	lfn_buffer[0] = '\0';
+	if (lfn)
+	{
+		strcpy(&lfn_buffer[0],lfn_pos);
+	}
+
+	if (res != FR_OK) dj->sect = 0;
+
+	return res;
+}
+#endif
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Pick a segment and create the object name in directory form           */
+/*-----------------------------------------------------------------------*/
+
+
+static
+FRESULT create_name (
+	DIR *dj,			/* Pointer to the directory object */
+	const char **path	/* Pointer to pointer to the segment in the path string */
+)
+{
+	BYTE c, ni, si, i, *sfn;
+	const char *p;
+#if _USE_LCC
+#ifdef _EXCVT
+	static const BYTE cvt[] = _EXCVT;
+#endif
+#endif
+
+	/* Create file name in directory form */
+	sfn = dj->fn;
+	mem_set(sfn, ' ', 11);
+	si = i = 0; ni = 8;
+	p = *path;
+	for (;;) {
+		c = p[si++];
+		if (c <= ' ' || c == '/') break;	/* Break on end of segment */
+		if (c == '.' || i >= ni) {
+			if (ni != 8 || c != '.') break;
+			i = 8; ni = 11;
+			continue;
+		}
+#if _USE_LCC
+#ifdef _EXCVT
+		if (c >= 0x80)					/* To upper extended char (SBCS) */
+			c = cvt[c - 0x80];
+#endif
+		if (IsDBCS1(c) && i < ni - 1) {	/* DBC 1st byte? */
+			BYTE d = p[si++];			/* Get 2nd byte */
+			sfn[i++] = c;
+			sfn[i++] = d;
+		} else
+#endif
+		{						/* Single byte code */
+			if (_USE_LCC && IsLower(c)) c -= 0x20;	/* toupper */
+			sfn[i++] = c;
+		}
+	}
+	*path = &p[si];						/* Rerurn pointer to the next segment */
+
+	sfn[11] = (c <= ' ') ? 1 : 0;		/* Set last segment flag if end of path */
+
+	return FR_OK;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Get file information from directory entry                             */
+/*-----------------------------------------------------------------------*/
+#if _USE_DIR
+static
+void get_fileinfo (		/* No return code */
+	DIR *dj,			/* Pointer to the directory object */
+	BYTE *dir,			/* 32-byte working buffer */
+	FILINFO *fno	 	/* Pointer to store the file information */
+)
+{
+	BYTE i, c;
+	char *p;
+
+
+	p = fno->fname;
+	if (dj->sect) {
+		for (i = 0; i < 8; i++) {	/* Copy file name body */
+			c = dir[i];
+			if (c == ' ') break;
+			if (c == 0x05) c = 0xE5;
+			*p++ = c;
+		}
+		if (dir[8] != ' ') {		/* Copy file name extension */
+			*p++ = '.';
+			for (i = 8; i < 11; i++) {
+				c = dir[i];
+				if (c == ' ') break;
+				*p++ = c;
+			}
+		}
+		fno->fattrib = dir[DIR_Attr];				/* Attribute */
+		fno->fsize = LD_DWORD(dir+DIR_FileSize);	/* Size */
+		fno->fdate = LD_WORD(dir+DIR_WrtDate);		/* Date */
+		fno->ftime = LD_WORD(dir+DIR_WrtTime);		/* Time */
+	}
+	*p = 0;
+}
+#endif /* _USE_DIR */
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Follow a file path                                                    */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT follow_path (	/* FR_OK(0): successful, !=0: error code */
+	DIR *dj,			/* Directory object to return last directory and found object */
+	BYTE *dir,			/* 32-byte working buffer */
+	const char *path	/* Full-path string to find a file or directory */
+)
+{
+	FRESULT res;
+
+
+	while (*path == ' ') path++;		/* Strip leading spaces */
+	if (*path == '/') path++;			/* Strip heading separator if exist */
+	dj->sclust = 0;						/* Set start directory (always root dir) */
+
+	if ((BYTE)*path < ' ') {			/* Null path means the root directory */
+		res = dir_rewind(dj);
+		dir[0] = 0;
+
+	} else {							/* Follow path */
+		for (;;) {
+			res = create_name(dj, &path);	/* Get a segment */
+			if (res != FR_OK) break;
+			res = dir_find(dj, dir);		/* Find it */
+			if (res != FR_OK) break;		/* Could not find the object */
+			if (dj->fn[11]) break;			/* Last segment match. Function completed. */
+			if (!(dir[DIR_Attr] & AM_DIR)) { /* Cannot follow path because it is a file */
+				res = FR_NO_FILE; break;
+			}
+			dj->sclust = get_clust(dir);	/* Follow next */
+		}
+	}
+
+	return res;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Check a sector if it is an FAT boot record                            */
+/*-----------------------------------------------------------------------*/
+
+static
+BYTE check_fs (	/* 0:The FAT boot record, 1:Valid boot record but not an FAT, 2:Not a boot record, 3:Error */
+	BYTE *buf,	/* Working buffer */
+	DWORD sect	/* Sector# (lba) to check if it is an FAT boot record or not */
+)
+{
+	if (disk_readp(buf, sect, 510, 2))		/* Read the boot record */
+		return 3;
+	if (LD_WORD(buf) != 0xAA55)				/* Check record signature */
+		return 2;
+
+	if (!_FS_32ONLY && !disk_readp(buf, sect, BS_FilSysType, 2) && LD_WORD(buf) == 0x4146)	/* Check FAT12/16 */
+		return 0;
+	if (_FS_FAT32 && !disk_readp(buf, sect, BS_FilSysType32, 2) && LD_WORD(buf) == 0x4146)	/* Check FAT32 */
+		return 0;
+	return 1;
+}
+
+
+
+
+/*--------------------------------------------------------------------------
+
+   Public Functions
+
+--------------------------------------------------------------------------*/
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Mount/Unmount a Locical Drive                                         */
+/*-----------------------------------------------------------------------*/
+
+FRESULT pf_mount (
+	FATFS *fs		/* Pointer to new file system object */
+)
+{
+	BYTE fmt, buf[36];
+	DWORD bsect, fsize, tsect, mclst;
+
+
+	FatFs = 0;
+
+	if (disk_initialize() & STA_NOINIT)	/* Check if the drive is ready or not */
+		return FR_NOT_READY;
+
+	/* Search FAT partition on the drive */
+	bsect = 0;
+	fmt = check_fs(buf, bsect);			/* Check sector 0 as an SFD format */
+	if (fmt == 1) {						/* Not an FAT boot record, it may be FDISK format */
+		/* Check a partition listed in top of the partition table */
+		if (disk_readp(buf, bsect, MBR_Table, 16)) {	/* 1st partition entry */
+			fmt = 3;
+		} else {
+			if (buf[4]) {					/* Is the partition existing? */
+				bsect = LD_DWORD(&buf[8]);	/* Partition offset in LBA */
+				fmt = check_fs(buf, bsect);	/* Check the partition */
+			}
+		}
+	}
+	if (fmt == 3) return FR_DISK_ERR;
+	if (fmt) return FR_NO_FILESYSTEM;	/* No valid FAT patition is found */
+
+	/* Initialize the file system object */
+	if (disk_readp(buf, bsect, 13, sizeof (buf))) return FR_DISK_ERR;
+
+	fsize = LD_WORD(buf+BPB_FATSz16-13);				/* Number of sectors per FAT */
+	if (!fsize) fsize = LD_DWORD(buf+BPB_FATSz32-13);
+
+	fsize *= buf[BPB_NumFATs-13];						/* Number of sectors in FAT area */
+	fs->fatbase = bsect + LD_WORD(buf+BPB_RsvdSecCnt-13); /* FAT start sector (lba) */
+	fs->csize = buf[BPB_SecPerClus-13];					/* Number of sectors per cluster */
+	fs->n_rootdir = LD_WORD(buf+BPB_RootEntCnt-13);		/* Nmuber of root directory entries */
+	tsect = LD_WORD(buf+BPB_TotSec16-13);				/* Number of sectors on the file system */
+	if (!tsect) tsect = LD_DWORD(buf+BPB_TotSec32-13);
+	mclst = (tsect						/* Last cluster# + 1 */
+		- LD_WORD(buf+BPB_RsvdSecCnt-13) - fsize - fs->n_rootdir / 16
+		) / fs->csize + 2;
+	fs->n_fatent = (CLUST)mclst;
+
+	fmt = 0;							/* Determine the FAT sub type */
+	if (_FS_FAT12 && mclst < 0xFF7)
+		fmt = FS_FAT12;
+	if (_FS_FAT16 && mclst >= 0xFF8 && mclst < 0xFFF7)
+		fmt = FS_FAT16;
+	if (_FS_FAT32 && mclst >= 0xFFF7)
+		fmt = FS_FAT32;
+	if (!fmt) return FR_NO_FILESYSTEM;
+	fs->fs_type = fmt;
+
+	if (_FS_32ONLY || (_FS_FAT32 && fmt == FS_FAT32))
+		fs->dirbase = LD_DWORD(buf+(BPB_RootClus-13));	/* Root directory start cluster */
+	else
+		fs->dirbase = fs->fatbase + fsize;				/* Root directory start sector (lba) */
+	fs->database = fs->fatbase + fsize + fs->n_rootdir / 16;	/* Data start sector (lba) */
+
+	fs->flag = 0;
+	FatFs = fs;
+
+	return FR_OK;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Open or Create a File                                                 */
+/*-----------------------------------------------------------------------*/
+
+FRESULT pf_open (
+	const char *path	/* Pointer to the file name */
+)
+{
+	FRESULT res;
+	DIR dj;
+	BYTE sp[12], dir[32];
+	FATFS *fs = FatFs;
+
+
+	if (!fs) return FR_NOT_ENABLED;		/* Check file system */
+
+	fs->flag = 0;
+	dj.fn = sp;
+	res = follow_path(&dj, dir, path);	/* Follow the file path */
+	if (res != FR_OK) return res;		/* Follow failed */
+	if (!dir[0] || (dir[DIR_Attr] & AM_DIR))	/* It is a directory */
+		return FR_NO_FILE;
+
+	fs->org_clust = get_clust(dir);		/* File start cluster */
+	fs->fsize = LD_DWORD(dir+DIR_FileSize);	/* File size */
+	fs->fptr = 0;						/* File pointer */
+	fs->flag = FA_OPENED;
+
+	return FR_OK;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Read File                                                             */
+/*-----------------------------------------------------------------------*/
+#if _USE_READ
+
+FRESULT pf_read (
+	void* buff,		/* Pointer to the read buffer (NULL:Forward data to the stream)*/
+	UINT btr,		/* Number of bytes to read */
+	UINT* br		/* Pointer to number of bytes read */
+)
+{
+	DRESULT dr;
+	CLUST clst;
+	DWORD sect, remain;
+	UINT rcnt;
+	BYTE cs, *rbuff = (BYTE *)buff;
+	FATFS *fs = FatFs;
+
+
+	*br = 0;
+	if (!fs) return FR_NOT_ENABLED;		/* Check file system */
+	if (!(fs->flag & FA_OPENED))		/* Check if opened */
+		return FR_NOT_OPENED;
+
+	remain = fs->fsize - fs->fptr;
+	if (btr > remain) btr = (UINT)remain;			/* Truncate btr by remaining bytes */
+
+	while (btr)	{									/* Repeat until all data transferred */
+		if ((fs->fptr % 512) == 0) {				/* On the sector boundary? */
+			cs = (BYTE)(fs->fptr / 512 & (fs->csize - 1));	/* Sector offset in the cluster */
+			if (!cs) {								/* On the cluster boundary? */
+				if (fs->fptr == 0)					/* On the top of the file? */
+					clst = fs->org_clust;
+				else
+					clst = get_fat(fs->curr_clust);
+				if (clst <= 1) ABORT(FR_DISK_ERR);
+				fs->curr_clust = clst;				/* Update current cluster */
+			}
+			sect = clust2sect(fs->curr_clust);		/* Get current sector */
+			if (!sect) ABORT(FR_DISK_ERR);
+			fs->dsect = sect + cs;
+		}
+		rcnt = 512 - (UINT)fs->fptr % 512;			/* Get partial sector data from sector buffer */
+		if (rcnt > btr) rcnt = btr;
+		dr = disk_readp(!buff ? 0 : rbuff, fs->dsect, (UINT)fs->fptr % 512, rcnt);
+		if (dr) ABORT(FR_DISK_ERR);
+		fs->fptr += rcnt; rbuff += rcnt;			/* Update pointers and counters */
+		btr -= rcnt; *br += rcnt;
+	}
+
+	return FR_OK;
+}
+#endif
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Write File                                                            */
+/*-----------------------------------------------------------------------*/
+#if _USE_WRITE
+
+FRESULT pf_write (
+	const void* buff,	/* Pointer to the data to be written */
+	UINT btw,			/* Number of bytes to write (0:Finalize the current write operation) */
+	UINT* bw			/* Pointer to number of bytes written */
+)
+{
+	CLUST clst;
+	DWORD sect, remain;
+	const BYTE *p = buff;
+	BYTE cs;
+	UINT wcnt;
+	FATFS *fs = FatFs;
+
+
+	*bw = 0;
+	if (!fs) return FR_NOT_ENABLED;		/* Check file system */
+	if (!(fs->flag & FA_OPENED))		/* Check if opened */
+		return FR_NOT_OPENED;
+
+	if (!btw) {		/* Finalize request */
+		if ((fs->flag & FA__WIP) && disk_writep(0, 0)) ABORT(FR_DISK_ERR);
+		fs->flag &= ~FA__WIP;
+		return FR_OK;
+	} else {		/* Write data request */
+		if (!(fs->flag & FA__WIP))		/* Round-down fptr to the sector boundary */
+			fs->fptr &= 0xFFFFFE00;
+	}
+	remain = fs->fsize - fs->fptr;
+	if (btw > remain) btw = (UINT)remain;			/* Truncate btw by remaining bytes */
+
+	while (btw)	{									/* Repeat until all data transferred */
+		if ((UINT)fs->fptr % 512 == 0) {			/* On the sector boundary? */
+			cs = (BYTE)(fs->fptr / 512 & (fs->csize - 1));	/* Sector offset in the cluster */
+			if (!cs) {								/* On the cluster boundary? */
+				if (fs->fptr == 0)					/* On the top of the file? */
+					clst = fs->org_clust;
+				else
+					clst = get_fat(fs->curr_clust);
+				if (clst <= 1) ABORT(FR_DISK_ERR);
+				fs->curr_clust = clst;				/* Update current cluster */
+			}
+			sect = clust2sect(fs->curr_clust);		/* Get current sector */
+			if (!sect) ABORT(FR_DISK_ERR);
+			fs->dsect = sect + cs;
+			if (disk_writep(0, fs->dsect)) ABORT(FR_DISK_ERR);	/* Initiate a sector write operation */
+			fs->flag |= FA__WIP;
+		}
+		wcnt = 512 - (UINT)fs->fptr % 512;			/* Number of bytes to write to the sector */
+		if (wcnt > btw) wcnt = btw;
+		if (disk_writep(p, wcnt)) ABORT(FR_DISK_ERR);	/* Send data to the sector */
+		fs->fptr += wcnt; p += wcnt;				/* Update pointers and counters */
+		btw -= wcnt; *bw += wcnt;
+		if ((UINT)fs->fptr % 512 == 0) {
+			if (disk_writep(0, 0)) ABORT(FR_DISK_ERR);	/* Finalize the currtent secter write operation */
+			fs->flag &= ~FA__WIP;
+		}
+	}
+
+	return FR_OK;
+}
+#endif
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Seek File R/W Pointer                                                 */
+/*-----------------------------------------------------------------------*/
+#if _USE_LSEEK
+
+FRESULT pf_lseek (
+	DWORD ofs		/* File pointer from top of file */
+)
+{
+	CLUST clst;
+	DWORD bcs, sect, ifptr;
+	FATFS *fs = FatFs;
+
+
+	if (!fs) return FR_NOT_ENABLED;		/* Check file system */
+	if (!(fs->flag & FA_OPENED))		/* Check if opened */
+			return FR_NOT_OPENED;
+
+	if (ofs > fs->fsize) ofs = fs->fsize;	/* Clip offset with the file size */
+	ifptr = fs->fptr;
+	fs->fptr = 0;
+	if (ofs > 0) {
+		bcs = (DWORD)fs->csize * 512;	/* Cluster size (byte) */
+		if (ifptr > 0 &&
+			(ofs - 1) / bcs >= (ifptr - 1) / bcs) {	/* When seek to same or following cluster, */
+			fs->fptr = (ifptr - 1) & ~(bcs - 1);	/* start from the current cluster */
+			ofs -= fs->fptr;
+			clst = fs->curr_clust;
+		} else {							/* When seek to back cluster, */
+			clst = fs->org_clust;			/* start from the first cluster */
+			fs->curr_clust = clst;
+		}
+		while (ofs > bcs) {				/* Cluster following loop */
+			clst = get_fat(clst);		/* Follow cluster chain */
+			if (clst <= 1 || clst >= fs->n_fatent) ABORT(FR_DISK_ERR);
+			fs->curr_clust = clst;
+			fs->fptr += bcs;
+			ofs -= bcs;
+		}
+		fs->fptr += ofs;
+		sect = clust2sect(clst);		/* Current sector */
+		if (!sect) ABORT(FR_DISK_ERR);
+		fs->dsect = sect + (fs->fptr / 512 & (fs->csize - 1));
+	}
+
+	return FR_OK;
+}
+#endif
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Create a Directroy Object                                             */
+/*-----------------------------------------------------------------------*/
+#if _USE_DIR
+
+FRESULT pf_opendir (
+	DIR *dj,			/* Pointer to directory object to create */
+	const char *path	/* Pointer to the directory path */
+)
+{
+	FRESULT res;
+	BYTE sp[12], dir[32];
+	FATFS *fs = FatFs;
+
+
+	if (!fs) {				/* Check file system */
+		res = FR_NOT_ENABLED;
+	} else {
+		dj->fn = sp;
+		res = follow_path(dj, dir, path);		/* Follow the path to the directory */
+		if (res == FR_OK) {						/* Follow completed */
+			if (dir[0]) {						/* It is not the root dir */
+				if (dir[DIR_Attr] & AM_DIR)		/* The object is a directory */
+					dj->sclust = get_clust(dir);
+				else							/* The object is not a directory */
+					res = FR_NO_FILE;
+			}
+			if (res == FR_OK)
+				res = dir_rewind(dj);			/* Rewind dir */
+		}
+	}
+
+	return res;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Read Directory Entry in Sequense                                      */
+/*-----------------------------------------------------------------------*/
+
+FRESULT pf_readdir (
+	DIR *dj,			/* Pointer to the open directory object */
+	FILINFO *fno		/* Pointer to file information to return */
+)
+{
+	FRESULT res;
+	BYTE sp[12], dir[32];
+	FATFS *fs = FatFs;
+
+
+	if (!fs) {				/* Check file system */
+		res = FR_NOT_ENABLED;
+	} else {
+		dj->fn = sp;
+		if (!fno) {
+			res = dir_rewind(dj);
+		} else {
+			res = dir_read(dj, dir, &fno->lfname[0]);
+			if (res == FR_NO_FILE) res = FR_OK;
+			if (res == FR_OK) {				/* A valid entry is found */
+				get_fileinfo(dj, dir, fno);	/* Get the object information */
+				res = dir_next2(dj);			/* Increment index for next */
+				if (res == FR_NO_FILE) res = FR_OK;
+			}
+		}
+	}
+
+	if (fno->lfname[0] == '\0') strcpy(&fno->lfname[0],&fno->fname[0]);
+	//printf("%s %s(%d)\n",&fno->fname[0], &fno->lfname[0],strlen(&fno->lfname[0]));
+	return res;
+}
+
+#endif /* _USE_DIR */
+
Index: firmware_legacy/fat/pffconf.h
===================================================================
--- firmware_legacy/fat/pffconf.h	(nonexistent)
+++ firmware_legacy/fat/pffconf.h	(revision 799)
@@ -0,0 +1,89 @@
+/*---------------------------------------------------------------------------/
+/  Petit FatFs - Configuration file  R0.03 (C)ChaN, 2014
+/---------------------------------------------------------------------------*/
+
+#ifndef _PFFCONF
+#define _PFFCONF 4004	/* Revision ID */
+
+/*---------------------------------------------------------------------------/
+/ Function Configurations
+/---------------------------------------------------------------------------*/
+
+#define	_USE_READ	1	/* Enable pf_read() function */
+#define	_USE_DIR	1	/* Enable pf_opendir() and pf_readdir() function */
+#define	_USE_LSEEK	1	/* Enable pf_lseek() function */
+#define	_USE_WRITE	0	/* Enable pf_write() function */
+
+#define _FS_FAT12	0	/* Enable FAT12 */
+#define _FS_FAT16	1	/* Enable FAT16 */
+#define _FS_FAT32	1	/* Enable FAT32 */
+
+
+/*---------------------------------------------------------------------------/
+/ Locale and Namespace Configurations
+/---------------------------------------------------------------------------*/
+
+#define _USE_LCC	1	/* Allow lower case characters for path name */
+
+#define	_CODE_PAGE	437
+/* The _CODE_PAGE specifies the code page to be used on the target system.
+/  SBCS code pages with _USE_LCC == 1 requiers a 128 byte of case conversion
+/  table. This might occupy RAM on some platforms, e.g. avr-gcc.
+/  When _USE_LCC == 0, _CODE_PAGE has no effect.
+/
+/   932  - Japanese Shift_JIS (DBCS, OEM, Windows)
+/   936  - Simplified Chinese GBK (DBCS, OEM, Windows)
+/   949  - Korean (DBCS, OEM, Windows)
+/   950  - Traditional Chinese Big5 (DBCS, OEM, Windows)
+/   1250 - Central Europe (Windows)
+/   1251 - Cyrillic (Windows)
+/   1252 - Latin 1 (Windows)
+/   1253 - Greek (Windows)
+/   1254 - Turkish (Windows)
+/   1255 - Hebrew (Windows)
+/   1256 - Arabic (Windows)
+/   1257 - Baltic (Windows)
+/   1258 - Vietnam (OEM, Windows)
+/   437  - U.S. (OEM)
+/   720  - Arabic (OEM)
+/   737  - Greek (OEM)
+/   775  - Baltic (OEM)
+/   850  - Multilingual Latin 1 (OEM)
+/   858  - Multilingual Latin 1 + Euro (OEM)
+/   852  - Latin 2 (OEM)
+/   855  - Cyrillic (OEM)
+/   866  - Russian (OEM)
+/   857  - Turkish (OEM)
+/   862  - Hebrew (OEM)
+/   874  - Thai (OEM, Windows)
+*/
+
+
+/*---------------------------------------------------------------------------/
+/ System Configurations
+/---------------------------------------------------------------------------*/
+
+#define _WORD_ACCESS	0
+/* The _WORD_ACCESS option is an only platform dependent option. It defines
+/  which access method is used to the word data on the FAT volume.
+/
+/   0: Byte-by-byte access. Always compatible with all platforms.
+/   1: Word access. Do not choose this unless under both the following conditions.
+/
+/  * Address misaligned memory access is always allowed for ALL instructions.
+/  * Byte order on the memory is little-endian.
+/
+/  If it is the case, _WORD_ACCESS can also be set to 1 to improve performance and
+/  reduce code size. Following table shows an example of some processor types.
+/
+/   ARM7TDMI    0           ColdFire    0           V850E       0
+/   Cortex-M3   0           Z80         0/1         V850ES      0/1
+/   Cortex-M0   0           RX600(LE)   0/1         TLCS-870    0/1
+/   AVR         0/1         RX600(BE)   0           TLCS-900    0/1
+/   AVR32       0           RL78        0           R32C        0
+/   PIC18       0/1         SH-2        0           M16C        0/1
+/   PIC24       0           H8S         0           MSP430      0
+/   PIC32       0           H8/300H     0           x86         0/1
+*/
+
+#endif /* _PFFCONF */
Index: firmware_legacy/Makefile
===================================================================
--- firmware_legacy/Makefile	(nonexistent)
+++ firmware_legacy/Makefile	(revision 799)
@@ -0,0 +1,348 @@
+BASE	= zpu-elf
+CC      = $(BASE)-gcc
+LD      = $(BASE)-gcc
+AS      = $(BASE)-as
+CP      = $(BASE)-objcopy
+DUMP    = $(BASE)-objdump
+
+SOCKIT_CC = arm-linux-gnueabihf-gcc
+SOCKIT_LD = arm-linux-gnueabihf-gcc
+
+SOCKIT_CFLAGS = -g -DLITTLE_ENDIAN -DSOCKIT -O2
+SOCKIT_CFLAGS+= -W -Wall
+SOCKIT_LDFLAGS = -g
+
+HOST_CC	= gcc
+HOST_LD	= gcc
+
+HOST_CFLAGS	= -g -DLINUX_BUILD -DLITTLE_ENDIAN -fno-builtin
+HOST_CFLAGS	+= -W -Wall
+HOST_LDFLAGS	= -g
+
+#HOST_CFLAGS	+= -m32
+#HOST_LDFLAGS	+= -m32
+
+HOST_CFLAGS	+= $(shell pkg-config --cflags ncurses)
+HOST_LDFLAGS	+= $(shell pkg-config --libs ncurses)
+
+# we use mincrt0.s from here
+STARTUP_DIR = .
+
+# we fetch ROM prologue / epilogue from here
+RTL_DIR = $(ZPUFLEXDIR)/RTL/
+
+
+BUILD_DIR=zpu_obj
+
+AEON_LITE_DIR = aeon_lite
+PAPILIODUO_DIR = papilioduo
+DE1_DIR = de1
+DE1_5200_DIR = de1_5200
+CHAMELEON_DIR = chameleon
+ECLAIREXL_DIR = eclairexl
+MCC_DIR = mcc
+MCC_5200_DIR = mcc_5200
+MCCTV_DIR = mcctv
+MCCTV_5200_DIR = mcctv_5200
+MIST_DIR = mist
+MIST_5200_DIR = mist_5200
+LINUXSIM_DIR = linux
+LINUXSIM_5200_DIR = linux_5200
+SOCKIT_DIR = sockit
+
+AEON_LITE_BUILD_DIR = $(BUILD_DIR)/$(AEON_LITE_DIR)
+PAPILIODUO_BUILD_DIR = $(BUILD_DIR)/$(PAPILIODUO_DIR)
+DE1_BUILD_DIR = $(BUILD_DIR)/$(DE1_DIR)
+SOCKIT_BUILD_DIR = $(BUILD_DIR)/$(SOCKIT_DIR)
+DE1_5200_BUILD_DIR = $(BUILD_DIR)/$(DE1_5200_DIR)
+CHAMELEON_BUILD_DIR = $(BUILD_DIR)/$(CHAMELEON_DIR)
+ECLAIREXL_BUILD_DIR = $(BUILD_DIR)/$(ECLAIREXL_DIR)
+MCC_BUILD_DIR = $(BUILD_DIR)/$(MCC_DIR)
+MCC_5200_BUILD_DIR = $(BUILD_DIR)/$(MCC_5200_DIR)
+MCCTV_BUILD_DIR = $(BUILD_DIR)/$(MCCTV_DIR)
+MCCTV_5200_BUILD_DIR = $(BUILD_DIR)/$(MCCTV_5200_DIR)
+MIST_BUILD_DIR = $(BUILD_DIR)/$(MIST_DIR)
+MIST_5200_BUILD_DIR = $(BUILD_DIR)/$(MIST_5200_DIR)
+LINUXSIM_BUILD_DIR = $(BUILD_DIR)/$(LINUXSIM_DIR)
+LINUXSIM_5200_BUILD_DIR = $(BUILD_DIR)/$(LINUXSIM_5200_DIR)
+
+#MINSTARTUP_SRC = mincrt0.s
+MINSTARTUP_SRC = mycrt0.s
+MINSTARTUP_OBJ = $(patsubst $(STARTUP_DIR)/%.s,$(BUILD_DIR)/%.o,$(MINSTARTUP_SRC))
+
+CORE_SRC = cartridge.c fileutils.c fileselector.c pokey/uart.c hexdump.c common/utils.c printf/printf.c 
+FAT_SRC = fat/pff_file.c fat/pff.c 
+COMMON_SRC = ${FAT_SRC} ${CORE_SRC}
+SDCARD_SRC = sd_direct/diskio_mmc.c sd_direct/spi.c sd_direct/mmc2.c
+A800_SRC_LIGHT = a800/freeze.c  a800/mainmenu.c atari_drive_emulator.c libgcc_divmod.c
+A800_SRC = ${A800_SRC_LIGHT} a800/joystick.c 
+5200_SRC_LIGHT = 5200/freeze.c  5200/mainmenu.c
+5200_SRC = ${5200_SRC_LIGHT} 5200/joystick.c
+USB_SRC = usb/hid.c  usb/hidparser.c  usb/hub.c usb/timer.c  usb/usb.c usb/debug.c
+
+AEON_LITE_PRJ = AEON_LITE
+AEON_LITE_SRC = $(COMMON_SRC) $(SDCARD_SRC) $(A800_SRC) de1/dirs.c
+AEON_LITE_OBJ = $(patsubst %.c,$(AEON_LITE_BUILD_DIR)/%.o,$(AEON_LITE_SRC))
+
+PAPILIODUO_PRJ = PAPILIODUO
+PAPILIODUO_SRC = $(COMMON_SRC) $(SDCARD_SRC) $(A800_SRC) de1/dirs.c
+PAPILIODUO_OBJ = $(patsubst %.c,$(PAPILIODUO_BUILD_DIR)/%.o,$(PAPILIODUO_SRC))
+
+DE1_PRJ = DE1
+DE1_SRC = $(COMMON_SRC) $(SDCARD_SRC) $(A800_SRC) de1/dirs.c
+DE1_OBJ = $(patsubst %.c,$(DE1_BUILD_DIR)/%.o,$(DE1_SRC))
+
+DE1_5200_PRJ = DE1_5200
+DE1_5200_SRC = $(COMMON_SRC) $(SDCARD_SRC) $(5200_SRC) de1_5200/dirs.c
+DE1_5200_OBJ = $(patsubst %.c,$(DE1_5200_BUILD_DIR)/%.o,$(DE1_5200_SRC))
+
+CHAMELEON_PRJ = CHAMELEON
+CHAMELEON_SRC = $(COMMON_SRC) $(SDCARD_SRC) $(A800_SRC) chameleon/dirs.c
+CHAMELEON_OBJ = $(patsubst %.c,$(CHAMELEON_BUILD_DIR)/%.o,$(CHAMELEON_SRC))
+
+ECLAIREXL_PRJ = ECLAIREXL
+ECLAIREXL_SRC = $(COMMON_SRC) $(SDCARD_SRC) $(A800_SRC) $(USB_SRC) de1/dirs.c
+ECLAIREXL_OBJ = $(patsubst %.c,$(ECLAIREXL_BUILD_DIR)/%.o,$(ECLAIREXL_SRC))
+
+MCC_PRJ = MCC216
+MCC_SRC = $(COMMON_SRC) $(SDCARD_SRC) $(A800_SRC) $(USB_SRC) mcc/dirs.c
+#MCC_SRC = $(COMMON_SRC) $(SDCARD_SRC) $(A800_SRC) mcc/dirs.c
+MCC_OBJ = $(patsubst %.c,$(MCC_BUILD_DIR)/%.o,$(MCC_SRC))
+
+MCC_5200_PRJ = MCC216_5200
+MCC_5200_SRC = $(COMMON_SRC) $(SDCARD_SRC) $(5200_SRC) $(USB_SRC) mcc_5200/dirs.c
+MCC_5200_OBJ = $(patsubst %.c,$(MCC_5200_BUILD_DIR)/%.o,$(MCC_5200_SRC))
+
+MCCTV_PRJ = MCCTV
+MCCTV_SRC = $(COMMON_SRC) $(SDCARD_SRC) $(A800_SRC) $(USB_SRC) mcc/dirs.c
+#MCCTV_SRC = $(COMMON_SRC) $(SDCARD_SRC) $(A800_SRC) mcc/dirs.c
+MCCTV_OBJ = $(patsubst %.c,$(MCCTV_BUILD_DIR)/%.o,$(MCCTV_SRC))
+
+MCCTV_5200_PRJ = MCCTV_5200
+MCCTV_5200_SRC = $(COMMON_SRC) $(SDCARD_SRC) $(5200_SRC) $(USB_SRC) mcc_5200/dirs.c
+MCCTV_5200_OBJ = $(patsubst %.c,$(MCCTV_5200_BUILD_DIR)/%.o,$(MCCTV_5200_SRC))
+
+MIST_PRJ = MIST
+MIST_SRC = $(COMMON_SRC) $(SDCARD_SRC) $(A800_SRC) mist/dirs.c
+MIST_OBJ = $(patsubst %.c,$(MIST_BUILD_DIR)/%.o,$(MIST_SRC))
+
+MIST_5200_PRJ = MIST_5200
+MIST_5200_SRC = $(COMMON_SRC) $(SDCARD_SRC) $(5200_SRC) mist_5200/dirs.c
+MIST_5200_OBJ = $(patsubst %.c,$(MIST_5200_BUILD_DIR)/%.o,$(MIST_5200_SRC))
+
+SOCKIT_PRJ = SOCKIT
+SOCKIT_SRC = $(CORE_SRC) a800/freeze.c  a800/mainmenu.c atari_drive_emulator.c a800/joystick.c sockit/dirs.c sockit/linuxfile.c sockit/linuxdir.c sockit/memory.c
+SOCKIT_OBJ = $(patsubst %.c,$(SOCKIT_BUILD_DIR)/%.o,$(SOCKIT_SRC))
+
+LINKMAP  = ./standalone_simple.ld
+LINKMAP_LARGE  = ./standalone_simple_large.ld
+
+LINUXSIM_EXE	= linuxsim
+LINUXSIM_SRC	= $(COMMON_SRC) $(A800_SRC_LIGHT) $(USB_SRC) linux/main.c linux/mmc.c \
+	sd_direct/diskio_mmc.c linux/dirs.c linux/linux_memory.c linux/curses_screen.c \
+	linux/linux_helper.c linux/emulate_usb.c
+
+LINUXSIM_5200_EXE	= linuxsim_5200
+LINUXSIM_5200_SRC	= $(COMMON_SRC) $(5200_SRC_LIGHT) linux/main.c linux/mmc.c \
+	sd_direct/diskio_mmc.c linux/dirs.c linux/linux_memory.c linux/curses_screen.c \
+	linux/linux_helper.c
+
+LINUXSIM_OBJ	= $(patsubst %.c,$(LINUXSIM_BUILD_DIR)/%.o,$(LINUXSIM_SRC))
+LINUXSIM_5200_OBJ	= $(patsubst %.c,$(LINUXSIM_5200_BUILD_DIR)/%.o,$(LINUXSIM_5200_SRC))
+
+# Commandline options for each tool.
+
+#ZPUOPTS= -mno-poppcrel -mno-pushspadd -mno-callpcrel -mno-shortop -mno-neg # No-neg requires bugfixed toolchain
+#Include everything -> need to include emulation rom...
+ZPUOPTS =
+CFLAGS  = -I. -Isd_direct -Iprintf -Ifat -Icommon -Isdram_common -c -g -Os $(ZPUOPTS) -DDISABLE_UART_RX -DMAX_RAM_SELECT=6
+CFLAGS_AEON  = -I. -Isd_direct -Iprintf -Ifat -Icommon -Iaeon_lite -c -g -Os $(ZPUOPTS) -DDISABLE_UART_RX -DMAX_RAM_SELECT=5
+CFLAGS_PAPILIODUO  = -I. -Isd_direct -Iprintf -Ifat -Icommon -Ipapilioduo -c -g -Os $(ZPUOPTS) -DDISABLE_UART_RX -DMAX_RAM_SELECT=3
+
+SOCKIT_CFLAGS += -I. -Icommon -Isockit -Iprintf -DMAX_RAM_SELECT=6
+
+HOST_CFLAGS += -I. -Isd_direct -Iprintf -Ifat -Icommon -Isdram_common -DDISABLE_UART_RX -DUSB -Iusb -DMAX_RAM_SELECT=6
+
+LFLAGS  = -nostartfiles -nostdlib -Wl,--relax -g -Os -Wl,-Map=out.map
+LFLAGS_5200  = -nostartfiles -Wl,--relax -g -Os -Wl,-Map=out.map
+#LFLAGS  = -nostartfiles -Os
+
+CFLAGS_USB = $(CFLAGS) -DUSB -Iusb
+CFLAGS_USB2 = $(CFLAGS) -DUSB -DUSB2 -Iusb
+CFLAGS_5200 = $(CFLAGS) -DFIRMWARE_5200
+CFLAGS_5200_USB = $(CFLAGS) -DFIRMWARE_5200 -DUSB -Iusb
+CFLAGS_5200_USB2 = $(CFLAGS) -DFIRMWARE_5200  -DUSB -DUSB2 -Iusb
+HOST_CFLAGS_5200 = $(HOST_CFLAGS) -DFIRMWARE_5200
+
+# Our target.
+all: eclairexl mcc mcctv mist de1 aeon_lite chameleon  de1_5200 mist_5200 mcc_5200 mcctv_5200 sockit papilioduo
+
+install:
+	cd ../common/romgen && ./createall && cd ../../firmware
+
+aeon_lite: $(BUILD_DIR) $(AEON_LITE_PRJ).bin $(AEON_LITE_PRJ).rpt
+
+papilioduo: $(BUILD_DIR) $(PAPILIODUO_PRJ).bin $(PAPILIODUO_PRJ).rpt
+
+de1: $(BUILD_DIR) $(DE1_PRJ).bin $(DE1_PRJ).rpt
+
+de1_5200: $(BUILD_DIR) $(DE1_5200_PRJ).bin $(DE1_5200_PRJ).rpt
+
+chameleon: $(BUILD_DIR) $(CHAMELEON_PRJ).bin $(CHAMELEON_PRJ).rpt
+
+eclairexl: $(BUILD_DIR) $(ECLAIREXL_PRJ).bin $(ECLAIREXL_PRJ).rpt
+
+mcc: $(BUILD_DIR) $(MCC_PRJ).bin $(MCC_PRJ).rpt
+
+mcc_5200: $(BUILD_DIR) $(MCC_5200_PRJ).bin $(MCC_5200_PRJ).rpt
+
+mcctv: $(BUILD_DIR) $(MCCTV_PRJ).bin $(MCCTV_PRJ).rpt
+
+mcctv_5200: $(BUILD_DIR) $(MCCTV_5200_PRJ).bin $(MCCTV_5200_PRJ).rpt
+
+mist: $(BUILD_DIR) $(MIST_PRJ).bin $(MIST_PRJ).rpt
+
+mist_5200: $(BUILD_DIR) $(MIST_5200_PRJ).bin $(MIST_5200_PRJ).rpt
+
+sockit: $(BUILD_DIR) $(SOCKIT_PRJ).elf
+
+.PHONY: linux
+linux: $(BUILD_DIR) $(LINUXSIM_EXE)
+
+.PHONY: linux_5200
+linux_5200: $(BUILD_DIR) $(LINUXSIM_5200_EXE)
+
+clean:
+	rm -rf $(BUILD_DIR)/* *.hex *.elf *.map *.lst *.srec *.bin *.rpt $(LINUXSIM_EXE) $(LINUXSIM_5200_EXE)
+
+
+# Convert ELF binary to bin file.
+%.bin: %.elf
+	$(CP) -O binary $< $@
+
+%.rpt: %.elf
+	echo >$@ -n "End of code:\t"
+	$(DUMP) -x $< | grep >>$@ _romend
+	echo >>$@ -n "Start of BSS:\t"
+	$(DUMP) -x $< | grep  >>$@ __bss_start__
+	echo >>$@ -n "End of BSS:\t"
+	$(DUMP) -x $< | grep >>$@ __bss_end__
+	cat $@
+
+# Link - this produces an ELF binary.
+
+$(AEON_LITE_PRJ).elf: $(MINSTARTUP_OBJ) $(AEON_LITE_OBJ)
+	$(LD) $(LFLAGS) -T $(LINKMAP) -o $@ $+ $(LIBS)
+
+$(PAPILIODUO_PRJ).elf: $(MINSTARTUP_OBJ) $(PAPILIODUO_OBJ)
+	$(LD) $(LFLAGS) -T $(LINKMAP) -o $@ $+ $(LIBS)
+
+$(DE1_PRJ).elf: $(MINSTARTUP_OBJ) $(DE1_OBJ)
+	$(LD) $(LFLAGS) -T $(LINKMAP) -o $@ $+ $(LIBS)
+
+$(DE1_5200_PRJ).elf: $(MINSTARTUP_OBJ) $(DE1_5200_OBJ)
+	$(LD) $(LFLAGS_5200) -T $(LINKMAP) -o $@ $+ $(LIBS)
+
+$(CHAMELEON_PRJ).elf: $(MINSTARTUP_OBJ) $(CHAMELEON_OBJ)
+	$(LD) $(LFLAGS) -T $(LINKMAP) -o $@ $+ $(LIBS)
+
+$(ECLAIREXL_PRJ).elf: $(MINSTARTUP_OBJ) $(ECLAIREXL_OBJ)
+	$(LD) $(LFLAGS) -T $(LINKMAP_LARGE) -o $@ $+ $(LIBS)
+
+$(MCC_PRJ).elf: $(MINSTARTUP_OBJ) $(MCC_OBJ)
+	$(LD) $(LFLAGS) -T $(LINKMAP_LARGE) -o $@ $+ $(LIBS)
+#	$(LD) $(LFLAGS) -T $(LINKMAP) -o $@ $+ $(LIBS)
+
+$(MCC_5200_PRJ).elf: $(MINSTARTUP_OBJ) $(MCC_5200_OBJ)
+	$(LD) $(LFLAGS_5200) -T $(LINKMAP_LARGE) -o $@ $+ $(LIBS)
+
+$(MCCTV_PRJ).elf: $(MINSTARTUP_OBJ) $(MCCTV_OBJ)
+	$(LD) $(LFLAGS) -T $(LINKMAP_LARGE) -o $@ $+ $(LIBS)
+
+$(MCCTV_5200_PRJ).elf: $(MINSTARTUP_OBJ) $(MCCTV_5200_OBJ)
+	$(LD) $(LFLAGS_5200) -T $(LINKMAP_LARGE) -o $@ $+ $(LIBS)
+
+$(MIST_PRJ).elf: $(MINSTARTUP_OBJ) $(MIST_OBJ)
+	$(LD) $(LFLAGS) -T $(LINKMAP) -o $@ $+ $(LIBS)
+
+$(MIST_5200_PRJ).elf: $(MINSTARTUP_OBJ) $(MIST_5200_OBJ)
+	$(LD) $(LFLAGS_5200) -T $(LINKMAP) -o $@ $+ $(LIBS)
+
+$(SOCKIT_PRJ).elf: $(SOCKIT_OBJ)
+	$(SOCKIT_LD) $(SOCKIT_LDFLAGS) -o $@ $+
+
+$(LINUXSIM_EXE): $(LINUXSIM_OBJ)
+	$(HOST_LD) $(HOST_LDFLAGS) -o $@ $+
+
+$(LINUXSIM_5200_EXE): $(LINUXSIM_5200_OBJ)
+	$(HOST_LD) $(HOST_LDFLAGS) -o $@ $+
+
+$(AEON_LITE_BUILD_DIR)/%.o: %.c Makefile
+	mkdir -p `dirname $@`
+	$(CC) -I$(AEON_LITE_DIR) $(CFLAGS_AEON)  -o $@ -c $<
+
+$(PAPILIODUO_BUILD_DIR)/%.o: %.c Makefile
+	mkdir -p `dirname $@`
+	$(CC) -I$(PAPILIODUO_DIR) $(CFLAGS_PAPILIODUO)  -o $@ -c $<
+
+$(CHAMELEON_BUILD_DIR)/%.o: %.c Makefile
+	mkdir -p `dirname $@`
+	$(CC) -I$(CHAMELEON_DIR) $(CFLAGS)  -o $@ -c $<
+
+$(DE1_BUILD_DIR)/%.o: %.c Makefile
+	mkdir -p `dirname $@`
+	$(CC) -I$(DE1_DIR) $(CFLAGS)  -o $@ -c $<
+
+$(DE1_5200_BUILD_DIR)/%.o: %.c Makefile
+	mkdir -p `dirname $@`
+	$(CC) -I$(DE1_5200_DIR) $(CFLAGS_5200)  -o $@ -c $<
+
+$(ECLAIREXL_BUILD_DIR)/%.o: %.c Makefile
+	mkdir -p `dirname $@`
+	$(CC) -I$(ECLAIREXL_DIR) $(CFLAGS_USB2)  -o $@ -c $<
+
+$(MCC_BUILD_DIR)/%.o: %.c Makefile
+	mkdir -p `dirname $@`
+	$(CC) -I$(MCC_DIR) $(CFLAGS_USB)  -o $@ -c $<
+
+$(MCC_5200_BUILD_DIR)/%.o: %.c Makefile
+	mkdir -p `dirname $@`
+	$(CC) -I$(MCC_5200_DIR) $(CFLAGS_5200_USB)  -o $@ -c $<
+
+$(MCCTV_BUILD_DIR)/%.o: %.c Makefile
+	mkdir -p `dirname $@`
+	$(CC) -I$(MCCTV_DIR) $(CFLAGS_USB2)  -o $@ -c $<
+
+$(MCCTV_5200_BUILD_DIR)/%.o: %.c Makefile
+	mkdir -p `dirname $@`
+	$(CC) -I$(MCCTV_5200_DIR) $(CFLAGS_5200_USB2)  -o $@ -c $<
+
+$(MIST_BUILD_DIR)/%.o: %.c Makefile
+	mkdir -p `dirname $@`
+	$(CC) -I$(MIST_DIR) $(CFLAGS)  -o $@ -c $<
+
+$(MIST_5200_BUILD_DIR)/%.o: %.c Makefile
+	mkdir -p `dirname $@`
+	$(CC) -I$(MIST_5200_DIR) $(CFLAGS_5200)  -o $@ -c $<
+
+$(SOCKIT_BUILD_DIR)/%.o: %.c Makefile
+	mkdir -p `dirname $@`
+	$(SOCKIT_CC) -I$(SOCKIT_DIR) $(SOCKIT_CFLAGS)  -o $@ -c $<
+
+$(LINUXSIM_BUILD_DIR)/%.o: %.c Makefile
+	@mkdir -p `dirname $@`
+	$(HOST_CC) -I$(LINUXSIM_DIR) $(HOST_CFLAGS)  -o $@ -c $<
+
+$(LINUXSIM_5200_BUILD_DIR)/%.o: %.c Makefile
+	@mkdir -p `dirname $@`
+	$(HOST_CC) -I$(LINUXSIM_DIR) $(HOST_CFLAGS_5200)  -o $@ -c $<
+
+$(BUILD_DIR)/%.o: %.s
+	$(AS) -o $@ $<
+
+$(BUILD_DIR)/%.o: $(STARTUP_DIR)/%.s
+	$(AS) -o $@ $<
+
+$(BUILD_DIR):
+	mkdir $(BUILD_DIR)
+
Index: firmware_legacy/aeon_lite/memory.h
===================================================================
--- firmware_legacy/aeon_lite/memory.h	(nonexistent)
+++ firmware_legacy/aeon_lite/memory.h	(revision 799)
@@ -0,0 +1,47 @@
+#ifndef MEMORY_H
+#define MEMORY_H
+
+//1024k memory map
+//(up to 576k atari mem)
+//----
+//64k (base)
+//64-127  (64k)= freeze backup
+//128k-255k=freezer ram (128k)
+//256k-415k=carts (160k)
+//288k-415k=dir cache (128k/shared)
+//416k-447k=os rom/ram (32k)
+//448k-511k=freezer rom
+//512-1023 (512k ext)
+
+#define SRAM_BASE ((void*) 0x200000)
+#define SDRAM_BASE ((void*) 0x800000)
+
+// Memory usage...
+// 0x10000-0x1FFFF (0x810000 in zpu space) = freeze backup - 64k
+// 0x20000-0x3FFFF (0x820000 in zpu space) = freezer ram (128k)
+// 0x40000-0x67FFF (0x840000 in zpu space) = carts - 160k
+// 0x48000-0x67FFF (0x848000 in zpu space) = directory cache - 128k
+// 0x68000-0x6FFFF (0x868000 in zpu space) = os rom/basic rom - 32k
+// 0x70000-0x7FFFF (0x870000 in zpu space) = freezer rom (64k)
+
+#define INIT_MEM
+
+#define DIR_INIT_MEM (SDRAM_BASE + 0x48000)
+#define DIR_INIT_MEMSIZE 131072
+#define FREEZE_MEM (SDRAM_BASE + 0x10000)
+#define FREEZER_RAM_MEM (SDRAM_BASE + 0x20000)
+#define FREEZER_ROM_MEM (SDRAM_BASE + 0x70000)
+#define HAVE_FREEZER_ROM_MEM 1
+
+#define CARTRIDGE_MEM (SDRAM_BASE + 0x40000) // Share with dir cache, long carts will be wired by dir listing
+
+// offset in SDRAM area
+#define ROM_OFS 0x68000
+
+
+#define atari_regbase  ((void*) 0x10000)
+#define atari_regmirror  ((void*) 0x20000)
+#define zpu_regbase ((void*) 0x40000)
+#define pokey_regbase ((void*) 0x40400)
+
+#endif
Index: firmware_legacy/linux/curses_screen.c
===================================================================
--- firmware_legacy/linux/curses_screen.c	(nonexistent)
+++ firmware_legacy/linux/curses_screen.c	(revision 799)
@@ -0,0 +1,200 @@
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <curses.h>
+#include "curses_screen.h"
+#include "linux_helper.h"
+#include "regs.h"
+
+static WINDOW* atari_window;
+static WINDOW* status_window;
+static WINDOW* log_window;
+
+static attr_t atari_color;
+static attr_t atari_inverse_color;
+static attr_t status_color;
+static attr_t log_color;
+
+int init_curses_screen(void)
+{
+	int height;
+	int width;
+
+	initscr();
+
+	getmaxyx(stdscr, height, width);
+
+	if (height < 24 || width < 80) {
+		fprintf(stderr, "screen is too small (must be 80x24)\n");
+		return 1;
+	}
+
+	nonl();
+	cbreak();
+	noecho();
+
+	atari_window = newwin(24, 40, 0, 0);
+	status_window = newwin(4, width - 40, 0, 40);
+	log_window = newwin(height - 4, width - 40, 4, 40);
+
+	atari_color = 0;
+	atari_inverse_color = A_REVERSE;
+	if (has_colors()) {
+		start_color();
+		init_pair(1, COLOR_YELLOW, COLOR_BLUE);
+		init_pair(2, COLOR_YELLOW, COLOR_BLACK);
+		status_color = COLOR_PAIR(1);
+		log_color = COLOR_PAIR(2);
+	} else {
+		status_color = A_REVERSE;
+		log_color = 0;
+	}
+	wbkgdset(atari_window, atari_color | ' ');
+	wbkgdset(log_window, log_color | ' ');
+	wbkgdset(status_window, status_color | ' ');
+	wbkgdset(log_window, log_color | ' ');
+
+	keypad(stdscr, TRUE);
+	scrollok(log_window, TRUE);
+
+	werase(atari_window);
+	werase(status_window);
+	werase(log_window);
+
+	curs_set(0);
+
+	refresh();
+	return 0;
+}
+
+void deinit_curses_screen(void)
+{
+	endwin();
+}
+
+#define MAXSTR 256
+static char tmpstr[MAXSTR];
+
+void display_out_regs(void)
+{
+	uint32_t out1 = *zpu_out1;
+
+	werase(status_window);
+	snprintf(tmpstr, MAXSTR, "out1: %08x", out1);
+	mvwaddstr(status_window, 0, 1, tmpstr);
+
+	snprintf(tmpstr, MAXSTR, "- - tur %02x ram %02x rom %02x car %02x frz %1d",
+		(out1 >> 2) & 0x3f,
+		(out1 >> 8) & 0x07,
+		(out1 >> 11) & 0x3f,
+		(out1 >> 17) & 0x3f,
+		(out1 >> 25) & 1);
+	if (out1 & 1) {
+		tmpstr[0] = 'P';
+	}
+	if (out1 & 2) {
+		tmpstr[2] = 'R';
+	}
+	mvwaddstr(status_window, 1, 1, tmpstr);
+
+	wrefresh(status_window);
+}
+
+void display_char(int x, int y, char c, int inverse)
+{
+	if (inverse) {
+		wattrset(atari_window, atari_inverse_color);
+	}
+	mvwaddch(atari_window, y, x, c);
+	wattrset(atari_window, atari_color);
+
+	wrefresh(atari_window);
+}
+
+void clearscreen(void)
+{
+	wattrset(atari_window, atari_color);
+	werase(atari_window);
+	wrefresh(atari_window);
+}
+
+void check_keys(void)
+{
+	int ch;
+	*zpu_in1 = 0;
+
+	while (1) {
+		ch = wgetch(stdscr);
+
+		switch (ch) {
+		case KEY_F(12):
+			*zpu_in1 = 1<<11; return;
+		case KEY_F(11):
+			*zpu_in1 = 1<<10; return;
+		}
+	}
+}
+
+void joystick_poll(struct joystick_status * status)
+{
+	// we are blocking instead of polling
+	int ch = wgetch(stdscr);
+
+	status->x_ = 0;
+	status->y_ = 0;
+	status->fire_ = 0;
+	status->escape_ = 0;
+
+
+	switch (ch) {
+	case KEY_UP: status->y_ = -1; break;
+	case KEY_DOWN: status->y_ = 1; break;
+	case KEY_LEFT: status->x_ = -1; break;
+	case KEY_RIGHT: status->x_ = 1; break;
+	case KEY_ENTER:
+	case 13:
+		status->fire_ = 1; break;
+	case 27: // ESCAPE:
+		status->escape_ = 1; break;
+	default: break;
+	}
+}
+
+void joystick_wait(struct joystick_status * status, enum JoyWait waitFor)
+{
+	if (waitFor == WAIT_QUIET)
+	{
+		status->x_ = 0;
+		status->y_ = 0;
+		status->fire_ = 0;
+		return;
+	}
+	while (1)
+	{
+		joystick_poll(status);
+		switch (waitFor)
+		{
+		case WAIT_QUIET:
+			break;
+		case WAIT_FIRE:
+			if (status->fire_ == 1) return;
+			break;
+		case WAIT_EITHER:
+			if (status->fire_ == 1) return;
+			// fall through
+		case WAIT_MOVE:
+			if (status->x_ !=0 || status->y_ != 0) return;
+			break;
+		}
+	}
+}
+
+void print_log(const char* format, ...)
+{
+	va_list arg;
+	va_start(arg, format);
+	vw_printw(log_window, format, arg);
+	va_end(arg);
+	wrefresh(log_window);
+}
+
Index: firmware_legacy/linux/linux_helper.h
===================================================================
--- firmware_legacy/linux/linux_helper.h	(nonexistent)
+++ firmware_legacy/linux/linux_helper.h	(revision 799)
@@ -0,0 +1,6 @@
+#ifndef LINUX_HELPER_H
+#define LINUX_HELPER_H
+
+extern char* sdcard_filename;
+
+#endif
Index: firmware_legacy/linux/dirs.c
===================================================================
--- firmware_legacy/linux/dirs.c	(nonexistent)
+++ firmware_legacy/linux/dirs.c	(revision 799)
@@ -0,0 +1,2 @@
+char USER_DIR[]="/atari800/user";
+char ROM_DIR[]="/atari800/rom";
Index: firmware_legacy/fileselector.c
===================================================================
--- firmware_legacy/fileselector.c	(nonexistent)
+++ firmware_legacy/fileselector.c	(revision 799)
@@ -0,0 +1,220 @@
+#include "simplefile.h"
+#include "simpledir.h"
+#include "joystick.h"
+#include "regs.h" // NO NEED!!! 
+#include "printf.h"
+#include "fileutils.h"
+
+extern int debug_pos; // ARG!
+extern int debug_adjust; // ARG!
+extern char USER_DIR[];
+
+// TODO!
+#define MAX_PATH_LENGTH (9*5 + 8+3+1 + 1) 
+
+int (* filter)(struct SimpleDirEntry * entry);
+
+int filter_disks(struct SimpleDirEntry * entry)
+{
+	if (dir_is_subdir(entry)) return 1;
+	char const * f = dir_filename(entry);
+	int res = (compare_ext(f,"ATR") || compare_ext(f,"XFD") || compare_ext(f,"XEX"));
+	//printf("filter_disks:%s:%d\n",f,res);
+	return res;
+}
+
+char const * fil_type;
+char const * fil_type_rom;
+char const * fil_type_bin;
+char const * fil_type_car;
+char const * fil_type_mem;
+int filter_specified(struct SimpleDirEntry * entry)
+{
+	if (dir_is_subdir(entry)) return 1;
+	char const * f = dir_filename(entry);
+	return (compare_ext(f,fil_type));
+}
+
+void dir_of(char * dir, char const * path); // TODO - into simpledir
+
+void file_selector(struct SimpleFile * file)
+{
+	char dir[MAX_PATH_LENGTH];
+	if (file_name(file)[0] == '\0')
+	{
+		strcpy(&dir[0],USER_DIR);
+	}
+	else
+	{
+		dir_of(&dir[0],file_path(file));
+	}
+
+	struct joystick_status joy;
+	joy.x_ = joy.y_ = joy.fire_ = joy.escape_ = 0;
+	for (;!joy.escape_;)
+	{
+		struct SimpleDirEntry * entry = dir_entries_filtered(dir,filter);
+
+		// Count how many we have
+		int entries = 0;
+		struct SimpleDirEntry * temp_entry = entry;
+		while (temp_entry)
+		{
+			++entries;
+			temp_entry = dir_next(temp_entry);
+		}
+		//printf("Entries:%d\n",entries);
+
+		// Selected item
+		int pos = 0;
+		int prevstartpos = -1;
+
+		for (;;)
+		{
+			if (pos<0) pos = 0;
+			if (pos>=entries) pos = entries-1;
+
+			// render
+			{
+				// find which chunk to render
+				int startpos = pos-10;
+				//printf("\nA pos:%d, startpos:%d\n",pos,startpos);
+				//startpos &= 0xfffffffe;
+				//printf("startpos:%d\n",startpos);
+				if (startpos<0) startpos=0;
+				//printf("pos:%d, startpos:%d\n",pos,startpos);
+
+				// get the dir entries for these
+				struct SimpleDirEntry * render_entry = entry;
+				int skip = startpos;
+				while (skip-->0)
+				{
+					render_entry =  dir_next(render_entry);
+				}
+
+				// clear the screen
+				if (startpos!=prevstartpos)
+				{
+					clearscreen();
+					prevstartpos = startpos;
+				}
+
+				// find selected entry
+				struct SimpleDirEntry * sel_entry = entry;
+				skip = pos;
+				while (skip-->0)
+				{
+					sel_entry =  dir_next(sel_entry);
+				}
+
+				// output the new entries
+				int line;
+				debug_pos = 0;
+				debug_adjust = 0;
+				printf("Choose ");
+				debug_adjust = 128;
+				printf("file");
+				debug_pos = 40;
+				int end = 22*40;
+				for (;;)
+				{
+					if (!render_entry) break;
+					
+					int prev_debug_pos = debug_pos;
+					if (render_entry == sel_entry)
+					{
+						debug_adjust = 128;
+					}
+					else
+					{
+						debug_adjust = 0;
+					}
+					if (dir_is_subdir(render_entry))
+					{
+						printf("DIR:");
+					}
+					printf("%s",dir_filename(render_entry));
+
+					render_entry = dir_next(render_entry);
+
+					while(prev_debug_pos<debug_pos)
+					{
+						prev_debug_pos+=40;
+					}
+					debug_pos = prev_debug_pos;
+					//printf("debug_pos:%d",debug_pos);
+					if (debug_pos>=end) break;
+				}
+
+				debug_pos = 40*23;
+				if (sel_entry)
+				{
+					//printf("%s %s %d %d %d",dir_is_subdir(sel_entry) ? "DIR":"", dir_filename(sel_entry), joy.x_, joy.y_, pos);
+					printf("%s %s",dir_is_subdir(sel_entry) ? "DIR":"", dir_filename(sel_entry));
+				}
+				int i;
+				for (i=0;i!=40;++i) printf(" ");
+			}
+
+			// Slow it down a bit
+			wait_us(100000);
+
+			// move
+			joystick_wait(&joy,WAIT_QUIET);
+			joystick_wait(&joy,WAIT_EITHER);
+			if (joy.escape_) break;
+			
+			if (joy.fire_)
+			{
+				int i = pos;
+				while(i--)
+				{
+					if (!entry) break;
+					entry = dir_next(entry);
+				}
+
+				if (entry)
+				{
+					if (!dir_is_subdir(entry))
+					{
+						file_open_dir(entry, file);
+						return;
+					}
+					else
+					{
+						char const *f = dir_filename(entry);
+						if (strcmp("..",f)==0)
+						{
+							int x = strlen(dir);
+							while (x-->0)
+							{
+								if (dir[x] == '/')
+								{
+									dir[x] = '\0';
+									break;
+								}
+							}
+							//printf("\nDIR UP! %s\n",dir);
+						}
+						else
+						{
+							//strcpy(dir + strlen(dir),"/");
+							//strcpy(dir + strlen(dir),f);
+							//printf("\nDIR DOWN:%s -> %s\n",f,dir);
+							strcpy(dir,dir_path(entry));
+						}
+					}
+					break;
+				}
+
+				return;
+			}
+			
+			pos += joy.x_*10;
+			pos += joy.y_;
+		}
+	}
+
+	joystick_wait(&joy,WAIT_QUIET);
+}
+
Index: firmware_legacy/linux/linux_helper.c
===================================================================
--- firmware_legacy/linux/linux_helper.c	(nonexistent)
+++ firmware_legacy/linux/linux_helper.c	(revision 799)
@@ -0,0 +1,3 @@
+#include "linux_helper.h"
+
+char* sdcard_filename = 0;
Index: firmware_legacy/linux/curses_screen.h
===================================================================
--- firmware_legacy/linux/curses_screen.h	(nonexistent)
+++ firmware_legacy/linux/curses_screen.h	(revision 799)
@@ -0,0 +1,19 @@
+#ifndef CURSES_SCREEN_H
+#define CURSES_SCREEN_H
+#include "joystick.h"
+
+int init_curses_screen(void);
+
+void deinit_curses_screen(void);
+
+void display_out_regs(void);
+
+void display_char(int x, int y, char c, int inverse);
+
+void clearscreen(void);
+
+void check_keys(void);
+
+void print_log(const char* format, ...) __attribute__ ((format (printf, 1, 2))) ;
+
+#endif
Index: firmware_legacy/standalone_simple_large.ld
===================================================================
--- firmware_legacy/standalone_simple_large.ld	(nonexistent)
+++ firmware_legacy/standalone_simple_large.ld	(revision 799)
@@ -0,0 +1,59 @@
+
+/* Memory Definitions for a ZPU program running either from external RAM (up to 8 meg).
+   or from unremapped Boot ROM / Stack RAM. */
+
+MEMORY
+{
+  CODE (rx) : ORIGIN = 0x00000000, LENGTH = 0x08000 /* 32k */
+  RAM (rx) : ORIGIN = 0x0000e000, LENGTH = 0x01200 /* 8k */
+}
+
+
+/* Section Definitions */
+
+SECTIONS
+{
+  /* first section is .fixed_vectors which is used for startup code */
+  . = 0x0000000;
+  .fixed_vectors :
+  {
+    *(.fixed_vectors)
+  }>CODE
+
+  /* Remaining code sections */
+  . = ALIGN(4);
+  .text :
+  {
+    *(.text)                   /* remaining code */
+  } >CODE
+
+  /* .rodata section which is used for read-only data (constants) */
+  . = ALIGN(4);
+  .rodata :
+  {
+    *(.rodata)
+  } >CODE
+  . = ALIGN(4);
+
+  /* .data section which is used for initialized data. */
+  . = ALIGN(4);
+  .data :
+  {
+    _data = . ;
+    *(.data)
+    SORT(CONSTRUCTORS)
+    . = ALIGN(4);
+  } >CODE
+  _romend = . ;
+
+  /* .bss section which is used for uninitialized data */
+  . = ALIGN(4);
+  .bss :
+  {
+    __bss_start = . ;
+    __bss_start__ = . ;
+    *(.bss)
+    *(COMMON)
+  } >RAM
+  __bss_end__ = . ;
+}
Index: firmware_legacy/atari_drive_emulator.h
===================================================================
--- firmware_legacy/atari_drive_emulator.h	(nonexistent)
+++ firmware_legacy/atari_drive_emulator.h	(revision 799)
@@ -0,0 +1,31 @@
+#pragma once
+
+// In principle the drive emulator itself just needs to have access to files from somewhere and then serves requests from the Atari.
+// So it doesn't need to depend on fat, just needs a way of reading the specified 'file'
+// So entry points are:
+// i) Provide function ptr to: fetch data, check file size
+// ii) Notify when disk has been changed/removed
+// iii) Drive - called frequently so we can respond to commands received from Pokey
+
+// To speak to the Atari we need:
+// a) Command line
+// b) Pokey
+// Both these are mapped into zpu config regs
+
+void actions(); // this is called whenever possible - should be quick
+
+void init_drive_emulator();
+void run_drive_emulator(); // Blocks. Pokey at its fastest is 6 cycles * 10 bits per byte. i.e. 60 cycles at 1.79MHz.
+
+// To remove a disk, set file to null
+// For a read-only disk, just have no write function!
+struct SimpleFile;
+void set_drive_status(int driveNumber, struct SimpleFile * file);
+struct SimpleFile * get_drive_status(int driveNumber);
+void describe_disk(int driveNumber, char * buffer);
+
+// Pokey divisor
+void set_turbo_drive(int pos);
+int get_turbo_drive();
+char const * get_turbo_drive_str();
+
Index: firmware_legacy/linux/main.c
===================================================================
--- firmware_legacy/linux/main.c	(nonexistent)
+++ firmware_legacy/linux/main.c	(revision 799)
@@ -0,0 +1,28 @@
+#include <stdio.h>
+
+#include "curses_screen.h"
+#include "linux_helper.h"
+#include "linux_memory.h"
+
+int zpu_main(void);
+
+extern char* sdcard_filename;
+
+int main(int argc, char** argv)
+{
+	if (argc > 1) {
+		sdcard_filename = argv[1];
+	}
+
+	if (init_curses_screen()) {
+		return 1;
+	}
+
+	init_memory();
+
+	print_log("starting zpu_main\n");
+	zpu_main();
+
+	deinit_curses_screen();
+	return 0;
+}
Index: firmware_legacy/linux/mmc.c
===================================================================
--- firmware_legacy/linux/mmc.c	(nonexistent)
+++ firmware_legacy/linux/mmc.c	(revision 799)
@@ -0,0 +1,90 @@
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include "mmc.h"
+#include "curses_screen.h"
+#include "linux_helper.h"
+
+#define LOG(x...) print_log(x)
+
+FILE * disk_image = NULL;
+
+char mmc_sector_buffer[512];
+
+void set_spi_clock_freq()
+{
+}
+
+//! Initialize AVR<->MMC hardware interface.
+/// Prepares hardware for MMC access.
+
+void mmcInit(void)
+{
+	if (!sdcard_filename) {
+		LOG("no sdcard\n");
+		return;
+	}
+	disk_image = fopen(sdcard_filename,"r+");
+	if (!disk_image) {
+		LOG("cannot open %s\n", sdcard_filename);
+	} else {
+		LOG("opened sdcard %s\n", sdcard_filename);
+	}
+}
+
+void mmc_init()
+{
+	mmcInit();
+}
+
+
+//! Initialize the card and prepare it for use.
+/// Returns zero if successful.
+u08 mmcReset(void){ return 0;}
+
+//! Read 512-byte sector from card to buffer
+/// Returns zero if successful.
+u08 mmcRead(u32 sector)
+{
+	if (!disk_image) {
+		goto no_data;
+	}
+	//fprintf(stderr,"mmcRead:%x\n",sector);
+
+	if (fseek(disk_image, sector*512, SEEK_SET)) {
+		LOG("seek to sector %d failed\n", sector);
+		goto no_data;
+	}
+	if (fread(&mmc_sector_buffer,512,1,disk_image) != 1) {
+		LOG("reading sector %d failed\n", sector);
+		goto no_data;
+	}
+
+	return 0;
+no_data:
+	memset(&mmc_sector_buffer, 0, 512);
+	return 0;
+}
+
+//! Write 512-byte sector from buffer to card
+/// Returns zero if successful.
+u08 mmcWrite(u32 sector)
+{
+	if (!disk_image) {
+		goto no_data;
+	}
+	//fprintf(stderr,"mmcWrite:%x\n",sector);
+
+	if (fseek(disk_image, sector*512, SEEK_SET)) {
+		LOG("seek to sector %d failed\n", sector);
+		goto no_data;
+	}
+	if (fwrite(&mmc_sector_buffer,512,1,disk_image) != 1) {
+		LOG("reading sector %d failed\n", sector);
+		goto no_data;
+	}
+	return 0;
+no_data:
+	return 0;
+}
+
Index: firmware_legacy/freeze.h
===================================================================
--- firmware_legacy/freeze.h	(nonexistent)
+++ firmware_legacy/freeze.h	(revision 799)
@@ -0,0 +1,22 @@
+#pragma once
+
+#include "simplefile.h"
+
+// Allow us to take over the system
+// NB: CPU should be frozen before calling these!
+
+// Provide 128K of RAM...
+void freeze_init(void * memory);
+
+// Set hardware registers to 'neutral'
+// Back up system ram
+void freeze();
+
+// Restore system ram
+// Restore hardware registers
+void restore();
+
+// Store system ram to a file for debugging (base 64k only)
+void freeze_save(struct SimpleFile * file);
+void freeze_load(struct SimpleFile * file);
+
Index: firmware_legacy/linux/linux_memory.c
===================================================================
--- firmware_legacy/linux/linux_memory.c	(nonexistent)
+++ firmware_legacy/linux/linux_memory.c	(revision 799)
@@ -0,0 +1,62 @@
+#include <stdint.h>
+#include <string.h>
+#include "regs.h"
+#include "memory.h"
+#include "linux_memory.h"
+
+void* SRAM_BASE;
+void* SDRAM_BASE;
+void* atari_regbase;
+void* atari_regmirror;
+void* zpu_regbase;
+void* pokey_regbase;
+void* CARTRIDGE_MEM;
+
+void* FREEZER_RAM_MEM;
+void* FREEZER_ROM_MEM;
+
+#define SRAM_SIZE (512*1024)
+#define SDRAM_SIZE (8*1024*1024)
+#define ATARI_SIZE (64*1024)
+#define CONFIG_SIZE (256)
+#define CARTRIDGE_SIZE (2*1024*1024)
+#define FREEZER_RAM_SIZE (128*1024)
+#define FREEZER_ROM_SIZE (64*1024)
+
+uint8_t sram_memory[SRAM_SIZE];
+uint32_t sdram_memory[SDRAM_SIZE / 4];
+uint8_t atari_memory[ATARI_SIZE];
+uint8_t atari_mirror_memory[ATARI_SIZE];
+uint32_t config_memory[CONFIG_SIZE/4];
+uint32_t cartridge_memory[CARTRIDGE_SIZE / 4];
+
+uint32_t freezer_ram_memory[FREEZER_RAM_SIZE / 4];
+uint32_t freezer_rom_memory[FREEZER_ROM_SIZE / 4];
+
+void init_memory(void)
+{
+	memset(sram_memory, SRAM_SIZE, 0);
+	memset(sdram_memory, SDRAM_SIZE, 0);
+	memset(atari_memory, ATARI_SIZE, 0);
+	memset(atari_mirror_memory, ATARI_SIZE, 0);
+	memset(config_memory, CONFIG_SIZE, 0);
+	memset(cartridge_memory, CARTRIDGE_SIZE, 0);
+	memset(freezer_ram_memory, FREEZER_RAM_SIZE, 0);
+	memset(freezer_rom_memory, FREEZER_ROM_SIZE, 0);
+
+	SRAM_BASE = sram_memory;
+	SDRAM_BASE = sdram_memory;
+	atari_regbase = atari_memory;
+	atari_regmirror = atari_mirror_memory;
+	zpu_regbase = config_memory;
+	pokey_regbase = config_memory+0x100*4;
+	CARTRIDGE_MEM = cartridge_memory;
+	FREEZER_RAM_MEM = freezer_ram_memory;
+	FREEZER_ROM_MEM = freezer_rom_memory;
+
+	// command line is high
+	*zpu_sio = 1;
+	// no trigger pressed
+	*atari_trig0 = 1;
+}
+
Index: firmware_legacy/linux/linux_memory.h
===================================================================
--- firmware_legacy/linux/linux_memory.h	(nonexistent)
+++ firmware_legacy/linux/linux_memory.h	(revision 799)
@@ -0,0 +1,6 @@
+#ifndef LINUX_MEMORY_H
+#define LINUX_MEMORY_H
+
+void init_memory();
+
+#endif
Index: firmware_legacy/fileselector.h
===================================================================
--- firmware_legacy/fileselector.h	(nonexistent)
+++ firmware_legacy/fileselector.h	(revision 799)
@@ -0,0 +1,14 @@
+#pragma once
+
+void file_selector(struct SimpleFile * file);
+
+int filter_disks(struct SimpleDirEntry * entry);
+extern char const * fil_type;
+extern char const * fil_type_rom;
+extern char const * fil_type_bin;
+extern char const * fil_type_car;
+extern char const * fil_type_mem;
+int filter_specified(struct SimpleDirEntry * entry);
+
+extern int (* filter)(struct SimpleDirEntry * entry);
+
Index: firmware_legacy/sockit/memory.c
===================================================================
--- firmware_legacy/sockit/memory.c	(nonexistent)
+++ firmware_legacy/sockit/memory.c	(revision 799)
@@ -0,0 +1,33 @@
+#include "sockit/memory.h"
+
+#include <stdio.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/select.h>
+#include <sched.h>
+
+unsigned char volatile * virtual_base;
+unsigned char volatile * zpu_base;
+
+unsigned int addr = 0xc0000000;
+unsigned int span = 0x1002000;
+
+void init_bridge()
+{
+	int fd = open("/dev/mem",(O_RDWR|O_SYNC));
+	virtual_base = (unsigned char volatile *)mmap(NULL,span,(PROT_READ|PROT_WRITE),MAP_SHARED,fd,addr);
+	printf("ADDR:%x %x\n",(int)virtual_base, (int)addr);
+
+	zpu_base = (unsigned char *)virtual_base + 0x1000000; 
+	//pokey_regbase = (unsigned char *)virtual_base + 0x1000400;
+
+	//struct sched_param param;
+	//param.sched_priority = 50;
+	//sched_setscheduler(0,SCHED_RR,&param);
+	nice(-20);
+}
+
Index: firmware_legacy/sockit/linuxfile.c
===================================================================
--- firmware_legacy/sockit/linuxfile.c	(nonexistent)
+++ firmware_legacy/sockit/linuxfile.c	(revision 799)
@@ -0,0 +1,105 @@
+#include <stdio.h>
+#include "linuxfile.h"
+#include "simplefile.h"
+#include <sys/stat.h>
+#include <unistd.h>
+
+char const * file_of(char const * path)
+{
+        char const * start = path + strlen(path);
+        while (start!=path)
+        {
+                --start;
+                if (*start == '/')
+                {
+                        ++start;
+                        break;
+                }
+        }
+        return start;
+}
+
+void dir_of(char * dir, char const * path)
+{
+        char const * end = file_of(path);
+        if (end != path)
+        {
+                int len = end-path;
+                while (len--)
+                {
+                        *dir++ = *path++;
+                }
+                --dir;
+        }
+
+        *dir = '\0';
+        return;
+}
+
+
+int file_struct_size()
+{
+	return sizeof(struct SimpleFile);
+}
+
+void file_init(struct SimpleFile * file)
+{
+	file->file = 0;
+	file->name[0] = '\0';
+	file->path[0] = '\0';
+}
+
+char const * file_path(struct SimpleFile * file)
+{
+	return &file->path[0];
+}
+
+char const * file_name(struct SimpleFile * file)
+{
+	return &file->name[0];
+}
+
+enum SimpleFileStatus file_read(struct SimpleFile * file, void * buffer, int bytes, int * bytesread)
+{
+	*bytesread = fread(buffer,1,bytes,file->file);
+	return SimpleFile_OK;
+}
+
+enum SimpleFileStatus file_seek(struct SimpleFile * file, int offsetFromStart)
+{
+	//printf("file_seek:%d\n",offsetFromStart);
+	fseek(file->file,offsetFromStart,SEEK_SET);
+	return SimpleFile_OK;
+}
+
+int file_size(struct SimpleFile * file)
+{
+/*	int pos = ftell(file->file);
+	fseek(file->file,0L,SEEK_SEND);
+	int size = ftell(file->file);
+	fseek(file->file,pos,SEEK_SET);*/
+
+	struct stat buf;
+	fstat(fileno(file->file),&buf);
+	return buf.st_size;
+}
+
+int file_readonly(struct SimpleFile * file)
+{
+	return (0==access(file->path,W_OK)) ? 0 : 1;
+}
+
+
+enum SimpleFileStatus file_write(struct SimpleFile * file, void * buffer, int bytes, int * byteswritten)
+{
+	//printf("file_write:%d\n",bytes);
+	*byteswritten = fwrite(buffer,1,bytes,file->file);
+	//printf("written:%d\n",*byteswritten);
+	return SimpleFile_OK;
+}
+
+enum SimpleFileStatus file_write_flush()
+{
+	return SimpleFile_OK;
+}
+
Index: firmware_legacy/native/joystick.c
===================================================================
--- firmware_legacy/native/joystick.c	(nonexistent)
+++ firmware_legacy/native/joystick.c	(revision 799)
@@ -0,0 +1,117 @@
+#include "joystick.h"
+#include <poll.h>
+#include <termios.h>
+#include <unistd.h>
+
+extern char native_porta;
+extern char native_trig;
+
+struct termios oldt, newt;
+void term_init()
+{
+	tcgetattr(STDIN_FILENO, &oldt);
+	newt = oldt;
+	newt.c_lflag &= ~( ICANON | ECHO );
+	tcsetattr( STDIN_FILENO, TCSANOW, &newt);
+}
+
+void term_close()
+{
+	tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
+}
+
+void read_keys()
+{
+	struct pollfd fds[1];
+	fds[0].fd = STDIN_FILENO;
+	fds[0].events = POLLIN;
+	native_porta = 0xff;
+	native_trig = 0xff;
+	while (poll(&fds[0], 1, 0))
+	{
+		char buffer[0];
+		read(0,&buffer[0],1);
+
+	/*	if (buffer[0] == 0x41) fprintf(stderr, "UP\n");
+		if (buffer[0] == 0x42) fprintf(stderr, "DOWN\n");
+		if (buffer[0] == 0x44) fprintf(stderr, "LEFT\n");
+		if (buffer[0] == 0x43) fprintf(stderr, "RIGHT\n");
+		if (buffer[0] == 0x20) fprintf(stderr, "FIRE\n");*/
+
+		// RLDU
+		if (buffer[0] == 0x41) native_porta=0xff&~(1<<0);
+		if (buffer[0] == 0x42) native_porta=0xff&~(1<<1);
+		if (buffer[0] == 0x44) native_porta=0xff&~(1<<2);
+		if (buffer[0] == 0x43) native_porta=0xff&~(1<<3);
+		if (buffer[0] == 0x20) native_trig=0xff&~1;
+
+		fds[0].fd = STDIN_FILENO;
+		fds[0].events = POLLIN;
+	}
+}
+
+#include "regs.h"
+
+void joystick_poll(struct joystick_status * status)
+{
+	static int first = 1;
+	if (first)
+	{
+		first = 0;
+		term_init();
+	}
+
+	read_keys();
+
+	status->x_ = 0;
+	status->y_ = 0;
+	status->fire_ = 0;
+	status->escape_ = 0;
+
+	unsigned char porta = *atari_porta;
+	if (0==(porta&0x2)) // down
+	{
+		status->y_ =1;
+	}
+	else if (0==(porta&0x1)) // up
+	{
+		status->y_ =-1;
+	}
+	if (0==(porta&0x8)) // right
+	{
+		status->x_ = 1;
+	}
+	else if (0==(porta&0x4)) // left
+	{
+		status->x_ = -1;
+	}
+	if (0==(1&*atari_trig0)) // fire
+	{
+		status->fire_ = 1;
+	}
+}
+
+void joystick_wait(struct joystick_status * status, enum JoyWait waitFor)
+{
+	while (1)
+	{
+		joystick_poll(status);
+		switch (waitFor)
+		{
+		case WAIT_QUIET:
+			if (status->x_ == 0 && status->y_ == 0 && status->fire_ == 0) return;
+			break;
+		case WAIT_FIRE:
+			if (status->fire_ == 1) return;
+			break;
+		case WAIT_EITHER:
+			if (status->fire_ == 1) return;
+			// fall through
+		case WAIT_MOVE:
+			if (status->x_ != 0 || status->y_ != 0) return;
+			break;
+		}
+	}
+}
+
+
Index: firmware_legacy/sockit/linuxdir.h
===================================================================
--- firmware_legacy/sockit/linuxdir.h	(nonexistent)
+++ firmware_legacy/sockit/linuxdir.h	(revision 799)
@@ -0,0 +1,17 @@
+#pragma once
+
+#include "simpledir.h"
+
+// Extends simple dir with way of opening files and looking at dirs!
+// Not all systems provide this...
+
+#include <dirent.h>
+
+struct SimpleDirEntry
+{
+        struct dirent entry;
+	char path[256];
+	struct SimpleDirEntry * next;
+};
+
+
Index: firmware_legacy/sdram_common/memory.h
===================================================================
--- firmware_legacy/sdram_common/memory.h	(nonexistent)
+++ firmware_legacy/sdram_common/memory.h	(revision 799)
@@ -0,0 +1,31 @@
+#ifndef MEMORY_H
+#define MEMORY_H
+
+#define SRAM_BASE ((void*) 0x200000)
+#define SDRAM_BASE ((void*) 0x800000)
+
+// Memory usage...
+// 0x410000-0x44FFFF (0xc10000 in zpu space) = directory cache - 256k
+// 0x450000-0x46FFFF (0xc50000 in zpu space) = freeze backup
+// 0x700000-0x77FFFF (0xf00000 in zpu space) = os rom/basic rom
+
+#define INIT_MEM
+
+#define DIR_INIT_MEM (SDRAM_BASE + 0x410000)
+#define DIR_INIT_MEMSIZE 262144
+#define FREEZE_MEM (SDRAM_BASE + 0x450000)
+#define FREEZER_RAM_MEM (SDRAM_BASE + 0x480000)
+#define FREEZER_ROM_MEM (SDRAM_BASE + 0x4A0000)
+#define HAVE_FREEZER_ROM_MEM 1
+
+#define CARTRIDGE_MEM (SDRAM_BASE + 0x500000)
+
+// offset into SDRAM
+#define ROM_OFS 0x700000
+
+#define atari_regbase  ((void*) 0x10000)
+#define atari_regmirror  ((void*) 0x20000)
+#define zpu_regbase ((void*) 0x40000)
+#define pokey_regbase ((void*) 0x40400)
+
+#endif
Index: firmware_legacy/native/diskio_mmc.c
===================================================================
--- firmware_legacy/native/diskio_mmc.c	(nonexistent)
+++ firmware_legacy/native/diskio_mmc.c	(revision 799)
@@ -0,0 +1 @@
+link ../sd_direct/diskio_mmc.c
\ No newline at end of file

Property changes on: firmware_legacy/native/diskio_mmc.c
___________________________________________________________________
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Index: firmware_legacy/native/uart.c
===================================================================
--- firmware_legacy/native/uart.c	(nonexistent)
+++ firmware_legacy/native/uart.c	(revision 799)
@@ -0,0 +1,57 @@
+#include "uart.h"
+
+#include <stdio.h>
+
+char native_command;
+
+char receive_buffer[1024*1024];
+int receive_buffer_pos=0;
+int receive_buffer_last=0;
+
+void USART_Init( u08 value )
+{
+	fprintf(stderr, "USART_Init:%d\n",value);
+}
+
+void USART_Transmit_Byte( unsigned char data )
+{
+	fprintf(stderr, "USART_Transmit:%02x\n", data);
+}
+
+unsigned char USART_Receive_Byte( void )
+{
+	unsigned char res = receive_buffer[receive_buffer_pos++];
+	fprintf(stderr, "USART_Receive:%02x\n",res);
+	return res;
+}
+
+int USART_Data_Ready()
+{
+	return 0;
+}
+
+void USART_Transmit_Mode()
+{
+	fprintf(stderr,"USART_Transmit mode\n");
+}
+
+void USART_Receive_Mode()
+{
+	fprintf(stderr,"USART_Receive mode\n");
+}
+
+int USART_Framing_Error()
+{
+	return 0;
+}
+
+void USART_Wait_Transmit_Complete()
+{
+	return;
+}
+
+int USART_Command_Line()
+{
+	return native_command;
+}
+
Index: firmware_legacy/common/x
===================================================================
--- firmware_legacy/common/x	(nonexistent)
+++ firmware_legacy/common/x	(revision 799)
@@ -0,0 +1,3 @@
+g++: error: fat/pff_file.c: No such file or directory
+g++: fatal error: no input files
+compilation terminated.
Index: firmware_legacy/sd_direct/diskio_mmc.c
===================================================================
--- firmware_legacy/sd_direct/diskio_mmc.c	(nonexistent)
+++ firmware_legacy/sd_direct/diskio_mmc.c	(revision 799)
@@ -0,0 +1,147 @@
+#include "diskio.h"
+
+#include "mmc.h"
+#include "spi.h"
+
+//#include "printf.h"
+
+void mmcReadCached(u32 sector);
+u32 n_actual_mmc_sector;
+extern unsigned char mmc_sector_buffer[512];
+
+void mmcReadCached(u32 sector)
+{
+	//debug("mmcReadCached");
+	//plotnext(toatarichar(' '));
+	//plotnextnumber(sector);
+	//debug("\n");
+	if(sector==n_actual_mmc_sector) return;
+	//debug("mmcReadREAL");
+	//plotnext(toatarichar(' '));
+	//plotnextnumber(sector);
+	//debug("\n");
+
+	u08 ret,retry;
+	//predtim nez nacte jiny, musi ulozit soucasny
+	// TODO mmcWriteCachedFlush();
+	//az ted nacte novy
+	retry=0; //zkusi to maximalne 256x
+	do
+	{
+		ret = mmcRead(sector);	//vraci 0 kdyz ok
+		retry--;
+	} while (ret && retry);
+	while(ret); //a pokud se vubec nepovedlo, tady zustane zablokovany cely SDrive!
+	n_actual_mmc_sector=sector;
+}
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Initialize Disk Drive                                                 */
+/*-----------------------------------------------------------------------*/
+
+DSTATUS disk_initialize (void)
+{
+	DSTATUS stat;
+
+	//printf(" in init ");
+	n_actual_mmc_sector = 0xffffffff;
+	for(;;)
+	{
+		mmc_init();
+		if (0==mmcRead(1))
+			break;
+	}
+
+	//printf(" setting freq ");
+
+	set_spi_clock_freq();
+
+	stat = RES_OK;
+
+	return stat;
+}
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Read Partial Sector                                                   */
+/*-----------------------------------------------------------------------*/
+
+DRESULT disk_readp (
+	BYTE* dest,			/* Pointer to the destination object */
+	DWORD sector,		/* Sector number (LBA) */
+	WORD sofs,			/* Offset in the sector */
+	WORD count			/* Byte count (bit15:destination) */
+)
+{
+	DRESULT res;
+
+	/*debug("readp:");
+	plotnextnumber(sector);
+	debug(" ");
+	plotnextnumber((int)dest);
+	debug(" ");
+	plotnextnumber(sofs);
+	debug(" ");
+	plotnextnumber(count);
+	debug(" ");
+	plotnextnumber(atari_sector_buffer);
+	debug(" ");
+	plotnextnumber(mmc_sector_buffer);
+	debug("\n");
+	*/
+	// Put your code here
+	mmcReadCached(sector);
+	for(;count>0;++sofs,--count)
+	{
+		unsigned char x = mmc_sector_buffer[sofs];
+		//printf("char:%c loc:%d ", x,sofs);
+		*dest++ = x;
+	}
+
+	res = RES_OK;
+
+	return res;
+}
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Write Partial Sector                                                  */
+/*-----------------------------------------------------------------------*/
+
+DRESULT disk_writep (const BYTE* buff, DWORD sofs, DWORD count)
+{
+	DRESULT res;
+
+	int i=sofs;
+	int end=sofs+count;
+	int pos = 0;
+	for (;i!=end;++i,++pos)
+	{
+		mmc_sector_buffer[i] = buff[pos];
+		//printf("char:%c loc:%d,", buff[pos],i);
+	}
+
+	res = RES_OK;
+
+	return res;
+}
+
+void disk_writeflush()
+{
+	// Finalize write process
+	int retry=16; //zkusi to maximalne 16x
+	int ret;
+	//printf(":WSECT:%d",n_actual_mmc_sector);
+	do
+	{
+		ret = mmcWrite(n_actual_mmc_sector); //vraci 0 kdyz ok
+		retry--;
+	} while (ret && retry);
+	//printf(":WD:");
+}
+
+
Index: firmware_legacy/sd_direct/spi.h
===================================================================
--- firmware_legacy/sd_direct/spi.h	(nonexistent)
+++ firmware_legacy/sd_direct/spi.h	(revision 799)
@@ -0,0 +1,68 @@
+/*! \file spi.h \brief SPI interface driver. */
+//*****************************************************************************
+//
+// File Name	: 'spi.h'
+// Title		: SPI interface driver
+// Author		: Pascal Stang - Copyright (C) 2000-2002
+// Created		: 11/22/2000
+// Revised		: 06/06/2002
+// Version		: 0.6
+// Target MCU	: Atmel AVR series
+// Editor Tabs	: 4
+//
+// NOTE: This code is currently below version 1.0, and therefore is considered
+// to be lacking in some functionality or documentation, or may not be fully
+// tested.  Nonetheless, you can expect most functions to work.
+//
+///	\ingroup driver_avr
+/// \defgroup spi SPI (Serial Peripheral Interface) Function Library (spi.c)
+/// \code #include "spi.h" \endcode
+/// \par Overview
+///		Provides basic byte and word transmitting and receiving via the AVR
+///	SPI interface.  Due to the nature of SPI, every SPI communication operation
+/// is both a transmit and simultaneous receive.
+///
+///	\note Currently, only MASTER mode is supported.
+//
+// ----------------------------------------------------------------------------
+// 17.8.2008
+// Bob!k & Raster, C.P.U.
+// Original code was modified especially for the SDrive device. 
+// Some parts of code have been added, removed, rewrited or optimized due to
+// lack of MCU AVR Atmega8 memory.
+// ----------------------------------------------------------------------------
+//
+// This code is distributed under the GNU Public License
+//		which can be found at http://www.gnu.org/licenses/gpl.txt
+//
+//*****************************************************************************
+
+
+#ifndef SPI_H
+#define SPI_H
+
+#include "integer.h"
+
+// function prototypes
+void mmcChipSelect(int select);
+
+void set_spi_clock_freq();
+
+// SPI interface initializer
+void spiInit(void);
+
+// spiTransferByte(u08 data) waits until the SPI interface is ready
+// and then sends a single byte over the SPI port.  The function also
+// returns the byte that was received during transmission.
+u08 spiTransferByte(u08 data);
+
+// spiTransferWord(u08 data) works just like spiTransferByte but
+// operates on a whole word (16-bits of data).
+u08 spiTransferFF();
+void spiTransferTwoFF();
+
+void spiDisplay(int i);
+
+void spiReceiveData(u08 * from, u08 * to);
+
+#endif
Index: firmware_legacy/cartridge.h
===================================================================
--- firmware_legacy/cartridge.h	(nonexistent)
+++ firmware_legacy/cartridge.h	(revision 799)
@@ -0,0 +1,6 @@
+#ifndef CARTRIDGE_H
+#define CARTRIDGE_H
+#include "simplefile.h"
+
+int load_car(struct SimpleFile* file);
+#endif
Index: firmware_legacy/native/mmc.h
===================================================================
--- firmware_legacy/native/mmc.h	(nonexistent)
+++ firmware_legacy/native/mmc.h	(revision 799)
@@ -0,0 +1 @@
+link ../sd_direct/mmc.h
\ No newline at end of file

Property changes on: firmware_legacy/native/mmc.h
___________________________________________________________________
Added: svn:special
## -0,0 +1 ##
+*
\ No newline at end of property
Index: firmware_legacy/common/integer.h
===================================================================
--- firmware_legacy/common/integer.h	(nonexistent)
+++ firmware_legacy/common/integer.h	(revision 799)
@@ -0,0 +1,48 @@
+/*-------------------------------------------*/
+/* Integer type definitions for FatFs module */
+/*-------------------------------------------*/
+
+#ifndef _FF_INTEGER
+#define _FF_INTEGER
+
+#ifdef _WIN32	/* FatFs development platform */
+
+#include <windows.h>
+#include <tchar.h>
+
+#else			/* Embedded platform */
+
+/* This type MUST be 8 bit */
+typedef unsigned char	BYTE;
+typedef unsigned char	u08;
+typedef unsigned char	uint8_t;
+
+typedef signed char	int8_t;
+
+/* These types MUST be 16 bit */
+typedef short			SHORT;
+typedef unsigned short	WORD;
+typedef unsigned short	WCHAR;
+typedef unsigned short	u16;
+typedef unsigned short	uint16_t;
+
+typedef signed short	int16_t;
+
+/* These types MUST be 16 bit or 32 bit */
+typedef int				INT;
+typedef unsigned int	UINT;
+
+/* These types MUST be 32 bit */
+typedef long			LONG;
+typedef unsigned int	DWORD;
+typedef unsigned int u32;
+typedef unsigned int uint32_t;
+
+typedef uint8_t bool;
+#define false (0)
+#define NULL (0)
+#define true (1)
+
+#endif
+
+#endif
Index: firmware_legacy/joystick.h
===================================================================
--- firmware_legacy/joystick.h	(nonexistent)
+++ firmware_legacy/joystick.h	(revision 799)
@@ -0,0 +1,17 @@
+#ifndef JOYSTICK_H
+#define JOYSTICK_H
+
+struct joystick_status
+{
+	int x_;
+	int y_;
+	int fire_;
+	int escape_;
+};
+
+enum JoyWait {WAIT_QUIET, WAIT_FIRE, WAIT_MOVE, WAIT_EITHER};
+
+void joystick_poll(struct joystick_status * status);
+void joystick_wait(struct joystick_status * status, enum JoyWait waitFor);
+
+#endif
Index: firmware_legacy/sockit/linuxdir.c
===================================================================
--- firmware_legacy/sockit/linuxdir.c	(nonexistent)
+++ firmware_legacy/sockit/linuxdir.c	(revision 799)
@@ -0,0 +1,286 @@
+#include "linuxdir.h"
+
+#include "linuxfile.h"
+
+#include <sys/types.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+enum SimpleFileStatus openfile(struct SimpleFile * file)
+{
+	char buffer[256];
+	strncpy(&buffer[0],file->path,sizeof(buffer));
+	strncat(&buffer[0],"/",sizeof(buffer));
+	strncat(&buffer[0],file->name,sizeof(buffer));
+
+	if (0==access(buffer,R_OK|W_OK))
+	{
+		file->file = fopen(buffer,"r+");
+	}
+	else if (0==access(buffer,R_OK))
+	{
+		file->file = fopen(buffer,"r");
+	}
+
+	if (file->file)
+	{
+		return SimpleFile_OK;
+	}
+	else
+	{
+		return SimpleFile_FAIL;
+	}
+}
+
+enum SimpleFileStatus file_open_name(char const * path, struct SimpleFile * file)
+{
+	strncpy(file->name,path,sizeof(file->name));
+	strncpy(file->path,path,sizeof(file->path));
+
+	return openfile(file);
+}
+
+enum SimpleFileStatus file_open_name_in_dir(struct SimpleDirEntry * entries, char const * filename, struct SimpleFile * file)
+{
+	//entries->filename + "/" + filename;
+	strncpy(&file->name[0],filename,sizeof(file->name));
+	strncpy(&file->path[0],entries->path,sizeof(file->name));
+
+	return openfile(file);
+}
+
+enum SimpleFileStatus file_open_dir(struct SimpleDirEntry * entry, struct SimpleFile * file)
+{
+	strncpy(&file->path[0],entry->path,sizeof(file->path));
+	strncpy(&file->name[0],entry->entry.d_name,sizeof(file->path));
+
+	return openfile(file);
+}
+
+// Reads entire dir into memory (i.e. give it a decent chunk of sdram)
+char * dir_mem;
+int dir_space;
+enum SimpleFileStatus dir_init(void * mem, int space)
+{
+	// Does own memory allow...
+	dir_mem = mem;
+	dir_space = space;
+	return SimpleFile_OK;
+}
+
+int dircmp(struct SimpleDirEntry * a, struct SimpleDirEntry * b)
+{
+	if (dir_is_subdir(a)==dir_is_subdir(b))
+		return strcmp(a->entry.d_name,b->entry.d_name);
+	else
+		return (dir_is_subdir(a)<dir_is_subdir(b));
+}
+
+void sort_ll(struct SimpleDirEntry * h)
+{
+//struct SimpleDirEntry
+//{
+//	char path[MAX_PATH_LENGTH];
+//	char * filename_ptr;
+//	int size;
+//	int is_subdir;
+//	struct SimpleDirEntry * next; // as linked list - want to allow sorting...
+//};
+
+	struct SimpleDirEntry * p,*temp,*prev;
+	int i,j,n,sorted=0;
+	temp=h;
+	prev=0;
+	for(n=0;temp!=0;temp=temp->next) n++;
+
+	for(i=0;i<n-1 && !sorted;i++){
+		p=h;sorted=1;
+		prev=0;
+		for(j=0;j<n-(i+1);j++){
+	//		printf("p->issubdir:%d(%s) p->next->issubdir:%d(%s)",p->is_subdir,p->path,p->next->is_subdir,p->next->path);
+
+			if(dircmp(p,p->next)>0) {
+	//			printf("SWITCH!\n");
+				struct SimpleDirEntry * a = p;
+				struct SimpleDirEntry * b = p->next;
+				a->next=b->next;
+				b->next=a;
+				if (prev)
+					prev->next=b;
+				p=b;
+
+				sorted=0;
+			}
+			prev=p;
+			p=p->next;
+		}
+	}
+
+	//temp=h;
+	//for(n=0;temp!=0;temp=temp->next) printf("POST:%s\n",temp->path);
+}
+
+struct SimpleDirEntry * dir_entries_filtered(char const * dirPath, int (*filter)(struct SimpleDirEntry *))
+{
+	struct SimpleDirEntry * entry = dir_entries(dirPath);
+	if (!entry) return 0;
+
+	struct SimpleDirEntry * temp1 = entry;
+	while (temp1)
+	{
+		printf("Entry_PRE filtered:%s\n",temp1->entry.d_name);
+		temp1 = temp1->next;
+	}
+
+	struct SimpleDirEntry * head = entry;
+	struct SimpleDirEntry * prev = 0;
+	while (entry)
+	{
+		if (!(*filter)(entry))
+		{
+			if (entry == head)
+				head = head->next;
+			else if (prev)
+				prev->next = entry->next;
+		}
+		else
+		{
+			prev = entry;
+		}
+
+		entry = entry->next;
+	}
+
+	struct SimpleDirEntry * temp = head;
+	while (temp)
+	{
+		printf("Entry_filtered:%s\n",temp->entry.d_name);
+		temp = temp->next;
+	}
+
+	printf("Sorting\n\n");
+
+	if (filter)
+	{
+		sort_ll((struct SimpleDirEntry *) head);
+	}
+
+	printf("sorted\n\n");
+	temp = head;
+	while (temp)
+	{
+		printf("Entry_sorted:%s\n",temp->entry.d_name);
+		temp = temp->next;
+	}
+
+	return head;
+}
+
+struct SimpleDirEntry * dir_entries(char const * dirPath)
+{
+	DIR * dir = opendir(dirPath);
+	if (!dir) return 0;
+
+	char * mem = dir_mem;
+	int remaining_space = dir_space;
+
+	struct SimpleDirEntry * head = (struct SimpleDirEntry *)(mem);
+	mem += sizeof(struct SimpleDirEntry);
+        remaining_space -= sizeof(struct SimpleDirEntry);
+
+	struct SimpleDirEntry * prev = head;
+        while (1)
+        {
+		if (remaining_space < (int)sizeof(struct SimpleDirEntry))
+		{
+			prev->next = 0;
+			return head;
+		}
+
+		struct SimpleDirEntry * myentry = (struct SimpleDirEntry *)(mem);
+		myentry->next = 0;
+
+		struct dirent * result;
+		readdir_r(dir,&myentry->entry,&result);
+
+		if (!result)
+		{
+			break;
+		}
+
+		if (strcmp(".",myentry->entry.d_name) == 0) continue;
+		if (strcmp("..",myentry->entry.d_name) == 0) 
+		{
+			strcpy(head->path,myentry->path);
+			head->entry = myentry->entry;
+			continue;
+		}
+
+		mem += sizeof(struct SimpleDirEntry);
+		remaining_space -= sizeof(struct SimpleDirEntry);
+
+		strncpy(myentry->path,dirPath,sizeof(myentry->path));
+
+		if (!head) head = myentry;
+		if (prev) prev->next = myentry;
+		prev = myentry;
+
+		printf("Entry:%s :%d\n",myentry->entry.d_name,dir_is_subdir(myentry));
+	}
+
+	closedir(dir);
+
+	printf("All done\n\n");
+
+	return head;
+}
+
+char const * dir_filename(struct SimpleDirEntry * entry)
+{
+	return &entry->entry.d_name[0];
+}
+
+char dir_buffer[256];
+char const * dir_path(struct SimpleDirEntry * entry)
+{
+	strncpy(&dir_buffer[0],entry->path,sizeof(dir_buffer));
+	strncat(&dir_buffer[0],"/",sizeof(dir_buffer));
+	strncat(&dir_buffer[0],entry->entry.d_name,sizeof(dir_buffer));
+	
+	return &dir_buffer[0];
+}
+
+int dir_filesize(struct SimpleDirEntry * entry)
+{
+	char buffer[256];
+	strncpy(&buffer[0],entry->path,sizeof(buffer));
+	strncat(&buffer[0],"/",sizeof(buffer));
+	strncat(&buffer[0],entry->entry.d_name,sizeof(buffer));
+
+	struct stat buf;
+	stat(buffer, &buf);
+	return buf.st_size;
+}
+
+struct SimpleDirEntry * dir_next(struct SimpleDirEntry * entry)
+{
+	return entry->next;
+}
+
+int dir_is_subdir(struct SimpleDirEntry * entry)
+{
+	char buffer[256];
+	strncpy(&buffer[0],entry->path,sizeof(buffer));
+	strncat(&buffer[0],"/",sizeof(buffer));
+	strncat(&buffer[0],entry->entry.d_name,sizeof(buffer));
+
+	struct stat buf;
+	stat(buffer, &buf);
+	return S_ISDIR(buf.st_mode);
+}
+
Index: firmware_legacy/sockit/memory.h
===================================================================
--- firmware_legacy/sockit/memory.h	(nonexistent)
+++ firmware_legacy/sockit/memory.h	(revision 799)
@@ -0,0 +1,34 @@
+#ifndef MEMORY_H
+#define MEMORY_H
+
+#include "stdlib.h"
+
+extern unsigned char volatile * virtual_base;
+extern unsigned char volatile * zpu_base;
+
+#define SRAM_BASE ((void*) virtual_base+0x200000)
+#define SDRAM_BASE ((void*) virtual_base+0x800000)
+
+// Memory usage...
+// 0x410000-0x44FFFF (0xc10000 in zpu space) = directory cache - 256k
+// 0x450000-0x46FFFF (0xc50000 in zpu space) = freeze backup
+// 0x700000-0x77FFFF (0xf00000 in zpu space) = os rom/basic rom
+
+#define INIT_MEM init_bridge();
+void init_bridge();
+
+#define DIR_INIT_MEMSIZE 262144
+#define DIR_INIT_MEM (char *)malloc(DIR_INIT_MEMSIZE)
+#define FREEZE_MEM (char unsigned *)malloc(128*1024)
+
+#define CARTRIDGE_MEM (SDRAM_BASE + 0x500000)
+
+// offset into SDRAM
+#define ROM_OFS 0x700000
+
+#define atari_regbase  ((void*) virtual_base + 0x10000)
+#define atari_regmirror  ((void*) virtual_base + 0x20000)
+#define zpu_regbase ((void*) zpu_base)
+#define pokey_regbase ((void*) zpu_base + 0x400)
+
+#endif
Index: firmware_legacy/native/screen.c
===================================================================
--- firmware_legacy/native/screen.c	(nonexistent)
+++ firmware_legacy/native/screen.c	(revision 799)
@@ -0,0 +1,4 @@
+void clearscreen()
+{
+}
+
Index: firmware_legacy/native/spi.h
===================================================================
Index: firmware_legacy/common/utils.h
===================================================================
--- firmware_legacy/common/utils.h	(nonexistent)
+++ firmware_legacy/common/utils.h	(revision 799)
@@ -0,0 +1,6 @@
+int strcmp(char const * a, char const * b);
+int stricmp(char const * a, char const * b);
+void strcpy(char * dest, char const * src);
+void stricpy(char * dest, char const * src);
+int strlen(char const * a);
+
Index: firmware_legacy/mist_5200/dirs.c
===================================================================
--- firmware_legacy/mist_5200/dirs.c	(nonexistent)
+++ firmware_legacy/mist_5200/dirs.c	(revision 799)
@@ -0,0 +1,2 @@
+char USER_DIR[]="/atar5200/user";
+char ROM_DIR[]="/atar5200/rom";
Index: firmware_legacy/sd_direct/spi.c
===================================================================
--- firmware_legacy/sd_direct/spi.c	(nonexistent)
+++ firmware_legacy/sd_direct/spi.c	(revision 799)
@@ -0,0 +1,126 @@
+/*! \file spi.c \brief SPI interface driver. */
+//*****************************************************************************
+//
+// File Name	: 'spi.c'
+// Title		: SPI interface driver
+// Author		: Pascal Stang - Copyright (C) 2000-2002
+// Created		: 11/22/2000
+// Revised		: 06/06/2002
+// Version		: 0.6
+// Target MCU	: Atmel AVR series
+// Editor Tabs	: 4
+//
+// NOTE: This code is currently below version 1.0, and therefore is considered
+// to be lacking in some functionality or documentation, or may not be fully
+// tested.  Nonetheless, you can expect most functions to work.
+//
+// ----------------------------------------------------------------------------
+// 17.8.2008
+// Bob!k & Raster, C.P.U.
+// Original code was modified especially for the SDrive device. 
+// Some parts of code have been added, removed, rewrited or optimized due to
+// lack of MCU AVR Atmega8 memory.
+// ----------------------------------------------------------------------------
+//
+// This code is distributed under the GNU Public License
+//		which can be found at http://www.gnu.org/licenses/gpl.txt
+//
+//*****************************************************************************
+
+#include "spi.h"
+
+#include "regs.h"
+#include "spi.h"
+
+#include "printf.h"
+
+int spi_slow; // 1 is slow
+int spi_chip_select_n; // 0 is selected
+int display;
+void updateSpiState()
+{
+	*zpu_spi_state = (spi_slow<<1)|(spi_chip_select_n);
+}
+
+// access routines
+void setSpiFast()
+{
+	spi_slow = 0;
+	updateSpiState();
+}
+
+void setSpiSlow()
+{
+	spi_slow = 1;
+	updateSpiState();
+}
+
+void set_spi_clock_freq() // avr handles spi clock?
+{
+	setSpiFast();
+}
+
+void spiInit()
+{
+	spiDisplay(0);
+	spi_slow = 1;
+	spi_chip_select_n = 1;
+	updateSpiState();
+}
+
+void mmcChipSelect(int select)
+{
+	spi_chip_select_n = !select;
+	updateSpiState();
+}
+
+u08 spiTransferByte(u08 data)
+{
+	u08 res = 0;
+
+	//debug("spiTransferByte");
+
+	/*if (display!=0)
+	{
+		plotnext(hextoatarichar((data&0xf0) >> 4));
+		plotnext(hextoatarichar((data&0xf)));
+	}*/
+
+	// send the given data
+	*zpu_spi_data = data;
+
+	// wait for transfer to complete
+	while ((1&*zpu_spi_state) == 1);
+
+	// return the received data
+	res = *zpu_spi_data;
+
+	if (display!=0)
+	{
+		//XXX plotnext(hextoatarichar((res&0xf0) >> 4));
+		//XXX plotnext(hextoatarichar((res&0xf)));
+
+		//plotnext(toatarichar(' '));
+	}
+
+	return res;
+}
+
+u08 spiTransferFF()
+{
+	return spiTransferByte(0xFF);
+}
+
+void spiDisplay(int i)
+{
+	display = i;
+}
+
+void spiReceiveData(u08 * from, u08 * to)
+{
+	u32 from32 = (u32)from;
+	u32 to32 = (u32)to;
+	u32 val = to32<<16 | from32;
+	*zpu_spi_dma = val;
+}
+
Index: firmware_legacy/libgcc_divmod.c
===================================================================
--- firmware_legacy/libgcc_divmod.c	(nonexistent)
+++ firmware_legacy/libgcc_divmod.c	(revision 799)
@@ -0,0 +1,86 @@
+unsigned long
+udivmodsi4(unsigned long num, unsigned long den, int modwanted)
+{
+  unsigned long bit = 1;
+  unsigned long res = 0;
+
+  while (den < num && bit && !(den & (1L<<31)))
+    {
+      den <<=1;
+      bit <<=1;
+    }
+  while (bit)
+    {
+      if (num >= den)
+        {
+          num -= den;
+          res |= bit;
+        }
+      bit >>=1;
+      den >>=1;
+    }
+  if (modwanted) return num;
+  return res;
+}
+
+long
+__udivsi3 (long a, long b)
+{
+  return udivmodsi4 (a, b, 0);
+}
+
+long
+__umodsi3 (long a, long b)
+{
+  return udivmodsi4 (a, b, 1);
+}
+
+long
+__divsi3 (long a, long b)
+{
+  int neg = 0;
+  long res;
+
+  if (a < 0)
+    {
+      a = -a;
+      neg = !neg;
+    }
+
+  if (b < 0)
+    {
+      b = -b;
+      neg = !neg;
+    }
+
+  res = udivmodsi4 (a, b, 0);
+
+  if (neg)
+    res = -res;
+
+  return res;
+}
+
+long
+__modsi3 (long a, long b)
+{
+  int neg = 0;
+  long res;
+
+  if (a < 0)
+    {
+      a = -a;
+      neg = 1;
+    }
+
+  if (b < 0)
+    b = -b;
+
+  res = udivmodsi4 (a, b, 1);
+
+  if (neg)
+    res = -res;
+
+  return res;
+}
+
Index: firmware_legacy/printf/printf.h
===================================================================
--- firmware_legacy/printf/printf.h	(nonexistent)
+++ firmware_legacy/printf/printf.h	(revision 799)
@@ -0,0 +1,124 @@
+/*
+File: printf.h
+ 
+Copyright (c) 2004,2012 Kustaa Nyholm / SpareTimeLabs
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, 
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list 
+of conditions and the following disclaimer.
+
+Redistributions in binary form must reproduce the above copyright notice, this 
+list of conditions and the following disclaimer in the documentation and/or other
+materials provided with the distribution.
+ 
+Neither the name of the Kustaa Nyholm or SpareTimeLabs nor the names of its 
+contributors may be used to endorse or promote products derived from this software 
+without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
+IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+
+This library is realy just two files: 'printf.h' and 'printf.c'.
+
+They provide a simple and small (+200 loc) printf functionality to 
+be used in embedded systems.
+
+I've found them so usefull in debugging that I do not bother with a 
+debugger at all.
+
+They are distributed in source form, so to use them, just compile them 
+into your project. 
+
+Two printf variants are provided: printf and sprintf. 
+
+The formats supported by this implementation are: 'd' 'u' 'c' 's' 'x' 'X'.
+
+Zero padding and field width are also supported.
+
+If the library is compiled with 'PRINTF_SUPPORT_LONG' defined then the 
+long specifier is also
+supported. Note that this will pull in some long math routines (pun intended!)
+and thus make your executable noticably longer.
+
+The memory foot print of course depends on the target cpu, compiler and 
+compiler options, but a rough guestimate (based on a H8S target) is about 
+1.4 kB for code and some twenty 'int's and 'char's, say 60 bytes of stack space. 
+Not too bad. Your milage may vary. By hacking the source code you can 
+get rid of some hunred bytes, I'm sure, but personally I feel the balance of 
+functionality and flexibility versus  code size is close to optimal for
+many embedded systems.
+
+To use the printf you need to supply your own character output function, 
+something like :
+
+void putc ( void* p, char c)
+	{
+	while (!SERIAL_PORT_EMPTY) ;
+	SERIAL_PORT_TX_REGISTER = c;
+	}
+
+Before you can call printf you need to initialize it to use your 
+character output function with something like:
+
+init_printf(NULL,putc);
+
+Notice the 'NULL' in 'init_printf' and the parameter 'void* p' in 'putc', 
+the NULL (or any pointer) you pass into the 'init_printf' will eventually be 
+passed to your 'putc' routine. This allows you to pass some storage space (or 
+anything realy) to the character output function, if necessary. 
+This is not often needed but it was implemented like that because it made 
+implementing the sprintf function so neat (look at the source code).
+
+The code is re-entrant, except for the 'init_printf' function, so it 
+is safe to call it from interupts too, although this may result in mixed output. 
+If you rely on re-entrancy, take care that your 'putc' function is re-entrant!
+
+The printf and sprintf functions are actually macros that translate to 
+'tfp_printf' and 'tfp_sprintf'. This makes it possible
+to use them along with 'stdio.h' printf's in a single source file. 
+You just need to undef the names before you include the 'stdio.h'.
+Note that these are not function like macros, so if you have variables
+or struct members with these names, things will explode in your face.
+Without variadic macros this is the best we can do to wrap these
+fucnction. If it is a problem just give up the macros and use the
+functions directly or rename them.
+
+For further details see source code.
+
+regs Kusti, 23.10.2004
+*/
+
+
+#ifndef __TFP_PRINTF__
+#define __TFP_PRINTF__
+
+#include <stdarg.h>
+
+void init_printf(void* putp,void (*putf) (void*,char));
+
+void tfp_printf(char *fmt, ...);
+void tfp_sprintf(char* s,char *fmt, ...);
+
+void tfp_format(void* putp,void (*putf) (void*,char),char *fmt, va_list va);
+
+#define printf(x...) tfp_printf(x)
+#define sprintf(x...) tfp_sprintf(x)
+
+#endif
+
+
+

Property changes on: firmware_legacy/printf/printf.h
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: firmware_legacy/test_file.c
===================================================================
--- firmware_legacy/test_file.c	(nonexistent)
+++ firmware_legacy/test_file.c	(revision 799)
@@ -0,0 +1,233 @@
+#include "simpledir.h"
+#include "simplefile.h"
+#include "fileselector.h"
+
+//#include "fat/pff_file.h"
+// XXX - BEST NOT to include this?
+char USER_DIR[]="/";
+char ROM_DIR[]="/";
+
+#include "stdio.h"
+#include "stdlib.h"
+
+int debug_pos = 0;
+int prev_debug_pos = 0;
+int debug_adjust = 0;
+void wait_us(int us)
+{
+	usleep(us);
+}
+
+void char_out ( void* p, char c)
+{
+	if (debug_pos!=prev_debug_pos)
+	{
+		fprintf(stderr,"\n");
+	}
+	//fprintf(stderr,"\n%dWTFWTF\n", debug_pos);
+	if (debug_adjust == 128)
+	{
+		putc('*',stderr);
+	}
+	putc(c, stderr);
+	++debug_pos;
+	prev_debug_pos = debug_pos;
+}
+
+struct SimpleFile * temp_file;
+
+/*void loadrom(char const * path, int size, void * ram_address)
+{
+	filter = 0;
+	fprintf(stderr,"loadrom:%s\n",path);
+	ram_address += 0x800000;
+	if (SimpleFile_OK == file_open_name(path, temp_file))
+	{
+		int read = 0;
+		//file_read(temp_file, ram_address, size, &read);
+		printf("file_read:%s %x %x\n",file_name(temp_file), ram_address,size); 
+	}
+	else
+	{
+		printf("%s:FAILED\n",path);
+	}
+}*/
+
+void loadromfile(struct SimpleFile * file, int size, void * ram_address)
+{
+	ram_address += 0x800000;
+	int read = 0;
+	//file_read(file, ram_address, size, &read);
+	printf("file_read:%s %x %x\n",file_name(temp_file), ram_address,size); 
+}
+
+void loadrom(char const * path, int size, void * ram_address)
+{
+	if (SimpleFile_OK == file_open_name(path, temp_file))
+	{
+		loadromfile(temp_file, size, ram_address);
+	}
+	else
+	{
+		printf("%s:FAILED\n",path);
+	}
+}
+
+void loadrom_indir(struct SimpleDirEntry * entries, char const * filename, int size, void * ram_address)
+{
+	if (SimpleFile_OK == file_open_name_in_dir(entries, filename, temp_file))
+	{
+		loadromfile(temp_file, size, ram_address);
+	}
+	else
+	{
+		printf("FAILED\n");
+	}
+}
+
+int main(void)
+{
+	init_printf(NULL, char_out);
+
+	char * mem = (char *)malloc(65536);
+	if (SimpleFile_OK != dir_init(mem, 65536))
+	{
+		fprintf(stderr,"Failed to open dir!");
+		return -1;
+	}
+	struct SimpleDirEntry * entry = dir_entries("");
+	while (entry)
+	{
+		fprintf(stderr, "Path:%s", dir_path(entry));
+		fprintf(stderr, " Name:%s", dir_filename(entry));
+		fprintf(stderr, " Size:%d", dir_filesize(entry));
+		fprintf(stderr, " Subdir:%d\n", dir_is_subdir(entry));
+
+		entry = dir_next(entry);
+	}
+
+	fprintf(stderr,"\n\n");
+
+	entry = dir_entries("/atari800");
+	while (entry)
+	{
+		fprintf(stderr, "Path:%s", dir_path(entry));
+		fprintf(stderr, " Name:%s", dir_filename(entry));
+		fprintf(stderr, " Size:%d", dir_filesize(entry));
+		fprintf(stderr, " Subdir:%d\n", dir_is_subdir(entry));
+
+		entry = dir_next(entry);
+	}
+
+	fprintf(stderr,"\n\n");
+
+	entry = dir_entries("/atari800/user");
+	while (entry)
+	{
+		fprintf(stderr, "Path:%s", dir_path(entry));
+		fprintf(stderr, " Name:%s", dir_filename(entry));
+		fprintf(stderr, " Size:%d", dir_filesize(entry));
+		fprintf(stderr, " Subdir:%d\n", dir_is_subdir(entry));
+
+		entry = dir_next(entry);
+	}
+
+
+/*
+	fprintf(stderr,"\n\n");
+//enum SimpleFileStatus file_open_name(char const * path, struct SimpleFile * file);
+//enum SimpleFileStatus file_open_dir(struct SimpleDirEntry * filename, struct SimpleFile * file);
+	entry = dir_entries("/UAE4ALL");
+	entry = dir_next(entry);
+	fprintf(stderr, " Name:%s", dir_filename(entry));
+	struct SimpleFile * file = alloca(file_struct_size());
+	file_open_dir(entry,file);
+
+//char const * file_name(struct SimpleFile * file);
+//enum SimpleFileStatus file_read(struct SimpleFile * file, void * buffer, int bytes, int * bytesread);
+//enum SimpleFileStatus file_write(struct SimpleFile * file, void * buffer, int bytes, int * byteswritten);
+//enum SimpleFileStatus file_seek(struct SimpleFile * file, int offsetFromStart);
+//int file_size(struct SimpleFile * file);
+	fprintf(stderr, " Size:%d\n---\n", file_size(file));
+
+	int read = 0;
+	char buffer[2048];
+	file_seek(file,10);
+	file_read(file,&buffer[0],2048,&read);
+	int i;
+	for (i=0; i!=read; ++i)
+	{
+		//fprintf(stderr,"%02x", buffer[i]);
+		fprintf(stderr,"%c", buffer[i]);
+	}
+
+	fprintf(stderr,"\n\n");
+
+	int written;
+	file_seek(file,10);
+	file_write(file,"Mark",4,&written); // in order to write 'mark' as position 10...
+	//file_write_flush(); // Done automatically on next read, or can be forced with this...
+
+	file_seek(file,512);
+//	for (i=0;i!=130;++i)
+//	{
+//		char towrite[9];
+//		sprintf(&towrite[0],"Mark:%03d",i);
+//		fprintf(stderr,"Writing \"%s\"\n",towrite);
+//		file_write(file,towrite,8,&written);
+//	}
+//	file_write(file,"Blah",4,&written);
+
+	printf("\n*** WTF:%s - %s - %s\n",file_name(file), file_of("/WTF"),file_of("/BLAH/BOOP"));
+
+	// So... for write can only seek to nearest 512...
+
+	fprintf(stderr,"\n\n");
+	file_seek(file,10);
+	file_read(file,&buffer[0],2048,&read);
+	for (i=0; i!=read; ++i)
+	{
+		//fprintf(stderr,"%02x", buffer[i]);
+		fprintf(stderr,"%c", buffer[i]);
+	}
+*/
+
+	temp_file = alloca(file_struct_size());
+		loadrom("ASTEROID.BIN",0x4000, (void *)0x704000);
+		loadrom("asteroid.bin",0x4000, (void *)0x704000);
+		loadrom("xlorig.rom",0x4000, (void *)0x704000);
+		loadrom("xlhias.rom",0x4000, (void *)0x708000);
+		loadrom("ultimon.rom",0x4000, (void *)0x70c000);
+		loadrom("osbhias.rom",0x4000, (void *)0x710000);
+		loadrom("osborig.rom",0x2800, (void *)0x715800);
+		loadrom("osaorig.rom",0x2800, (void *)0x719800);
+		loadrom("ataribas.rom",0x2000,(void *)0x700000);
+
+	/*{
+		printf("WTF\n");
+		struct SimpleDirEntry * entries = dir_entries("/system/rom/atari800");
+		entries = dir_next(entries);
+		printf("WTF:%s\n",dir_filename(entries));
+		
+		loadrom_indir(entries,"xlorig.rom",0x4000, (void *)0x704000);
+		loadrom_indir(entries,"xlhias.rom",0x4000, (void *)0x708000);
+		loadrom_indir(entries,"ultimon.rom",0x4000, (void *)0x70c000);
+		loadrom_indir(entries,"osbhias.rom",0x4000, (void *)0x710000);
+		loadrom_indir(entries,"osborig.rom",0x2800, (void *)0x715800);
+		loadrom_indir(entries,"osaorig.rom",0x2800, (void *)0x719800);
+		loadrom_indir(entries,"ataribas.rom",0x2000,(void *)0x700000);
+	}*/
+
+	//entry = dir_entries("/atari800/user");
+	//entry = dir_next(entry);
+	//fprintf(stderr, " Name:%s", dir_filename(entry));
+	struct SimpleFile * file = alloca(file_struct_size());
+	//file_open_name("/atari800/user/acid800.atr",file);
+	//fprintf(stderr, "XXX Name:%s", file_name(file));
+	filter = filter_disks;
+	file_selector(file);
+
+	return 0;
+}
+
+
Index: firmware_legacy/sockit/dirs.c
===================================================================
--- firmware_legacy/sockit/dirs.c	(nonexistent)
+++ firmware_legacy/sockit/dirs.c	(revision 799)
@@ -0,0 +1,2 @@
+char USER_DIR[]="/home/root/atari800/user";
+char ROM_DIR[]="/home/root/atari800/rom";
Index: firmware_legacy/sockit/linuxfile.h
===================================================================
--- firmware_legacy/sockit/linuxfile.h	(nonexistent)
+++ firmware_legacy/sockit/linuxfile.h	(revision 799)
@@ -0,0 +1,13 @@
+#pragma once
+
+#include "simplefile.h"
+
+#include <stdio.h>
+
+struct SimpleFile
+{
+	FILE * file;
+	char path[256];
+	char name[256];
+};
+
Index: firmware_legacy/native/mmc.c
===================================================================
--- firmware_legacy/native/mmc.c	(nonexistent)
+++ firmware_legacy/native/mmc.c	(revision 799)
@@ -0,0 +1,56 @@
+#include "mmc.h"
+
+#include <stdio.h>
+
+FILE * disk_image;
+char mmc_sector_buffer[512];
+
+void set_spi_clock_freq()
+{
+}
+
+//! Initialize AVR<->MMC hardware interface.
+/// Prepares hardware for MMC access.
+
+void mmc_init()
+{
+	mmcInit();
+}
+
+void mmcInit(void)
+{
+	//disk_image = fopen("/home/markw/fpga/sd_images/sd.image","r+");
+	//disk_image = fopen("/home/markw/fpga/sd_images/sd_large.image","r+");
+	disk_image = fopen("/home/markw/fpga/sd_images/sdimage_elektraglide","r+");
+
+	fprintf(stderr,"mmcInit:%x\n",disk_image);
+}
+
+//! Initialize the card and prepare it for use.
+/// Returns zero if successful.
+u08 mmcReset(void){ return 0;}
+
+//! Read 512-byte sector from card to buffer
+/// Returns zero if successful.
+u08 mmcRead(u32 sector)
+{
+	//fprintf(stderr,"mmcRead:%x\n",sector);
+
+	fseek(disk_image, sector*512, SEEK_SET);
+	fread(&mmc_sector_buffer,512,1,disk_image);
+
+	return 0;
+}
+
+//! Write 512-byte sector from buffer to card
+/// Returns zero if successful.
+u08 mmcWrite(u32 sector)
+{
+	fprintf(stderr,"mmcWrite:%x\n",sector);
+
+	fseek(disk_image, sector*512, SEEK_SET);
+	fwrite(&mmc_sector_buffer,512,1,disk_image);
+
+	return 0;
+}
+
Index: firmware_legacy/native/regs.c
===================================================================
--- firmware_legacy/native/regs.c	(nonexistent)
+++ firmware_legacy/native/regs.c	(revision 799)
@@ -0,0 +1,8 @@
+#include "regs.h"
+
+char native_porta;
+char native_trig;
+
+unsigned char volatile * atari_porta = (unsigned char volatile *)&native_porta;
+unsigned char volatile * atari_trig0 = (unsigned char volatile *)&native_trig;
+
Index: firmware_legacy/common/utils.c
===================================================================
--- firmware_legacy/common/utils.c	(nonexistent)
+++ firmware_legacy/common/utils.c	(revision 799)
@@ -0,0 +1,50 @@
+#include "utils.h"
+
+int strcmp(char const * a, char const * b)
+{
+	while (*a || *b)
+	{
+		if (*a<*b)
+			return -1;
+		else if (*a>*b)
+			return 1;
+
+		++a;
+		++b;
+	}
+	return 0;
+}
+
+int stricmp(char const * a, char const * b)
+{
+	char buffer[128];
+	char buffer2[128];
+	stricpy(&buffer[0],a);
+	stricpy(&buffer2[0],b);
+	return strcmp(&buffer[0],&buffer2[0]);
+}
+
+void strcpy(char * dest, char const * src)
+{
+	while (*dest++=*src++);
+}
+
+void stricpy(char * dest, char const * src)
+{
+	while (*src)
+	{
+		char val = *src++;
+		if (val>='A' && val<='Z') val+=-'A'+'a';
+
+		*dest++ = val;
+	}
+	*dest = '\0';
+}
+
+int strlen(char const * a)
+{
+	int count;
+	for (count=0; *a; ++a,++count);
+	return count;
+}
+
Index: firmware_legacy/de1_5200/dirs.c
===================================================================
--- firmware_legacy/de1_5200/dirs.c	(nonexistent)
+++ firmware_legacy/de1_5200/dirs.c	(revision 799)
@@ -0,0 +1,2 @@
+char USER_DIR[]="/atar5200/user";
+char ROM_DIR[]="/atar5200/rom";
Index: firmware_legacy/sd_direct/mmc.h
===================================================================
--- firmware_legacy/sd_direct/mmc.h	(nonexistent)
+++ firmware_legacy/sd_direct/mmc.h	(revision 799)
@@ -0,0 +1,145 @@
+/*! \file mmc.h \brief MultiMedia and SD Flash Card Interface. */
+//*****************************************************************************
+//
+// File Name	: 'mmc.h'
+// Title		: MultiMedia and SD Flash Card Interface
+// Author		: Pascal Stang - Copyright (C) 2004
+// Created		: 2004.09.22
+// Revised		: 2004.09.22
+// Version		: 0.1
+// Target MCU	: Atmel AVR Series
+// Editor Tabs	: 4
+//
+///	\ingroup driver_hw
+/// \defgroup mmc MultiMedia and SD Flash Card Interface (mmc.c)
+/// \code #include "mmc.h" \endcode
+/// \par Description
+///		This library offers some simple functions which can be used
+///		to read and write data on a MultiMedia or SecureDigital (SD) Flash
+///		Card.  Although MM and SD Cards are designed to operate with their own
+///		special bus wiring and protocols, both types of cards also provide a
+///		simple SPI-like interface mode which is exceptionally useful when 
+///		attempting to use the cards in embedded systems.
+///
+/// \par Wiring
+///		To work with this library, the card must be wired to the SPI port of
+///		the Atmel microcontroller as described below.  Typical cards can
+///		operate at up to 25MHz maximum SPI clock rate (thus faster than most
+///		AVR's maximum SPI clock rate).
+/// <pre>
+///	      _________________
+///	     /  1 2 3 4 5 6 78 |	<- view of MMC/SD card looking at contacts
+///	    / 9                |	Pins 8 and 9 are present only on SD cards
+///	    |    MMC/SD Card   |
+///	    |                  |
+///	    --------------------
+///	    1 - CS   (chip select)          - wire to any available I/O pin(*)
+///	    2 - DIN  (data in, card<-host)  - wire to SPI MOSI pin
+///	    3 - VSS  (ground)               - wire to ground
+///	    4 - VDD  (power, 3.3V only?)    - wire to power (MIGHT BE 3.3V ONLY!)
+///	    5 - SCLK (data clock)           - wire to SPI SCK pin
+///	    6 - VSS  (ground)               - wire to ground
+///	    7 - DOUT (data out, card->host) - wire to SPI MISO pin
+///
+///	    (*) you must define this chip select I/O pin in mmcconf.h
+/// </pre>
+/// \note This code is currently below version 1.0, and therefore is considered
+/// to be lacking in some functionality or documentation, or may not be fully
+/// tested.  Nonetheless, you can expect most functions to work.
+//
+// ----------------------------------------------------------------------------
+// 17.8.2008
+// Bob!k & Raster, C.P.U.
+// Original code was modified especially for the SDrive device. 
+// Some parts of code have been added, removed, rewrited or optimized due to
+// lack of MCU AVR Atmega8 memory.
+// ----------------------------------------------------------------------------
+//
+// This code is distributed under the GNU Public License
+//		which can be found at http://www.gnu.org/licenses/gpl.txt
+//
+//*****************************************************************************
+
+
+#ifndef MMC_H
+#define MMC_H
+
+#include "integer.h"
+
+// constants/macros/typdefs
+// MMC commands (taken from sandisk MMC reference)
+#define MMC_GO_IDLE_STATE			0		///< initialize card to SPI-type access
+#define MMC_SEND_OP_COND			1		///< set card operational mode
+#define MMC_SEND_CSD				9		///< get card's CSD
+#define MMC_SEND_CID				10		///< get card's CID
+#define MMC_SEND_STATUS				13
+#define MMC_SET_BLOCKLEN			16		///< Set number of bytes to transfer per block
+#define MMC_READ_SINGLE_BLOCK		17		///< read a block
+#define MMC_WRITE_BLOCK				24		///< write a block
+#define MMC_PROGRAM_CSD				27
+#define MMC_SET_WRITE_PROT			28
+#define MMC_CLR_WRITE_PROT			29
+#define MMC_SEND_WRITE_PROT			30
+#define MMC_TAG_SECTOR_START		32
+#define MMC_TAG_SECTOR_END			33
+#define MMC_UNTAG_SECTOR			34
+#define MMC_TAG_ERASE_GROUP_START 	35		///< Sets beginning of erase group (mass erase)
+#define MMC_TAG_ERARE_GROUP_END		36		///< Sets end of erase group (mass erase)
+#define MMC_UNTAG_ERASE_GROUP		37		///< Untag (unset) erase group (mass erase)
+#define MMC_ERASE					38		///< Perform block/mass erase
+#define MMC_CRC_ON_OFF				59		///< Turns CRC check on/off
+// R1 Response bit-defines
+#define MMC_R1_BUSY					0x80	///< R1 response: bit indicates card is busy
+#define MMC_R1_PARAMETER			0x40
+#define MMC_R1_ADDRESS				0x20
+#define MMC_R1_ERASE_SEQ			0x10
+#define MMC_R1_COM_CRC				0x08
+#define MMC_R1_ILLEGAL_COM			0x04
+#define MMC_R1_ERASE_RESET			0x02
+#define MMC_R1_IDLE_STATE			0x01
+// Data Start tokens
+#define MMC_STARTBLOCK_READ			0xFE	///< when received from card, indicates that a block of data will follow
+#define MMC_STARTBLOCK_WRITE		0xFE	///< when sent to card, indicates that a block of data will follow
+#define MMC_STARTBLOCK_MWRITE		0xFC
+// Data Stop tokens
+#define MMC_STOPTRAN_WRITE			0xFD
+// Data Error Token values
+#define MMC_DE_MASK					0x1F
+#define MMC_DE_ERROR				0x01
+#define MMC_DE_CC_ERROR				0x02
+#define MMC_DE_ECC_FAIL				0x04
+#define MMC_DE_OUT_OF_RANGE			0x04
+#define MMC_DE_CARD_LOCKED			0x04
+// Data Response Token values
+#define MMC_DR_MASK					0x1F
+#define MMC_DR_ACCEPT				0x05
+#define MMC_DR_REJECT_CRC			0x0B
+#define MMC_DR_REJECT_WRITE_ERROR	0x0D
+
+// functions
+
+//! Initialize AVR<->MMC hardware interface.
+/// Prepares hardware for MMC access.
+void mmc_init(void);
+
+//! Initialize the card and prepare it for use.
+/// Returns zero if successful.
+//u08 mmcReset(void);
+
+//! Send card an MMC command.
+/// Returns R1 result code.
+//u08 mmcSendCommand(u08 cmd, u32 arg);
+
+//! Read 512-byte sector from card to buffer
+/// Returns zero if successful.
+u08 mmcRead(u32 sector);
+
+//! Write 512-byte sector from buffer to card
+/// Returns zero if successful.
+u08 mmcWrite(u32 sector);
+
+//! Internal command function.
+/// Issues a generic MMC command as specified by cmd and arg.
+//u08 mmcCommand(u08 cmd, u32 arg);
+
+#endif
Index: firmware_legacy/cartridge.c
===================================================================
--- firmware_legacy/cartridge.c	(nonexistent)
+++ firmware_legacy/cartridge.c	(revision 799)
@@ -0,0 +1,122 @@
+#include "memory.h"
+#include "simpledir.h"
+#include "cartridge.h"
+#include "log.h"
+
+struct CartDef {
+	unsigned char carttype;	// type from CAR header
+	unsigned char mode;		// mode used in cartridge emulation
+	unsigned short size;		// size in k
+};
+
+// 8k modes (0xA000-$BFFF)
+#define TC_MODE_OFF             0x00           // cart disabled
+#define TC_MODE_8K              0x01           // 8k banks at $A000
+#define TC_MODE_ATARIMAX1       0x02           // 8k using Atarimax 1MBit compatible banking
+#define TC_MODE_ATARIMAX8       0x03           // 8k using Atarimax 8MBit compatible banking
+#define TC_MODE_OSS             0x04           // 16k OSS cart, M091 banking
+
+#define TC_MODE_SDX64           0x08           // SDX 64k cart, $D5Ex banking
+#define TC_MODE_DIAMOND64       0x09           // Diamond GOS 64k cart, $D5Dx banking
+#define TC_MODE_EXPRESS64       0x0A           // Express 64k cart, $D57x banking
+
+#define TC_MODE_ATRAX128        0x0C           // Atrax 128k cart
+#define TC_MODE_WILLIAMS64      0x0D           // Williams 64k cart
+
+// 16k modes (0x8000-$BFFF)
+//#define TC_MODE_FLEXI           0x20           // flexi mode
+#define TC_MODE_16K             0x21           // 16k banks at $8000-$BFFF
+#define TC_MODE_MEGAMAX16       0x22           // MegaMax 16k mode (up to 2MB)
+#define TC_MODE_BLIZZARD        0x23           // Blizzard 16k
+#define TC_MODE_SIC             0x24           // Sic!Cart 512k
+
+#define TC_MODE_MEGA_16         0x28           // switchable MegaCarts
+#define TC_MODE_MEGA_32         0x29
+#define TC_MODE_MEGA_64         0x2A
+#define TC_MODE_MEGA_128        0x2B
+#define TC_MODE_MEGA_256        0x2C
+#define TC_MODE_MEGA_512        0x2D
+#define TC_MODE_MEGA_1024       0x2E
+#define TC_MODE_MEGA_2048       0x2F
+
+#define TC_MODE_XEGS_32         0x30           // non-switchable XEGS carts
+#define TC_MODE_XEGS_64         0x31
+#define TC_MODE_XEGS_128        0x32
+#define TC_MODE_XEGS_256        0x33
+#define TC_MODE_XEGS_512        0x34
+#define TC_MODE_XEGS_1024       0x35
+
+#define TC_MODE_SXEGS_32        0x38           // switchable XEGS carts
+#define TC_MODE_SXEGS_64        0x39
+#define TC_MODE_SXEGS_128       0x3A
+#define TC_MODE_SXEGS_256       0x3B
+#define TC_MODE_SXEGS_512       0x3C
+#define TC_MODE_SXEGS_1024      0x3D
+
+static struct CartDef cartdef[] = {
+        { 1, TC_MODE_8K, 8 },
+        { 2, TC_MODE_16K, 16 },
+        { 8, TC_MODE_WILLIAMS64, 64 },
+        { 9, TC_MODE_EXPRESS64, 64 },
+        { 10, TC_MODE_DIAMOND64, 64 },
+        { 11, TC_MODE_SDX64, 64 },
+        { 12, TC_MODE_XEGS_32, 32 },
+        { 13, TC_MODE_XEGS_64, 64 },
+        { 14, TC_MODE_XEGS_128, 128 },
+        { 15, TC_MODE_OSS, 16 },
+        { 17, TC_MODE_ATRAX128, 128 },
+        { 23, TC_MODE_XEGS_256, 256 },
+        { 24, TC_MODE_XEGS_512, 512 },
+        { 26, TC_MODE_MEGA_16, 16 },
+        { 27, TC_MODE_MEGA_32, 32 },
+        { 28, TC_MODE_MEGA_64, 64 },
+        { 29, TC_MODE_MEGA_128, 128 },
+        { 30, TC_MODE_MEGA_256, 256 },
+        { 31, TC_MODE_MEGA_512, 512 },
+        { 33, TC_MODE_SXEGS_32, 32 },
+        { 34, TC_MODE_SXEGS_64, 64 },
+        { 35, TC_MODE_SXEGS_128, 128 },
+        { 36, TC_MODE_SXEGS_256, 256 },
+        { 37, TC_MODE_SXEGS_512, 512 },
+        { 40, TC_MODE_BLIZZARD, 16 },
+        { 41, TC_MODE_ATARIMAX1, 128 },
+        { 42, TC_MODE_ATARIMAX8, 1024 },
+        { 56, TC_MODE_SIC, 512 },
+	{ 0, 0, 0 }
+};
+
+int load_car(struct SimpleFile* file)
+{
+	if (CARTRIDGE_MEM == 0) {
+		LOG("no cartridge memory\n");
+		return 0;
+	}
+	int len;
+	enum SimpleFileStatus ok;
+	unsigned char header[16];
+	ok = file_read(file, header, 16, &len);
+	if (ok != SimpleFile_OK || len != 16) {
+		LOG("cannot read cart header\n");
+		return 0;
+	}
+	unsigned char carttype = header[7];
+
+	// search for cartridge definition
+	struct CartDef* def = cartdef;
+	while (def->carttype && def->carttype != carttype) {
+		def++;
+	}
+	if (def->carttype == 0) {
+		LOG("illegal cart type %d\n", carttype);
+		return 0;
+	}
+	unsigned int byte_len = (unsigned int) def->size << 10;
+	ok = file_read(file, CARTRIDGE_MEM, byte_len, &len);
+	if (ok != SimpleFile_OK || len != byte_len) {
+		LOG("cannot read cart data\n");
+		return 0;
+	}
+	LOG("cart type: %d size: %dk\n",
+		 def->mode, def->size);
+	return def->mode;
+}
Index: firmware_legacy/test_freeze.c
===================================================================
--- firmware_legacy/test_freeze.c	(nonexistent)
+++ firmware_legacy/test_freeze.c	(revision 799)
@@ -0,0 +1,86 @@
+#include "memory.h"
+#include "regs.h"
+
+void clearscreen()
+{
+/*	unsigned volatile char * screen;
+	for (screen=(unsigned volatile char *)(screen_address+atari_regbase); screen!=(unsigned volatile char *)(atari_regbase+screen_address+1024); ++screen)
+		*screen = 0x00;*/
+}
+
+#include "stdlib.h"
+#include "stdio.h"
+
+void memset8(void * address, int value, int length)
+{
+	char * mem = address;
+	while (length--)
+		*mem++=value;
+}
+
+#undef atari_regbase
+static char * atari_regbase = (char *)malloc(65536);
+#undef atari_regmirror
+static char * atari_regmirror = (char *)malloc(65536);
+#include "freeze.h"
+#include "a800/freeze_ci.c"
+#include "regs.c"
+
+int main(void)
+{
+	char * buffer = (char *)malloc(1024*128);
+	freeze_init(buffer);
+
+	for (int i=0; i!=64*1024; ++i)
+	{
+		*((unsigned char *)(atari_regbase+i)) = i%256;
+	}
+	
+	for (int i=0;i!=0x10000;++i)
+	{
+		*((atari_regmirror+i)) = i%256-2;
+	}
+
+	freeze();
+
+	for (int i=0; i!=64*1024; ++i)
+	{
+		fprintf(stderr,"i:%x stored:%x regbase:%x mirror:%x\n",i,
+			*((unsigned char *)(buffer+i)),
+			*((unsigned char *)(atari_regbase+i)),
+			*((unsigned char *)(atari_regmirror+i))
+		);
+/*		if (i%256!=*((unsigned char *)(buffer+i)))
+		{
+			fprintf(stderr,"!!FAIL!%d %d %d", i, i%256, *(unsigned char *)(atari_regbase+i));
+			return -1;
+		}*/
+	}
+	return 0;
+
+	for (int i=0;i!=0xd000; ++i)
+	{
+		*((atari_regbase+i)) = 0;
+	}
+	for (int i=0xd800;i!=0x10000; ++i)
+	{
+		*((atari_regbase+i)) = 0;
+	}
+	restore();
+
+	for (int i=0; i!=64*1024; ++i)
+	{
+		unsigned char exp = i%256;
+		if (i>=0xd000 && i<0xd800) exp-=2;
+		if (i>=0xd020 && i<0xd200) exp+=2;
+		if (i>=0xd220 && i<0xd400) exp+=2;
+		if (i>=0xd410 && i<0xd800) exp+=2;
+		if (exp!=*((unsigned char *)(atari_regbase+i)))
+		{
+			fprintf(stderr,"FAIL!addr:%x exp:%d got:%d", i, exp, *(unsigned char *)(atari_regbase+i));
+			return -1;
+		}
+	}
+	return 0;
+}
+
Index: firmware_legacy/mist/dirs.c
===================================================================
--- firmware_legacy/mist/dirs.c	(nonexistent)
+++ firmware_legacy/mist/dirs.c	(revision 799)
@@ -0,0 +1,2 @@
+char USER_DIR[]="/atari800/user";
+char ROM_DIR[]="/atari800/rom";
Index: firmware_legacy/sd_direct/mmc2.c
===================================================================
--- firmware_legacy/sd_direct/mmc2.c	(nonexistent)
+++ firmware_legacy/sd_direct/mmc2.c	(revision 799)
@@ -0,0 +1,255 @@
+/*-------------------------------------------------------------------------*/
+/* PFF - Low level disk control module for PIC            (C)ChaN, 2014    */
+/*-------------------------------------------------------------------------*/
+
+#include "pff.h"
+#include "diskio.h"
+
+//#include "printf.h"
+
+/*-------------------------------------------------------------------------*/
+/* Platform dependent macros and functions needed to be modified           */
+/*-------------------------------------------------------------------------*/
+
+#define SELECT() mmcChipSelect(1)
+#define	DESELECT() mmcChipSelect(0)
+
+unsigned char mmc_sector_buffer[512];
+
+extern u32 n_actual_mmc_sector;
+
+/*--------------------------------------------------------------------------
+
+   Module Private Functions
+
+---------------------------------------------------------------------------*/
+
+/* Definitions for MMC/SDC command */
+#define CMD0	(0x40+0)	/* GO_IDLE_STATE */
+#define CMD1	(0x40+1)	/* SEND_OP_COND (MMC) */
+#define	ACMD41	(0xC0+41)	/* SEND_OP_COND (SDC) */
+#define CMD8	(0x40+8)	/* SEND_IF_COND */
+#define CMD16	(0x40+16)	/* SET_BLOCKLEN */
+#define CMD17	(0x40+17)	/* READ_SINGLE_BLOCK */
+#define CMD24	(0x40+24)	/* WRITE_BLOCK */
+#define CMD55	(0x40+55)	/* APP_CMD */
+#define CMD58	(0x40+58)	/* READ_OCR */
+
+
+/* Card type flags (CardType) */
+#define CT_MMC				0x01	/* MMC ver 3 */
+#define CT_SD1				0x02	/* SD ver 1 */
+#define CT_SD2				0x04	/* SD ver 2 */
+#define CT_BLOCK			0x08	/* Block addressing */
+
+BYTE CardType;
+
+
+extern int debug_pos;
+
+void disk_debug()
+{
+/*	{
+		char buffer[512];
+		set_pause_6502(1);
+		freeze();
+		debug_pos = 0;	
+
+		printf("Hello world 5");
+		debug_pos = 40;
+
+		printf("Di");
+
+		debug_pos = 80;
+		disk_initialize();
+
+		printf("Did:%02x",CardType);
+
+		debug_pos = 120;
+
+		n_actual_mmc_sector = -1;
+		printf(" PP");
+		disk_readp(&buffer[0],0,0,512);
+		printf(" DD");
+		hexdump_pure(&buffer[0],512);
+
+		wait_us(10000000);
+		restore();
+	}
+*/
+}
+
+/*-----------------------------------------------------------------------*/
+/* Send a command packet to the SDC/MMC                                  */
+/*-----------------------------------------------------------------------*/
+
+static
+BYTE send_cmd (
+	BYTE cmd,		/* 1st byte (Start + Index) */
+	DWORD arg		/* Argument (32 bits) */
+)
+{
+	BYTE n, res;
+
+
+	if (cmd & 0x80) {	/* ACMD<n> is the command sequense of CMD55-CMD<n> */
+		cmd &= 0x7F;
+		res = send_cmd(CMD55, 0);
+		if (res > 1) return res;
+	}
+
+	/* Select the card */
+	DESELECT();
+	spiTransferFF();
+	SELECT();
+	spiTransferFF();
+
+	/* Send a command packet */
+	spiTransferByte(cmd);						/* Start + Command index */
+	spiTransferByte((BYTE)(arg >> 24));		/* Argument[31..24] */
+	spiTransferByte((BYTE)(arg >> 16));		/* Argument[23..16] */
+	spiTransferByte((BYTE)(arg >> 8));			/* Argument[15..8] */
+	spiTransferByte((BYTE)arg);				/* Argument[7..0] */
+	n = 0x01;							/* Dummy CRC + Stop */
+	if (cmd == CMD0) n = 0x95;			/* Valid CRC for CMD0(0) */
+	if (cmd == CMD8) n = 0x87;			/* Valid CRC for CMD8(0x1AA) */
+	spiTransferByte(n);
+
+	/* Receive a command response */
+	n = 10;								/* Wait for a valid response in timeout of 10 attempts */
+	do {
+		res = spiTransferFF();
+	} while ((res & 0x80) && --n);
+
+	return res;			/* Return with the response value */
+}
+
+
+
+
+/*--------------------------------------------------------------------------
+
+   Public Functions
+
+---------------------------------------------------------------------------*/
+
+/*-----------------------------------------------------------------------*/
+/* Initialize Disk Drive                                                 */
+/*-----------------------------------------------------------------------*/
+
+void mmc_init (void)
+{
+	BYTE n, cmd, ty, ocr[4];
+	UINT tmr;
+
+	// initialize SPI interface
+	spiInit();
+
+	DESELECT();
+	for (n = 10; n; n--) spiTransferFF();	/* 80 Dummy clocks with CS=H */
+
+	ty = 0;
+	if (send_cmd(CMD0, 0) == 1) {			/* Enter Idle state */
+		if (send_cmd(CMD8, 0x1AA) == 1) {	/* SDv2 */
+			for (n = 0; n < 4; n++) ocr[n] = spiTransferFF();		/* Get trailing return value of R7 resp */
+			if (ocr[2] == 0x01 && ocr[3] == 0xAA) {			/* The card can work at vdd range of 2.7-3.6V */
+				for (tmr = 10000; tmr && send_cmd(ACMD41, 1UL << 30); tmr--) wait_us(100);	/* Wait for leaving idle state (ACMD41 with HCS bit) */
+				if (tmr && send_cmd(CMD58, 0) == 0) {		/* Check CCS bit in the OCR */
+					for (n = 0; n < 4; n++) ocr[n] = spiTransferFF();
+					ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2;	/* SDv2 (HC or SC) */
+				}
+			}
+		} else {							/* SDv1 or MMCv3 */
+			if (send_cmd(ACMD41, 0) <= 1) 	{
+				ty = CT_SD1; cmd = ACMD41;	/* SDv1 */
+			} else {
+				ty = CT_MMC; cmd = CMD1;	/* MMCv3 */
+			}
+			for (tmr = 10000; tmr && send_cmd(cmd, 0); tmr--) wait_us(100);	/* Wait for leaving idle state */
+			if (!tmr || send_cmd(CMD16, 512) != 0)			/* Set R/W block length to 512 */
+				ty = 0;
+		}
+	}
+	CardType = ty;
+	DESELECT();
+	spiTransferFF();
+}
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Read partial sector                                                   */
+/*-----------------------------------------------------------------------*/
+
+u08 mmcRead(u32 sector)
+{
+	BYTE rc;
+	UINT bc;
+	int res = 0;
+
+	//printf("mr:%x",sector);
+
+	if (!(CardType & CT_BLOCK)) sector *= 512;	/* Convert to byte address if needed */
+
+	if (send_cmd(CMD17, sector) == 0) {		/* READ_SINGLE_BLOCK */
+
+		bc = 40000;
+		do {							/* Wait for data packet */
+			rc = spiTransferFF();
+		} while (rc == 0xFF && --bc);
+
+		if (rc == 0xFE) {				/* A data packet arrived */
+			bc = 514 - 512;
+
+			u08 *buffer=mmc_sector_buffer;	//natvrdo!
+
+			spiReceiveData(buffer,buffer+512);
+
+			/* Skip remaining bytes and CRC */
+			do spiTransferFF(); while (--bc); // checksum
+		}
+	}
+	else
+	{
+		res = 1;
+	}
+
+	DESELECT();
+	spiTransferFF();
+	return res;
+}
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Write partial sector                                                  */
+/*-----------------------------------------------------------------------*/
+
+u08 mmcWrite(u32 sc)
+{
+	u08 *buff=mmc_sector_buffer;	//natvrdo!
+
+	WORD wc;
+
+	SELECT();
+
+	if (!(CardType & CT_BLOCK)) sc *= 512;	/* Convert to byte address if needed */
+	if (send_cmd(CMD24, sc) == 0) {			/* WRITE_SINGLE_BLOCK */
+		spiTransferByte(0xFF); spiTransferByte(0xFE);		/* Data block header */
+		wc = 512;							/* Set byte counter */
+
+		while (wc) {		/* Send data bytes to the card */
+			spiTransferByte(*buff++);
+			wc--; 
+		}
+
+		DWORD bc = 2;
+		while (bc--) spiTransferByte(0);	/* Fill left bytes and CRC with zeros */
+		if ((spiTransferFF() & 0x1F) == 0x05) {	/* Receive data resp and wait for end of write process in timeout of 500ms */
+			for (bc = 5000; spiTransferFF() != 0xFF && bc; bc--) wait_us(100);	/* Wait ready */
+		}
+		DESELECT();
+		spiTransferFF();
+	}
+	return 0;
+}
Index: firmware_legacy/sd_direct/mmcconf.h
===================================================================
--- firmware_legacy/sd_direct/mmcconf.h	(nonexistent)
+++ firmware_legacy/sd_direct/mmcconf.h	(revision 799)
@@ -0,0 +1,33 @@
+/*! \file mmcconf.h \brief MultiMedia and SD Flash Card Interface Configuration. */
+//*****************************************************************************
+//
+// File Name	: 'mmcconf.h'
+// Title		: MultiMedia and SD Flash Card Interface Configuration
+// Author		: Pascal Stang - Copyright (C) 2004
+// Created		: 2004.09.22
+// Revised		: 2004.09.22
+// Version		: 0.1
+// Target MCU	: Atmel AVR Series
+// Editor Tabs	: 4
+//
+// NOTE: This code is currently below version 1.0, and therefore is considered
+// to be lacking in some functionality or documentation, or may not be fully
+// tested.  Nonetheless, you can expect most functions to work.
+//
+// ----------------------------------------------------------------------------
+// 17.8.2008
+// Bob!k & Raster, C.P.U.
+// Original code was modified especially for the SDrive device. 
+// Some parts of code have been added, removed, rewrited or optimized due to
+// lack of MCU AVR Atmega8 memory.
+// ----------------------------------------------------------------------------
+//
+// This code is distributed under the GNU Public License
+//		which can be found at http://www.gnu.org/licenses/gpl.txt
+//
+//*****************************************************************************
+
+#ifndef MMCCONF_H
+#define MMCCONF_H
+
+#endif
Index: firmware_legacy/log.h
===================================================================
--- firmware_legacy/log.h	(nonexistent)
+++ firmware_legacy/log.h	(revision 799)
@@ -0,0 +1,11 @@
+#ifndef LOG_H
+#define LOG_H
+
+#ifdef LINUX_BUILD
+#include "curses_screen.h"
+#define LOG(x...) print_log(x)
+#else
+#define LOG(x...) do { } while(0)
+#endif
+
+#endif
Index: firmware_legacy/mist/diskio_sectorrequest.c
===================================================================
--- firmware_legacy/mist/diskio_sectorrequest.c	(nonexistent)
+++ firmware_legacy/mist/diskio_sectorrequest.c	(revision 799)
@@ -0,0 +1,202 @@
+#include "diskio.h"
+
+#include "regs.h"
+
+#include "printf.h"
+extern int debug_pos;
+
+void mmcReadCached(u32 sector);
+u32 n_actual_mmc_sector;
+unsigned char * mmc_sector_buffer;
+
+void mmcReadCached(u32 sector)
+{
+	//debug("mmcReadCached");
+	//plotnext(toatarichar(' '));
+	//plotnextnumber(sector);
+	//debug("\n");
+	if(sector==n_actual_mmc_sector) return;
+	//debug("mmcReadREAL");
+	//plotnext(toatarichar(' '));
+	//plotnextnumber(sector);
+	//debug("\n");
+
+	//u08 ret,retry;
+	//predtim nez nacte jiny, musi ulozit soucasny
+	// TODO mmcWriteCachedFlush();
+	//az ted nacte novy
+	//retry=0; //zkusi to maximalne 256x
+	/*do
+	{
+		ret = mmcRead(sector);	//vraci 0 kdyz ok
+		retry--;
+	} while (ret && retry);
+	while(ret); //a pokud se vubec nepovedlo, tady zustane zablokovany cely SDrive!
+*/
+
+	//printf("Reading sector:%d", sector);
+	*zpu_out4 = sector|0x04000000;
+	while (!*zpu_in4)
+	{
+		// Wait until ready
+	}
+	*zpu_out4 = 0;
+	//printf(" RD1 ");
+	while (*zpu_in4)
+	{
+		// Wait until ready cleared
+	}
+
+	//printf(" RD2 ");
+
+	n_actual_mmc_sector=sector;
+}
+
+
+/*-----------------------------------------------------------------------*/
+/* Initialize Disk Drive                                                 */
+/*-----------------------------------------------------------------------*/
+
+DSTATUS disk_initialize (void)
+{
+	DSTATUS stat;
+
+	n_actual_mmc_sector = 0xffffffff;
+	//do
+	//{
+	//	mmcInit();
+	//}
+	//while(mmcReset());	//dokud nenulove, tak smycka (return 0 => ok!)
+
+	//set_spi_clock_freq();
+
+	// no longer in ram (yet!), misuse will break us...
+	mmc_sector_buffer = (unsigned char *)0x4000;  // 512 bytes in the middle of memory space!
+
+	stat = RES_OK;
+
+	return stat;
+}
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Read Partial Sector                                                   */
+/*-----------------------------------------------------------------------*/
+
+DRESULT disk_readp (
+	BYTE* dest,			/* Pointer to the destination object */
+	DWORD sector,		/* Sector number (LBA) */
+	WORD sofs,			/* Offset in the sector */
+	WORD count			/* Byte count (bit15:destination) */
+)
+{
+	DRESULT res;
+
+	/*debug("readp:");
+	plotnextnumber(sector);
+	debug(" ");
+	plotnextnumber((int)dest);
+	debug(" ");
+	plotnextnumber(sofs);
+	debug(" ");
+	plotnextnumber(count);
+	debug(" ");
+	plotnextnumber(atari_sector_buffer);
+	debug(" ");
+	plotnextnumber(mmc_sector_buffer);
+	debug("\n");
+	*/
+	// Put your code here
+	mmcReadCached(sector);
+	for(;count>0;++sofs,--count)
+	{
+		unsigned char x = mmc_sector_buffer[sofs];
+		//printf("char:%02x loc:%d", x,sofs);
+		*dest++ = x;
+	}
+
+	res = RES_OK;
+
+	return res;
+}
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Write Partial Sector                                                  */
+/*-----------------------------------------------------------------------*/
+
+DRESULT disk_writep (const BYTE* buff, DWORD sofs, DWORD count)
+{
+	DRESULT res;
+
+	int i=sofs;
+	int end=sofs+count;
+	int pos = 0;
+
+/*	debug_pos = 0;
+	printf("WP:%x %d %d"),buff,sofs,count;
+	debug_pos = -1;*/
+
+	for (;i!=end;++i,++pos)
+	{
+                unsigned char temp = buff[pos];
+
+                unsigned int volatile* addr = (unsigned int volatile *)&mmc_sector_buffer[i&~3];
+                unsigned int prev = *(unsigned int volatile*)addr;
+                ((char unsigned *)&prev)[i&3] = temp;
+                *addr = prev;
+		
+		//mmc_sector_buffer[i] = buff[pos];
+		//printf("char:%c loc:%d,", buff[pos],i);
+	}
+
+/*	debug_pos = 40;
+	printf("WP DONE:%x %d %d"),buff,sofs,count;
+	debug_pos = -1;*/
+
+	res = RES_OK;
+
+	return res;
+}
+
+void disk_writeflush()
+{
+/*	// Finalize write process
+	int retry=16; //zkusi to maximalne 16x
+	int ret;
+	//printf(":WSECT:%d",n_actual_mmc_sector);
+	do
+	{
+		ret = mmcWrite(n_actual_mmc_sector); //vraci 0 kdyz ok
+		retry--;
+	} while (ret && retry);
+	//printf(":WD:");
+*/
+
+	/*debug_pos = 0;
+	printf("WF");
+	debug_pos = -1;*/
+
+	//printf(" WTF:%d:%x ", n_actual_mmc_sector, ((unsigned int *)mmc_sector_buffer)[0]);
+
+	*zpu_out4 = n_actual_mmc_sector|0x08000000;
+	while (!*zpu_in4)
+	{
+		// Wait until ready
+	}
+	*zpu_out4 = 0;
+	//printf(" PT1 ");
+	while (*zpu_in4)
+	{
+		// Wait until ready cleared
+	}
+
+	//printf(" PT2 ");
+
+	/*debug_pos = 40;
+	printf("DONE");
+	debug_pos = -1;*/
+}
+
Index: firmware_legacy/chameleon/dirs.c
===================================================================
--- firmware_legacy/chameleon/dirs.c	(nonexistent)
+++ firmware_legacy/chameleon/dirs.c	(revision 799)
@@ -0,0 +1,2 @@
+char USER_DIR[]="/atari800/user";
+char ROM_DIR[]="/atari800/rom";
Index: firmware_legacy/test_drive.c
===================================================================
--- firmware_legacy/test_drive.c	(nonexistent)
+++ firmware_legacy/test_drive.c	(revision 799)
@@ -0,0 +1,152 @@
+#include "simpledir.h"
+#include "simplefile.h"
+
+#include "atari_drive_emulator.h"
+
+#include "stdio.h"
+#include "stdlib.h"
+
+#include <sys/time.h>
+
+extern char native_command;
+extern char receive_buffer[];
+extern int receive_buffer_pos;
+extern int receive_buffer_last;
+
+double start_time;
+double now()
+{
+	struct timeval tv;
+	gettimeofday(&tv,0);
+
+	return ((double)tv.tv_sec + (double)tv.tv_usec/1e6);
+}
+
+void char_out ( void* p, char c)
+{
+	putc(c, stderr);
+}
+
+struct SimpleFile * files[5];
+
+int main(void)
+{
+	init_printf(NULL, char_out);
+
+	struct SimpleDirEntry * entry;
+	char * mem = (char *)malloc(8192);
+	if (SimpleFile_OK != dir_init(mem, 8192))
+	{
+		fprintf(stderr,"Failed to open dir!");
+		return -1;
+	}
+	entry = dir_entries("");
+	entry = dir_next(dir_next(dir_next(entry)));
+	fprintf(stderr, " Name:%s", dir_filename(entry));
+	int i;
+	for (i=0;i!=5;++i)
+	{
+		struct SimpleFile * file = alloca(file_struct_size());
+		file_init(file);
+		files[i] = file;
+	}
+	//file_open_dir(entry,file);
+	if (SimpleFile_OK == file_open_name("GUNPOWDR.ATR",files[0]))
+	{
+	}
+	else
+	{
+		fprintf(stderr,"\nARG\n");
+	}
+
+	int read = 0;
+	char buffer[1024];
+	//file_seek(file,100);
+	file_read(files[0],&buffer[0],1024,&read);
+	for (i=0; i!=read; ++i)
+	{
+		fprintf(stderr,"|%02x", (unsigned char)buffer[i]);
+		//fprintf(stderr,"%c", buffer[i]);
+	}
+
+	fprintf(stderr,"\n");
+
+	native_command = 1;
+
+	init_drive_emulator();
+
+	//set_drive_status(0,files[0]);
+	for (i=1;i!=5;++i)
+	{
+		char buffer[20];
+		describe_disk(i-1,&buffer[0]);
+		fprintf(stderr, "Drive %d:%s %s\n", i, file_name(get_file_status(i-1)), &buffer[0]);
+	}
+
+					int row = 6;
+					{
+						// Swap files
+						struct SimpleFile * temp = files[row-3];
+						files[row-3] = files[0];
+						files[0] = temp;
+					}
+
+					{
+						// Swap disks
+						struct SimpleFile * temp = get_drive_status(row-3);
+						set_drive_status(row-3, get_drive_status(0));
+						set_drive_status(0,temp);
+					}
+	for (i=1;i!=5;++i)
+	{
+		char buffer[20];
+		describe_disk(i-1,&buffer[0]);
+		fprintf(stderr, "Drive %d:%s %s\n", i, file_name(get_file_status(i-1)), &buffer[0]);
+	}
+
+	start_time = now();
+	run_drive_emulator();
+
+	return 0;
+}
+
+void actions()
+{
+	// USART_TransmitByte();
+	// native_command
+
+	double when = now();
+	if ((when-start_time) > 1.0 && (when-start_time)<1.1)
+	{
+		native_command = 0;
+
+		static int once = 0;
+		if (!once)
+		{
+			once = 1;
+
+			receive_buffer[receive_buffer_last++] = 0x31;
+			//receive_buffer[receive_buffer_last++] = 0x32;
+			receive_buffer[receive_buffer_last++] = 0x52;
+			receive_buffer[receive_buffer_last++] = 0x01;
+			receive_buffer[receive_buffer_last++] = 0x00;
+			receive_buffer[receive_buffer_last++] = 0x84;
+			//receive_buffer[receive_buffer_last++] = 0x85;
+		}
+		else
+		{
+			native_command = 1;
+		}
+	}
+	else
+	{
+		native_command = 1;
+	}
+}
+
+void
+wait_us(int unsigned num)
+{
+	usleep(num);
+}
+
Index: firmware_legacy/build_native_drive
===================================================================
--- firmware_legacy/build_native_drive	(nonexistent)
+++ firmware_legacy/build_native_drive	(revision 799)
@@ -0,0 +1 @@
+gcc -g -O0 -DLITTLE_ENDIAN test_drive.c fileutils.c atari_drive_emulator.c native/uart.c hexdump.c printf/printf.c fat/pff_file.c fat/pff.c common/utils.c sd_direct/diskio_mmc.c native/mmc.c -I. -Iprintf -Ifat -Icommon

Property changes on: firmware_legacy/build_native_drive
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: firmware_legacy/printf/printf.c
===================================================================
--- firmware_legacy/printf/printf.c	(nonexistent)
+++ firmware_legacy/printf/printf.c	(revision 799)
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2004,2012 Kustaa Nyholm / SpareTimeLabs
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, 
+ * are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list 
+ * of conditions and the following disclaimer.
+ * 
+ * Redistributions in binary form must reproduce the above copyright notice, this 
+ * list of conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *  
+ * Neither the name of the Kustaa Nyholm or SpareTimeLabs nor the names of its 
+ * contributors may be used to endorse or promote products derived from this software 
+ * without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+#include "printf.h"
+
+typedef void (*putcf) (void*,char);
+static putcf stdout_putf;
+static void* stdout_putp;
+
+
+#ifdef PRINTF_LONG_SUPPORT
+
+static void uli2a(unsigned long int num, unsigned int base, int uc,char * bf)
+	{
+	int n=0;
+	unsigned int d=1;
+	while (num/d >= base)
+		d*=base;		 
+	while (d!=0) {
+		int dgt = num / d;
+		num%=d;
+		d/=base;
+		if (n || dgt>0|| d==0) {
+			*bf++ = dgt+(dgt<10 ? '0' : (uc ? 'A' : 'a')-10);
+			++n;
+			}
+		}
+	*bf=0;
+	}
+
+static void li2a (long num, char * bf)
+	{
+	if (num<0) {
+		num=-num;
+		*bf++ = '-';
+		}
+	uli2a(num,10,0,bf);
+	}
+
+#endif
+
+static void ui2a(unsigned int num, unsigned int base, int uc,char * bf)
+	{
+	int n=0;
+	unsigned int d=1;
+	while (num/d >= base)
+		d*=base;		
+	while (d!=0) {
+		int dgt = num / d;
+		num%= d;
+		d/=base;
+		if (n || dgt>0 || d==0) {
+			*bf++ = dgt+(dgt<10 ? '0' : (uc ? 'A' : 'a')-10);
+			++n;
+			}
+		}
+	*bf=0;
+	}
+
+static void i2a (int num, char * bf)
+	{
+	if (num<0) {
+		num=-num;
+		*bf++ = '-';
+		}
+	ui2a(num,10,0,bf);
+	}
+
+static int a2d(char ch)
+	{
+	if (ch>='0' && ch<='9') 
+		return ch-'0';
+	else if (ch>='a' && ch<='f')
+		return ch-'a'+10;
+	else if (ch>='A' && ch<='F')
+		return ch-'A'+10;
+	else return -1;
+	}
+
+static char a2i(char ch, char** src,int base,int* nump)
+	{
+	char* p= *src;
+	int num=0;
+	int digit;
+	while ((digit=a2d(ch))>=0) {
+		if (digit>base) break;
+		num=num*base+digit;
+		ch=*p++;
+		}
+	*src=p;
+	*nump=num;
+	return ch;
+	}
+
+static void putchw(void* putp,putcf putf,int n, char z, char* bf)
+	{
+	char fc=z? '0' : ' ';
+	char ch;
+	char* p=bf;
+	while (*p++ && n > 0)
+		n--;
+	while (n-- > 0) 
+		putf(putp,fc);
+	while ((ch= *bf++))
+		putf(putp,ch);
+	}
+
+void tfp_format(void* putp,putcf putf,char *fmt, va_list va)
+	{
+	char bf[12];
+    
+	char ch;
+
+
+	while ((ch=*(fmt++))) {
+		if (ch!='%') 
+			putf(putp,ch);
+		else {
+			char lz=0;
+#ifdef 	PRINTF_LONG_SUPPORT
+			char lng=0;
+#endif
+			int w=0;
+			ch=*(fmt++);
+			if (ch=='0') {
+				ch=*(fmt++);
+				lz=1;
+				}
+			if (ch>='0' && ch<='9') {
+				ch=a2i(ch,&fmt,10,&w);
+				}
+#ifdef 	PRINTF_LONG_SUPPORT
+			if (ch=='l') {
+				ch=*(fmt++);
+				lng=1;
+			}
+#endif
+			switch (ch) {
+				case 0: 
+					goto abort;
+				case 'u' : {
+#ifdef 	PRINTF_LONG_SUPPORT
+					if (lng)
+						uli2a(va_arg(va, unsigned long int),10,0,bf);
+					else
+#endif
+					ui2a(va_arg(va, unsigned int),10,0,bf);
+					putchw(putp,putf,w,lz,bf);
+					break;
+					}
+				case 'd' :  {
+#ifdef 	PRINTF_LONG_SUPPORT
+					if (lng)
+						li2a(va_arg(va, unsigned long int),bf);
+					else
+#endif
+					i2a(va_arg(va, int),bf);
+					putchw(putp,putf,w,lz,bf);
+					break;
+					}
+				case 'x': case 'X' : 
+#ifdef 	PRINTF_LONG_SUPPORT
+					if (lng)
+						uli2a(va_arg(va, unsigned long int),16,(ch=='X'),bf);
+					else
+#endif
+					ui2a(va_arg(va, unsigned int),16,(ch=='X'),bf);
+					putchw(putp,putf,w,lz,bf);
+					break;
+				case 'c' : 
+					putf(putp,(char)(va_arg(va, int)));
+					break;
+				case 's' : 
+					putchw(putp,putf,w,0,va_arg(va, char*));
+					break;
+				case '%' :
+					putf(putp,ch);
+				default:
+					break;
+				}
+			}
+		}
+	abort:;
+	}
+
+
+void init_printf(void* putp,void (*putf) (void*,char))
+	{
+	stdout_putf=putf;
+	stdout_putp=putp;
+	}
+
+void tfp_printf(char *fmt, ...)
+	{
+	va_list va;
+	va_start(va,fmt);
+	tfp_format(stdout_putp,stdout_putf,fmt,va);
+	va_end(va);
+	}
+
+static void putcp(void* p,char c)
+	{
+	*(*((char**)p))++ = c;
+	}
+
+
+
+void tfp_sprintf(char* s,char *fmt, ...)
+	{
+	va_list va;
+	va_start(va,fmt);
+	tfp_format(&s,putcp,fmt,va);
+	putcp(&s,0);
+	va_end(va);
+	}
+
+

Property changes on: firmware_legacy/printf/printf.c
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: firmware_legacy/fileutils.c
===================================================================
--- firmware_legacy/fileutils.c	(nonexistent)
+++ firmware_legacy/fileutils.c	(revision 799)
@@ -0,0 +1,21 @@
+#include "printf.h"
+
+#include "utils.h"
+
+int compare_ext(char const * filename, char const * ext)
+{
+	int dot = 0;
+	//printf("WTFA:%s %s\n",filenamein, extin);
+	//printf("WTFB:%s %s\n",filename, ext);
+
+	char const * end = strlen(filename) + filename;
+	while (--end != filename)
+	{
+		if (*end == '.')
+			break;
+	}
+	if (0==stricmp(end+1,ext)) return 1;
+
+	return 0;
+}
+
Index: firmware_legacy/mcc/dirs.c
===================================================================
--- firmware_legacy/mcc/dirs.c	(nonexistent)
+++ firmware_legacy/mcc/dirs.c	(revision 799)
@@ -0,0 +1,2 @@
+char USER_DIR[]="/atari800/user";
+char ROM_DIR[]="/system/rom/atari800";
Index: firmware_legacy/standalone_simple.ld
===================================================================
--- firmware_legacy/standalone_simple.ld	(nonexistent)
+++ firmware_legacy/standalone_simple.ld	(revision 799)
@@ -0,0 +1,59 @@
+
+/* Memory Definitions for a ZPU program running either from external RAM (up to 8 meg).
+   or from unremapped Boot ROM / Stack RAM. */
+
+MEMORY
+{
+  CODE (rx) : ORIGIN = 0x00000000, LENGTH = 0x04000 /* 16k */
+  RAM (rx) : ORIGIN = 0x0000f000, LENGTH = 0x600 /* 32 bytes */
+}
+
+
+/* Section Definitions */
+
+SECTIONS
+{
+  /* first section is .fixed_vectors which is used for startup code */
+  . = 0x0000000;
+  .fixed_vectors :
+  {
+    *(.fixed_vectors)
+  }>CODE
+
+  /* Remaining code sections */
+  . = ALIGN(4);
+  .text :
+  {
+    *(.text)                   /* remaining code */
+  } >CODE
+
+  /* .rodata section which is used for read-only data (constants) */
+  . = ALIGN(4);
+  .rodata :
+  {
+    *(.rodata)
+  } >CODE
+  . = ALIGN(4);
+
+  /* .data section which is used for initialized data. */
+  . = ALIGN(4);
+  .data :
+  {
+    _data = . ;
+    *(.data)
+    SORT(CONSTRUCTORS)
+    . = ALIGN(4);
+  } >CODE
+  _romend = . ;
+
+  /* .bss section which is used for uninitialized data */
+  . = ALIGN(4);
+  .bss :
+  {
+    __bss_start = . ;
+    __bss_start__ = . ;
+    *(.bss)
+    *(COMMON)
+  } >RAM
+  __bss_end__ = . ;
+}
Index: firmware_legacy/de1/dirs.c
===================================================================
--- firmware_legacy/de1/dirs.c	(nonexistent)
+++ firmware_legacy/de1/dirs.c	(revision 799)
@@ -0,0 +1,2 @@
+char USER_DIR[]="/atari800/user";
+char ROM_DIR[]="/atari800/rom";
Index: firmware_legacy/simpledir.h
===================================================================
--- firmware_legacy/simpledir.h	(nonexistent)
+++ firmware_legacy/simpledir.h	(revision 799)
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "simplefile.h"
+
+// Extends simple dir with way of opening files and looking at dirs!
+// Not all systems provide this...
+
+struct SimpleDirEntry;
+
+enum SimpleFileStatus file_open_name(char const * path, struct SimpleFile * file);
+enum SimpleFileStatus file_open_name_in_dir(struct SimpleDirEntry * entries, char const * filename, struct SimpleFile * file);
+enum SimpleFileStatus file_open_dir(struct SimpleDirEntry * filename, struct SimpleFile * file);
+
+// Reads entire dir into memory (i.e. give it a decent chunk of sdram)
+enum SimpleFileStatus dir_init(void * mem, int space);
+struct SimpleDirEntry * dir_entries_filtered(char const * dirPath, int (*filter)(struct SimpleDirEntry *));
+struct SimpleDirEntry * dir_entries(char const * dirPath);
+
+char const * dir_filename(struct SimpleDirEntry *);
+char const * dir_path(struct SimpleDirEntry *);
+int dir_filesize(struct SimpleDirEntry *);
+struct SimpleDirEntry * dir_next(struct SimpleDirEntry *);
+int dir_is_subdir(struct SimpleDirEntry *);
+
Index: firmware_legacy/fileutils.h
===================================================================
--- firmware_legacy/fileutils.h	(nonexistent)
+++ firmware_legacy/fileutils.h	(revision 799)
@@ -0,0 +1,4 @@
+#pragma once
+
+int compare_ext(char const * filename, char const * ext);
+
Index: firmware_legacy/build_native_joystick
===================================================================
--- firmware_legacy/build_native_joystick	(nonexistent)
+++ firmware_legacy/build_native_joystick	(revision 799)
@@ -0,0 +1 @@
+gcc -g -O0 test_joy.c joystick.c native/regs.c -I.

Property changes on: firmware_legacy/build_native_joystick
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: firmware_legacy/defunct/fat.h
===================================================================
--- firmware_legacy/defunct/fat.h	(nonexistent)
+++ firmware_legacy/defunct/fat.h	(revision 799)
@@ -0,0 +1,435 @@
+/*! \file fat.h \brief FAT16/32 file system driver. */
+//*****************************************************************************
+//
+// File Name	: 'fat.h'
+// Title		: FAT16/32 file system driver
+// Author		: Pascal Stang
+// Date			: 11/07/2000
+// Revised		: 12/12/2000
+// Version		: 0.3
+// Target MCU	: ATmega103 (should work for Atmel AVR Series)
+// Editor Tabs	: 4
+//
+// NOTE: This code is currently below version 1.0, and therefore is considered
+// to be lacking in some functionality or documentation, or may not be fully
+// tested.  Nonetheless, you can expect most functions to work.
+//
+///	\ingroup general
+/// \defgroup fat FAT16/32 File System Interface (fat.c)
+/// \code #include "fat.h" \endcode
+/// \par Overview
+///		This FAT16/32 interface allows you to detect and mount FAT16/32
+///		partitions, browse directories and files, and read file data.
+///		The interface is designed to operate with the avrlib IDE/ATA driver.
+///		Reading FAT efficiently requires at least 512+ bytes of RAM so this
+///		interface may not be suitable for processors with less than 1K of RAM.
+///		This interface will properly follow a file's cluster chain so files
+///		need not be defragmented.
+///
+/// \note This code is based in part on work done by Jesper Hansen for his
+///		excellent YAMPP MP3 player project.
+//
+// ----------------------------------------------------------------------------
+// 17.8.2008
+// Bob!k & Raster, C.P.U.
+// Original code was modified especially for the SDrive device. 
+// Some parts of code have been added, removed, rewrited or optimized due to
+// lack of MCU AVR Atmega8 memory.
+// ----------------------------------------------------------------------------
+//
+// This code is distributed under the GNU Public License
+//		which can be found at http://www.gnu.org/licenses/gpl.txt
+//
+//*****************************************************************************
+
+#ifndef FAT_H
+#define FAT_H
+
+#define FALSE 0
+#define TRUE -1
+
+#define DRIVE0 1
+
+// Some useful cluster numbers
+#define MSDOSFSROOT     0		// cluster 0 means the root dir
+#define CLUST_FREE      0               // cluster 0 also means a free cluster
+#define MSDOSFSFREE     CLUST_FREE
+#define CLUST_FIRST     2               // first legal cluster number
+#define CLUST_RSRVD     0xfffffff6      // reserved cluster range
+#define CLUST_BAD       0xfffffff7      // a cluster with a defect
+#define CLUST_EOFS      0xfffffff8      // start of eof cluster range
+#define CLUST_EOFE      0xffffffff      // end of eof cluster range
+
+#define FAT12_MASK      0x00000fff      // mask for 12 bit cluster numbers
+#define FAT16_MASK      0x0000ffff      // mask for 16 bit cluster numbers
+#define FAT32_MASK      0x0fffffff      // mask for FAT32 cluster numbers
+
+
+// Partition Type used in the partition record
+#define PART_TYPE_UNKNOWN		0x00
+#define PART_TYPE_FAT12			0x01
+#define PART_TYPE_XENIX			0x02
+#define PART_TYPE_DOSFAT16		0x04
+#define PART_TYPE_EXTDOS		0x05
+#define PART_TYPE_FAT16			0x06
+#define PART_TYPE_NTFS			0x07
+#define PART_TYPE_FAT32			0x0B
+#define PART_TYPE_FAT32LBA		0x0C
+#define PART_TYPE_FAT16LBA		0x0E
+#define PART_TYPE_EXTDOSLBA		0x0F
+#define PART_TYPE_ONTRACK		0x33
+#define PART_TYPE_NOVELL		0x40
+#define PART_TYPE_PCIX			0x4B
+#define PART_TYPE_PHOENIXSAVE	0xA0
+#define PART_TYPE_CPM			0xDB
+#define PART_TYPE_DBFS			0xE0
+#define PART_TYPE_BBT			0xFF
+
+struct partrecord // length 16 bytes
+{			
+	unsigned char	prIsActive;					// 0x80 indicates active partition
+	unsigned char	prStartHead;				// starting head for partition
+	unsigned short	prStartCylSect;				// starting cylinder and sector
+	unsigned char	prPartType;					// partition type (see above)
+	unsigned char	prEndHead;					// ending head for this partition
+	unsigned short	prEndCylSect;				// ending cylinder and sector
+	unsigned long	prStartLBA;					// first LBA sector for this partition
+	unsigned long	prSize;						// size of this partition (bytes or sectors ?)
+};
+
+        
+struct partsector
+{
+	unsigned char	psPartCode[512-64-2];		// pad so struct is 512b
+	unsigned char	psPart[64];					// four partition records (64 bytes)
+	unsigned char	psBootSectSig0;				// two signature bytes (2 bytes)
+	unsigned char	psBootSectSig1;
+#define BOOTSIG0        0x55
+#define BOOTSIG1        0xaa
+};
+
+
+// Format of a boot sector.  This is the first sector on a DOS floppy disk
+// or the first sector of a partition on a hard disk.  But, it is not the
+// first sector of a partitioned hard disk.
+struct bootsector33 {
+	unsigned char 	bsJump[3];					// jump inst E9xxxx or EBxx90
+	unsigned char	bsOemName[8];				// OEM name and version
+	unsigned char	bsBPB[19];					// BIOS parameter block
+	unsigned char	bsDriveNumber;				// drive number (0x80)
+	unsigned char	bsBootCode[479];			// pad so struct is 512b
+	unsigned char	bsBootSectSig0;				// boot sector signature byte 0x55
+	unsigned char	bsBootSectSig1;				// boot sector signature byte 0xAA
+#define BOOTSIG0        0x55
+#define BOOTSIG1        0xaa
+};
+
+struct extboot {
+	unsigned char	exDriveNumber;				// drive number (0x80)
+	unsigned char	exReserved1;				// reserved
+	unsigned char	exBootSignature;			// ext. boot signature (0x29)
+#define EXBOOTSIG       0x29
+	unsigned char	exVolumeID[4];				// volume ID number
+	unsigned char	exVolumeLabel[11];			// volume label
+	unsigned char	exFileSysType[8];			// fs type (FAT12 or FAT16)
+};
+
+struct bootsector50 {
+	unsigned char	bsJump[3];					// jump inst E9xxxx or EBxx90
+	unsigned char	bsOemName[8];				// OEM name and version
+	unsigned char	bsBPB[25];					// BIOS parameter block
+	unsigned char	bsExt[26];					// Bootsector Extension
+	unsigned char	bsBootCode[448];			// pad so structure is 512b
+	unsigned char	bsBootSectSig0;				// boot sector signature byte 0x55 
+	unsigned char	bsBootSectSig1;				// boot sector signature byte 0xAA
+#define BOOTSIG0        0x55
+#define BOOTSIG1        0xaa
+};
+
+struct bootsector710 {
+	unsigned char	bsJump[3];					// jump inst E9xxxx or EBxx90
+	unsigned char	bsOEMName[8];				// OEM name and version
+	unsigned char	bsBPB[53];					// BIOS parameter block
+	unsigned char	bsExt[26];					// Bootsector Extension
+	unsigned char	bsBootCode[418];			// pad so structure is 512b
+	unsigned char	bsBootSectSig2;				// 2 & 3 are only defined for FAT32?
+	unsigned char	bsBootSectSig3;
+	unsigned char	bsBootSectSig0;				// boot sector signature byte 0x55
+	unsigned char	bsBootSectSig1;				// boot sector signature byte 0xAA
+#define BOOTSIG0        0x55
+#define BOOTSIG1        0xaa
+#define BOOTSIG2        0
+#define BOOTSIG3        0
+};
+
+
+/***************************************************************/
+/***************************************************************/
+
+// BIOS Parameter Block (BPB) for DOS 3.3
+struct bpb33 {
+        unsigned short	bpbBytesPerSec; // bytes per sector
+        unsigned char    bpbSecPerClust;	// sectors per cluster
+        unsigned short	bpbResSectors;	// number of reserved sectors
+        unsigned char	bpbFATs;		// number of FATs
+        unsigned short	bpbRootDirEnts;	// number of root directory entries
+        unsigned short	bpbSectors;		// total number of sectors
+        unsigned char	bpbMedia;		// media descriptor
+        unsigned short	bpbFATsecs;     // number of sectors per FAT
+        unsigned short	bpbSecPerTrack; // sectors per track
+        unsigned short	bpbHeads;       // number of heads
+        unsigned short	bpbHiddenSecs;  // number of hidden sectors
+};
+
+// BPB for DOS 5.0
+// The difference is bpbHiddenSecs is a short for DOS 3.3,
+// and bpbHugeSectors is not present in the DOS 3.3 bpb.
+struct bpb50 {
+        unsigned short	bpbBytesPerSec; // bytes per sector
+        unsigned char	bpbSecPerClust; // sectors per cluster
+        unsigned short	bpbResSectors;  // number of reserved sectors
+        unsigned char	bpbFATs;        // number of FATs
+        unsigned short	bpbRootDirEnts; // number of root directory entries
+        unsigned short	bpbSectors;     // total number of sectors
+        unsigned char	bpbMedia;       // media descriptor
+        unsigned short	bpbFATsecs;     // number of sectors per FAT
+        unsigned short	bpbSecPerTrack; // sectors per track
+        unsigned short	bpbHeads;       // number of heads
+        unsigned long	bpbHiddenSecs;  // # of hidden sectors
+// 3.3 compat ends here
+        unsigned long	bpbHugeSectors; // # of sectors if bpbSectors == 0
+};
+
+// BPB for DOS 7.10 (FAT32)
+// This one has a few extensions to bpb50.
+struct bpb710 {
+		unsigned short	bpbBytesPerSec;	// bytes per sector
+		unsigned char	bpbSecPerClust;	// sectors per cluster
+		unsigned short	bpbResSectors;	// number of reserved sectors
+		unsigned char	bpbFATs;		// number of FATs
+		unsigned short	bpbRootDirEnts;	// number of root directory entries
+		unsigned short	bpbSectors;		// total number of sectors
+		unsigned char	bpbMedia;		// media descriptor
+		unsigned short	bpbFATsecs;		// number of sectors per FAT
+		unsigned short	bpbSecPerTrack;	// sectors per track
+		unsigned short	bpbHeads;		// number of heads
+		unsigned long	bpbHiddenSecs;	// # of hidden sectors
+// 3.3 compat ends here
+		unsigned long	bpbHugeSectors;	// # of sectors if bpbSectors == 0
+// 5.0 compat ends here
+		unsigned long     bpbBigFATsecs;// like bpbFATsecs for FAT32
+		unsigned short      bpbExtFlags;	// extended flags:
+#define FATNUM    0xf			// mask for numbering active FAT
+#define FATMIRROR 0x80			// FAT is mirrored (like it always was)
+		unsigned short      bpbFSVers;	// filesystem version
+#define FSVERS    0				// currently only 0 is understood
+		unsigned long     bpbRootClust;	// start cluster for root directory
+		unsigned short      bpbFSInfo;	// filesystem info structure sector
+		unsigned short      bpbBackup;	// backup boot sector
+		// There is a 12 byte filler here, but we ignore it
+};
+
+
+// ***************************************************************
+// * byte versions of the above structs                          *
+// ***************************************************************
+
+// BIOS Parameter Block (BPB) for DOS 3.3
+struct byte_bpb33 {
+        unsigned char bpbBytesPerSec[2];		// bytes per sector
+        unsigned char bpbSecPerClust;        // sectors per cluster
+        unsigned char bpbResSectors[2];      // number of reserved sectors
+        unsigned char bpbFATs;               // number of FATs
+        unsigned char bpbRootDirEnts[2];     // number of root directory entries
+        unsigned char bpbSectors[2];         // total number of sectors
+        unsigned char bpbMedia;              // media descriptor
+        unsigned char bpbFATsecs[2];         // number of sectors per FAT
+        unsigned char bpbSecPerTrack[2];     // sectors per track
+        unsigned char bpbHeads[2];           // number of heads
+        unsigned char bpbHiddenSecs[2];      // number of hidden sectors
+};
+
+// BPB for DOS 5.0
+// The difference is bpbHiddenSecs is a short for DOS 3.3,
+// and bpbHugeSectors is not in the 3.3 bpb.
+struct byte_bpb50 {
+        unsigned char bpbBytesPerSec[2];     // bytes per sector
+        unsigned char bpbSecPerClust;        // sectors per cluster
+        unsigned char bpbResSectors[2];      // number of reserved sectors
+        unsigned char bpbFATs;               // number of FATs
+        unsigned char bpbRootDirEnts[2];     // number of root directory entries
+        unsigned char bpbSectors[2];         // total number of sectors
+        unsigned char bpbMedia;              // media descriptor
+        unsigned char bpbFATsecs[2];         // number of sectors per FAT
+        unsigned char bpbSecPerTrack[2];     // sectors per track
+        unsigned char bpbHeads[2];           // number of heads
+        unsigned char bpbHiddenSecs[4];      // number of hidden sectors
+        unsigned char bpbHugeSectors[4];		// # of sectors if bpbSectors == 0
+};
+
+// BPB for DOS 7.10 (FAT32).
+// This one has a few extensions to bpb50.
+struct byte_bpb710 {
+        unsigned char bpbBytesPerSec[2];     // bytes per sector
+        unsigned char bpbSecPerClust;        // sectors per cluster
+        unsigned char bpbResSectors[2];      // number of reserved sectors
+        unsigned char bpbFATs;               // number of FATs
+        unsigned char bpbRootDirEnts[2];     // number of root directory entries
+        unsigned char bpbSectors[2];         // total number of sectors
+        unsigned char bpbMedia;              // media descriptor
+        unsigned char bpbFATsecs[2];         // number of sectors per FAT
+        unsigned char bpbSecPerTrack[2];     // sectors per track
+        unsigned char bpbHeads[2];           // number of heads
+        unsigned char bpbHiddenSecs[4];      // # of hidden sectors
+        unsigned char bpbHugeSectors[4];     // # of sectors if bpbSectors == 0
+        unsigned char bpbBigFATsecs[4];      // like bpbFATsecs for FAT32
+        unsigned char bpbExtFlags[2];        // extended flags:
+        unsigned char bpbFSVers[2];          // filesystem version
+        unsigned char bpbRootClust[4];       // start cluster for root directory
+        unsigned char bpbFSInfo[2];          // filesystem info structure sector
+        unsigned char bpbBackup[2];          // backup boot sector
+        // There is a 12 byte filler here, but we ignore it
+};
+
+// FAT32 FSInfo block.
+struct fsinfo {
+        unsigned char fsisig1[4];
+        unsigned char fsifill1[480];
+        unsigned char fsisig2[4];
+        unsigned char fsinfree[4];
+        unsigned char fsinxtfree[4];
+        unsigned char fsifill2[12];
+        unsigned char fsisig3[4];
+        unsigned char fsifill3[508];
+        unsigned char fsisig4[4];
+};
+
+
+// Structure of a dos directory entry.
+struct direntry {
+		unsigned char		deName[8];      // filename, blank filled
+#define SLOT_EMPTY      0x00            // slot has never been used
+#define SLOT_E5         0x05            // the real value is 0xE5
+#define SLOT_DELETED    0xE5            // file in this slot deleted
+		unsigned char		deExtension[3]; // extension, blank filled
+		unsigned char		deAttributes;   // file attributes
+#define ATTR_NORMAL     0x00            // normal file
+#define ATTR_READONLY   0x01            // file is readonly
+#define ATTR_HIDDEN     0x02            // file is hidden
+#define ATTR_SYSTEM     0x04            // file is a system file
+#define ATTR_VOLUME     0x08            // entry is a volume label
+#define ATTR_LONG_FILENAME	0x0F		// this is a long filename entry			    
+#define ATTR_DIRECTORY  0x10            // entry is a directory name
+#define ATTR_ARCHIVE    0x20            // file is new or modified
+		unsigned char        deLowerCase;    // NT VFAT lower case flags  (set to zero)
+#define LCASE_BASE      0x08            // filename base in lower case
+#define LCASE_EXT       0x10            // filename extension in lower case
+		unsigned char        deCHundredth;   // hundredth of seconds in CTime
+		unsigned char        deCTime[2];     // create time
+		unsigned char        deCDate[2];     // create date
+		unsigned char        deADate[2];     // access date
+		unsigned short        deHighClust; 	// high bytes of cluster number
+		unsigned char        deMTime[2];     // last update time
+		unsigned char        deMDate[2];     // last update date
+		unsigned short        deStartCluster; // starting cluster of file
+		unsigned long       deFileSize;  	// size of file in bytes
+};
+
+// number of directory entries in one sector
+#define DIRENTRIES_PER_SECTOR	0x10
+
+// Structure of a Win95 long name directory entry
+struct winentry {
+		unsigned char		weCnt;			// 
+#define WIN_LAST        0x40
+#define WIN_CNT         0x3f
+		unsigned char		wePart1[10];
+		unsigned char		weAttributes;
+#define ATTR_WIN95      0x0f
+		unsigned char		weReserved1;
+		unsigned char		weChksum;
+		unsigned char		wePart2[12];
+		unsigned short       	weReserved2;
+		unsigned char		wePart3[4];
+};
+
+#define WIN_ENTRY_CHARS	13      // Number of chars per winentry
+
+// Maximum filename length in Win95
+// Note: Must be < sizeof(dirent.d_name)
+#define WIN_MAXLEN      255
+
+// This is the format of the contents of the deTime field in the direntry
+// structure.
+// We don't use bitfields because we don't know how compilers for
+// arbitrary machines will lay them out.
+#define DT_2SECONDS_MASK        0x1F    // seconds divided by 2
+#define DT_2SECONDS_SHIFT       0
+#define DT_MINUTES_MASK         0x7E0   // minutes
+#define DT_MINUTES_SHIFT        5
+#define DT_HOURS_MASK           0xF800  // hours
+#define DT_HOURS_SHIFT          11
+
+// This is the format of the contents of the deDate field in the direntry
+// structure.
+#define DD_DAY_MASK				0x1F	// day of month
+#define DD_DAY_SHIFT			0
+#define DD_MONTH_MASK			0x1E0	// month
+#define DD_MONTH_SHIFT			5
+#define DD_YEAR_MASK			0xFE00	// year - 1980
+#define DD_YEAR_SHIFT			9
+
+
+#define FLAGS_ATRMEDIUMSIZE		0x80
+#define FLAGS_XEXLOADER			0x40
+#define FLAGS_ATRDOUBLESECTORS	0x20
+#define FLAGS_XFDTYPE			0x10
+#define FLAGS_READONLY			0x08
+#define FLAGS_WRITEERROR		0x04
+#define FLAGS_DRIVEON			0x01
+
+// Stuctures
+typedef struct						//2+2+2+2+2+4+1=15
+{
+	unsigned short start_cluster;		//< file starting cluster
+	unsigned short dir_cluster;
+	unsigned short current_cluster;
+	unsigned short ncluster;
+	unsigned short file_index;			//< file index
+	unsigned long size;					//< file size
+	unsigned char flags;				//< file flags
+}virtual_disk_t;
+
+struct FileInfoStruct
+{
+	unsigned char Attr;				//< file attr for last file accessed
+	unsigned short Date;			//< last update date
+	unsigned short Time;			//< last update time
+	unsigned char percomstate;		//=0 default, 1=percomwrite ok (single sectors), 2=percomwrite ok (double sectors), 3=percomwrite bad
+	//
+	virtual_disk_t vDisk;
+};
+
+struct GlobalSystemValues			//4+4+2+2+1=13 bytes
+{
+	unsigned long FirstFATSector;
+	unsigned long FirstDataSector;
+	unsigned short RootDirSectors;
+	unsigned short BytesPerSector;
+	unsigned char SectorsPerCluster;
+};
+
+#define FirstFATSector		GS.FirstFATSector
+#define FirstDataSector		GS.FirstDataSector
+#define RootDirSectors		GS.RootDirSectors
+#define BytesPerSector		GS.BytesPerSector
+#define SectorsPerCluster	GS.SectorsPerCluster
+
+
+unsigned char fatInit();
+unsigned long fatClustToSect(unsigned short clust);
+unsigned char fatChangeDirectory(unsigned short entry);
+unsigned char fatGetDirEntry(unsigned short entry, unsigned char use_long_names);
+unsigned short nextCluster(unsigned short cluster);
+
+#endif
Index: firmware_legacy/defunct/stuff.c
===================================================================
--- firmware_legacy/defunct/stuff.c	(nonexistent)
+++ firmware_legacy/defunct/stuff.c	(revision 799)
@@ -0,0 +1,13 @@
+#include "regs.h"
+#include "regs.c"
+#include "main.c"
+#include "fat.c" 
+#include "SDrive.c"
+#include "mmc.c"
+#include "spi.c"
+#include "uart.c"
+#include "led.c"
+#include "pind.c" 
+#include "eeprom.c"
+#include "pause.c"
+
Index: firmware_legacy/hexdump.h
===================================================================
--- firmware_legacy/hexdump.h	(nonexistent)
+++ firmware_legacy/hexdump.h	(revision 799)
@@ -0,0 +1,4 @@
+#pragma once
+
+void hexdump_pure(void const * str, int length);
+
Index: firmware_legacy/sdrive_parts/bootdump.c
===================================================================
--- firmware_legacy/sdrive_parts/bootdump.c	(nonexistent)
+++ firmware_legacy/sdrive_parts/bootdump.c	(revision 799)
@@ -0,0 +1,23 @@
+unsigned char boot_xex_loader[179] = {
+	0x72,0x02,0x5f,0x07,0xf8,0x07,0xa9,0x00,0x8d,0x04,0x03,0x8d,0x44,0x02,0xa9,0x07,
+	0x8d,0x05,0x03,0xa9,0x70,0x8d,0x0a,0x03,0xa9,0x01,0x8d,0x0b,0x03,0x85,0x09,0x60,
+	0x7d,0x8a,0x48,0x20,0x53,0xe4,0x88,0xd0,0xfa,0x68,0xaa,0x8c,0x8e,0x07,0xad,0x7d,
+	0x07,0xee,0x8e,0x07,0x60,0xa9,0x93,0x8d,0xe2,0x02,0xa9,0x07,0x8d,0xe3,0x02,0xa2,
+	0x02,0x20,0xda,0x07,0x95,0x43,0x20,0xda,0x07,0x95,0x44,0x35,0x43,0xc9,0xff,0xf0,
+	0xf0,0xca,0xca,0x10,0xec,0x30,0x06,0xe6,0x45,0xd0,0x02,0xe6,0x46,0x20,0xda,0x07,
+	0xa2,0x01,0x81,0x44,0xb5,0x45,0xd5,0x43,0xd0,0xed,0xca,0x10,0xf7,0x20,0xd2,0x07,
+	0x4c,0x94,0x07,0xa9,0x03,0x8d,0x0f,0xd2,0x6c,0xe2,0x02,0xad,0x8e,0x07,0xcd,0x7f,
+	0x07,0xd0,0xab,0xee,0x0a,0x03,0xd0,0x03,0xee,0x0b,0x03,0xad,0x7d,0x07,0x0d,0x7e,
+	0x07,0xd0,0x8e,0x20,0xd2,0x07,0x6c,0xe0,0x02,0x20,0xda,0x07,0x8d,0xe0,0x02,0x20,
+	0xda,0x07,0x8d,0xe1,0x02,0x2d,0xe0,0x02,0xc9,0xff,0xf0,0xed,0xa9,0x00,0x8d,0x8e,
+	0x07,0xf0,0x82 };
+
+int main(void)
+{
+	for (int i=0;i!=sizeof(boot_xex_loader);++i)
+	{
+		printf("%c",boot_xex_loader[i]);
+	}
+	return 0;
+}
+
Index: firmware_legacy/uart.h
===================================================================
--- firmware_legacy/uart.h	(nonexistent)
+++ firmware_legacy/uart.h	(revision 799)
@@ -0,0 +1,25 @@
+#ifndef UART_H
+#define UART_H
+
+#include "integer.h"
+
+// Might be simplest to use another Pokey as the UART...
+
+void USART_Init( u08 value ); // value is baud rate
+// must flush too
+
+void USART_Transmit_Byte( unsigned char data );
+unsigned char USART_Receive_Byte( void );
+
+int USART_Data_Ready();
+
+void USART_Transmit_Mode();
+void USART_Receive_Mode();
+
+int USART_Framing_Error();
+
+void USART_Wait_Transmit_Complete();
+
+int USART_Command_Line();
+
+#endif
Index: firmware_legacy/build
===================================================================
--- firmware_legacy/build	(nonexistent)
+++ firmware_legacy/build	(revision 799)
@@ -0,0 +1,17 @@
+zpu-elf-gcc -I. -Isd_direct -Iprintf -Ifat -Icommon -c -g -O2  -DDISABLE_UART_RX  -o zpu_obj/uart.o -c pokey/uart.c
+zpu-elf-gcc -I. -Isd_direct -Iprintf -Ifat -Icommon -c -g -O2  -DDISABLE_UART_RX  -o zpu_obj/hexdump.o -c hexdump.c
+zpu-elf-gcc -I. -Isd_direct -Iprintf -Ifat -Icommon -c -g -O2  -DDISABLE_UART_RX  -o zpu_obj/printf.o -c printf/printf.c
+zpu-elf-gcc -I. -Isd_direct -Iprintf -Ifat -Icommon -c -g -O2  -DDISABLE_UART_RX  -o zpu_obj/pff_file.o -c fat/pff_file.c
+zpu-elf-gcc -I. -Isd_direct -Iprintf -Ifat -Icommon -c -g -O2  -DDISABLE_UART_RX  -o zpu_obj/pff.o -c fat/pff.c
+zpu-elf-gcc -I. -Isd_direct -Iprintf -Ifat -Icommon -c -g -O2  -DDISABLE_UART_RX  -o zpu_obj/utils.o -c common/utils.c
+zpu-elf-gcc -I. -Isd_direct -Iprintf -Ifat -Icommon -c -g -O2  -DDISABLE_UART_RX  -o zpu_obj/diskio_mmc.o -c diskio_mmc.c
+zpu-elf-gcc -nostartfiles -Wl,--relax -g -Os -T ./standalone_simple.ld -o JustStartAtari.elf mycrt0.s zpu_obj/main.o zpu_obj/regs.o zpu_obj/atari_drive_emulator.o zpu_obj/pokey/uart.o zpu_obj/hexdump.o zpu_obj/printf/printf.o zpu_obj/fat/pff_file.o zpu_obj/fat/pff.o zpu_obj/common/utils.o zpu_obj/diskio_mmc.o 
+zpu-elf-objcopy -O binary JustStartAtari.elf JustStartAtari.bin
+echo >JustStartAtari.rpt -n "End of code:\t"
+zpu-elf-objdump -x JustStartAtari.elf | grep >>JustStartAtari.rpt _romend
+echo >>JustStartAtari.rpt -n "Start of BSS:\t"
+zpu-elf-objdump -x JustStartAtari.elf | grep  >>JustStartAtari.rpt __bss_start__
+echo >>JustStartAtari.rpt -n "End of BSS:\t"
+zpu-elf-objdump -x JustStartAtari.elf | grep >>JustStartAtari.rpt __bss_end__
+cat JustStartAtari.rpt
+

Property changes on: firmware_legacy/build
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: firmware_legacy/defunct/fat.c
===================================================================
--- firmware_legacy/defunct/fat.c	(nonexistent)
+++ firmware_legacy/defunct/fat.c	(revision 799)
@@ -0,0 +1,445 @@
+/*! \file fat.c \brief FAT16/32 file system driver. */
+//*****************************************************************************
+//
+// File Name	: 'fat.c'
+// Title		: FAT16/32 file system driver
+// Author		: Pascal Stang
+// Date			: 11/07/2000
+// Revised		: 12/12/2000
+// Version		: 0.3
+// Target MCU	: ATmega103 (should work for Atmel AVR Series)
+// Editor Tabs	: 4
+//
+// This code is based in part on work done by Jesper Hansen for his
+//		YAMPP MP3 player project.
+//
+// NOTE: This code is currently below version 1.0, and therefore is considered
+// to be lacking in some functionality or documentation, or may not be fully
+// tested.  Nonetheless, you can expect most functions to work.
+//
+// ----------------------------------------------------------------------------
+// 17.8.2008
+// Bob!k & Raster, C.P.U.
+// Original code was modified especially for the SDrive device. 
+// Some parts of code have been added, removed, rewrited or optimized due to
+// lack of MCU AVR Atmega8 memory.
+// ----------------------------------------------------------------------------
+//
+// This code is distributed under the GNU Public License
+//		which can be found at http://www.gnu.org/licenses/gpl.txt
+//
+//*****************************************************************************
+
+#include <stdio.h>
+#include <string.h>
+
+#include "fat.h"
+#include "mmc.h"
+#include "spi.h"
+
+void USART_SendString(char *buff);
+void mmcReadCached(u32 sector);
+
+
+#define FileNameBuffer atari_sector_buffer
+extern unsigned char atari_sector_buffer[256];
+extern unsigned char mmc_sector_buffer[512];	// one sector
+extern struct GlobalSystemValues GS;
+extern struct FileInfoStruct FileInfo;			//< file information for last file accessed
+
+
+unsigned long fatClustToSect(unsigned short clust)
+{
+	u32 ret;
+	if(clust==MSDOSFSROOT)
+	{
+		debug("fatClustToSect:");
+		u32 res = (u32)((u32)(FirstDataSector) - (u32)(RootDirSectors));
+		plotnextnumber(res);
+		debug(" ");
+		plotnextnumber(FirstDataSector);
+		debug(" ");
+		plotnextnumber(RootDirSectors);
+		debug("\n");
+		return res;
+	}
+	
+	ret = (u32)(clust-2);
+	ret *= (u32)SectorsPerCluster;
+	ret += (u32)FirstDataSector;
+	return ((unsigned long)ret);
+}
+
+
+//POZOR - DEBUG !!!
+//prvne definovana promenna
+u32 debug_endofvariables;		//promenna co je v pameti jako posledni (za ni je uz jen stack)
+//POZOR - DEBUG !!!
+
+unsigned short last_dir_start_cluster;
+unsigned char last_dir_valid;
+unsigned short last_dir_entry;
+unsigned long last_dir_sector;
+unsigned char last_dir_sector_count;
+unsigned short last_dir_cluster;
+unsigned char last_dir_index;
+
+
+unsigned char fatInit()
+{
+	struct partrecord PartInfo;
+	struct bpb710 *bpb;
+
+	// Moved here since init vars are in ROM!
+	last_dir_entry=0x0;
+	last_dir_sector=0;
+	last_dir_sector_count=0;
+	last_dir_cluster=0;
+	last_dir_index=0;
+
+	// read partition table
+	// TODO.... error checking
+	debug("FAT INIT:");
+	mmcReadCached(0);
+	// map first partition record	
+	// save partition information to global PartInfo
+	PartInfo = *((struct partrecord *) ((struct partsector *) (char*)mmc_sector_buffer)->psPart);
+
+	if(mmc_sector_buffer[0x36]=='F' && mmc_sector_buffer[0x37]=='A' && mmc_sector_buffer[0x38]=='T' && mmc_sector_buffer[0x39]=='1' && mmc_sector_buffer[0x3a]=='6')
+	{
+		PartInfo.prPartType = PART_TYPE_FAT16LBA; //0x04
+		PartInfo.prStartLBA = 0x00;
+	}
+	
+	// Read the Partition BootSector
+	// **first sector of partition in PartInfo.prStartLBA
+	mmcReadCached(PartInfo.prStartLBA);
+	bpb = (struct bpb710 *) ((struct bootsector710 *) (char*)mmc_sector_buffer)->bsBPB;
+
+	// setup global disk constants
+	PartInfo.prStartLBA = 0x1e8; // FIXME
+	FirstDataSector	= PartInfo.prStartLBA;
+
+	RootDirSectors = bpb->bpbRootDirEnts>>4; // /16 ; 512/16 = 32  (sector size / max entries in one sector = number of sectors)
+
+	debug("PartInto ");
+	plotnextnumber(PartInfo.prStartLBA);
+	debug(" ");
+	plotnextnumber(bpb->bpbRootDirEnts>>4);
+	debug("\n");
+
+	// bpbFATsecs is non-zero and is therefore valid
+	FirstDataSector	+= bpb->bpbResSectors + bpb->bpbFATs * bpb->bpbFATsecs + RootDirSectors;
+
+	SectorsPerCluster	= bpb->bpbSecPerClust;
+	BytesPerSector		= bpb->bpbBytesPerSec;
+	FirstFATSector		= bpb->bpbResSectors + PartInfo.prStartLBA;
+
+	// set current directory to root (\)
+	FileInfo.vDisk.dir_cluster = MSDOSFSROOT; //RootDirStartCluster;
+
+    last_dir_start_cluster=0xffff;
+	//last_dir_valid=0;		//<-- neni potreba, protoze na zacatku fatGetDirEntry se pri zjisteni
+							//ze je (FileInfo.vDisk.dir_cluster!=last_dir_start_cluster)
+							//vynuluje last_dir_valid=0;
+
+	if (   PartInfo.prPartType==PART_TYPE_DOSFAT16
+		|| PartInfo.prPartType==PART_TYPE_FAT16
+		|| PartInfo.prPartType==PART_TYPE_FAT16LBA
+	   )
+	{
+		return 1; //je to ok
+		debug("OK\n");
+	}
+	else
+	{
+		return 0; //neni to zadny filesystem co umime
+		debug("FAIL\n");
+	}
+}
+
+//////////////////////////////////////////////////////////////
+
+unsigned char fatGetDirEntry(unsigned short entry, unsigned char use_long_names)
+{
+	unsigned long sector;
+	struct direntry *de = 0;	// avoid compiler warning by initializing
+	struct winentry *we;
+	unsigned char haveLongNameEntry;
+	unsigned char gotEntry;
+	unsigned short b;
+	u08 index;
+	unsigned short entrycount = 0;
+	unsigned short actual_cluster = FileInfo.vDisk.dir_cluster;
+	unsigned char seccount=0;
+
+	haveLongNameEntry = 0;
+	gotEntry = 0;
+
+	if (FileInfo.vDisk.dir_cluster!=last_dir_start_cluster)
+	{
+		//zmenil se adresar, takze musi pracovat s nim
+		//a zneplatnit last_dir polozky
+		last_dir_start_cluster=FileInfo.vDisk.dir_cluster;
+		last_dir_valid=0;
+
+		debug("LastDirStartCluster:");
+		plotnextnumber(last_dir_start_cluster);
+		plotnextnumber(last_dir_valid);
+		debug("\n");
+	}
+
+	if ( !last_dir_valid
+		 || (entry<=last_dir_entry && (entry!=last_dir_entry || last_dir_valid!=1 || use_long_names!=0))
+	   )
+	{
+		//musi zacit od zacatku
+		sector = fatClustToSect(FileInfo.vDisk.dir_cluster);
+		//index = 0;
+		debug("ReadFromBegin:");
+		plotnextnumber(sector);
+		debug("\n");
+		goto fat_read_from_begin;
+	}
+	else
+	{
+		//muze zacit od posledne pouzite
+		entrycount=last_dir_entry;
+		index = last_dir_index;
+		sector=last_dir_sector;
+		actual_cluster=last_dir_cluster;
+		seccount = last_dir_sector_count;
+		debug("ReadFromLastEntry:");
+		plotnextnumber(sector);
+		debug("\n");
+		goto fat_read_from_last_entry;
+	}
+
+	while(1)
+	{
+		debug("Index:");
+		plotnextnumber(index);
+		debug("\n");
+		if(index==16)	// time for next sector ?
+		{
+			if ( actual_cluster==MSDOSFSROOT )
+			{
+				//v MSDOSFSROOT se nerozlisuji clustery
+				//protoze MSDOSFSROOT ma sektory stale dal za sebou bez clusterovani
+				if (seccount>=RootDirSectors) return 0; //prekrocil maximalni pocet polozek v MSDOSFSROOT
+			}
+			else //MUSI BYT!!! (aby neporovnaval seccount je-li actual_cluster==MSDOSFSROOT)
+			if( seccount>=SectorsPerCluster )
+			{
+				//next cluster
+				//pri prechodu pres pocet sektoru v clusteru
+				actual_cluster = nextCluster(actual_cluster);
+				sector=fatClustToSect(actual_cluster);
+				seccount=0;
+			}
+fat_read_from_begin:
+			index = 0;
+			seccount++;		//ted bude nacitat dalsi sektor (musi ho zapocitat)
+fat_read_from_last_entry:
+			mmcReadCached( sector++ ); 	//prave ho nacetl
+			de = (struct direntry *) (char*)mmc_sector_buffer;
+			de+=index;
+		}
+		
+		// check the status of this directory entry slot
+		if(de->deName[0] == 0x00) //SLOT_EMPTY
+		{
+			// slot is empty and this is the end of directory
+			gotEntry = 0;
+			break;
+		}
+		else if(de->deName[0] == 0xE5)	//SLOT_DELETED
+		{
+			// this is an empty slot
+			// do nothing and move to the next one
+		}
+		else
+		{
+			// this is a valid and occupied entry
+			// is it a part of a long file/dir name?
+			if( de->deAttributes==ATTR_LONG_FILENAME )
+			{
+				// we have a long name entry
+				// cast this directory entry as a "windows" (LFN: LongFileName) entry
+				u08 i;
+				unsigned char *fnbPtr;
+
+				//pokud nechceme longname, NESMI je vubec kompletovat
+				//a preskoci na dalsi polozku
+				//( takze ani haveLongNameEntry nikdy nebude nastaveno na 1)
+				//Jinak by totiz preplacaval dalsi kusy atari_sector_bufferu 12-255 ! BACHA!!!
+				if (!use_long_names) goto fat_next_dir_entry;
+
+				we = (struct winentry *) de;
+				
+				b = WIN_ENTRY_CHARS*( (unsigned short)((we->weCnt-1) & 0x0f));		// index into string
+				fnbPtr = &FileNameBuffer[b];
+
+				for (i=0;i<5;i++)	*fnbPtr++ = we->wePart1[i*2];	// copy first part
+				for (i=0;i<6;i++)	*fnbPtr++ = we->wePart2[i*2];	// second part
+				for (i=0;i<2;i++)	*fnbPtr++ = we->wePart3[i*2];	// and third part
+
+				/*
+				{
+				//unsigned char * sptr;
+				//sptr=we->wePart1;
+				//do { *fnbPtr++ = *sptr++; sptr++; } while (sptr<(we->wePart1+10)); // copy first part
+				//^-- pouziti jen tohoto prvniho a druhe dva pres normalni for(..) uspori 10 bajtu,
+				//pri pouziti i dalsich dvou timto stylem uz se to ale zase prodlouzi - nechaaaaaapu!
+				//sptr=we->wePart2;
+				//do { *fnbPtr++ = *sptr++; sptr++; } while (sptr<(we->wePart2+12)); // second part
+				//sptr=we->wePart3;
+				//do { *fnbPtr++ = *sptr++; sptr++; } while (sptr<(we->wePart3+4));  // and third part
+				}
+				*/
+
+				if (we->weCnt & WIN_LAST) *fnbPtr = 0;				// in case dirnamelength is multiple of 13, add termination
+				if ((we->weCnt & 0x0f) == 1) haveLongNameEntry = 1;	// flag that we have a complete long name entry set
+			}
+			else
+			{
+				// we have a short name entry
+				
+				// check if this is the short name entry corresponding
+				// to the end of a multi-part long name entry
+				if(haveLongNameEntry)
+				{
+					// a long entry name has been collected
+					if(entrycount == entry)		
+					{
+						// desired entry has been found, break out
+						gotEntry = 2;
+						break;
+					}
+					// otherwise
+					haveLongNameEntry = 0;	// clear long name flag
+					entrycount++;			// increment entry counter		
+				}
+				else
+				{
+					// entry is a short name (8.3 format) without a
+					// corresponding multi-part long name entry
+
+					//Zcela vynecha adresar "." a disk label
+					if( (de->deName[0]=='.' && de->deName[1]==' ' && (de->deAttributes & ATTR_DIRECTORY) ) //je to "." adresar
+						|| (de->deAttributes & ATTR_VOLUME) ) goto fat_next_dir_entry;
+
+					if(entrycount == entry)
+					{
+						/*
+						fnbPtr = &FileNameBuffer[string_offset];
+						for (i=0;i<8;i++)	*fnbPtr++ = de->deName[i];		// copy name
+						for (i=0;i<3;i++)	*fnbPtr++ = de->deExtension[i];	// copy extension
+						*fnbPtr = 0;										// null-terminate
+						*/
+						u08 i;
+						unsigned char *dptr;
+
+						dptr = &FileNameBuffer;
+						for (i=0;i<11;i++)	*dptr++ = de->deName[i];		// copy name+ext
+						*dptr=0;	//ukonceni za nazvem
+
+						// desired entry has been found, break out
+						//pokud chtel longname, tak to neni a proto upravi 8+3 jmeno na nazev.ext
+						//aby to melo formatovani jako longname
+						if (use_long_names)
+						{
+							//upravi 'NAME    EXT' na 'NAME.EXT'
+							//(vyhazi mezery a prida tecku)
+							//krome nazvu '.          ', a '..         ', tam jen vyhaze mezery
+							unsigned char *sptr;
+							//EXT => .EXT   (posune vcetne 0x00 za koncem extenderu)
+							dptr=(FileNameBuffer+12);
+							i=4; do { sptr=dptr-1; *dptr=*sptr; dptr=sptr; i--; } while(i>0);
+							if (FileNameBuffer[0]!='.') *dptr='.'; //jen pro jine nez '.' a '..'
+							//NAME    .EXT => NAME.EXT
+							sptr=dptr=&FileNameBuffer;
+							do
+							{
+							 if ((*sptr)!=' ') *dptr++=*sptr;
+							 sptr++;
+							} while (*sptr);
+							*dptr=0; //ukonceni
+						}
+						//
+						gotEntry = 1;
+						break;
+					}
+					// otherwise
+					entrycount++;			// increment entry counter		
+				}
+			}
+		}
+fat_next_dir_entry:
+		// next directory entry
+		de++;
+		// next index
+		index++;
+	}
+	
+	// we have a file/dir to return
+	// store file/dir starting cluster (start of data)
+	FileInfo.vDisk.start_cluster = (unsigned short) (de->deStartCluster);
+	// fileindex
+	FileInfo.vDisk.file_index = entry;	//fileindex teto polozky
+	// store file/dir size (note: size field for subdirectory entries is always zero)
+	FileInfo.vDisk.size = de->deFileSize;
+	// store file/dir attributes
+	FileInfo.Attr = de->deAttributes;
+	// store file/dir last update time
+	FileInfo.Time = (unsigned short) (de->deMTime[0] | de->deMTime[1]<<8);
+	// store file/dir last update date
+	FileInfo.Date = (unsigned short) (de->deMDate[0] | de->deMDate[1]<<8);
+
+	if(gotEntry)
+	{
+		debug(" gotEntry ");
+		last_dir_entry = entrycount;
+		last_dir_index = index;
+		last_dir_sector = sector-1; //protoze ihned po nacteni se posune
+		last_dir_cluster = actual_cluster;
+		last_dir_sector_count = seccount; //skace se az za inkrementaci seccount, takze tady se 1 neodecita!
+		last_dir_valid=gotEntry;
+	}
+	else
+	{
+		debug(" not gotEntry ");
+	}
+
+	return gotEntry;
+}
+
+
+unsigned short nextCluster(unsigned short cluster)
+{
+	  unsigned short nextCluster;
+	  unsigned long fatOffset;
+	  unsigned long sector;
+	  unsigned long offset;
+
+	  // two FAT bytes (16 bits) for every cluster
+	  fatOffset = ((u32)cluster) << 1;
+
+	  // calculate the FAT sector that we're interested in
+	  sector = FirstFATSector + (fatOffset / ((u32)BytesPerSector));
+	  // calculate offset of the our entry within that FAT sector
+	  offset = fatOffset % ((u32)BytesPerSector);
+
+	  // if we don't already have this FAT chunk loaded, go get it
+	  // read sector of FAT table
+  	  mmcReadCached( sector );
+
+	  // read the nextCluster value
+	  nextCluster = (*((unsigned short*) &((char*)mmc_sector_buffer)[offset])) & FAT16_MASK;
+
+	  // check to see if we're at the end of the chain
+	  if (nextCluster == (CLUST_EOFE & FAT16_MASK))
+		nextCluster = 0;
+
+	return (nextCluster&0xFFFF);
+}
Index: firmware_legacy/actions.c
===================================================================
--- firmware_legacy/actions.c	(nonexistent)
+++ firmware_legacy/actions.c	(revision 799)
@@ -0,0 +1,59 @@
+int bit_set(int var, int bit)
+{
+	return (((1<<bit)&var)!=0);
+}
+
+void actions()
+{
+	unsigned int i = 0;
+	//unsigned volatile char * store = 0xf00000; // SDRAM - fails!!
+	//unsigned volatile char * store  = 0xf80000; // SRAM...
+	//unsigned volatile char * store2 = 0xfc0000; // custom chips...
+
+	// cold start (need to clear a few key locations to make OS cold start)
+	// file selector (where applicable)
+	// options (where applicable)
+
+	int keys = *zpu_in;
+
+	if (bit_set(keys,0))
+	{
+		coldstart();
+	}
+	else if (bit_set(keys,1))
+	{
+		set_pause_6502(1);
+		freeze();
+		menu_options();
+		restore();
+		set_pause_6502(0);
+	}
+	else if (bit_set(keys,2))
+	{
+		set_pause_6502(1);
+		freeze();
+		menu_fileselector();
+		coldstart();
+	}
+}
+
+void menu_options()
+{
+	// title
+	// memory
+	// rom
+	// turbo
+	// disks
+	// exit/reboot
+
+	// simple state machine for menu, so I set up a small data structure then it just runs from that...
+}
+
+void menu_fileselector()
+{
+	// title
+	// loads of stuff, filtered by type
+	// directories can be selected
+	// initial directory set, after that starts where it was left
+}
+
Index: firmware_legacy/simplefile.h
===================================================================
--- firmware_legacy/simplefile.h	(nonexistent)
+++ firmware_legacy/simplefile.h	(revision 799)
@@ -0,0 +1,22 @@
+#pragma once
+
+enum SimpleFileStatus {SimpleFile_OK, SimpleFile_FAIL};
+
+struct SimpleFile;
+
+// NB when switching file, the other file may loose its position, depending on implementation!
+
+int file_struct_size();
+
+void file_init(struct SimpleFile * file);
+
+char const * file_path(struct SimpleFile * file);
+char const * file_name(struct SimpleFile * file);
+enum SimpleFileStatus file_read(struct SimpleFile * file, void * buffer, int bytes, int * bytesread);
+enum SimpleFileStatus file_seek(struct SimpleFile * file, int offsetFromStart);
+int file_size(struct SimpleFile * file);
+int file_readonly(struct SimpleFile * file);
+
+enum SimpleFileStatus file_write(struct SimpleFile * file, void * buffer, int bytes, int * byteswritten);
+enum SimpleFileStatus file_write_flush();
+
Index: firmware_legacy/build_native_file_test
===================================================================
--- firmware_legacy/build_native_file_test	(nonexistent)
+++ firmware_legacy/build_native_file_test	(revision 799)
@@ -0,0 +1 @@
+gcc -g -O0 printf/printf.c test_file.c fileutils.c fileselector.c fat/pff_file.c fat/pff.c common/utils.c native/regs.c native/joystick.c native/diskio_mmc.c native/mmc.c native/screen.c -I. -Ifat -Icommon -Iprintf

Property changes on: firmware_legacy/build_native_file_test
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: firmware_legacy/crt0.S
===================================================================
--- firmware_legacy/crt0.S	(nonexistent)
+++ firmware_legacy/crt0.S	(revision 799)
@@ -0,0 +1,974 @@
+/* Startup code for ZPU
+   Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file 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, or (at your option) any
+later version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file with other programs, and to distribute
+those programs without any restriction coming from the use of this
+file.  (The General Public License restrictions do apply in other
+respects; for example, they cover modification of the file, and
+distribution when not linked into another program.)
+
+This file 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; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+	.file	"crt0.S"
+	
+	
+	
+	
+;	.section ".fixed_vectors","ax"
+; KLUDGE!!! we remove the executable bit to avoid relaxation 
+	.section ".fixed_vectors","a" 
+
+; DANGER!!!! 
+; we need to align these code sections to 32 bytes, which
+; means we must not use any assembler instructions that are relaxed
+; at linker time
+; DANGER!!!! 
+
+	.macro fixedim value
+			im \value
+	.endm
+
+	.macro  jsr address
+			im _memreg     	; save R0
+			load
+			im _memreg+4	; save R1
+			load
+			im _memreg+8	; save R2
+			load
+			fixedim \address
+			call
+			im _memreg+8
+			store		; restore R2
+			im _memreg+4
+			store		; restore R1
+			im _memreg
+			store		; restore R0
+	.endm
+
+
+	.macro  jmp address
+			fixedim \address
+			poppc
+	.endm
+		
+
+	.macro fast_neg
+	not
+	im 1
+	add
+	.endm
+	
+	.macro cimpl funcname
+	; save R0
+	im _memreg
+	load
+	
+	; save R1
+	im _memreg+4
+	load
+	
+	; save R2
+	im _memreg+8
+	load
+	
+	loadsp 20
+	loadsp 20
+	
+	fixedim \funcname
+	call
+
+	; destroy arguments on stack
+	storesp 0
+	storesp 0	
+	 
+	im _memreg
+	load
+	
+	; poke the result into the right slot
+	storesp 24
+
+	; restore R2
+	im _memreg+8
+	store
+	
+	; restore R1
+	im _memreg+4
+	store
+	
+	; restore r0
+	im _memreg
+	store
+	
+	
+	storesp 4
+	poppc
+	.endm
+
+	.macro mult1bit
+	; create mask of lowest bit in A
+	loadsp 8 ; A
+	im 1
+	and
+	im -1
+	add
+	not
+	loadsp 8 ; B
+	and 
+	add ; accumulate in C
+	
+	; shift B left 1 bit
+	loadsp 4 ; B
+	addsp 0
+	storesp 8 ; B
+	
+	; shift A right 1 bit
+	loadsp 8 ; A
+	flip
+	addsp 0
+	flip
+	storesp 12 ; A
+	.endm
+
+
+
+/* vectors */
+        .balign 32,0
+# offset 0x0000 0000
+		.globl _start
+_start:
+		; intSp must be 0 when we jump to _premain
+		
+		im ZPU_ID
+		loadsp 0
+		im _cpu_config
+		store
+		config
+		jmp _premain
+
+
+
+        .balign 32,0
+# offset 0x0000 0020
+		.globl _zpu_interrupt_vector
+_zpu_interrupt_vector:
+		jmp ___zpu_interrupt_vector
+
+
+        .balign 16,0
+# offset 0x0000 0030
+		.globl _memreg
+		.weak _memreg
+_memreg:
+
+
+/* instruction emulation code */
+
+# opcode 34
+# offset 0x0000 0040
+	.balign 32,0
+_loadh:
+	loadsp 4
+	; by not masking out bit 0, we cause a memory access error 
+	; on unaligned access
+	im ~0x2
+	and
+	load
+
+	; mult 8	
+	loadsp 8
+	im 3
+	and
+	fast_neg
+	im 2
+	add
+	im 3
+	ashiftleft
+	; shift right addr&3 * 8
+	lshiftright
+	im 0xffff
+	and
+	storesp 8
+	
+	poppc
+
+# opcode 35
+# offset 0x0000 0060
+	.balign 32,0
+_storeh:
+	loadsp 4
+	; by not masking out bit 0, we cause a memory access error 
+	; on unaligned access
+	im ~0x2
+	and
+	load
+
+	; mask
+	im 0xffff
+	loadsp 12
+	im 3
+	and
+	fast_neg
+	im 2
+	add
+	im 3
+	ashiftleft
+	ashiftleft
+	not
+
+	and
+
+	loadsp 12
+	im 0xffff
+
+	nop
+		
+	fixedim _storehtail
+	poppc
+
+
+# opcode 36
+# offset 0x0000 0080
+	.balign 32,0
+_lessthan:
+	loadsp 8
+	fast_neg
+	loadsp 8
+	add
+
+	; DANGER!!!!
+	; 0x80000000 will overflow when negated, so we need to mask
+	; the result above with the compare positive to negative
+	; number case
+	loadsp 12
+	loadsp 12
+	not
+	and
+	not
+	and
+
+
+	; handle case where we are comparing a negative number
+	; and positve number. This can underflow. E.g. consider 0x8000000 < 0x1000
+	loadsp 12
+	not
+	loadsp 12
+	and
+	
+	or
+
+
+
+	flip
+	im 1
+	and	
+
+	
+	storesp 12
+	storesp 4
+	poppc
+	
+
+# opcode 37
+# offset 0x0000 00a0
+	.balign 32,0
+_lessthanorequal:
+	loadsp 8
+	loadsp 8
+	lessthan
+	loadsp 12
+	loadsp 12
+	eq
+	or
+	
+	storesp 12
+	storesp 4
+	poppc
+
+	
+# opcode 38
+# offset 0x0000 00c0
+	.balign 32,0
+_ulessthan:
+	; fish up arguments 
+	loadsp 4
+	loadsp 12
+	
+	/* low: -1 if low bit dif is negative 0 otherwise:  neg (not x&1 and (y&1))
+		x&1		y&1		neg (not x&1 and (y&1))
+		1		1		0
+		1		0 		0
+		0		1		-1
+		0		0		0
+	
+	*/
+	loadsp 4 
+	not
+	loadsp 4
+	and
+	im 1
+	and
+	neg
+	
+	
+	/* high: upper 31-bit diff is only wrong when diff is 0 and low=-1
+		high=x>>1 - y>>1 + low
+		
+		extremes
+		
+		0000 - 1111:
+		low= neg(not 0 and 1) = 1111 (-1)
+		high=000+ neg(111) +low = 000 + 1001 + low = 1000 
+		OK
+		
+		1111 - 0000
+		low=neg(not 1 and 0) = 0
+		high=111+neg(000) + low = 0111
+		OK
+		 
+		
+	 */
+	loadsp 8
+	
+	flip 
+	addsp 0
+	flip
+	
+	loadsp 8
+	
+	flip	
+	addsp 0
+	flip
+
+	sub
+
+	; if they are equal, then the last bit decides...	
+	add
+	
+	/* test if negative: result = flip(diff) & 1 */
+	flip
+	im 1
+	and
+
+	; destroy a&b which are on stack	
+	storesp 4
+	storesp 4
+	
+	storesp 12
+	storesp 4
+	poppc			
+
+# opcode 39
+# offset 0x0000 00e0
+	.balign 32,0
+_ulessthanorequal:
+	loadsp 8
+	loadsp 8
+	ulessthan
+	loadsp 12
+	loadsp 12
+	eq
+	or
+	
+	storesp 12
+	storesp 4
+	poppc
+
+
+# opcode 40
+# offset 0x0000 0100
+	.balign 32,0
+	.globl _swap
+_swap:
+	breakpoint ; tbd
+
+# opcode 41
+# offset 0x0000 0120
+	.balign 32,0
+_slowmult:
+	im _slowmultImpl
+	poppc
+
+# opcode 42
+# offset 0x0000 0140
+	.balign 32,0
+_lshiftright:
+	loadsp 8
+	flip
+
+	loadsp 8
+	ashiftleft
+	flip
+	
+	storesp 12
+	storesp 4
+
+	poppc
+	
+
+# opcode 43
+# offset 0x0000 0160
+	.balign 32,0
+_ashiftleft:
+	loadsp 8
+	
+	loadsp 8
+	im 0x1f
+	and
+	fast_neg
+	im _ashiftleftEnd
+	add
+	poppc
+	
+	
+	
+# opcode 44
+# offset 0x0000 0180
+	.balign 32,0
+_ashiftright:
+	loadsp 8
+	loadsp 8
+	lshiftright
+	
+	; handle signed value
+	im -1
+	loadsp 12
+	im 0x1f
+	and
+	lshiftright
+	not	; now we have an integer on the stack with the signed 
+		; bits in the right position
+
+	; mask these bits with the signed bit.
+	loadsp 16
+	not
+	flip
+	im 1
+	and
+	im -1
+	add
+	
+	and	
+	
+	; stuff in the signed bits...
+	or
+	
+	; store result into correct stack slot	
+	storesp 12
+	
+	; move up return value 
+	storesp 4
+	poppc
+
+# opcode 45
+# offset 0x0000 01a0
+	.balign 32,0
+_call:
+	; fn
+	loadsp 4
+	
+	; return address
+	loadsp 4
+
+	; store return address
+	storesp 12
+	
+	; fn to call
+	storesp 4
+	
+	pushsp	; flush internal stack
+	popsp
+		
+	poppc
+
+_storehtail:
+
+	and
+	loadsp 12
+	im 3
+	and
+	fast_neg
+	im 2
+	add
+	im 3
+	ashiftleft
+	nop
+	ashiftleft
+	
+	or
+	
+	loadsp 8
+	im  ~0x3
+	and
+
+	store
+	
+	storesp 4
+	storesp 4
+	poppc
+
+
+# opcode 46
+# offset 0x0000 01c0
+	.balign 32,0
+_eq:
+	loadsp 8
+	fast_neg
+	loadsp 8
+	add
+	
+	not 
+	loadsp 0
+	im 1
+	add
+	not
+	and
+	flip
+	im 1
+	and
+	
+	storesp 12
+	storesp 4
+	poppc
+
+# opcode 47
+# offset 0x0000 01e0
+	.balign 32,0
+_neq:
+	loadsp 8
+	fast_neg
+	loadsp 8
+	add
+	
+	not 
+	loadsp 0
+	im 1
+	add
+	not
+	and
+	flip
+
+	not
+
+	im 1
+	and
+		
+	storesp 12
+	storesp 4
+	poppc
+	
+
+# opcode 48
+# offset 0x0000 0200
+	.balign 32,0
+_neg:
+	loadsp 4
+	not
+	im 1
+	add
+	storesp 8
+	
+	poppc
+	
+
+# opcode 49
+# offset 0x0000 0220
+	.balign 32,0
+_sub:
+	loadsp 8
+	loadsp 8
+	fast_neg
+	add
+	storesp 12
+
+	storesp 4
+
+	poppc
+
+
+# opcode 50
+# offset 0x0000 0240
+	.balign 32,0
+_xor:
+	loadsp 8
+	not
+	loadsp 8
+	and
+	
+	loadsp 12
+	loadsp 12
+	not
+	and
+
+	or
+
+	storesp 12
+	storesp 4
+	poppc
+
+# opcode 51
+# offset 0x0000 0260
+	.balign 32,0
+_loadb:
+	loadsp 4
+	im ~0x3
+	and
+	load
+
+	loadsp 8
+	im 3
+	and
+	fast_neg
+	im 3
+	add
+	; x8
+	addsp 0
+	addsp 0
+	addsp 0
+
+	lshiftright
+
+	im 0xff
+	and
+	storesp 8
+	
+	poppc
+
+
+# opcode 52
+# offset 0x0000 0280
+	.balign 32,0
+_storeb:
+	loadsp 4
+	im ~0x3
+	and
+	load
+
+	; mask away destination
+	im _mask
+	loadsp 12
+	im 3
+	and
+	addsp 0
+	addsp 0
+	add
+	load
+
+	and
+
+
+	im _storebtail
+	poppc
+	
+# opcode 53
+# offset 0x0000 02a0
+	.balign 32,0
+_div:
+	jmp ___div
+	
+# opcode 54
+# offset 0x0000 02c0
+	.balign 32,0
+_mod:
+	jmp ___mod
+
+# opcode 55
+# offset 0x0000 02e0
+	.balign 32,0
+	.globl _eqbranch
+_eqbranch:
+	loadsp 8
+	
+	; eq
+
+	not 
+	loadsp 0
+	im 1
+	add
+	not
+	and
+	flip
+	im 1
+	and
+
+	; mask
+	im -1
+	add
+	loadsp 0
+	storesp 16
+
+	; no branch address
+	loadsp 4
+	
+	and
+
+	; fetch boolean & neg mask
+	loadsp 12
+	not
+	
+	; calc address & mask for branch
+	loadsp 8
+	loadsp 16
+	add
+	; subtract 1 to find PC of branch instruction
+	im -1
+	add
+	
+	and
+
+	or	
+	
+	storesp 4
+	storesp 4
+	storesp 4
+	poppc	
+
+
+# opcode 56
+# offset 0x0000 0300
+	.balign 32,0
+	.globl _neqbranch
+_neqbranch:
+	loadsp 8
+	
+	; neq
+
+	not 
+	loadsp 0
+	im 1
+	add
+	not
+	and
+	flip
+	
+	not
+	
+	im 1
+	and
+
+	; mask
+	im -1
+	add
+	loadsp 0
+	storesp 16
+
+	; no branch address
+	loadsp 4
+	
+	and
+
+	; fetch boolean & neg mask
+	loadsp 12
+	not
+	
+	; calc address & mask for branch
+	loadsp 8
+	loadsp 16
+	add
+	; find address of branch instruction
+	im -1
+	add
+	
+	and
+
+	or	
+	
+	storesp 4
+	storesp 4
+	storesp 4
+	poppc	
+
+# opcode 57
+# offset 0x0000 0320
+	.balign 32,0
+	.globl _poppcrel
+_poppcrel:
+	add
+	; address of poppcrel
+	im -1
+	add
+	poppc
+		
+# opcode 58
+# offset 0x0000 0340
+	.balign 32,0
+	.globl _config
+_config:
+	im 1 
+	nop
+	im _hardware
+	store
+	storesp 4
+	poppc
+
+# opcode 59
+# offset 0x0000 0360
+	.balign 32,0
+_pushpc:
+	loadsp 4
+	im 1
+	add 
+	storesp 8
+	poppc
+	
+# opcode 60
+# offset 0x0000 0380
+	.balign 32,0
+_syscall_emulate:
+	.byte 0
+	
+# opcode 61
+# offset 0x0000 03a0
+	.balign 32,0
+_pushspadd:
+	pushsp
+	im 4
+	add
+	loadsp 8
+	addsp 0
+	addsp 0
+	add
+	storesp 8
+	
+	poppc
+
+# opcode 62
+# offset 0x0000 03c0
+	.balign 32,0
+_halfmult:
+	breakpoint
+	
+# opcode 63
+# offset 0x0000 03e0
+	.balign 32,0
+_callpcrel:
+	loadsp 4
+	loadsp 4
+	add
+	im -1
+	add
+	loadsp 4
+	
+	storesp 12	; return address
+	storesp 4 
+	pushsp		; this will flush the internal stack.
+	popsp
+	poppc
+
+	.text
+
+	
+
+
+_ashiftleftBegin:
+	.rept 0x1f
+	addsp 0
+	.endr
+_ashiftleftEnd:
+	storesp 12
+	storesp 4
+	poppc
+	
+_storebtail:
+	loadsp 12
+	im 0xff
+	and
+	loadsp 12
+	im 3
+	and
+
+	fast_neg
+	im 3
+	add
+	; x8
+	addsp 0
+	addsp 0
+	addsp 0
+
+	ashiftleft
+	 
+	or
+	
+	loadsp 8
+	im  ~0x3
+	and
+
+	store
+	
+	storesp 4
+	storesp 4
+	poppc
+	
+
+
+
+; NB! this is not an EMULATE instruction. It is a varargs fn.
+	.globl _syscall	
+_syscall:
+	syscall
+	poppc
+	
+_slowmultImpl:
+	
+	loadsp 8 ; A
+	loadsp 8 ; B
+	im 0 ; C
+
+.LmoreMult:
+	mult1bit
+	
+	; cutoff
+	loadsp 8
+	.byte (.LmoreMult-.Lbranch)&0x7f+0x80
+.Lbranch:
+	neqbranch
+
+	storesp 4
+	storesp 4
+	storesp 12
+	storesp 4
+	poppc
+
+___mod:
+	cimpl __modsi3
+___div:
+	cimpl __divsi3
+
+        .globl ___zpu_interrupt_vector
+        .weak ___zpu_interrupt_vector
+
+___zpu_interrupt_vector:
+	jsr _zpu_interrupt
+	poppc
+
+	.section ".rodata"
+	.balign 4,0
+_mask:
+	.long 0x00ffffff
+	.long 0xff00ffff
+	.long 0xffff00ff
+	.long 0xffffff00
+
+	.data
+	.balign 4,0
+	
+	.globl _hardware
+_hardware:
+	.long 0
+	.globl _cpu_config
+_cpu_config:
+	.long 0
+

Property changes on: firmware_legacy/crt0.S
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: firmware_legacy/defunct/led.c
===================================================================
--- firmware_legacy/defunct/led.c	(nonexistent)
+++ firmware_legacy/defunct/led.c	(revision 799)
@@ -0,0 +1,20 @@
+#include "led.h"
+
+#include "regs.h"
+
+void set_green_led(int i)
+{
+	*zpu_ledg = i;
+}
+void set_red_led(int i)
+{
+	*zpu_ledr = i;
+}
+void set_drive_number(int i)
+{
+	*zpu_hex = i;
+}
+void init_display()
+{
+	*zpu_hex = 0;
+}
Index: firmware_legacy/defunct/test.c
===================================================================
--- firmware_legacy/defunct/test.c	(nonexistent)
+++ firmware_legacy/defunct/test.c	(revision 799)
@@ -0,0 +1,71 @@
+
+
+unsigned char toatarichar(int val)
+{
+	if (val>='A' && val<='Z')
+	{
+		val+=-'A'+33;
+	}
+	else if (val>='a' && val<='z')
+	{
+		val+=-'a'+33+64;
+	}
+	else if (val>='0' && val<='9')
+	{
+		val+=-'0'+16;	
+	}
+	else
+	{
+		val = 0;
+	}
+	return val;
+}
+
+int xpos = 0;
+int ypos = 0;
+
+void nextline()
+{
+	xpos=0;
+	ypos+=1;
+	if (ypos==24)
+		ypos = 0;
+}
+void plot(unsigned char a, int x, int y)
+{
+	printf("%d %d %d\n",a,x,y);
+}
+
+void debug(char const * str)
+{
+//        char buffer[256];
+//        buffer[0] = 'W';
+//        buffer[1] = 'T';
+//        buffer[2] = 'F';
+//        buffer[3] = 0;
+//        str = buffer;
+
+        while (1)
+        {
+                int val = *str++;
+                if (val==0) break;
+
+                plot(toatarichar(val),xpos,ypos);
+                ++xpos;
+                if (xpos==40)
+                {
+                        nextline();
+                }
+        }
+        nextline();
+        //Delay100usX(10000);
+}
+
+
+int main(void)
+{
+	printf("%d %d\n", 'H', toatarichar('H'));
+	debug("Goodbye sweet world!");
+	return 0;
+}
+
Index: firmware_legacy/mycrt0.s
===================================================================
--- firmware_legacy/mycrt0.s	(nonexistent)
+++ firmware_legacy/mycrt0.s	(revision 799)
@@ -0,0 +1,976 @@
+/* Startup code for ZPU
+   Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file 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, or (at your option) any
+later version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file with other programs, and to distribute
+those programs without any restriction coming from the use of this
+file.  (The General Public License restrictions do apply in other
+respects; for example, they cover modification of the file, and
+distribution when not linked into another program.)
+
+This file 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; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+	.file	"mincrt0.S"
+
+
+/* Minimal startup code, usable where the core is complete enough not to require emulated instructions */
+	
+
+	.section ".fixed_vectors","ax"
+; KLUDGE!!! we remove the executable bit to avoid relaxation 
+	.section ".fixed_vectors","a" 
+
+	.macro fixedim value
+			im \value
+	.endm
+
+	.macro  jmp address
+			fixedim \address
+			poppc
+	.endm
+
+	.macro fast_neg
+	not
+	im 1
+	add
+	.endm
+
+	.macro mult1bit
+	; create mask of lowest bit in A
+	loadsp 8 ; A
+	im 1
+	and
+	im -1
+	add
+	not
+	loadsp 8 ; B
+	and 
+	add ; accumulate in C
+	
+	; shift B left 1 bit
+	loadsp 4 ; B
+	addsp 0
+	storesp 8 ; B
+	
+	; shift A right 1 bit
+	loadsp 8 ; A
+	flip
+	addsp 0
+	flip
+	storesp 12 ; A
+	.endm
+
+	.macro cimpl funcname
+	; save R0
+	im _memreg
+	load
+	
+	; save R1
+	im _memreg+4
+	load
+	
+	; save R2
+	im _memreg+8
+	load
+	
+	loadsp 20
+	loadsp 20
+	
+	fixedim \funcname
+	call
+
+	; destroy arguments on stack
+	storesp 0
+	storesp 0	
+	 
+	im _memreg
+	load
+	
+	; poke the result into the right slot
+	storesp 24
+
+	; restore R2
+	im _memreg+8
+	store
+	
+	; restore R1
+	im _memreg+4
+	store
+	
+	; restore r0
+	im _memreg
+	store
+	
+	
+	storesp 4
+	poppc
+	.endm
+
+
+		.globl _start
+_start:
+		jmp _premain
+
+/* vectors */
+/* instruction emulation code */
+        nop
+        nop
+        nop
+	nop
+        nop
+        nop
+        nop
+        nop
+	nop
+        nop
+        nop
+        nop
+        nop
+        nop
+        nop
+	nop
+        nop
+        nop
+        nop
+        nop
+	nop
+        nop
+        nop
+        nop
+        nop
+        nop
+	nop
+        nop
+        nop
+        nop
+
+# opcode 34
+# offset 0x0000 0040
+	.balign 32,0
+_loadh:
+	loadsp 4
+	; by not masking out bit 0, we cause a memory access error 
+	; on unaligned access
+	im ~0x2
+	and
+	load
+
+	; mult 8	
+	loadsp 8
+	im 3
+	and
+	fast_neg
+	im 2
+	add
+	im 3
+	ashiftleft
+	; shift right addr&3 * 8
+	lshiftright
+	im 0xffff
+	and
+	storesp 8
+	
+	poppc
+
+# opcode 35
+# offset 0x0000 0060
+	.balign 32,0
+_storeh:
+	loadsp 4
+	; by not masking out bit 0, we cause a memory access error 
+	; on unaligned access
+	im ~0x2
+	and
+	load
+
+	; mask
+	im 0xffff
+	loadsp 12
+	im 3
+	and
+	fast_neg
+	im 2
+	add
+	im 3
+	ashiftleft
+	ashiftleft
+	not
+
+	and
+
+	loadsp 12
+	im 0xffff
+
+	nop
+		
+	fixedim _storehtail
+	poppc
+
+
+# opcode 36
+# offset 0x0000 0080
+	.balign 32,0
+_lessthan:
+	loadsp 8
+	fast_neg
+	loadsp 8
+	add
+
+	; DANGER!!!!
+	; 0x80000000 will overflow when negated, so we need to mask
+	; the result above with the compare positive to negative
+	; number case
+	loadsp 12
+	loadsp 12
+	not
+	and
+	not
+	and
+
+
+	; handle case where we are comparing a negative number
+	; and positve number. This can underflow. E.g. consider 0x8000000 < 0x1000
+	loadsp 12
+	not
+	loadsp 12
+	and
+	
+	or
+
+
+
+	flip
+	im 1
+	and	
+
+	
+	storesp 12
+	storesp 4
+	poppc
+	
+
+# opcode 37
+# offset 0x0000 00a0
+	.balign 32,0
+_lessthanorequal:
+	loadsp 8
+	loadsp 8
+	lessthan
+	loadsp 12
+	loadsp 12
+	eq
+	or
+	
+	storesp 12
+	storesp 4
+	poppc
+
+	
+# opcode 38
+# offset 0x0000 00c0
+	.balign 32,0
+_ulessthan:
+	; fish up arguments 
+	loadsp 4
+	loadsp 12
+	
+	/* low: -1 if low bit dif is negative 0 otherwise:  neg (not x&1 and (y&1))
+		x&1		y&1		neg (not x&1 and (y&1))
+		1		1		0
+		1		0 		0
+		0		1		-1
+		0		0		0
+	
+	*/
+	loadsp 4 
+	not
+	loadsp 4
+	and
+	im 1
+	and
+	neg
+	
+	
+	/* high: upper 31-bit diff is only wrong when diff is 0 and low=-1
+		high=x>>1 - y>>1 + low
+		
+		extremes
+		
+		0000 - 1111:
+		low= neg(not 0 and 1) = 1111 (-1)
+		high=000+ neg(111) +low = 000 + 1001 + low = 1000 
+		OK
+		
+		1111 - 0000
+		low=neg(not 1 and 0) = 0
+		high=111+neg(000) + low = 0111
+		OK
+		 
+		
+	 */
+	loadsp 8
+	
+	flip 
+	addsp 0
+	flip
+	
+	loadsp 8
+	
+	flip	
+	addsp 0
+	flip
+
+	sub
+
+	; if they are equal, then the last bit decides...	
+	add
+	
+	/* test if negative: result = flip(diff) & 1 */
+	flip
+	im 1
+	and
+
+	; destroy a&b which are on stack	
+	storesp 4
+	storesp 4
+	
+	storesp 12
+	storesp 4
+	poppc			
+
+# opcode 39
+# offset 0x0000 00e0
+	.balign 32,0
+_ulessthanorequal:
+	loadsp 8
+	loadsp 8
+	ulessthan
+	loadsp 12
+	loadsp 12
+	eq
+	or
+	
+	storesp 12
+	storesp 4
+	poppc
+
+
+# opcode 40
+# offset 0x0000 0100
+	.balign 32,0
+	.globl _swap
+_swap:
+	breakpoint ; tbd
+
+# opcode 41
+# offset 0x0000 0120
+	.balign 32,0
+_slowmult:
+	im _slowmultImpl
+	poppc
+
+# opcode 42
+# offset 0x0000 0140
+	.balign 32,0
+_lshiftright:
+	loadsp 8
+	flip
+
+	loadsp 8
+	ashiftleft
+	flip
+	
+	storesp 12
+	storesp 4
+
+	poppc
+	
+
+# opcode 43
+# offset 0x0000 0160
+	.balign 32,0
+_ashiftleft:
+	loadsp 8
+	
+	loadsp 8
+	im 0x1f
+	and
+	fast_neg
+	im _ashiftleftEnd
+	add
+	poppc
+	
+	
+	
+# opcode 44
+# offset 0x0000 0180
+	.balign 32,0
+_ashiftright:
+	loadsp 8
+	loadsp 8
+	lshiftright
+	
+	; handle signed value
+	im -1
+	loadsp 12
+	im 0x1f
+	and
+	lshiftright
+	not	; now we have an integer on the stack with the signed 
+		; bits in the right position
+
+	; mask these bits with the signed bit.
+	loadsp 16
+	not
+	flip
+	im 1
+	and
+	im -1
+	add
+	
+	and	
+	
+	; stuff in the signed bits...
+	or
+	
+	; store result into correct stack slot	
+	storesp 12
+	
+	; move up return value 
+	storesp 4
+	poppc
+
+# opcode 45
+# offset 0x0000 01a0
+	.balign 32,0
+_call:
+	; fn
+	loadsp 4
+	
+	; return address
+	loadsp 4
+
+	; store return address
+	storesp 12
+	
+	; fn to call
+	storesp 4
+	
+	pushsp	; flush internal stack
+	popsp
+		
+	poppc
+
+_storehtail:
+
+	and
+	loadsp 12
+	im 3
+	and
+	fast_neg
+	im 2
+	add
+	im 3
+	ashiftleft
+	nop
+	ashiftleft
+	
+	or
+	
+	loadsp 8
+	im  ~0x3
+	and
+
+	store
+	
+	storesp 4
+	storesp 4
+	poppc
+
+
+# opcode 46
+# offset 0x0000 01c0
+	.balign 32,0
+_eq:
+	loadsp 8
+	fast_neg
+	loadsp 8
+	add
+	
+	not 
+	loadsp 0
+	im 1
+	add
+	not
+	and
+	flip
+	im 1
+	and
+	
+	storesp 12
+	storesp 4
+	poppc
+
+# opcode 47
+# offset 0x0000 01e0
+	.balign 32,0
+_neq:
+	loadsp 8
+	fast_neg
+	loadsp 8
+	add
+	
+	not 
+	loadsp 0
+	im 1
+	add
+	not
+	and
+	flip
+
+	not
+
+	im 1
+	and
+		
+	storesp 12
+	storesp 4
+	poppc
+	
+
+# opcode 48
+# offset 0x0000 0200
+	.balign 32,0
+_neg:
+	loadsp 4
+	not
+	im 1
+	add
+	storesp 8
+	
+	poppc
+	
+
+# opcode 49
+# offset 0x0000 0220
+	.balign 32,0
+_sub:
+	loadsp 8
+	loadsp 8
+	fast_neg
+	add
+	storesp 12
+
+	storesp 4
+
+	poppc
+
+
+# opcode 50
+# offset 0x0000 0240
+	.balign 32,0
+_xor:
+	loadsp 8
+	not
+	loadsp 8
+	and
+	
+	loadsp 12
+	loadsp 12
+	not
+	and
+
+	or
+
+	storesp 12
+	storesp 4
+	poppc
+
+# opcode 51
+# offset 0x0000 0260
+	.balign 32,0
+_loadb:
+	loadsp 4
+	im ~0x3
+	and
+	load
+
+	loadsp 8
+	im 3
+	and
+	fast_neg
+	im 3
+	add
+	; x8
+	addsp 0
+	addsp 0
+	addsp 0
+
+	lshiftright
+
+	im 0xff
+	and
+	storesp 8
+	
+	poppc
+
+
+# opcode 52
+# offset 0x0000 0280
+	.balign 32,0
+_storeb:
+	loadsp 4
+	im ~0x3
+	and
+	load
+
+	; mask away destination
+	im _mask
+	loadsp 12
+	im 3
+	and
+	addsp 0
+	addsp 0
+	add
+	load
+
+	and
+
+
+	im _storebtail
+	poppc
+	
+# opcode 53
+# offset 0x0000 02a0
+	.balign 32,0
+_div:
+	jmp ___div
+	
+# opcode 54
+# offset 0x0000 02c0
+	.balign 32,0
+_mod:
+	jmp ___mod
+
+# opcode 55
+# offset 0x0000 02e0
+	.balign 32,0
+	.globl _eqbranch
+_eqbranch:
+	loadsp 8
+	
+	; eq
+
+	not 
+	loadsp 0
+	im 1
+	add
+	not
+	and
+	flip
+	im 1
+	and
+
+	; mask
+	im -1
+	add
+	loadsp 0
+	storesp 16
+
+	; no branch address
+	loadsp 4
+	
+	and
+
+	; fetch boolean & neg mask
+	loadsp 12
+	not
+	
+	; calc address & mask for branch
+	loadsp 8
+	loadsp 16
+	add
+	; subtract 1 to find PC of branch instruction
+	im -1
+	add
+	
+	and
+
+	or	
+	
+	storesp 4
+	storesp 4
+	storesp 4
+	poppc	
+
+
+# opcode 56
+# offset 0x0000 0300
+	.balign 32,0
+	.globl _neqbranch
+_neqbranch:
+	loadsp 8
+	
+	; neq
+
+	not 
+	loadsp 0
+	im 1
+	add
+	not
+	and
+	flip
+	
+	not
+	
+	im 1
+	and
+
+	; mask
+	im -1
+	add
+	loadsp 0
+	storesp 16
+
+	; no branch address
+	loadsp 4
+	
+	and
+
+	; fetch boolean & neg mask
+	loadsp 12
+	not
+	
+	; calc address & mask for branch
+	loadsp 8
+	loadsp 16
+	add
+	; find address of branch instruction
+	im -1
+	add
+	
+	and
+
+	or	
+	
+	storesp 4
+	storesp 4
+	storesp 4
+	poppc	
+
+# opcode 57
+# offset 0x0000 0320
+	.balign 32,0
+	.globl _poppcrel
+_poppcrel:
+	add
+	; address of poppcrel
+	im -1
+	add
+	poppc
+		
+# opcode 58
+# offset 0x0000 0340
+	.balign 32,0
+	.globl _config
+_config:
+	im 1 
+	nop
+	im _hardware
+	store
+	storesp 4
+	poppc
+
+# opcode 59
+# offset 0x0000 0360
+	.balign 32,0
+_pushpc:
+	loadsp 4
+	im 1
+	add 
+	storesp 8
+	poppc
+	
+# opcode 60
+# offset 0x0000 0380
+	.balign 32,0
+_syscall_emulate:
+	.byte 0
+	
+# opcode 61
+# offset 0x0000 03a0
+	.balign 32,0
+_pushspadd:
+	pushsp
+	im 4
+	add
+	loadsp 8
+	addsp 0
+	addsp 0
+	add
+	storesp 8
+	
+	poppc
+
+# opcode 62
+# offset 0x0000 03c0
+	.balign 32,0
+_halfmult:
+	breakpoint
+	
+# opcode 63
+# offset 0x0000 03e0
+	.balign 32,0
+_callpcrel:
+	loadsp 4
+	loadsp 4
+	add
+	im -1
+	add
+	loadsp 4
+	
+	storesp 12	; return address
+	storesp 4 
+	pushsp		; this will flush the internal stack.
+	popsp
+	poppc
+
+	.text
+
+	
+
+
+_ashiftleftBegin:
+	.rept 0x1f
+	addsp 0
+	.endr
+_ashiftleftEnd:
+	storesp 12
+	storesp 4
+	poppc
+	
+_storebtail:
+	loadsp 12
+	im 0xff
+	and
+	loadsp 12
+	im 3
+	and
+
+	fast_neg
+	im 3
+	add
+	; x8
+	addsp 0
+	addsp 0
+	addsp 0
+
+	ashiftleft
+	 
+	or
+	
+	loadsp 8
+	im  ~0x3
+	and
+
+	store
+	
+	storesp 4
+	storesp 4
+	poppc
+	
+
+
+
+; NB! this is not an EMULATE instruction. It is a varargs fn.
+	.globl _syscall	
+_syscall:
+	syscall
+	poppc
+	
+_slowmultImpl:
+	
+	loadsp 8 ; A
+	loadsp 8 ; B
+	im 0 ; C
+
+.LmoreMult:
+	mult1bit
+	
+	; cutoff
+	loadsp 8
+	.byte (.LmoreMult-.Lbranch)&0x7f+0x80
+.Lbranch:
+	neqbranch
+
+	storesp 4
+	storesp 4
+	storesp 12
+	storesp 4
+	poppc
+
+___mod:
+	cimpl __modsi3
+___div:
+	cimpl __divsi3
+
+	.section ".rodata"
+	.balign 4,0
+_mask:
+	.long 0x00ffffff
+	.long 0xff00ffff
+	.long 0xffff00ff
+	.long 0xffffff00
+
+	.section ".text","ax"
+	.global _boot
+	.balign 4,0
+_boot:
+	im 0
+	poppc
+
+	.global _break;
+_break:
+	im	_break
+	poppc ; infinite loop
+
+_premain:
+	im _break
+	nop
+	fixedim main
+	poppc
+
+
+	.data
+	.balign 4,0
+	
+	.globl _hardware
+_hardware:
+	.long 0
+	.globl _cpu_config
+_cpu_config:
+	.long 0
+
+
+	.section ".bss"
+    .balign 4,0
+	.globl _memreg
+_memreg:
+		.long 0
+		.long 0
+		.long 0
+		.long 0
+
Index: firmware_legacy/sdrive_parts/bootloader
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: firmware_legacy/sdrive_parts/bootloader
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: firmware_legacy/defunct/chksum.c
===================================================================
--- firmware_legacy/defunct/chksum.c	(nonexistent)
+++ firmware_legacy/defunct/chksum.c	(revision 799)
@@ -0,0 +1,40 @@
+unsigned char abuffer[] = {
+0x00,0x03,0x00,0x07,0x14,0x07,0x4c,0x14,0x07,0x74,0x0d,0x00,0x00,0xa9,0x46,0x8d
+,0xc6,0x02,0xd0,0xfe,0xa0,0x00,0xa9,0x6b,0x91,0x58,0x20,0xd9,0x07,0xb0,0xee,0x20
+,0xc4,0x07,0xad,0x7a,0x08,0x0d,0x76,0x08,0xd0,0xe3,0xa5,0x80,0x8d,0xe0,0x02,0xa5
+,0x81,0x8d,0xe1,0x02,0xa9,0x00,0x8d,0xe2,0x02,0x8d,0xe3,0x02,0x20,0xeb,0x07,0xb0
+,0xcc,0xa0,0x00,0x91,0x80,0xa5,0x80,0xc5,0x82,0xd0,0x06,0xa5,0x81,0xc5,0x83,0xf0
+,0x08,0xe6,0x80,0xd0,0x02,0xe6,0x81,0xd0,0xe3,0xad,0x76,0x08,0xd0,0xaf,0xad,0xe2
+,0x02,0x8d,0x70,0x07,0x0d,0xe3,0x02,0xf0,0x0e,0xad,0xe3,0x02,0x8d,0x71,0x07,0x20
+,0xff,0xff,0xad,0x7a,0x08,0xd0,0x13,0xa9,0x00,0x8d,0xe2,0x02,0x8d,0xe3,0x02,0x20
+};
+
+
+unsigned char buffer[] = {
+0x98,0xff,0xe0,0x00
+};
+
+typedef unsigned short u16;
+typedef unsigned char u08;
+
+unsigned char get_checksum(unsigned char* buffer, u16 len)
+{
+        u16 i;
+        u08 sumo,sum;
+        sum=sumo=0;
+        for(i=0;i<len;i++)
+        {
+                sum+=buffer[i];
+                if(sum<sumo) sum++;
+                sumo = sum;
+        }
+        return sum;
+}
+
+int main(void)
+{
+	int res = get_checksum(buffer,sizeof(buffer));
+	printf("%x %d\n",res,sizeof(buffer));
+	return 0;
+}
+
Index: firmware_legacy/defunct/led.h
===================================================================
--- firmware_legacy/defunct/led.h	(nonexistent)
+++ firmware_legacy/defunct/led.h	(revision 799)
@@ -0,0 +1,10 @@
+#ifndef LEDS_H
+#define LEDS_H
+
+void set_green_led(int i);
+void set_red_led(int i);
+void set_drive_number(int i);
+void init_display();
+
+#endif
+
Index: firmware_legacy/defunct/types.h
===================================================================
--- firmware_legacy/defunct/types.h	(nonexistent)
+++ firmware_legacy/defunct/types.h	(revision 799)
@@ -0,0 +1,13 @@
+#ifndef types_h
+#define types_h
+
+typedef unsigned char u08;
+typedef unsigned char uint8_t;
+typedef unsigned short u16;
+typedef unsigned int u32;
+
+#define EEMEM
+
+#endif
+
+
Index: firmware_legacy/pause.h
===================================================================
--- firmware_legacy/pause.h	(nonexistent)
+++ firmware_legacy/pause.h	(revision 799)
@@ -0,0 +1,6 @@
+#ifndef PAUSE_H
+#define PAUSE_H
+
+void wait_us(int unsigned num);
+
+#endif
Index: firmware_legacy/setup
===================================================================
--- firmware_legacy/setup	(nonexistent)
+++ firmware_legacy/setup	(revision 799)
@@ -0,0 +1 @@
+export PATH=${PATH}:/home/markw/fpga/zpugcc/toolchain/install/bin/
Index: firmware_legacy/defunct/mt6502dis
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: firmware_legacy/defunct/mt6502dis
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: firmware_legacy/hexdump.c
===================================================================
--- firmware_legacy/hexdump.c	(nonexistent)
+++ firmware_legacy/hexdump.c	(revision 799)
@@ -0,0 +1,11 @@
+#include "hexdump.h"
+#include "printf.h"
+
+void hexdump_pure(void const * str, int length)
+{
+	for (;length>0;--length)
+	{
+		unsigned char val= *(unsigned char *)str++;
+		printf("%02x",val);
+	}
+}
Index: firmware_legacy/sdrive_parts/bootdump
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: firmware_legacy/sdrive_parts/bootdump
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: firmware_legacy/test_joy.c
===================================================================
--- firmware_legacy/test_joy.c	(nonexistent)
+++ firmware_legacy/test_joy.c	(revision 799)
@@ -0,0 +1,83 @@
+#include "joystick.h"
+
+#include <stdio.h>
+#include <poll.h>
+#include <termios.h>
+#include <unistd.h>
+
+extern char native_porta;
+extern char native_trig;
+
+void read_keys();
+
+struct termios oldt, newt;
+void term_init()
+{
+	tcgetattr(STDIN_FILENO, &oldt);
+	newt = oldt;
+	newt.c_lflag &= ~( ICANON | ECHO );
+	tcsetattr( STDIN_FILENO, TCSANOW, &newt);
+}
+
+void term_close()
+{
+	tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
+}
+
+int main(void)
+{
+	term_init();
+
+	fprintf(stderr,"Polling\n");
+	int i;
+	for (i=0;i!=200;++i)
+	{
+		struct joystick_status joy;
+		read_keys();
+		joystick_poll(&joy);
+
+		fprintf(stderr, "x:%d y:%d fire:%d\n", joy.x_, joy.y_, joy.fire_);
+
+		usleep(100000);
+	}
+
+
+//void joystick_poll(struct joystick_status * status);
+//void joystick_wait(struct joystick_status * status, enum JoyWait waitFor);
+
+	term_close();
+
+	return 0;
+}
+
+void read_keys()
+{
+	struct pollfd fds[1];
+	fds[0].fd = STDIN_FILENO;
+	fds[0].events = POLLIN;
+	native_porta = 0xff;
+	native_trig = 0xff;
+	while (poll(&fds[0], 1, 0))
+	{
+		char buffer[0];
+		read(0,&buffer[0],1);
+
+		if (buffer[0] == 0x41) fprintf(stderr, "UP\n");
+		if (buffer[0] == 0x42) fprintf(stderr, "DOWN\n");
+		if (buffer[0] == 0x44) fprintf(stderr, "LEFT\n");
+		if (buffer[0] == 0x43) fprintf(stderr, "RIGHT\n");
+		if (buffer[0] == 0x20) fprintf(stderr, "FIRE\n");
+
+		// RLDU
+		if (buffer[0] == 0x41) native_porta=0xff&~(1<<0);
+		if (buffer[0] == 0x42) native_porta=0xff&~(1<<1);
+		if (buffer[0] == 0x44) native_porta=0xff&~(1<<2);
+		if (buffer[0] == 0x43) native_porta=0xff&~(1<<3);
+		if (buffer[0] == 0x20) native_trig=0xff&~1;
+
+		fds[0].fd = STDIN_FILENO;
+		fds[0].events = POLLIN;
+	}
+}
+
+
