Index: firmware/Makefile
===================================================================
--- firmware/Makefile	(nonexistent)
+++ firmware/Makefile	(revision 46)
@@ -0,0 +1,78 @@
+BASE	= zpu-elf
+CC      = $(BASE)-gcc
+LD      = $(BASE)-gcc
+AS      = $(BASE)-as
+CP      = $(BASE)-objcopy
+DUMP    = $(BASE)-objdump
+
+# we use mincrt0.s from here
+STARTUP_DIR = .
+
+# we fetch ROM prologue / epilogue from here
+RTL_DIR = $(ZPUFLEXDIR)/RTL/
+
+
+BUILD_DIR=zpu_obj
+
+#MINSTARTUP_SRC = mincrt0.s
+MINSTARTUP_SRC = mycrt0.s
+MINSTARTUP_OBJ = $(patsubst $(STARTUP_DIR)/%.s,$(BUILD_DIR)/%.o,$(MINSTARTUP_SRC))
+
+MAIN_PRJ = JustStartAtari
+MAIN_SRC = main.c regs.c atari_drive_emulator.c pokey/uart.c hexdump.c printf/printf.c fat/pff_file.c fat/pff.c common/utils.c sd_direct/diskio_mmc.c sd_direct/spi.c sd_direct/mmc.c
+#gcc -g -O0 -DLITTLE_ENDIAN test_drive.c atari_drive_emulator.c native/uart.c hexdump.c printf/printf.c fat/pff_file.c fat/pff.c common/utils.c native/diskio_image.c -I. -Iprintf -Ifat -Icommon
+#MAIN_SRC = stuff.c
+MAIN_OBJ = $(COMMON_OBJ) $(patsubst %.c,$(BUILD_DIR)/%.o,$(MAIN_SRC))
+
+LINKMAP  = ./standalone_simple.ld
+
+
+# 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 -c -g -Os $(ZPUOPTS) -DDISABLE_UART_RX
+
+LFLAGS  = -nostartfiles -Wl,--relax -g -Os
+#LFLAGS  = -nostartfiles -Os
+
+
+# Our target.
+all: $(BUILD_DIR) $(MAIN_PRJ).bin $(MAIN_PRJ).rpt
+
+clean:
+	rm -f $(BUILD_DIR)/*.o *.hex *.elf *.map *.lst *.srec $(MAIN_PRJ).rom *~ */*.o *.bin
+
+
+# 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.
+
+$(MAIN_PRJ).elf: $(MINSTARTUP_OBJ) $(MAIN_OBJ)
+	$(LD) $(LFLAGS) -T $(LINKMAP) -o $@ $+ $(LIBS)
+
+$(BUILD_DIR)/%.o: %.c Makefile
+	mkdir -p `dirname $@`
+	$(CC) $(CFLAGS)  -o $@ -c $<
+
+$(BUILD_DIR)/%.o: %.s
+	$(AS) -o $@ $<
+
+$(BUILD_DIR)/%.o: $(STARTUP_DIR)/%.s
+	$(AS) -o $@ $<
+
+$(BUILD_DIR):
+	mkdir $(BUILD_DIR)
+
Index: firmware/hexdump.c
===================================================================
--- firmware/hexdump.c	(nonexistent)
+++ firmware/hexdump.c	(revision 46)
@@ -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/joystick.h
===================================================================
--- firmware/joystick.h	(nonexistent)
+++ firmware/joystick.h	(revision 46)
@@ -0,0 +1,14 @@
+#pragma once
+
+struct joystick_status
+{
+	char x_;
+	char y_;
+	char fire_;
+};
+
+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);
+
Index: firmware/mif_file_stuff/rom_prologue.vhd
===================================================================
--- firmware/mif_file_stuff/rom_prologue.vhd	(nonexistent)
+++ firmware/mif_file_stuff/rom_prologue.vhd	(revision 46)
@@ -0,0 +1,10 @@
+DEPTH = 4096; % 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/actions.c
===================================================================
--- firmware/actions.c	(nonexistent)
+++ firmware/actions.c	(revision 46)
@@ -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/atari_drive_emulator.c
===================================================================
--- firmware/atari_drive_emulator.c	(nonexistent)
+++ firmware/atari_drive_emulator.c	(revision 46)
@@ -0,0 +1,639 @@
+#include "atari_drive_emulator.h"
+
+#include "uart.h"
+#include "pause.h"
+#include "simplefile.h"
+
+#include "printf.h"
+#include "integer.h"
+
+#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 0x6
+#define XEX_SECTOR_SIZE 128
+
+#define MAX_DRIVES 4
+
+struct SimpleFile * drives[MAX_DRIVES];
+
+struct ATRHeader
+{
+	u16 wMagic;
+	u16 wPars;
+	u16 wSecSize;
+	u08 btParsHigh;
+	u32 dwCRC;
+} __attribute__((packed));
+struct ATRHeader atr_header;
+int speed;
+
+int badcommandcount;
+int commandcount;
+int opendrive;
+
+unsigned char atari_sector_buffer[256];
+
+unsigned char get_checksum(unsigned char* buffer, u16 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;
+}
+
+int offset;
+int xex_loader;
+int xex_size;
+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));
+void getCommand(struct command * cmd)
+{
+	int expchk;
+
+	//printf("Waiting for command\n");
+	//USART_Data_Ready();
+	while (0 == USART_Command_Line());
+	//printf("Init:");
+	//printf("%d",*zpu_sio);
+	USART_Init(speed+6);
+	//printf("%d",speed);
+	//printf("\n");
+	while (1 == USART_Command_Line())
+	{
+		actions();
+	}
+	cmd->deviceId = USART_Receive_Byte();
+	cmd->command = USART_Receive_Byte();
+	cmd->aux1 = USART_Receive_Byte();
+	cmd->aux2 = USART_Receive_Byte();
+	cmd->chksum = USART_Receive_Byte();
+	while (0 == USART_Command_Line())
+	{
+		actions();
+	}
+	printf("cmd:");
+	//printf("Gone high\n");
+	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);
+
+	//printf("Device id:");
+	printf("%d",cmd->deviceId);
+	//printf("\n");
+	//printf("command:");
+	printf("%d",cmd->command);
+	//printf("\n");
+	//printf("aux1:");
+	printf("%d",cmd->aux1);
+	//printf("\n");
+	//printf("aux2:");
+	printf("%d",cmd->aux2);
+	//printf("\n");
+	//printf("chksum:");
+	printf("%d",cmd->chksum);
+	printf("%d",expchk);
+
+	if (expchk!=cmd->chksum || USART_Framing_Error())
+	{
+		printf("ERR ");
+		//wait_us(1000000);
+		if (speed == speedslow)
+		{
+			speed = speedfast;
+			printf("SPDF");
+			printf("%d",speed);
+		}
+		else
+		{
+			speed = speedslow;
+			printf("SPDS");
+			printf("%d",speed);
+		}
+	}
+	printf("\n");
+
+	DELAY_T2_MIN;
+}
+
+int compare_ext(char const * filename, char const * ext)
+{
+	int dot = 0;
+
+	while (1)
+	{
+		if (filename[dot] == '\0')
+			break;
+		if (filename[dot] != '.')
+		{
+			++dot;
+			continue;
+		}
+		if (filename[dot+1] == ext[0])
+			if (filename[dot+2] == ext[1])
+				if (filename[dot+3] == ext[2])
+				{
+					return 1;
+					break;
+				}
+		break;
+	}
+
+	return 0;
+}
+
+// Called whenever file changed
+void set_drive_status(int driveNumber, struct SimpleFile * file)
+{
+	int read = 0;
+	int xfd = 0;
+
+	drives[driveNumber] = 0;
+
+	if (!file) return;
+
+	// 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") || 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;
+	}
+	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;
+	}
+	else if (atr_header.wMagic == 0x296) // ATR
+	{
+		printf("ATR ");
+		offset = 16;
+	}
+	else
+	{
+		printf("Unknown file type");
+		return;
+	}
+
+	if (atr_header.wSecSize == 0x80)
+	{
+		if (atr_header.wPars>(720*128/16))
+			printf("MD ");
+		else
+			printf("SD ");
+	}
+	else if (atr_header.wSecSize == 0x100)
+	{
+		printf("DD ");
+	}
+	else if (atr_header.wSecSize < 0x100)
+	{
+		printf("XD ");
+	}
+	else
+	{
+		printf("BAD sector size");
+		return;
+	}	
+	printf("%d",atr_header.wPars);
+	printf("0\n");
+
+	drives[driveNumber] = file;
+}
+
+void init_drive_emulator()
+{
+	int i;
+
+	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();
+		actions();
+	}
+}
+
+/////////////////////////
+
+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("%d",drive);
+		if (drive!=opendrive)
+		{
+			if (drive<MAX_DRIVES)
+			{
+				opendrive = 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");
+			return;
+		}
+
+		file = drives[opendrive];
+
+		switch (command.command)
+		{
+		case 0x3f:
+			{
+			printf("Speed:");
+			int sector = ((int)command.aux1) + (((int)command.aux2&0x7f)<<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;
+			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;
+		case 0x50: // write
+		case 0x57: // write with verify
+		default:
+			// TODO
+			//USART_Transmit_Mode();
+			//send_NACK();
+			//USART_Wait_Transmit_Complete();
+			//USART_Receive_Mode();
+			break;
+		case 0x52: // read
+			{
+			int sector = ((int)command.aux1) + (((int)command.aux2&0x7f)<<8);
+			int sectorSize = 0;
+			int read = 0;
+			int location =0;
+
+			USART_Transmit_Mode();
+			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");
+				file_seek(file,location);
+				file_read(file,&atari_sector_buffer[0], sectorSize, &read);
+			}
+
+			//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, 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;
+}
+
+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;
+	send_CMPL();
+
+	// Hias: changed to 100us so that Qmeg3 works again with the
+	// new bit-banging transmission code
+	DELAY_T3_PERIPH;
+
+	check_sum = 0;
+	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);
+	//hexdump_pure(atari_sector_buffer,len);
+	printf(":chk:");
+	printf("%d",check_sum);
+	printf(")");
+}
Index: firmware/mycrt0.s
===================================================================
--- firmware/mycrt0.s	(nonexistent)
+++ firmware/mycrt0.s	(revision 46)
@@ -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/native/uart.c
===================================================================
--- firmware/native/uart.c	(nonexistent)
+++ firmware/native/uart.c	(revision 46)
@@ -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/fat/diskio.h
===================================================================
--- firmware/fat/diskio.h	(nonexistent)
+++ firmware/fat/diskio.h	(revision 46)
@@ -0,0 +1,41 @@
+/*-----------------------------------------------------------------------
+/  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*, DWORD);
+
+#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/fat/pff.h
===================================================================
--- firmware/fat/pff.h	(nonexistent)
+++ firmware/fat/pff.h	(revision 46)
@@ -0,0 +1,192 @@
+/*---------------------------------------------------------------------------/
+/  Petit FatFs - FAT file system module include file  R0.02a   (C)ChaN, 2010
+/----------------------------------------------------------------------------/
+/ 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) 2010, 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.
+/
+/----------------------------------------------------------------------------*/
+
+#include "integer.h"
+
+/*---------------------------------------------------------------------------/
+/ Petit FatFs Configuration Options
+/
+/ CAUTION! Do not forget to make clean the project after any changes to
+/ the configuration options.
+/
+/----------------------------------------------------------------------------*/
+#ifndef _FATFS
+#define _FATFS
+
+#define	_USE_READ	1	/* 1:Enable pf_read() */
+
+#define	_USE_DIR	1	/* 1:Enable pf_opendir() and pf_readdir() */
+
+#define	_USE_LSEEK	1	/* 1:Enable pf_lseek() */
+
+#define	_USE_WRITE	1	/* 1:Enable pf_write() */
+
+#define _FS_FAT12	1	/* 1:Enable FAT12 support */
+#define _FS_FAT32	1	/* 1:Enable FAT32 support */
+
+
+#define	_CODE_PAGE	1
+/* Defines which code page is used for path name. Supported code pages are:
+/  932, 936, 949, 950, 437, 720, 737, 775, 850, 852, 855, 857, 858, 862, 866,
+/  874, 1250, 1251, 1252, 1253, 1254, 1255, 1257, 1258 and 1 (ASCII only).
+/  SBCS code pages except for 1 requiers a case conversion table. This
+/  might occupy 128 bytes on the RAM on some platforms, e.g. avr-gcc. */
+
+
+#define _WORD_ACCESS	0
+/* The _WORD_ACCESS option defines which access method is used to the word
+/  data in the FAT structure.
+/
+/   0: Byte-by-byte access. Always compatible with all platforms.
+/   1: Word access. Do not choose this unless following condition is met.
+/
+/  When the byte order on the memory is big-endian or address miss-aligned
+/  word access results incorrect behavior, the _WORD_ACCESS must be set to 0.
+/  If it is not the case, the value can also be set to 1 to improve the
+/  performance and code efficiency. */
+
+
+/* End of configuration options. Do not change followings without care.     */
+/*--------------------------------------------------------------------------*/
+
+
+
+#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 */
+} 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_NO_PATH,			/* 4 */
+	FR_NOT_OPENED,		/* 5 */
+	FR_NOT_ENABLED,		/* 6 */
+	FR_NO_FILESYSTEM	/* 7 */
+} FRESULT;
+
+
+
+/*--------------------------------------------------------------*/
+/* Petit FatFs module application interface                     */
+
+FRESULT pf_mount (FATFS*);						/* Mount/Unmount a logical drive */
+FRESULT pf_open (const char*);					/* Open a file */
+FRESULT pf_read (void*, WORD, WORD*);			/* Read data from the open file */
+FRESULT pf_write (const void*, WORD, WORD*);	/* Write data to the open file */
+FRESULT pf_lseek (DWORD);						/* Move file pointer of the open file */
+FRESULT pf_opendir (DIR*, const char*);			/* Open a directory */
+FRESULT pf_readdir (DIR*, FILINFO*);			/* 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
+
+
+#endif /* _FATFS */
Index: firmware/fat/pff_file.h
===================================================================
--- firmware/fat/pff_file.h	(nonexistent)
+++ firmware/fat/pff_file.h	(revision 46)
@@ -0,0 +1,25 @@
+#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 size;
+};
+
+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...
+};
+
Index: firmware/fileselector.h
===================================================================
--- firmware/fileselector.h	(nonexistent)
+++ firmware/fileselector.h	(revision 46)
@@ -0,0 +1,4 @@
+#pragma once
+
+void file_select(void (*filter) (char const *), char const * path, struct SimpleFile * file);
+
Index: firmware/freeze.h
===================================================================
--- firmware/freeze.h	(nonexistent)
+++ firmware/freeze.h	(revision 46)
@@ -0,0 +1,13 @@
+#pragma once
+
+// Allow us to take over the system
+// NB: CPU should be frozen before calling these!
+
+// Set hardware registers to 'neutral'
+// Back up system ram
+void freeze();
+
+// Restore system ram
+// Restore hardware registers
+void restore();
+
Index: firmware/joystick.c
===================================================================
--- firmware/joystick.c	(nonexistent)
+++ firmware/joystick.c	(revision 46)
@@ -0,0 +1,56 @@
+#include "joystick.h"
+
+#include "regs.h"
+
+void joystick_poll(struct joystick_status * status)
+{
+	status->x_ = 0;
+	status->y_ = 0;
+	status->fire_ = 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/mif_file_stuff/rom_epilogue.vhd
===================================================================
--- firmware/mif_file_stuff/rom_epilogue.vhd	(nonexistent)
+++ firmware/mif_file_stuff/rom_epilogue.vhd	(revision 46)
@@ -0,0 +1 @@
+END; 
Index: firmware/mif_file_stuff/zpuromgen.c
===================================================================
--- firmware/mif_file_stuff/zpuromgen.c	(nonexistent)
+++ firmware/mif_file_stuff/zpuromgen.c	(revision 46)
@@ -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/native/regs.c
===================================================================
--- firmware/native/regs.c	(nonexistent)
+++ firmware/native/regs.c	(revision 46)
@@ -0,0 +1,8 @@
+#include "regs.h"
+
+char native_porta;
+char native_trig;
+
+unsigned char volatile * atari_porta = &native_porta;
+unsigned char volatile * atari_trig0 = &native_trig;
+
Index: firmware/atari_drive_emulator.h
===================================================================
--- firmware/atari_drive_emulator.h	(nonexistent)
+++ firmware/atari_drive_emulator.h	(revision 46)
@@ -0,0 +1,24 @@
+#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);
+
Index: firmware/build
===================================================================
--- firmware/build	(nonexistent)
+++ firmware/build	(revision 46)
@@ -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/build
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: firmware/build_native_drive
===================================================================
--- firmware/build_native_drive	(nonexistent)
+++ firmware/build_native_drive	(revision 46)
@@ -0,0 +1 @@
+gcc -g -O0 -DLITTLE_ENDIAN test_drive.c atari_drive_emulator.c native/uart.c hexdump.c printf/printf.c fat/pff_file.c fat/pff.c common/utils.c native/diskio_image.c -I. -Iprintf -Ifat -Icommon

Property changes on: firmware/build_native_drive
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: firmware/build_native_file_test
===================================================================
--- firmware/build_native_file_test	(nonexistent)
+++ firmware/build_native_file_test	(revision 46)
@@ -0,0 +1 @@
+gcc -g -O0 test_file.c fat/pff_file.c fat/pff.c common/utils.c native/diskio_image.c -I. -Ifat -Icommon

Property changes on: firmware/build_native_file_test
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: firmware/build_native_joystick
===================================================================
--- firmware/build_native_joystick	(nonexistent)
+++ firmware/build_native_joystick	(revision 46)
@@ -0,0 +1 @@
+gcc -g -O0 test_joy.c joystick.c native/regs.c -I.

Property changes on: firmware/build_native_joystick
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: firmware/common/integer.h
===================================================================
--- firmware/common/integer.h	(nonexistent)
+++ firmware/common/integer.h	(revision 46)
@@ -0,0 +1,30 @@
+#ifndef _INTEGER
+#define _INTEGER
+
+/* These types must be 16-bit, 32-bit or larger integer */
+typedef int				INT;
+typedef unsigned int	UINT;
+
+/* These types must be 8-bit integer */
+typedef char			CHAR;
+typedef unsigned char	UCHAR;
+typedef unsigned char	BYTE;
+typedef unsigned char u08;
+typedef unsigned char uint8_t;
+
+/* These types must be 16-bit integer */
+typedef short			SHORT;
+typedef unsigned short	USHORT;
+typedef unsigned short	WORD;
+typedef unsigned short	WCHAR;
+typedef unsigned short u16;
+
+/* These types must be 32-bit integer */
+typedef long			LONG;
+typedef unsigned long	ULONG;
+typedef unsigned long	DWORD;
+typedef unsigned int u32;
+
+#define EEMEM
+
+#endif
Index: firmware/common/utils.c
===================================================================
--- firmware/common/utils.c	(nonexistent)
+++ firmware/common/utils.c	(revision 46)
@@ -0,0 +1,27 @@
+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;
+}
+
+void strcpy(char * dest, char const * src)
+{
+	while (*dest++=*src++);
+}
+
+int strlen(char const * a)
+{
+	int count;
+	for (count=0; *a; ++a,++count);
+	return count;
+}
+
Index: firmware/common/utils.h
===================================================================
--- firmware/common/utils.h	(nonexistent)
+++ firmware/common/utils.h	(revision 46)
@@ -0,0 +1,4 @@
+int strcmp(char const * a, char const * b);
+void strcpy(char * dest, char const * src);
+int strlen(char const * a);
+
Index: firmware/common/x
===================================================================
--- firmware/common/x	(nonexistent)
+++ firmware/common/x	(revision 46)
@@ -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/crt0.S
===================================================================
--- firmware/crt0.S	(nonexistent)
+++ firmware/crt0.S	(revision 46)
@@ -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/crt0.S
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: firmware/debug.c
===================================================================
--- firmware/debug.c	(nonexistent)
+++ firmware/debug.c	(revision 46)
@@ -0,0 +1,177 @@
+#include "debug.h"
+#include "pause.h"
+
+int xpos;
+int ypos;
+int onoff; // perhaps we can plot to another address buffer, which we can scroll through in the monitor?
+
+int debugoffsetval;
+
+void topofscreen()
+{
+	xpos = 0;
+	ypos = 0;
+}
+
+void setxpos(int val)
+{
+	xpos = val;
+}
+
+void setypos(int val)
+{
+	ypos = val;
+}
+
+void initdebug(int onoff_in)
+{
+	xpos = 0;
+	ypos = 0;
+	onoff = onoff_in;
+}
+
+void nextline()
+{
+	int i;
+	xpos=0;
+	ypos+=1;
+	if (ypos==24)
+		ypos = 0;
+	for (i=0;i!=40;++i)
+		plot(0,i,ypos);
+
+	//Delay100usX(5000);
+}
+
+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
+	{
+		val = 0;
+	}
+	if (inv)
+	{
+		val+=128;
+	}
+	return val;
+}
+unsigned char hextoatarichar(int val)
+{
+	if (val>=0 && val<=9)
+	{
+		val+=+16;	
+	}
+	else if (val>=10 && val<=15)
+	{
+		val+=-10+33;
+	}
+	return val;
+}
+void plot(unsigned char val, int x, int y)
+{
+	if (onoff == 0) return;
+
+	unsigned char volatile * baseaddr = (unsigned char volatile *)(40000 + atari_regbase);
+	*(baseaddr + y*40+x) = val+debugoffsetval;
+}
+void debugoffset(int x)
+{
+	debugoffsetval = x;
+}
+void debug(char const * str)
+{
+	while (1)
+	{
+		int val = *str++;
+		if (val==0) break;
+		if (val=='\n') {nextline();continue;};
+
+		plot(toatarichar(val),xpos,ypos);
+		++xpos;
+		if (xpos==40)
+		{
+			nextline();
+		}
+	}
+	debugoffsetval = 0;
+}
+
+void plotnext(unsigned char val)
+{
+	plot(val,xpos,ypos);
+
+	++xpos;
+	if (xpos==40) nextline();
+}
+
+void plotnextnumber(unsigned short val)
+{
+	plotnext(hextoatarichar((val&0xf000)>>12));
+	plotnext(hextoatarichar((val&0x0f00)>>8));
+	plotnext(hextoatarichar((val&0x00f0)>>4));
+	plotnext(hextoatarichar((val&0x000f)>>0));
+	debugoffsetval = 0;
+}
+
+void hexdump(unsigned void const * str, int length)
+{
+	nextline();
+
+	for (;length>0;--length)
+	{
+		unsigned char val= *str++;
+		
+		// LH 10 cols = char
+		// RH 20 cols = hex
+
+		plot(toatarichar(val),xpos,ypos);
+		plot(hextoatarichar((val&0xf0) >> 4),xpos*2+20,ypos);
+		plot(hextoatarichar(val&0xf),xpos*2+21,ypos);
+
+		++xpos;
+		if (xpos==10)
+		{
+			nextline();
+		}
+	}
+	nextline();
+}
+
+void hexdump_pure(unsigned void const * str, int length)
+{
+	xpos = xpos&0xfffe;
+	for (;length>0;--length)
+	{
+		unsigned char val= *str++;
+		
+		plot(hextoatarichar((val&0xf0) >> 4),xpos++,ypos);
+		plot(hextoatarichar(val&0xf),xpos++,ypos);
+
+		if (xpos==40)
+		{
+			nextline();
+		}
+	}
+}
+
Index: firmware/debug.h
===================================================================
--- firmware/debug.h	(nonexistent)
+++ firmware/debug.h	(revision 46)
@@ -0,0 +1,20 @@
+#ifndef debug_h
+#define debug_h
+
+void topofscreen();
+void setxpos(int val);
+void setypos(int val);
+unsigned char toatarichar(int val);
+unsigned char hextoatarichar(int val);
+void plot(unsigned char val, int x, int y);
+void plotnext(unsigned char val);
+void plotnextnumber(unsigned short val);
+void debugoffset(int x);
+void debug(char const * str);
+
+void hexdump(char const * str, int length);
+void hexdump_pure(char const * str, int length);
+
+void initdebug(int onoff_in);
+
+#endif //debug_h
Index: firmware/defunct/chksum.c
===================================================================
--- firmware/defunct/chksum.c	(nonexistent)
+++ firmware/defunct/chksum.c	(revision 46)
@@ -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/defunct/fat.c
===================================================================
--- firmware/defunct/fat.c	(nonexistent)
+++ firmware/defunct/fat.c	(revision 46)
@@ -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/defunct/fat.h
===================================================================
--- firmware/defunct/fat.h	(nonexistent)
+++ firmware/defunct/fat.h	(revision 46)
@@ -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/defunct/led.c
===================================================================
--- firmware/defunct/led.c	(nonexistent)
+++ firmware/defunct/led.c	(revision 46)
@@ -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/defunct/led.h
===================================================================
--- firmware/defunct/led.h	(nonexistent)
+++ firmware/defunct/led.h	(revision 46)
@@ -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/defunct/mt6502dis
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: firmware/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/defunct/stuff.c
===================================================================
--- firmware/defunct/stuff.c	(nonexistent)
+++ firmware/defunct/stuff.c	(revision 46)
@@ -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/defunct/test.c
===================================================================
--- firmware/defunct/test.c	(nonexistent)
+++ firmware/defunct/test.c	(revision 46)
@@ -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/defunct/types.h
===================================================================
--- firmware/defunct/types.h	(nonexistent)
+++ firmware/defunct/types.h	(revision 46)
@@ -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/diskio_sectorrequest.c
===================================================================
--- firmware/diskio_sectorrequest.c	(nonexistent)
+++ firmware/diskio_sectorrequest.c	(revision 46)
@@ -0,0 +1,141 @@
+#include "diskio.h"
+
+#include "regs.h"
+
+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!
+*/
+
+	*zpu_out4 = (sector<<8)|0xa5;
+	while (*zpu_in4 != *zpu_out4)
+	{
+		// Wait until ready
+	}
+
+	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 *)0x8000;  // 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 sc)
+{
+	DRESULT res;
+
+
+	if (!buff) {
+		if (sc) {
+
+			// Initiate write process
+
+		} else {
+
+			// Finalize write process
+
+		}
+	} else {
+
+		// Send data to the disk
+
+	}
+
+	return res;
+}
+
Index: firmware/fat/pff.c
===================================================================
--- firmware/fat/pff.c	(nonexistent)
+++ firmware/fat/pff.c	(revision 46)
@@ -0,0 +1,1114 @@
+/*----------------------------------------------------------------------------/
+/  Petit FatFs - FAT file system module  R0.02a                (C)ChaN, 2010
+/-----------------------------------------------------------------------------/
+/ 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) 2010, 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.
+/
+/-----------------------------------------------------------------------------/
+/ Jun 15,'09  R0.01a  First release. (Branched from FatFs R0.07b.)
+/
+/ 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.
+/----------------------------------------------------------------------------*/
+
+#include "pff.h"		/* Petit FatFs configurations and declarations */
+#include "diskio.h"		/* Declarations of low level disk I/O functions */
+
+
+
+/*--------------------------------------------------------------------------
+
+   Module Private Definitions
+
+---------------------------------------------------------------------------*/
+
+
+#if _FS_FAT32
+#define LD_CLUST(dir)	(((DWORD)LD_WORD(dir+DIR_FstClusHI)<<16) | LD_WORD(dir+DIR_FstClusLO))
+#else
+#define LD_CLUST(dir)	LD_WORD(dir+DIR_FstClusLO)
+#endif
+
+
+/*--------------------------------------------------------*/
+/* 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 _DF1S	0
+#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 _DF1S	0
+#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 _DF1S	0
+#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 _DF1S	0
+#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 _DF1S	0
+#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 _DF1S	0
+#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 _DF1S	0
+#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 _DF1S	0
+#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 _DF1S	0
+#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 _DF1S	0
+#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 _DF1S	0
+#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 _DF1S	0
+#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 _DF1S	0
+#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 _DF1S	0
+#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 _DF1S	0
+#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 _DF1S	0
+#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 _DF1S	0
+#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 _DF1S	0
+#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 _DF1S	0
+#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 _DF1S	0
+#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 _DF1S	0
+#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}
+
+#elif _CODE_PAGE == 1	/* ASCII (for only non-LFN cfg) */
+#define _DF1S	0
+
+#else
+#error Unknown code page
+
+#endif
+
+
+
+/* Character code support macros */
+
+#define IsUpper(c)	(((c)>='A')&&((c)<='Z'))
+#define IsLower(c)	(((c)>='a')&&((c)<='z'))
+
+#if _DF1S		/* 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 /* _DF1S */
+
+
+/* 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 */
+)
+{
+	WORD wc, bc, ofs;
+	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 :
+		bc = (WORD)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
+	case FS_FAT16 :
+		if (disk_readp(buf, fs->fatbase + clst / 256, (WORD)(((WORD)clst % 256) * 2), 2)) break;
+		return LD_WORD(buf);
+#if _FS_FAT32
+	case FS_FAT32 :
+		if (disk_readp(buf, fs->fatbase + clst / 128, (WORD)(((WORD)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#                                             */
+/*-----------------------------------------------------------------------*/
+
+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;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* 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->fs_type == FS_FAT32)	/* Replace cluster# 0 with root cluster# if in FAT32 */
+		clst = (CLUST)fs->dirbase;
+	dj->clust = clst;						/* Current cluster */
+	dj->sect = clst ? clust2sect(clst) : fs->dirbase;	/* Current sector */
+
+	return FR_OK;	/* Seek succeeded */
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Directory handling - Move directory index next                        */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT dir_next (	/* 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, (WORD)((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_next(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 */
+)
+{
+	FRESULT res;
+	BYTE a, c;
+
+
+	res = FR_NO_FILE;
+	while (dj->sect) {
+		res = disk_readp(dir, dj->sect, (WORD)((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;
+		if (c != 0xE5 && c != '.' && !(a & AM_VOL))	/* Is it a valid entry? */
+			break;
+		res = dir_next(dj);			/* Next entry */
+		if (res != FR_OK) break;
+	}
+
+	if (res != FR_OK) dj->sect = 0;
+
+	return res;
+}
+#endif
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Pick a segment and create the object name in directory form           */
+/*-----------------------------------------------------------------------*/
+
+#ifdef _EXCVT
+	static const BYTE cvt[] = _EXCVT;
+#endif
+
+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, d, ni, si, i, *sfn;
+	const char *p;
+
+	/* 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;
+		}
+#ifdef _EXCVT
+		if (c >= 0x80)					/* To upper extended char (SBCS) */
+			c = cvt[c - 0x80];
+#endif
+		if (IsDBCS1(c) && i < ni - 1) {	/* DBC 1st byte? */
+			d = p[si++];				/* Get 2nd byte */
+			sfn[i++] = c;
+			sfn[i++] = d;
+		} else {						/* Single byte code */
+			if (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++;		/* Skip leading spaces */
+	if (*path == '/') path++;			/* Strip heading separator */
+	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) {				/* Could not find the object */
+				if (res == FR_NO_FILE && !*(dj->fn+11))
+					res = FR_NO_PATH;
+				break;
+			}
+			if (*(dj->fn+11)) break;		/* Last segment match. Function completed. */
+			if (!(dir[DIR_Attr] & AM_DIR)) { /* Cannot follow because it is a file */
+				res = FR_NO_PATH; break;
+			}
+			dj->sclust = LD_CLUST(dir);
+		}
+	}
+
+	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 sector */
+		return 3;
+	if (LD_WORD(buf) != 0xAA55)				/* Check record signature */
+		return 2;
+
+	if (!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 (NULL: Unmount) */
+)
+{
+	BYTE fmt, buf[36];
+	DWORD bsect, fsize, tsect, mclst;
+
+
+	FatFs = 0;
+	if (!fs) return FR_OK;				/* Unregister fs object */
+
+	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 = FS_FAT16;							/* Determine the FAT sub type */
+	if (mclst < 0xFF7) 						/* Number of clusters < 0xFF5 */
+#if _FS_FAT12
+		fmt = FS_FAT12;
+#else
+		return FR_NO_FILESYSTEM;
+#endif
+	if (mclst >= 0xFFF7)					/* Number of clusters >= 0xFFF5 */
+#if _FS_FAT32
+		fmt = FS_FAT32;
+#else
+		return FR_NO_FILESYSTEM;
+#endif
+
+	fs->fs_type = fmt;		/* FAT sub-type */
+	if (_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)						/* Check file system */
+		return FR_NOT_ENABLED;
+
+	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 = LD_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)*/
+	WORD btr,		/* Number of bytes to read */
+	WORD* br		/* Pointer to number of bytes read */
+)
+{
+	DRESULT dr;
+	CLUST clst;
+	DWORD sect, remain;
+	WORD 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 = (WORD)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? */
+				clst = (fs->fptr == 0) ?			/* On the top of the file? */
+					fs->org_clust : get_fat(fs->curr_clust);
+				if (clst <= 1) goto fr_abort;
+				fs->curr_clust = clst;				/* Update current cluster */
+			}
+			sect = clust2sect(fs->curr_clust);		/* Get current sector */
+			if (!sect) goto fr_abort;
+			fs->dsect = sect + cs;
+		}
+		rcnt = (WORD)(512 - (fs->fptr % 512));		/* Get partial sector data from sector buffer */
+		if (rcnt > btr) rcnt = btr;
+		dr = disk_readp(!buff ? 0 : rbuff, fs->dsect, (WORD)(fs->fptr % 512), rcnt);
+		if (dr) goto fr_abort;
+		fs->fptr += rcnt; rbuff += rcnt;			/* Update pointers and counters */
+		btr -= rcnt; *br += rcnt;
+	}
+
+	return FR_OK;
+
+fr_abort:
+	fs->flag = 0;
+	return FR_DISK_ERR;
+}
+#endif
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Write File                                                            */
+/*-----------------------------------------------------------------------*/
+#if _USE_WRITE
+
+FRESULT pf_write (
+	const void* buff,	/* Pointer to the data to be written */
+	WORD btw,			/* Number of bytes to write (0:Finalize the current write operation) */
+	WORD* bw			/* Pointer to number of bytes written */
+)
+{
+	CLUST clst;
+	DWORD sect, remain;
+	const BYTE *p = buff;
+	BYTE cs;
+	WORD 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)) goto fw_abort;
+		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 = (WORD)remain;			/* Truncate btw by remaining bytes */
+
+	while (btw)	{									/* Repeat until all data transferred */
+		if (((WORD)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? */
+				clst = (fs->fptr == 0) ?			/* On the top of the file? */
+					fs->org_clust : get_fat(fs->curr_clust);
+				if (clst <= 1) goto fw_abort;
+				fs->curr_clust = clst;				/* Update current cluster */
+			}
+			sect = clust2sect(fs->curr_clust);		/* Get current sector */
+			if (!sect) goto fw_abort;
+			fs->dsect = sect + cs;
+			if (disk_writep(0, fs->dsect)) goto fw_abort;	/* Initiate a sector write operation */
+			fs->flag |= FA__WIP;
+		}
+		wcnt = 512 - ((WORD)fs->fptr % 512);		/* Number of bytes to write to the sector */
+		if (wcnt > btw) wcnt = btw;
+		if (disk_writep(p, wcnt)) goto fw_abort;	/* Send data to the sector */
+		fs->fptr += wcnt; p += wcnt;				/* Update pointers and counters */
+		btw -= wcnt; *bw += wcnt;
+		if (((WORD)fs->fptr % 512) == 0) {
+			if (disk_writep(0, 0)) goto fw_abort;	/* Finalize the currtent secter write operation */
+			fs->flag &= ~FA__WIP;
+		}
+	}
+
+	return FR_OK;
+
+fw_abort:
+	fs->flag = 0;
+	return FR_DISK_ERR;
+}
+#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) goto fe_abort;
+			fs->curr_clust = clst;
+			fs->fptr += bcs;
+			ofs -= bcs;
+		}
+		fs->fptr += ofs;
+		sect = clust2sect(clst);		/* Current sector */
+		if (!sect) goto fe_abort;
+		fs->dsect = sect + (fs->fptr / 512 & (fs->csize - 1));
+	}
+
+	return FR_OK;
+
+fe_abort:
+	fs->flag = 0;
+	return FR_DISK_ERR;
+}
+#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 = LD_CLUST(dir);
+				else							/* The object is not a directory */
+					res = FR_NO_PATH;
+			}
+			if (res == FR_OK)
+				res = dir_rewind(dj);			/* Rewind dir */
+		}
+		if (res == FR_NO_FILE) res = FR_NO_PATH;
+	}
+
+	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);
+			if (res == FR_NO_FILE) {
+				dj->sect = 0;
+				res = FR_OK;
+			}
+			if (res == FR_OK) {				/* A valid entry is found */
+				get_fileinfo(dj, dir, fno);	/* Get the object information */
+				res = dir_next(dj);			/* Increment index for next */
+				if (res == FR_NO_FILE) {
+					dj->sect = 0;
+					res = FR_OK;
+				}
+			}
+		}
+	}
+
+	return res;
+}
+
+#endif /* _USE_DIR */
+
Index: firmware/fat/pff_file.c
===================================================================
--- firmware/fat/pff_file.c	(nonexistent)
+++ firmware/fat/pff_file.c	(revision 46)
@@ -0,0 +1,266 @@
+#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;
+
+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 = '\0';
+	return;
+}
+
+char const * file_name(struct SimpleFile * file)
+{
+	return file_of(&file->path[0]);
+}
+
+void file_check_open(struct SimpleFile * file)
+{
+	if (openfile!=file)
+	{
+		pf_open(&file->path[0]);
+		openfile = file;
+	}
+}
+
+enum SimpleFileStatus file_read(struct SimpleFile * file, void * buffer, int bytes, int * bytesread)
+{
+	WORD bytesread_word;
+	FRESULT res;
+
+	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)
+{
+	WORD byteswritten_word;
+	FRESULT res;
+
+	file_check_open(file);
+	
+	res = pf_write(buffer, bytes, &byteswritten_word);
+	*byteswritten = byteswritten_word;
+
+	return translateStatus(res);
+}
+
+enum SimpleFileStatus file_seek(struct SimpleFile * file, int offsetFromStart)
+{
+	FRESULT res;
+
+	file_check_open(file);
+
+	pf_lseek(offsetFromStart);
+	return translateStatus(res);
+}
+
+int file_size(struct SimpleFile * file)
+{
+	return file->size;
+}
+
+int file_struct_size()
+{
+	return sizeof(struct SimpleFile);
+}
+
+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);
+
+	printf("filename:%s dirname:%s ", filename,&dirname[0]);
+
+	struct SimpleDirEntry * entry = dir_entries(&dirname[0]);
+	while (entry)
+	{
+		printf("%s ",entry->filename_ptr);
+		if (0==strcmp(filename,entry->filename_ptr))
+		{
+			return file_open_dir(entry, file);
+		}
+		entry = entry->next;
+	}
+
+	return SimpleFile_FAIL;
+}
+
+enum SimpleFileStatus file_open_dir(struct SimpleDirEntry * dir, struct SimpleFile * file)
+{
+	FRESULT res;
+
+	strcpy(&file->path[0],dir->path);
+	file->size = dir->size;
+
+	res = pf_open(&file->path[0]);
+	openfile = file;
+
+	return translateStatus(res);
+}
+
+enum SimpleFileStatus dir_init(void * mem, int space)
+{
+	FRESULT fres;
+	DSTATUS res;
+
+	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)
+// TODO - dir cache, so we don't need to know where everywhere!
+struct SimpleDirEntry * dir_entries(char const * dirPath)
+{
+	struct SimpleDirEntry * entry = 0;
+	int room = dir_cache_size/sizeof(struct SimpleDirEntry);
+
+	printf("opendir ");
+	if (FR_OK != pf_opendir(&dir,dirPath))
+	{
+		printf("FAIL ");
+		return 0;
+	}
+	printf("OK ");
+
+	while (FR_OK == pf_readdir(&dir,&filinfo) && filinfo.fname[0]!='\0')
+	{
+		char * ptr;
+
+		if (filinfo.fattrib & AM_SYS)
+		{
+			continue;
+		}
+		if (filinfo.fattrib & AM_HID)
+		{
+			continue;
+		}
+
+		if (!entry)
+			entry = (struct SimpleDirEntry *) dir_cache;
+		else if (room)
+		{
+			printf("inc %x %x ",entry,entry->next);
+			entry = entry->next;
+			--room;
+		}
+		else
+		{
+			break; // OUT OF ROOM!
+		}
+
+		printf("next %x %d ",entry,room);
+
+		entry->is_subdir = (filinfo.fattrib & AM_DIR) ? 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;
+
+		entry->next = entry + 1;
+		printf("n %d %d %x ",filinfo.fsize, entry->size, entry->next);
+	}
+
+	printf("dir_entries done ");
+
+	entry->next = 0;
+	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;
+}
+
+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/fileselector.c
===================================================================
--- firmware/fileselector.c	(nonexistent)
+++ firmware/fileselector.c	(revision 46)
@@ -0,0 +1,136 @@
+
+void file_select(void (*filter) (char const *), char const * path, struct SimpleFile * file)
+{
+	// Read in the whole dir
+
+	// Write it to screen memory
+
+	// Allow user to scroll around with hotkeys/joystick
+
+	// If user selects dir, then we 
+
+	int fileno;
+	int skip;
+	int plotted = 0;
+	wait_us(200000);
+	for(;;)
+	{
+		int i = 0;
+		int go = 0;
+		fileno = 0;
+		topofscreen();
+		for (i=0; i!=(24*40); ++i)
+		{
+			*(unsigned char volatile *)(i+0x10000+40000) = 0x00;
+		}
+		if (FR_OK != pf_opendir(&dir,"/"))
+		{
+			debug("opendir failed\n");
+			mmcReadCached(0);
+			hexdump_pure(mmc_sector_buffer,512);
+			
+			while(1);
+		}
+
+		plotted = 0;
+		skip = 0;
+		if (selfileno>20)
+		{
+			skip = selfileno-20;
+			skip&=0xfffffffe;
+		}
+		if (selfileno<0)
+		{
+			selfileno = 0;
+		}
+		while (FR_OK == pf_readdir(&dir,&filinfo) && filinfo.fname[0]!='\0')
+		{
+			if (filinfo.fattrib & AM_SYS)
+			{
+				continue;
+			}
+			if (filinfo.fattrib & AM_HID)
+			{
+				continue;
+			}
+			if (filinfo.fattrib & AM_DIR)
+			{
+				debug("DIR ");
+			}
+			if (selfileno == fileno)
+			{
+				for (i=0;i!=15;++i)
+				{
+					filename[i] = filinfo.fname[i];
+					if (0==filinfo.fname[i]) break;
+					filinfo.fname[i]+=128;
+				}
+			}
+			if (--skip<0)
+			{
+				debug(filinfo.fname);
+				++plotted;
+				if (plotted&1)
+				{
+					setxpos(20);
+				}
+				else
+				{
+					debug("\n");
+				}
+				if (plotted==40)
+				{
+					break;
+				}
+			}
+			fileno++;
+		}
+		debug("\n");
+		setypos(21);
+		opendrive = 0;
+		openfile(filename);
+		for (;;)
+		{
+			unsigned char porta = *atari_porta;
+			if (0==(porta&0x2)) // down
+			{
+				selfileno+=2;
+				break;
+			}
+			else if (0==(porta&0x1)) // up
+			{
+				selfileno-=2;
+				break;
+			}
+			else if (0==(porta&0x8)) // right
+			{
+				selfileno|=1;
+				break;
+			}
+			else if (0==(porta&0x4)) // left
+			{
+				selfileno&=0xfffffffe;
+				break;
+			}
+			else if (0==(*atari_trig0)) // fire
+			{
+				go = 1;
+				while(0==(*atari_trig0));
+				break;
+			}
+			topofscreen();
+			//plotnextnumber(porta);
+			*atari_colbk = *atari_random;
+			//wait_us(200);
+		}
+		if (go == 1)
+		{
+			wait_us(200000);
+			return validfile; // TODO, another way to quit without selecting...
+		}
+		wait_us(80000);
+	}
+	return 0;
+}
+
+
Index: firmware/freeze.c
===================================================================
--- firmware/freeze.c	(nonexistent)
+++ firmware/freeze.c	(revision 46)
@@ -0,0 +1,111 @@
+#include "freeze.h"
+
+void freeze()
+{
+	// Copy base 64k to ...
+
+	unsigned volatile char * store  = 0xf80000; // SRAM...
+	unsigned volatile char * store2 = 0xfc0000; // custom chips...
+
+	mem = 0x9c00 + 0x10000;
+	// Copy 1k from 0x$9c00 to sdram
+	// 0x200000; sram
+	// 0x800000; sdram (always use...)
+	for (i=0x0; i!=1024; i++)
+	{
+		store[i] = mem[i];
+	}
+	for (i=0x40; i!=1024; i++)
+	{
+		mem[i] = 0;
+	}
+
+	// store custom chips
+	store_portb = *atari_portb;
+	{
+		//gtia
+		mem2 = 0x20000;
+		mem3 = 0x10000;
+		for (i=0xd000; i!=0xd01f; i++)
+		{
+			store2[i] = mem2[i];
+			mem3[i] = 0;
+		}
+		//pokey1/2
+		for (i=0xd200; i!=0xd21f; i++)
+		{
+			store2[i] = mem2[i];
+			mem3[i] = 0;
+		}
+		//antic
+		for (i=0xd400; i!=0xd40f; i++)
+		{
+			store2[i] = mem2[i];
+			mem3[i] = 0;
+		}
+	}
+
+	// Put custom chips in a safe state
+	// write a display list at 9c00
+	char dl[] = {
+		0x70,0x70,0x70,
+		0x42,0x40,0x9c,
+		0x2,0x2,0x2,0x2,0x2,
+		0x2,0x2,0x2,0x2,0x2,
+		0x2,0x2,0x2,0x2,0x2,
+		0x2,0x2,0x2,0x2,0x2,
+		0x2,0x2,0x2,
+		0x70,
+		0x41,0x00,0x9c
+	};
+	for (i=0; i!=sizeof(dl); ++i)
+	{
+		mem[i] = dl[i];
+	}
+
+	// point antic at my display list
+	*atari_dlistl = 0x00;
+	*atari_dlisth = 0x9c;
+	*atari_colbk = 0x00;
+	*atari_colpf1 = 0x0f;
+	*atari_colpf2 = 0x00;
+	*atari_prior = 0x00;
+	*atari_chbase = 0xe0;
+	*atari_dmactl = 0x22;
+	*atari_portb = 0xff;
+	*atari_skctl = 0x3;
+	*atari_chactl = 0x2;
+}
+
+void restore()
+{
+	// Restore memory
+	mem = 0x9c00 + 0x10000;
+	for (i=0x040; i!=1024; i++)
+	{
+		mem[i] = store[i];
+	}
+
+	// Restore custom chips
+	{
+		//gtia
+		mem3 = 0x10000;
+		for (i=0xd000; i!=0xd01f; i++)
+		{
+			mem3[i] = store2[i];
+		}
+		//pokey1/2
+		for (i=0xd200; i!=0xd21f; i++)
+		{
+			mem3[i] = store2[i];
+		}
+		//antic
+		for (i=0xd400; i!=0xd40f; i++)
+		{
+			mem3[i] = store2[i];
+		}
+	}
+
+	*atari_portb = store_portb;
+}
+
Index: firmware/hexdump.h
===================================================================
--- firmware/hexdump.h	(nonexistent)
+++ firmware/hexdump.h	(revision 46)
@@ -0,0 +1,4 @@
+#pragma once
+
+void hexdump_pure(void const * str, int length);
+
Index: firmware/main.c
===================================================================
--- firmware/main.c	(nonexistent)
+++ firmware/main.c	(revision 46)
@@ -0,0 +1,189 @@
+#include "integer.h"
+#include "regs.h"
+#include "pause.h"
+#include "printf.h"
+
+#include "simpledir.h"
+#include "simplefile.h"
+
+#include "atari_drive_emulator.h"
+
+// 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
+// rom_select: bit 8-13:
+//    		ROM_SELECT : in std_logic_vector(5 downto 0); -- 16KB ROM Bank
+
+#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; \
+}
+
+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)
+
+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;
+}
+
+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_64k_ram()
+{
+	memset8((void *)0x200000, 0, 65536); // SRAM, if present (TODO)
+	memset32((void *)0x800000, 0, 16384);
+}
+
+void
+coldstart(int clearram)
+{
+	set_reset_6502(1);
+	if (clearram)
+	{
+		clear_64k_ram();
+	}
+	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
+	{
+		val = 0;
+	}
+	if (inv)
+	{
+		val+=128;
+	}
+	return val;
+}
+
+int debug_pos;
+unsigned char volatile * baseaddr;
+
+void char_out ( void* p, char c)
+{
+	unsigned char val = toatarichar(c);
+	//*(baseaddr+debug_pos) = val;
+	//++debug_pos;
+}
+
+// Memory usage...
+// 0x410000-0x41FFFF (0xc10000 in zpu space) = directory cache - 64k
+
+int main(void)
+{
+	debug_pos = 0;
+	baseaddr = (unsigned char volatile *)(40000 + atari_regbase);
+	set_reset_6502(1);
+	set_turbo_6502(1);
+
+	init_printf(0, char_out);
+
+	debug_pos = 0;
+
+	// TODO...
+
+	printf("Hello World\n I am an Atari!\n");
+
+	if (SimpleFile_OK == dir_init((void *)0xc10000, 65536))
+	{
+		printf("DIR init ok\n");
+		struct SimpleFile * file = alloca(file_struct_size());
+		printf("Opening file\n");
+		if (SimpleFile_OK == file_open_name("GUNPOWDR.ATR",file))
+		{
+			printf("FILE open ok\n");
+			init_drive_emulator();
+
+			set_drive_status(0,file);
+
+			coldstart(1);
+
+			run_drive_emulator();
+		}
+		else
+		{
+			printf("FILE open failed\n");
+		}
+	}
+	else
+	{
+		printf("DIR init failed\n");
+	}
+
+	for(;;) actions();
+}
+
+void actions()
+{
+	// NOP
+	*atari_colbk = *atari_random;
+}
+
+
Index: firmware/mif_file_stuff/zpuromgen
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: firmware/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/native/diskio_image.c
===================================================================
--- firmware/native/diskio_image.c	(nonexistent)
+++ firmware/native/diskio_image.c	(revision 46)
@@ -0,0 +1,74 @@
+#include "diskio.h"
+
+#include "stdio.h"
+
+FILE * disk_image;
+
+/*-----------------------------------------------------------------------*/
+/* Initialize Disk Drive                                                 */
+/*-----------------------------------------------------------------------*/
+
+DSTATUS disk_initialize (void)
+{
+	DSTATUS stat;
+
+ 	disk_image = fopen("sd.image","rb");
+
+	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;
+
+	fseek(disk_image,sector*512+sofs,SEEK_SET);
+	fread(dest,count,1,disk_image);
+
+	res = RES_OK;
+
+	return res;
+}
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Write Partial Sector                                                  */
+/*-----------------------------------------------------------------------*/
+
+DRESULT disk_writep (const BYTE* buff, DWORD sc)
+{
+	DRESULT res;
+
+
+	if (!buff) {
+		if (sc) {
+
+			// Initiate write process
+
+		} else {
+
+			// Finalize write process
+
+		}
+	} else {
+
+		// Send data to the disk
+
+	}
+
+	return res;
+}
+
Index: firmware/printf/printf.c
===================================================================
--- firmware/printf/printf.c	(nonexistent)
+++ firmware/printf/printf.c	(revision 46)
@@ -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/printf/printf.c
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: firmware/sd_direct/diskio_mmc.c
===================================================================
--- firmware/sd_direct/diskio_mmc.c	(nonexistent)
+++ firmware/sd_direct/diskio_mmc.c	(revision 46)
@@ -0,0 +1,136 @@
+#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;
+	do
+	{
+		mmcInit();
+	}
+	while(mmcReset());	//dokud nenulove, tak smycka (return 0 => ok!)
+
+	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:%02x loc:%d", x,sofs);
+		*dest++ = x;
+	}
+
+	res = RES_OK;
+
+	return res;
+}
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Write Partial Sector                                                  */
+/*-----------------------------------------------------------------------*/
+
+DRESULT disk_writep (const BYTE* buff, DWORD sc)
+{
+	DRESULT res;
+
+
+	if (!buff) {
+		if (sc) {
+
+			// Initiate write process
+
+		} else {
+
+			// Finalize write process
+
+		}
+	} else {
+
+		// Send data to the disk
+
+	}
+
+	return res;
+}
Index: firmware/sd_direct/spi.c
===================================================================
--- firmware/sd_direct/spi.c	(nonexistent)
+++ firmware/sd_direct/spi.c	(revision 46)
@@ -0,0 +1,118 @@
+/*! \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;
+}
+
Index: firmware/pokey/uart.c
===================================================================
--- firmware/pokey/uart.c	(nonexistent)
+++ firmware/pokey/uart.c	(revision 46)
@@ -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 (0xc0&(*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/regs.h
===================================================================
--- firmware/regs.h	(nonexistent)
+++ firmware/regs.h	(revision 46)
@@ -0,0 +1,54 @@
+#ifndef regs_h
+#define regs_h
+
+#define atari_regbase  0x10000
+
+extern int volatile * zpu_in1;
+extern int volatile * zpu_in2;
+extern int volatile * zpu_in3;
+extern int volatile * zpu_in4;
+
+extern int volatile * zpu_out1;
+extern int volatile * zpu_out2;
+extern int volatile * zpu_out3;
+extern int volatile * zpu_out4;
+
+extern int volatile * zpu_pause;
+extern int volatile * zpu_spi_data;
+extern int volatile * zpu_spi_state;
+extern int volatile * zpu_sio;
+extern int volatile * zpu_board;
+ 
+extern unsigned char volatile * zpu_pokey_audf0;
+extern unsigned char volatile * zpu_pokey_audc0;
+extern unsigned char volatile * zpu_pokey_audf1;
+extern unsigned char volatile * zpu_pokey_audc1;
+extern unsigned char volatile * zpu_pokey_audf2;
+extern unsigned char volatile * zpu_pokey_audc2;
+extern unsigned char volatile * zpu_pokey_audf3;
+extern unsigned char volatile * zpu_pokey_audc3;
+ 
+extern unsigned char volatile * zpu_pokey_audctl;
+ 
+extern unsigned char volatile * zpu_pokey_skrest;
+extern unsigned char volatile * zpu_pokey_serout;
+extern unsigned char volatile * zpu_pokey_irqen;
+extern unsigned char volatile * zpu_pokey_skctl;
+
+extern unsigned char volatile * atari_nmien;
+extern unsigned char volatile * atari_dlistl;
+extern unsigned char volatile * atari_dlisth;
+extern unsigned char volatile * atari_colbk;
+extern unsigned char volatile * atari_colpf1;
+extern unsigned char volatile * atari_colpf2;
+extern unsigned char volatile * atari_prior;
+extern unsigned char volatile * atari_random;
+extern unsigned char volatile * atari_porta;
+extern unsigned char volatile * atari_portb;
+extern unsigned char volatile * atari_trig0;
+extern unsigned char volatile * atari_chbase;
+extern unsigned char volatile * atari_chactl;
+extern unsigned char volatile * atari_dmactl;
+extern unsigned char volatile * atari_skctl;
+
+#endif // regs_h
Index: firmware/sd_direct/mmcconf.h
===================================================================
--- firmware/sd_direct/mmcconf.h	(nonexistent)
+++ firmware/sd_direct/mmcconf.h	(revision 46)
@@ -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/sdrive_parts/bootloader
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: firmware/sdrive_parts/bootloader
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: firmware/standalone_simple.ld
===================================================================
--- firmware/standalone_simple.ld	(nonexistent)
+++ firmware/standalone_simple.ld	(revision 46)
@@ -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 = 0x500 /* 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/uart.h
===================================================================
--- firmware/uart.h	(nonexistent)
+++ firmware/uart.h	(revision 46)
@@ -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/pause.h
===================================================================
--- firmware/pause.h	(nonexistent)
+++ firmware/pause.h	(revision 46)
@@ -0,0 +1,6 @@
+#ifndef PAUSE_H
+#define PAUSE_H
+
+void wait_us(int unsigned num);
+
+#endif
Index: firmware/regs.c
===================================================================
--- firmware/regs.c	(nonexistent)
+++ firmware/regs.c	(revision 46)
@@ -0,0 +1,54 @@
+#include "regs.h"
+
+#define config_regbase 0x40000
+int volatile * zpu_in1 = (int *)(0*4+config_regbase);
+int volatile * zpu_in2 = (int *)(1*4+config_regbase);
+int volatile * zpu_in3 = (int *)(2*4+config_regbase);
+int volatile * zpu_in4 = (int *)(3*4+config_regbase);
+
+int volatile * zpu_out1 = (int *)(4*4+config_regbase);
+int volatile * zpu_out2 = (int *)(5*4+config_regbase);
+int volatile * zpu_out3 = (int *)(6*4+config_regbase);
+int volatile * zpu_out4 = (int *)(7*4+config_regbase);
+
+int volatile * zpu_pause = (int *)(8*4+config_regbase);
+
+int volatile * zpu_spi_data = (int *)(9*4+config_regbase);
+int volatile * zpu_spi_state = (int *)(10*4+config_regbase);
+
+int volatile * zpu_sio = (int *)(11*4+config_regbase);
+
+int volatile * zpu_board = (int *)(12*4+config_regbase);
+
+unsigned char volatile * zpu_pokey_audf0 = (unsigned char *)(0x10*4+config_regbase);
+unsigned char volatile * zpu_pokey_audc0 = (unsigned char *)(0x11*4+config_regbase);
+unsigned char volatile * zpu_pokey_audf1 = (unsigned char *)(0x12*4+config_regbase);
+unsigned char volatile * zpu_pokey_audc1 = (unsigned char *)(0x13*4+config_regbase);
+unsigned char volatile * zpu_pokey_audf2 = (unsigned char *)(0x14*4+config_regbase);
+unsigned char volatile * zpu_pokey_audc2 = (unsigned char *)(0x15*4+config_regbase);
+unsigned char volatile * zpu_pokey_audf3 = (unsigned char *)(0x16*4+config_regbase);
+unsigned char volatile * zpu_pokey_audc3 = (unsigned char *)(0x17*4+config_regbase);
+
+unsigned char volatile * zpu_pokey_audctl = (unsigned char *)(0x18*4+config_regbase);
+
+unsigned char volatile * zpu_pokey_skrest = (unsigned char *)(0x1a*4+config_regbase);
+unsigned char volatile * zpu_pokey_serout = (unsigned char *)(0x1d*4+config_regbase);
+unsigned char volatile * zpu_pokey_irqen = (unsigned char *)(0x1e*4+config_regbase);
+unsigned char volatile * zpu_pokey_skctl = (unsigned char *)(0x1f*4+config_regbase);
+
+unsigned char volatile * atari_nmien = (unsigned char *)(0xd40e + atari_regbase);
+unsigned char volatile * atari_dlistl = (unsigned char *)(0xd402 + atari_regbase);
+unsigned char volatile * atari_dlisth = (unsigned char *)(0xd403 + atari_regbase);
+unsigned char volatile * atari_colbk = (unsigned char *)(0xd01a + atari_regbase);
+unsigned char volatile * atari_colpf1 = (unsigned char *)(0xd017 + atari_regbase);
+unsigned char volatile * atari_colpf2 = (unsigned char *)(0xd018 + atari_regbase);
+unsigned char volatile * atari_prior = (unsigned char *)(0xd01b + atari_regbase);
+unsigned char volatile * atari_random = (unsigned char *)(0xd20a + atari_regbase);
+unsigned char volatile * atari_porta = (unsigned char *)(0xd300 + atari_regbase);
+unsigned char volatile * atari_portb = (unsigned char *)(0xd301 + atari_regbase);
+unsigned char volatile * atari_trig0 = (unsigned char *)(0xd010 + atari_regbase);
+unsigned char volatile * atari_chbase = (unsigned char *)(0xd409 + atari_regbase);
+unsigned char volatile * atari_chactl = (unsigned char *)(0xd401 + atari_regbase);
+unsigned char volatile * atari_dmactl = (unsigned char *)(0xd400 + atari_regbase);
+unsigned char volatile * atari_skctl = (unsigned char *)(0xd20f + atari_regbase);
+
Index: firmware/sd_direct/mmc.h
===================================================================
--- firmware/sd_direct/mmc.h	(nonexistent)
+++ firmware/sd_direct/mmc.h	(revision 46)
@@ -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 mmcInit(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/printf/printf.h
===================================================================
--- firmware/printf/printf.h	(nonexistent)
+++ firmware/printf/printf.h	(revision 46)
@@ -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 tfp_printf 
+#define sprintf tfp_sprintf 
+
+#endif
+
+
+

Property changes on: firmware/printf/printf.h
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: firmware/sd_direct/mmc.c
===================================================================
--- firmware/sd_direct/mmc.c	(nonexistent)
+++ firmware/sd_direct/mmc.c	(revision 46)
@@ -0,0 +1,269 @@
+/*! \file mmc.c \brief MultiMedia and SD Flash Card Interface. */
+//*****************************************************************************
+//
+// File Name	: 'mmc.c'
+// 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
+//
+// 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 Files ---------------------------------------------------------
+#include "spi.h"		// include spi bus support
+
+
+//#define spiTransferTwoFF()	{ spiTransferFF(); spiTransferFF(); }
+
+
+#include "mmc.h"
+
+// include project-specific hardware configuration
+#include "mmcconf.h"
+#include "debug.h"
+
+void mmcInit(void)
+{
+	// initialize SPI interface
+	spiInit();
+	// release chip select
+	mmcChipSelect(0);
+}
+
+u08 mmcReset(void)
+{
+	u16 retry;
+	u08 r1;
+	u08 i;
+	u08 sdcard;
+
+	//
+	i=0xff; //255x
+	do { spiTransferFF(); i--; } while(i);	//255x
+
+	//
+	r1 = mmcSendCommand(MMC_GO_IDLE_STATE, 0);
+	if (r1!=1) return -1;
+
+	retry=0xffff; //65535x
+	do
+	{
+		r1 = mmcSendCommand(55, 0);
+		if (r1!=1) break; //MMC
+		//if (r1==5) break; //MMC  <--- kontrolovat takhle rekl Bob 27.6.2008
+								//Strana 120 ve specifikaci.
+								//bit 0 - in idle state, bit 2 - illegal command
+
+		r1 = mmcSendCommand(41, 0);
+		if (r1==0) break; //SD
+
+		retry--;
+	}
+	while(retry);
+
+	// initializing card for operation
+	r1 = mmcSendCommand(MMC_SEND_OP_COND, 0);
+	// SDkarty vraceji 0
+	// MMCkarta vraci 1
+	//if (r1>=2) return -1; //problem (MMC taky nefunguje)
+	if (r1!=0) return -1;
+
+	//kdyz jsem to tady nechal jit s MMC kartou dal (s r1=1)
+	//tak to na nekterem z dalsich povelu zustalo zasekle
+	//a po vytazeni MMC a vlozeni jine SD se muset mackat Reset :-(
+
+	/*
+	if( r1!=0  &&  r1!=5)
+	{
+		u08 v;
+		v=inb(PINC)&0xf0;
+		v|=(0x0f ^ (r1 & 0x0f) );
+		PORTC=v;
+	 	while(1); //nekonecna smycka
+	 return -1;
+	}
+	*/
+
+	// turn off CRC checking to simplify communication
+	//r1 = 
+	mmcSendCommand(MMC_CRC_ON_OFF, 0);
+
+	// set block length to 512 bytes
+	//r1 = 
+	mmcSendCommand(MMC_SET_BLOCKLEN, 512);
+
+	// return success
+	return 0;
+}
+
+u08 mmcSendCommand(u08 cmd, u32 arg)
+{
+	u08 r1;
+
+	// assert chip select
+	mmcChipSelect(1);
+	//
+	//spiTransferFF();			//pribude 34 bajtu kodu (!)
+	// issue the command
+	r1 = mmcCommand(cmd, arg);
+	//
+	//spiTransferFF();
+	// release chip select
+	mmcChipSelect(0);
+
+	return r1;
+}
+
+unsigned char mmc_sector_buffer[512];
+
+void mmcReadLoop()
+{
+	u16 i;
+	u08 *buffer=mmc_sector_buffer;	//natvrdo!
+
+	i=0x80;	//512
+	do { *buffer++ = spiTransferFF(); i--; } while(i);
+
+	//spiDisplay(1);
+	i=0x80;	//512
+	do { *buffer++ = spiTransferFF(); i--; } while(i);
+
+	i=0x80;	//512
+	do { *buffer++ = spiTransferFF(); i--; } while(i);
+
+	i=0x80;	//512
+	do { *buffer++ = spiTransferFF(); i--; } while(i);
+
+	//spiDisplay(0);
+
+}
+
+u08 mmcRead(u32 sector)
+{
+	u08 r1;
+
+	// assert chip select
+	mmcChipSelect(1);
+	// issue command
+	r1 = mmcCommand(MMC_READ_SINGLE_BLOCK, sector<<9);
+
+	// check for valid response
+	if(r1 != 0x00) return r1;
+
+	// wait for block start
+	while(spiTransferFF() != MMC_STARTBLOCK_READ);
+
+	//zacatek bloku
+
+	//nacti 512 bytu
+	mmcReadLoop();
+
+	// read 16-bit CRC
+	//2x FF:
+	spiTransferFF();
+	spiTransferFF();
+	//// + 1x FF navic pred releasnutim chip selectu
+	//spiTransferFF();
+	//
+	// release chip select
+	mmcChipSelect(0);
+
+	//debug("Hexdump\n");
+	//hexdump(mmc_sector_buffer,80);
+
+	//
+	return 0;	//success
+}
+
+u08 mmcWrite(u32 sector)
+{
+	u08 r1;
+	u16 i;
+	u08 *buffer=mmc_sector_buffer;	//natvrdo!
+
+	// assert chip select
+	mmcChipSelect(1);
+	// issue command
+	r1 = mmcCommand(MMC_WRITE_BLOCK, sector<<9);
+	// check for valid response
+	if(r1 != 0x00)
+		return r1;
+	// send dummy
+	spiTransferFF();
+	// send data start token
+	spiTransferByte(MMC_STARTBLOCK_WRITE);
+
+	// write data (512 bytes)
+	i=0x200;
+	do { spiTransferByte(*buffer++); i--; }	while(i);
+
+	// write 16-bit CRC (dummy values)
+	//2x FF:
+	spiTransferFF();
+	spiTransferFF();
+	// read data response token
+	r1 = spiTransferFF();
+	if( (r1&MMC_DR_MASK) != MMC_DR_ACCEPT)
+		return r1;
+	// wait until card not busy
+	while(!spiTransferFF());
+	// release chip select
+	mmcChipSelect(0);
+	// return success
+	return 0;
+}
+
+u08 mmcCommand(u08 cmd, u32 arg)
+{
+	u08 r1;
+	u08 retry=0xff;	//255x
+	//
+
+	spiTransferFF();
+
+	spiTransferFF();	//pridano navic! 27.6.2008 doporucil Bob!k
+	spiTransferFF();	//pridano navic! 27.6.2008 doporucil Bob!k
+	spiTransferFF();	//pridano navic! 27.6.2008 doporucil Bob!k
+
+	// send command
+	spiTransferByte(cmd | 0x40);
+	//
+	spiTransferByte(arg>>24);
+	spiTransferByte(arg>>16);
+	spiTransferByte(arg>>8);
+	spiTransferByte(arg);
+	//Alternativni zpusob pres ((u08*)&arg)[] je delsi.
+
+	spiTransferByte(0x95);	// crc valid only for MMC_GO_IDLE_STATE
+	// end command
+	// wait for response
+	// if more than 255 retries, card has timed-out
+	// return the received 0xFF
+	do
+	{
+		r1 = spiTransferFF();
+		retry--;
+	}
+	while(retry && (r1 == 0xFF) );
+
+	// return response
+	return r1;
+}
Index: firmware/sd_direct/spi.h
===================================================================
--- firmware/sd_direct/spi.h	(nonexistent)
+++ firmware/sd_direct/spi.h	(revision 46)
@@ -0,0 +1,66 @@
+/*! \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);
+
+#endif
Index: firmware/setup
===================================================================
--- firmware/setup	(nonexistent)
+++ firmware/setup	(revision 46)
@@ -0,0 +1 @@
+export PATH=${PATH}:/home/markw/fpga/zpugcc/toolchain/install/bin/
Index: firmware/test_drive.c
===================================================================
--- firmware/test_drive.c	(nonexistent)
+++ firmware/test_drive.c	(revision 46)
@@ -0,0 +1,110 @@
+#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);
+}
+
+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));
+	struct SimpleFile * file = alloca(file_struct_size());
+	//file_open_dir(entry,file);
+	file_open_name("GUNPOWDR.ATR",file);
+
+	int read = 0;
+	char buffer[1024];
+	//file_seek(file,100);
+	file_read(file,&buffer[0],1024,&read);
+	int i;
+	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,file);
+
+	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++] = 0x52;
+			receive_buffer[receive_buffer_last++] = 0x01;
+			receive_buffer[receive_buffer_last++] = 0x00;
+			receive_buffer[receive_buffer_last++] = 0x84;
+		}
+		else
+		{
+			native_command = 1;
+		}
+	}
+	else
+	{
+		native_command = 1;
+	}
+}
+
+void
+wait_us(int unsigned num)
+{
+	usleep(num);
+}
+
Index: firmware/sdrive_parts/bootdump.c
===================================================================
--- firmware/sdrive_parts/bootdump.c	(nonexistent)
+++ firmware/sdrive_parts/bootdump.c	(revision 46)
@@ -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/simplefile.h
===================================================================
--- firmware/simplefile.h	(nonexistent)
+++ firmware/simplefile.h	(revision 46)
@@ -0,0 +1,16 @@
+#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();
+
+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);
+
Index: firmware/test_joy.c
===================================================================
--- firmware/test_joy.c	(nonexistent)
+++ firmware/test_joy.c	(revision 46)
@@ -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;
+	}
+}
+
+
Index: firmware/sdrive_parts/bootdump
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: firmware/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/simpledir.h
===================================================================
--- firmware/simpledir.h	(nonexistent)
+++ firmware/simpledir.h	(revision 46)
@@ -0,0 +1,22 @@
+#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_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(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/test_file.c
===================================================================
--- firmware/test_file.c	(nonexistent)
+++ firmware/test_file.c	(revision 46)
@@ -0,0 +1,85 @@
+#include "simpledir.h"
+#include "simplefile.h"
+
+//#include "fat/pff_file.h"
+// XXX - BEST NOT to include this?
+
+#include "stdio.h"
+#include "stdlib.h"
+
+int main(void)
+{
+	char * mem = (char *)malloc(8192);
+	if (SimpleFile_OK != dir_init(mem, 8192))
+	{
+		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("/UAE4ALL");
+	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("/UAE4ALL/DATA");
+	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");
+	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", file_size(file));
+
+	int read = 0;
+	char buffer[1024];
+	file_seek(file,100);
+	file_read(file,&buffer[0],1024,&read);
+	int i;
+	for (i=0; i!=read; ++i)
+	{
+		//fprintf(stderr,"%02x", buffer[i]);
+		fprintf(stderr,"%c", buffer[i]);
+	}
+
+	return 0;
+}
+
+
