mk2 fw wip

This commit is contained in:
ikari 2010-09-17 00:37:50 +02:00
parent 96e57b4f76
commit 40248e61af
35 changed files with 3035 additions and 44 deletions

View File

@ -55,7 +55,7 @@ TARGET = $(OBJDIR)/sd2snes
# List C source files here. (C dependencies are automatically generated.)
SRC = main.c ff.c clock.c uart.c
SRC = main.c ff.c ccsbcs.c clock.c uart.c power.c led.c timer.c printf.c sdcard.c spi.c fileops.c rtc.c
# List Assembler source files here.
@ -65,7 +65,7 @@ SRC = main.c ff.c clock.c uart.c
# Even though the DOS/Win* filesystem matches both .s and .S the same,
# it will preserve the spelling of the filenames, and gcc itself does
# care about how the name is spelled on its command-line.
ASRC = startup.S
ASRC = startup.S crc.S
# Optimization level, can be [0, 1, 2, 3, s].
@ -137,7 +137,7 @@ CFLAGS += -O$(OPT)
CFLAGS += $(CPUFLAGS) -nostartfiles
#CFLAGS += -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
CFLAGS += -Wall -Wstrict-prototypes -Werror
#CFLAGS += -Wa,-adhlns=$(OBJDIR)/$(<:.c=.lst)
CFLAGS += -Wa,-adhlns=$(OBJDIR)/$(<:.c=.lst)
CFLAGS += -I$(OBJDIR)
CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
CFLAGS += $(CSTANDARD)

14
src/bits.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef _ARM_BITS_H
#define _ARM_BITS_H
/* The classic macro */
#define BV(x) (1<<(x))
/* CM3 bit-band access macro - no error checks! */
#define BITBAND(addr,bit) \
(*((volatile unsigned long *)( \
((unsigned long)&(addr) & 0x01ffffff)*32 + \
(bit)*4 + 0x02000000 + ((unsigned long)&(addr) & 0xfe000000) \
)))
#endif

540
src/ccsbcs.c Normal file
View File

@ -0,0 +1,540 @@
/*------------------------------------------------------------------------*/
/* Unicode - Local code bidirectional converter (C)ChaN, 2009 */
/* (SBCS code pages) */
/*------------------------------------------------------------------------*/
/* 437 U.S. (OEM)
/ 720 Arabic (OEM)
/ 1256 Arabic (Windows)
/ 737 Greek (OEM)
/ 1253 Greek (Windows)
/ 1250 Central Europe (Windows)
/ 775 Baltic (OEM)
/ 1257 Baltic (Windows)
/ 850 Multilingual Latin 1 (OEM)
/ 852 Latin 2 (OEM)
/ 1252 Latin 1 (Windows)
/ 855 Cyrillic (OEM)
/ 1251 Cyrillic (Windows)
/ 866 Russian (OEM)
/ 857 Turkish (OEM)
/ 1254 Turkish (Windows)
/ 858 Multilingual Latin 1 + Euro (OEM)
/ 862 Hebrew (OEM)
/ 1255 Hebrew (Windows)
/ 874 Thai (OEM, Windows)
/ 1258 Vietnam (OEM, Windows)
*/
#include "../ff.h"
#if _CODE_PAGE == 437
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP437(0x80-0xFF) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7,
0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9,
0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4,
0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248,
0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 720
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP720(0x80-0xFF) to Unicode conversion table */
0x0000, 0x0000, 0x00E9, 0x00E2, 0x0000, 0x00E0, 0x0000, 0x00E7,
0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0000, 0x0000, 0x0000,
0x0000, 0x0651, 0x0652, 0x00F4, 0x00A4, 0x0640, 0x00FB, 0x00F9,
0x0621, 0x0622, 0x0623, 0x0624, 0x00A3, 0x0625, 0x0626, 0x0627,
0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F,
0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x0636, 0x0637, 0x0638, 0x0639, 0x063A, 0x0641, 0x00B5, 0x0642,
0x0643, 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064A,
0x2261, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, 0xO650, 0x2248,
0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 737
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP737(0x80-0xFF) to Unicode conversion table */
0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398,
0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0,
0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9,
0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8,
0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0,
0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x03C9, 0x03AC, 0x03AD, 0x03AE, 0x03CA, 0x03AF, 0x03CC, 0x03CD,
0x03CB, 0x03CE, 0x0386, 0x0388, 0x0389, 0x038A, 0x038C, 0x038E,
0x038F, 0x00B1, 0x2265, 0x2264, 0x03AA, 0x03AB, 0x00F7, 0x2248,
0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 775
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP775(0x80-0xFF) to Unicode conversion table */
0x0106, 0x00FC, 0x00E9, 0x0101, 0x00E4, 0x0123, 0x00E5, 0x0107,
0x0142, 0x0113, 0x0156, 0x0157, 0x012B, 0x0179, 0x00C4, 0x00C5,
0x00C9, 0x00E6, 0x00C6, 0x014D, 0x00F6, 0x0122, 0x00A2, 0x015A,
0x015B, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x00A4,
0x0100, 0x012A, 0x00F3, 0x017B, 0x017C, 0x017A, 0x201D, 0x00A6,
0x00A9, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x0141, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0104, 0x010C, 0x0118,
0x0116, 0x2563, 0x2551, 0x2557, 0x255D, 0x012E, 0x0160, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0172, 0x016A,
0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x017D,
0x0105, 0x010D, 0x0119, 0x0117, 0x012F, 0x0161, 0x0173, 0x016B,
0x017E, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x00D3, 0x00DF, 0x014C, 0x0143, 0x00F5, 0x00D5, 0x00B5, 0x0144,
0x0136, 0x0137, 0x013B, 0x013C, 0x0146, 0x0112, 0x0145, 0x2019,
0x00AD, 0x00B1, 0x201C, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x201E,
0x00B0, 0x2219, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 850
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP850(0x80-0xFF) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7,
0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9,
0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0,
0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3,
0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x0131, 0x00CD, 0x00CE,
0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580,
0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE,
0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4,
0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8,
0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 852
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP852(0x80-0xFF) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x016F, 0x0107, 0x00E7,
0x0142, 0x00EB, 0x0150, 0x0151, 0x00EE, 0x0179, 0x00C4, 0x0106,
0x00C9, 0x0139, 0x013A, 0x00F4, 0x00F6, 0x013D, 0x013E, 0x015A,
0x015B, 0x00D6, 0x00DC, 0x0164, 0x0165, 0x0141, 0x00D7, 0x010D,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x0104, 0x0105, 0x017D, 0x017E,
0x0118, 0x0119, 0x00AC, 0x017A, 0x010C, 0x015F, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x011A,
0x015E, 0x2563, 0x2551, 0x2557, 0x255D, 0x017B, 0x017C, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0102, 0x0103,
0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
0x0111, 0x0110, 0x010E, 0x00CB, 0x010F, 0x0147, 0x00CD, 0x00CE,
0x011B, 0x2518, 0x250C, 0x2588, 0x2584, 0x0162, 0x016E, 0x2580,
0x00D3, 0x00DF, 0x00D4, 0x0143, 0x0144, 0x0148, 0x0160, 0x0161,
0x0154, 0x00DA, 0x0155, 0x0170, 0x00FD, 0x00DD, 0x0163, 0x00B4,
0x00AD, 0x02DD, 0x02DB, 0x02C7, 0x02D8, 0x00A7, 0x00F7, 0x00B8,
0x00B0, 0x00A8, 0x02D9, 0x0171, 0x0158, 0x0159, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 855
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP855(0x80-0xFF) to Unicode conversion table */
0x0452, 0x0402, 0x0453, 0x0403, 0x0451, 0x0401, 0x0454, 0x0404,
0x0455, 0x0405, 0x0456, 0x0406, 0x0457, 0x0407, 0x0458, 0x0408,
0x0459, 0x0409, 0x045A, 0x040A, 0x045B, 0x040B, 0x045C, 0x040C,
0x045E, 0x040E, 0x045F, 0x040F, 0x044E, 0x042E, 0x044A, 0x042A,
0x0430, 0x0410, 0x0431, 0x0411, 0x0446, 0x0426, 0x0434, 0x0414,
0x0435, 0x0415, 0x0444, 0x0424, 0x0433, 0x0413, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0445, 0x0425, 0x0438,
0x0418, 0x2563, 0x2551, 0x2557, 0x255D, 0x0439, 0x0419, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x043A, 0x041A,
0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
0x043B, 0x041B, 0x043C, 0x041C, 0x043D, 0x041D, 0x043E, 0x041E,
0x043F, 0x2518, 0x250C, 0x2588, 0x2584, 0x041F, 0x044F, 0x2580,
0x042F, 0x0440, 0x0420, 0x0441, 0x0421, 0x0442, 0x0422, 0x0443,
0x0423, 0x0436, 0x0416, 0x0432, 0x0412, 0x044C, 0x042C, 0x2116,
0x00AD, 0x044B, 0x042B, 0x0437, 0x0417, 0x0448, 0x0428, 0x044D,
0x042D, 0x0449, 0x0429, 0x0447, 0x0427, 0x00A7, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 857
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP857(0x80-0xFF) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7,
0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0131, 0x00C4, 0x00C5,
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9,
0x0130, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x015E, 0x015F,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x011E, 0x011F,
0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0,
0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3,
0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
0x00BA, 0x00AA, 0x00CA, 0x00CB, 0x00C8, 0x0000, 0x00CD, 0x00CE,
0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580,
0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x0000,
0x00D7, 0x00DA, 0x00DB, 0x00D9, 0x00EC, 0x00FF, 0x00AF, 0x00B4,
0x00AD, 0x00B1, 0x0000, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8,
0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 858
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP858(0x80-0xFF) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7,
0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9,
0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0,
0x00A9, 0x2563, 0x2551, 0x2557, 0x2550, 0x00A2, 0x00A5, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3,
0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x20AC, 0x00CD, 0x00CE,
0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00C6, 0x00CC, 0x2580,
0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE,
0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4,
0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8,
0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 862
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP862(0x80-0xFF) to Unicode conversion table */
0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7,
0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7,
0x05E8, 0x05E9, 0x05EA, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4,
0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248,
0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 866
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP866(0x80-0xFF) to Unicode conversion table */
0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
0x0401, 0x0451, 0x0404, 0x0454, 0x0407, 0x0457, 0x040E, 0x045E,
0x00B0, 0x2219, 0x00B7, 0x221A, 0x2116, 0x00A4, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 874
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP874(0x80-0xFF) to Unicode conversion table */
0x20AC, 0x0000, 0x0000, 0x0000, 0x0000, 0x2026, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x00A0, 0x0E01, 0x0E02, 0x0E03, 0x0E04, 0x0E05, 0x0E06, 0x0E07,
0x0E08, 0x0E09, 0x0E0A, 0x0E0B, 0x0E0C, 0x0E0D, 0x0E0E, 0x0E0F,
0x0E10, 0x0E11, 0x0E12, 0x0E13, 0x0E14, 0x0E15, 0x0E16, 0x0E17,
0x0E18, 0x0E19, 0x0E1A, 0x0E1B, 0x0E1C, 0x0E1D, 0x0E1E, 0x0E1F,
0x0E20, 0x0E21, 0x0E22, 0x0E23, 0x0E24, 0x0E25, 0x0E26, 0x0E27,
0x0E28, 0x0E29, 0x0E2A, 0x0E2B, 0x0E2C, 0x0E2D, 0x0E2E, 0x0E2F,
0x0E30, 0x0E31, 0x0E32, 0x0E33, 0x0E34, 0x0E35, 0x0E36, 0x0E37,
0x0E38, 0x0E39, 0x0E3A, 0x0000, 0x0000, 0x0000, 0x0000, 0x0E3F,
0x0E40, 0x0E41, 0x0E42, 0x0E43, 0x0E44, 0x0E45, 0x0E46, 0x0E47,
0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x0E4D, 0x0E4E, 0x0E4F,
0x0E50, 0x0E51, 0x0E52, 0x0E53, 0x0E54, 0x0E55, 0x0E56, 0x0E57,
0x0E58, 0x0E59, 0x0E5A, 0x0E5B, 0x0000, 0x0000, 0x0000, 0x0000
};
#elif _CODE_PAGE == 1250
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP1250(0x80-0xFF) to Unicode conversion table */
0x20AC, 0x0000, 0x201A, 0x0000, 0x201E, 0x2026, 0x2020, 0x2021,
0x0000, 0x2030, 0x0160, 0x2039, 0x015A, 0x0164, 0x017D, 0x0179,
0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
0x0000, 0x2122, 0x0161, 0x203A, 0x015B, 0x0165, 0x017E, 0x017A,
0x00A0, 0x02C7, 0x02D8, 0x0141, 0x00A4, 0x0104, 0x00A6, 0x00A7,
0x00A8, 0x00A9, 0x015E, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x017B,
0x00B0, 0x00B1, 0x02DB, 0x0142, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
0x00B8, 0x0105, 0x015F, 0x00BB, 0x013D, 0x02DD, 0x013E, 0x017C,
0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7,
0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E,
0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7,
0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF,
0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7,
0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F,
0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7,
0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9
};
#elif _CODE_PAGE == 1251
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP1251(0x80-0xFF) to Unicode conversion table */
0x0402, 0x0403, 0x201A, 0x0453, 0x201E, 0x2026, 0x2020, 0x2021,
0x20AC, 0x2030, 0x0409, 0x2039, 0x040A, 0x040C, 0x040B, 0x040F,
0x0452, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
0x0000, 0x2111, 0x0459, 0x203A, 0x045A, 0x045C, 0x045B, 0x045F,
0x00A0, 0x040E, 0x045E, 0x0408, 0x00A4, 0x0490, 0x00A6, 0x00A7,
0x0401, 0x00A9, 0x0404, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x0407,
0x00B0, 0x00B1, 0x0406, 0x0456, 0x0491, 0x00B5, 0x00B6, 0x00B7,
0x0451, 0x2116, 0x0454, 0x00BB, 0x0458, 0x0405, 0x0455, 0x0457,
0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F
};
#elif _CODE_PAGE == 1252
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP1252(0x80-0xFF) to Unicode conversion table */
0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x0000, 0x017D, 0x0000,
0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0x0000, 0x017E, 0x0178,
0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF,
0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF
};
#elif _CODE_PAGE == 1253
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP1253(0x80-0xFF) to Unicode conversion table */
0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
0x0000, 0x2030, 0x0000, 0x2039, 0x000C, 0x0000, 0x0000, 0x0000,
0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
0x0000, 0x2122, 0x0000, 0x203A, 0x0000, 0x0000, 0x0000, 0x0000,
0x00A0, 0x0385, 0x0386, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
0x00A8, 0x00A9, 0x0000, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x2015,
0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x0384, 0x00B5, 0x00B6, 0x00B7,
0x0388, 0x0389, 0x038A, 0x00BB, 0x038C, 0x00BD, 0x038E, 0x038F,
0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397,
0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F,
0x03A0, 0x03A1, 0x0000, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7,
0x03A8, 0x03A9, 0x03AA, 0x03AD, 0x03AC, 0x03AD, 0x03AE, 0x03AF,
0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7,
0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7,
0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0x0000
};
#elif _CODE_PAGE == 1254
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP1254(0x80-0xFF) to Unicode conversion table */
0x20AC, 0x0000, 0x210A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x0000, 0x0000, 0x0000,
0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0x0000, 0x0000, 0x0178,
0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
0x011E, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
0x00D8, 0x00D9, 0x00DA, 0x00BD, 0x00DC, 0x0130, 0x015E, 0x00DF,
0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
0x011F, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0131, 0x015F, 0x00FF
};
#elif _CODE_PAGE == 1255
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP1255(0x80-0xFF) to Unicode conversion table */
0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
0x02C6, 0x2030, 0x0000, 0x2039, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
0x02DC, 0x2122, 0x0000, 0x203A, 0x0000, 0x0000, 0x0000, 0x0000,
0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
0x00A8, 0x00A9, 0x00D7, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
0x00B8, 0x00B9, 0x00F7, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
0x05B0, 0x05B1, 0x05B2, 0x05B3, 0x05B4, 0x05B5, 0x05B6, 0x05B7,
0x05B8, 0x05B9, 0x0000, 0x05BB, 0x05BC, 0x05BD, 0x05BE, 0x05BF,
0x05C0, 0x05C1, 0x05C2, 0x05C3, 0x05F0, 0x05F1, 0x05F2, 0x05F3,
0x05F4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7,
0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7,
0x05E8, 0x05E9, 0x05EA, 0x0000, 0x0000, 0x200E, 0x200F, 0x0000
};
#elif _CODE_PAGE == 1256
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP1256(0x80-0xFF) to Unicode conversion table */
0x20AC, 0x067E, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
0x02C6, 0x2030, 0x0679, 0x2039, 0x0152, 0x0686, 0x0698, 0x0688,
0x06AF, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
0x06A9, 0x2122, 0x0691, 0x203A, 0x0153, 0x200C, 0x200D, 0x06BA,
0x00A0, 0x060C, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
0x00A8, 0x00A9, 0x06BE, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
0x00B8, 0x00B9, 0x061B, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x061F,
0x06C1, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627,
0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F,
0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x00D7,
0x0637, 0x0638, 0x0639, 0x063A, 0x0640, 0x0640, 0x0642, 0x0643,
0x00E0, 0x0644, 0x00E2, 0x0645, 0x0646, 0x0647, 0x0648, 0x00E7,
0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x0649, 0x064A, 0x00EE, 0x00EF,
0x064B, 0x064C, 0x064D, 0x064E, 0x00F4, 0x064F, 0x0650, 0x00F7,
0x0651, 0x00F9, 0x0652, 0x00FB, 0x00FC, 0x200E, 0x200F, 0x06D2
}
#elif _CODE_PAGE == 1257
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP1257(0x80-0xFF) to Unicode conversion table */
0x20AC, 0x0000, 0x201A, 0x0000, 0x201E, 0x2026, 0x2020, 0x2021,
0x0000, 0x2030, 0x0000, 0x2039, 0x0000, 0x00A8, 0x02C7, 0x00B8,
0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
0x0000, 0x2122, 0x0000, 0x203A, 0x0000, 0x00AF, 0x02DB, 0x0000,
0x00A0, 0x0000, 0x00A2, 0x00A3, 0x00A4, 0x0000, 0x00A6, 0x00A7,
0x00D8, 0x00A9, 0x0156, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
0x00B8, 0x00B9, 0x0157, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00E6,
0x0104, 0x012E, 0x0100, 0x0106, 0x00C4, 0x00C5, 0x0118, 0x0112,
0x010C, 0x00C9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012A, 0x013B,
0x0160, 0x0143, 0x0145, 0x00D3, 0x014C, 0x00D5, 0x00D6, 0x00D7,
0x0172, 0x0141, 0x015A, 0x016A, 0x00DC, 0x017B, 0x017D, 0x00DF,
0x0105, 0x012F, 0x0101, 0x0107, 0x00E4, 0x00E5, 0x0119, 0x0113,
0x010D, 0x00E9, 0x017A, 0x0117, 0x0123, 0x0137, 0x012B, 0x013C,
0x0161, 0x0144, 0x0146, 0x00F3, 0x014D, 0x00F5, 0x00F6, 0x00F7,
0x0173, 0x014E, 0x015B, 0x016B, 0x00FC, 0x017C, 0x017E, 0x02D9
};
#elif _CODE_PAGE == 1258
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP1258(0x80-0xFF) to Unicode conversion table */
0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
0x02C6, 0x2030, 0x0000, 0x2039, 0x0152, 0x0000, 0x0000, 0x0000,
0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
0x02DC, 0x2122, 0x0000, 0x203A, 0x0153, 0x0000, 0x0000, 0x0178,
0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
0x00C0, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x0300, 0x00CD, 0x00CE, 0x00CF,
0x0110, 0x00D1, 0x0309, 0x00D3, 0x00D4, 0x01A0, 0x00D6, 0x00D7,
0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x01AF, 0x0303, 0x00DF,
0x00E0, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x0301, 0x00ED, 0x00EE, 0x00EF,
0x0111, 0x00F1, 0x0323, 0x00F3, 0x00F4, 0x01A1, 0x00F6, 0x00F7,
0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x01B0, 0x20AB, 0x00FF
};
#endif
#if !_TBLDEF || !_USE_LFN
#error This file is not needed in current configuration. Remove from the project.
#endif
WCHAR ff_convert ( /* Converted character, Returns zero on error */
WCHAR src, /* Character code to be converted */
UINT dir /* 0: Unicode to OEMCP, 1: OEMCP to Unicode */
)
{
WCHAR c;
if (src < 0x80) { /* ASCII */
c = src;
} else {
if (dir) { /* OEMCP to Unicode */
c = (src >= 0x100) ? 0 : Tbl[src - 0x80];
} else { /* Unicode to OEMCP */
for (c = 0; c < 0x80; c++) {
if (src == Tbl[c]) break;
}
c = (c + 0x80) & 0xFF;
}
}
return c;
}
WCHAR ff_wtoupper ( /* Upper converted character */
WCHAR chr /* Input character */
)
{
static const WCHAR tbl_lower[] = { 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0xA1, 0x00A2, 0x00A3, 0x00A5, 0x00AC, 0x00AF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0x0FF, 0x101, 0x103, 0x105, 0x107, 0x109, 0x10B, 0x10D, 0x10F, 0x111, 0x113, 0x115, 0x117, 0x119, 0x11B, 0x11D, 0x11F, 0x121, 0x123, 0x125, 0x127, 0x129, 0x12B, 0x12D, 0x12F, 0x131, 0x133, 0x135, 0x137, 0x13A, 0x13C, 0x13E, 0x140, 0x142, 0x144, 0x146, 0x148, 0x14B, 0x14D, 0x14F, 0x151, 0x153, 0x155, 0x157, 0x159, 0x15B, 0x15D, 0x15F, 0x161, 0x163, 0x165, 0x167, 0x169, 0x16B, 0x16D, 0x16F, 0x171, 0x173, 0x175, 0x177, 0x17A, 0x17C, 0x17E, 0x192, 0x3B1, 0x3B2, 0x3B3, 0x3B4, 0x3B5, 0x3B6, 0x3B7, 0x3B8, 0x3B9, 0x3BA, 0x3BB, 0x3BC, 0x3BD, 0x3BE, 0x3BF, 0x3C0, 0x3C1, 0x3C3, 0x3C4, 0x3C5, 0x3C6, 0x3C7, 0x3C8, 0x3C9, 0x3CA, 0x430, 0x431, 0x432, 0x433, 0x434, 0x435, 0x436, 0x437, 0x438, 0x439, 0x43A, 0x43B, 0x43C, 0x43D, 0x43E, 0x43F, 0x440, 0x441, 0x442, 0x443, 0x444, 0x445, 0x446, 0x447, 0x448, 0x449, 0x44A, 0x44B, 0x44C, 0x44D, 0x44E, 0x44F, 0x451, 0x452, 0x453, 0x454, 0x455, 0x456, 0x457, 0x458, 0x459, 0x45A, 0x45B, 0x45C, 0x45E, 0x45F, 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, 0x2178, 0x2179, 0x217A, 0x217B, 0x217C, 0x217D, 0x217E, 0x217F, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47, 0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F, 0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57, 0xFF58, 0xFF59, 0xFF5A, 0 };
static const WCHAR tbl_upper[] = { 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x21, 0xFFE0, 0xFFE1, 0xFFE5, 0xFFE2, 0xFFE3, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0x178, 0x100, 0x102, 0x104, 0x106, 0x108, 0x10A, 0x10C, 0x10E, 0x110, 0x112, 0x114, 0x116, 0x118, 0x11A, 0x11C, 0x11E, 0x120, 0x122, 0x124, 0x126, 0x128, 0x12A, 0x12C, 0x12E, 0x130, 0x132, 0x134, 0x136, 0x139, 0x13B, 0x13D, 0x13F, 0x141, 0x143, 0x145, 0x147, 0x14A, 0x14C, 0x14E, 0x150, 0x152, 0x154, 0x156, 0x158, 0x15A, 0x15C, 0x15E, 0x160, 0x162, 0x164, 0x166, 0x168, 0x16A, 0x16C, 0x16E, 0x170, 0x172, 0x174, 0x176, 0x179, 0x17B, 0x17D, 0x191, 0x391, 0x392, 0x393, 0x394, 0x395, 0x396, 0x397, 0x398, 0x399, 0x39A, 0x39B, 0x39C, 0x39D, 0x39E, 0x39F, 0x3A0, 0x3A1, 0x3A3, 0x3A4, 0x3A5, 0x3A6, 0x3A7, 0x3A8, 0x3A9, 0x3AA, 0x410, 0x411, 0x412, 0x413, 0x414, 0x415, 0x416, 0x417, 0x418, 0x419, 0x41A, 0x41B, 0x41C, 0x41D, 0x41E, 0x41F, 0x420, 0x421, 0x422, 0x423, 0x424, 0x425, 0x426, 0x427, 0x428, 0x429, 0x42A, 0x42B, 0x42C, 0x42D, 0x42E, 0x42F, 0x401, 0x402, 0x403, 0x404, 0x405, 0x406, 0x407, 0x408, 0x409, 0x40A, 0x40B, 0x40C, 0x40E, 0x40F, 0x2160, 0x2161, 0x2162, 0x2163, 0x2164, 0x2165, 0x2166, 0x2167, 0x2168, 0x2169, 0x216A, 0x216B, 0x216C, 0x216D, 0x216E, 0x216F, 0xFF21, 0xFF22, 0xFF23, 0xFF24, 0xFF25, 0xFF26, 0xFF27, 0xFF28, 0xFF29, 0xFF2A, 0xFF2B, 0xFF2C, 0xFF2D, 0xFF2E, 0xFF2F, 0xFF30, 0xFF31, 0xFF32, 0xFF33, 0xFF34, 0xFF35, 0xFF36, 0xFF37, 0xFF38, 0xFF39, 0xFF3A, 0 };
int i;
for (i = 0; tbl_lower[i] && chr != tbl_lower[i]; i++) ;
return tbl_lower[i] ? tbl_upper[i] : chr;
}

View File

@ -4,12 +4,18 @@
#include <arm/NXP/LPC17xx/LPC17xx.h>
#include "clock.h"
#include "bits.h"
uint32_t f_cpu;
uint32_t f_cpu=4000000;
uint16_t pll_mult = 1;
uint8_t pll_prediv = 1;
uint8_t cclk_div = 1;
void clock_disconnect() {
disconnectPLL0();
disablePLL0();
}
void clock_init() {
/* set flash access time to 5 clks (80<f<=100MHz) */
@ -25,16 +31,14 @@ void clock_init() {
-> FPGA freq = 11289473.7Hz
First, disable and disconnect PLL0.
*/
disconnectPLL0();
disablePLL0();
clock_disconnect();
/* PLL is disabled and disconnected. setup PCLK NOW as it cannot be changed
reliably with PLL0 connected.
see:
http://ics.nxp.com/support/documents/microcontrollers/pdf/errata.lpc1754.pdf
*/
LPC_SC->PCLKSEL1 = ( PCLK_CCLK(PCLK_TIMER3)
| PCLK_CCLK8(PCLK_UART3) );
/* continue with PLL0 setup:
enable the xtal oscillator and wait for it to become stable

View File

@ -49,6 +49,8 @@
#define PCLK_SYSCON (28)
#define PCLK_MC (30)
void clock_disconnect(void);
void clock_init(void);
void setFlashAccessTime(uint8_t clocks);

View File

@ -1,10 +1,18 @@
#ifndef _CONFIG_H
#define _CONFIG_H
#define SDCARD_DETECT (1)
#define SDCARD_WP (0)
#define SD_SUPPLY_VOLTAGE (1L<<21) /* 3.3V - 3.4V */
#define CONFIG_SD_BLOCKTRANSFER 1
#define CONFIG_SD_AUTO_RETRIES 10
#define CONFIG_SD_DATACRC 1
#define CONFIG_UART_NUM 3
#define CONFIG_CPU_FREQUENCY 90315789
#define CONFIG_UART_PCLKDIV 1
#define CONFIG_UART_TX_BUF_SHIFT 7
#define CONFIG_UART_BAUDRATE 115200
#define CONFIG_UART_TX_BUF_SHIFT 5
#define CONFIG_UART_BAUDRATE 921600
#define CONFIG_UART_DEADLOCKABLE
#endif

91
src/crc.S Normal file
View File

@ -0,0 +1,91 @@
/* CRC-7/CRC-16 (XModem) implementation for Cortex M3
*
* Written 2010 by Ingo Korb
*/
.syntax unified
.section .text
/* uint8_t crc7update(uint8_t crc, const uint8_t data) */
.global crc7update
.thumb_func
crc7update:
mov r2, #8 // number of bits to process
lsl r1, r1, #24 // pre-shift data byte to top of word
loop:
lsl r0, r0, #1 // shift CRC
lsls r1, r1, #1 // shift data byte (highest bit now in C)
bcc 0f // jump if bit was 0
eor r0, r0, #0x80 // invert top bit of CRC if not
0: tst r0, #0x80 // test top bit of CRC
beq 1f // skip if top bit is clear
eor r0, r0, #0x09 // apply polinomial
1: subs r2, r2, #1 // decrememt bit cointer
bne loop // loop for next bit
uxtb r0, r0 // clear top bits of result
bx lr // return
/* uint16_t crc_xmodem_block(uint16_t crc, uint8_t *data, uint32_t len) */
.global crc_xmodem_block
.thumb_func
crc_xmodem_block:
adr r12, crc_table // load address of crc table
blockloop:
ldrb.w r3, [r1], #1 // read data byte
eor r3, r3, r0, lsr #8 // EOR data byte
ldrh r3, [r12, r3, lsl #1] // load value from CRC table
eor r0, r3, r0, lsl #8 // update CRC
uxth r0, r0 // clear top bits of result
subs r2, r2, #1 // decrement length
bne blockloop // loop while length > 0
bx lr // return
/* uint16_t crc_xmodem_block(uint16_t crc, uint8_t *data, uint32_t len) */
.global crc_xmodem_update
.thumb_func
crc_xmodem_update:
adr r2, crc_table // load address of crc table
eor r1, r1, r0, lsr #8 // EOR data byte
ldrh r3, [r2, r1, lsl #1] // load value from CRC table
eor r0, r3, r0, lsl #8 // update CRC
uxth r0, r0 // clear top bits of result
bx lr // return
crc_table:
.short 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7
.short 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef
.short 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6
.short 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de
.short 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485
.short 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d
.short 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4
.short 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc
.short 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823
.short 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b
.short 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12
.short 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a
.short 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41
.short 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49
.short 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70
.short 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78
.short 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f
.short 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067
.short 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e
.short 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256
.short 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d
.short 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405
.short 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c
.short 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634
.short 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab
.short 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3
.short 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a
.short 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92
.short 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9
.short 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1
.short 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8
.short 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
.end

11
src/crc.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef CRC_H
#define CRC_H
uint8_t crc7update(uint8_t crc, uint8_t data);
uint16_t crc_xmodem_update(uint16_t crc, uint8_t data);
uint16_t crc_xmodem_block(uint16_t crc, const uint8_t *data, uint32_t length);
// AVR-libc compatibility
#define _crc_xmodem_update(crc,data) crc_xmodem_update(crc,data)
#endif

View File

@ -7,6 +7,8 @@
#define _READONLY 0 /* 1: Remove write functions */
#define _USE_IOCTL 1 /* 1: Use disk_ioctl fucntion */
#include <arm/NXP/LPC17xx/LPC17xx.h>
#include "integer.h"
@ -22,6 +24,26 @@ typedef enum {
RES_PARERR /* 4: Invalid Parameter */
} DRESULT;
/**
* struct diskinfo0_t - disk info data structure for page 0
* @validbytes : Number of valid bytes in this struct
* @maxpage : Highest diskinfo page supported
* @disktype : type of the disk (DISK_TYPE_* values)
* @sectorsize : sector size divided by 256
* @sectorcount: number of sectors on the disk
*
* This is the struct returned in the data buffer when disk_getinfo
* is called with page=0.
*/
typedef struct {
uint8_t validbytes;
uint8_t maxpage;
uint8_t disktype;
uint8_t sectorsize; /* divided by 256 */
uint32_t sectorcount; /* 2 TB should be enough... (512 byte sectors) */
} diskinfo0_t;
/*---------------------------------------*/
/* Prototypes for disk control functions */
@ -35,6 +57,20 @@ DRESULT disk_write (BYTE, const BYTE*, DWORD, BYTE);
#endif
DRESULT disk_ioctl (BYTE, BYTE, void*);
void disk_init(void);
/* Will be set to DISK_ERROR if any access on the card fails */
enum diskstates { DISK_CHANGED = 0, DISK_REMOVED, DISK_OK, DISK_ERROR };
extern volatile enum diskstates disk_state;
/* Disk type - part of the external API except for ATA2! */
#define DISK_TYPE_ATA 0
#define DISK_TYPE_ATA2 1
#define DISK_TYPE_SD 2
#define DISK_TYPE_DF 3
#define DISK_TYPE_NONE 7
/* Disk Status Bits (DSTATUS) */

View File

@ -87,7 +87,7 @@
#include "ff.h" /* FatFs configurations and declarations */
#include "diskio.h" /* Declarations of low level disk I/O functions */
#include "uart.h"
/*--------------------------------------------------------------------------
@ -319,7 +319,7 @@ void mem_cpy (void* dst, const void* src, UINT cnt) {
#if _WORD_ACCESS == 1
while (cnt >= sizeof(int)) {
*(int*)d = *(int*)s;
*((int*)d) = *((int*)s);
d += sizeof(int); s += sizeof(int);
cnt -= sizeof(int);
}
@ -1815,6 +1815,8 @@ FRESULT chk_mounted ( /* FR_OK(0): successful, !=0: any error occurred */
fs->fs_type = 0; /* Clear the file system object */
fs->drv = (BYTE)LD2PD(vol); /* Bind the logical drive and a physical drive */
stat = disk_initialize(fs->drv); /* Initialize low level disk I/O layer */
printf("disk_initialize status: %d\n", stat);
if (stat & STA_NOINIT) /* Check if the initialization succeeded */
return FR_NOT_READY; /* Failed to initialize due to no media or hard error */
#if _MAX_SS != 512 /* Get disk sector size (variable sector size cfg only) */

View File

@ -48,7 +48,7 @@
/* To enable f_forward function, set _USE_FORWARD to 1 and set _FS_TINY to 1. */
#define _USE_FASTSEEK 0 /* 0:Disable or 1:Enable */
#define _USE_FASTSEEK 1 /* 0:Disable or 1:Enable */
/* To enable fast seek feature, set _USE_FASTSEEK to 1. */
@ -57,7 +57,7 @@
/ Locale and Namespace Configurations
/----------------------------------------------------------------------------*/
#define _CODE_PAGE 932
#define _CODE_PAGE 1252
/* The _CODE_PAGE specifies the OEM code page to be used on the target system.
/ Incorrect setting of the code page can cause a file open failure.
/
@ -110,7 +110,7 @@
/ enable LFN feature and set _LFN_UNICODE to 1. */
#define _FS_RPATH 2 /* 0 to 2 */
#define _FS_RPATH 0 /* 0 to 2 */
/* The _FS_RPATH option configures relative path feature.
/
/ 0: Disable relative path feature and remove related functions.
@ -125,7 +125,7 @@
/ Physical Drive Configurations
/----------------------------------------------------------------------------*/
#define _VOLUMES 2
#define _VOLUMES 1
/* Number of volumes (logical drives) to be used. */

80
src/fileops.c Normal file
View File

@ -0,0 +1,80 @@
/* sd2snes - SD card based universal cartridge for the SNES
Copyright (C) 2009-2010 Maximilian Rehkopf <otakon@gmx.net>
AVR firmware portion
Inspired by and based on code from sd2iec, written by Ingo Korb et al.
See sdcard.c|h, config.h.
FAT file system access based on code by ChaN, Jim Brain, Ingo Korb,
see ff.c|h.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License only.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
fileops.c: simple file access functions
*/
#include "config.h"
#include "uart.h"
#include "ff.h"
#include "fileops.h"
/*WCHAR ff_convert(WCHAR w, UINT dir) {
return w;
}*/
void file_init() {
file_res=f_mount(0, &fatfs);
}
/*void file_open_by_filinfo(FILINFO* fno) {
file_res = l_openfilebycluster(&fatfs, &file_handle, (UCHAR*)"", fno->clust, fno->fsize);
}*/
void file_open(uint8_t* filename, BYTE flags) {
file_res = f_open(&file_handle, (TCHAR*)filename, flags);
}
void file_close() {
file_res = f_close(&file_handle);
}
UINT file_read() {
UINT bytes_read;
file_res = f_read(&file_handle, file_buf, sizeof(file_buf), &bytes_read);
return bytes_read;
}
UINT file_write() {
UINT bytes_written;
file_res = f_write(&file_handle, file_buf, sizeof(file_buf), &bytes_written);
return bytes_written;
}
UINT file_readblock(void* buf, uint32_t addr, uint16_t size) {
UINT bytes_read;
file_res = f_lseek(&file_handle, addr);
if(file_handle.fptr != addr) {
return 0;
}
file_res = f_read(&file_handle, buf, size, &bytes_read);
return bytes_read;
}
UINT file_writeblock(void* buf, uint32_t addr, uint16_t size) {
UINT bytes_written;
file_res = f_lseek(&file_handle, addr);
if(file_res) return 0;
file_res = f_write(&file_handle, buf, size, &bytes_written);
return bytes_written;
}

45
src/fileops.h Normal file
View File

@ -0,0 +1,45 @@
/* sd2snes - SD card based universal cartridge for the SNES
Copyright (C) 2009-2010 Maximilian Rehkopf <otakon@gmx.net>
AVR firmware portion
Inspired by and based on code from sd2iec, written by Ingo Korb et al.
See sdcard.c|h, config.h.
FAT file system access based on code by ChaN, Jim Brain, Ingo Korb,
see ff.c|h.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License only.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
fileops.h: simple file access functions
*/
#ifndef FILEOPS_H
#define FILEOPS_H
#include "ff.h"
BYTE file_buf[4096];
FATFS fatfs;
FIL file_handle;
FRESULT file_res;
uint8_t file_lfn[256];
void file_init(void);
void file_open(uint8_t* filename, BYTE flags);
void file_open_by_filinfo(FILINFO* fno);
void file_close(void);
UINT file_read(void);
UINT file_write(void);
UINT file_readblock(void* buf, uint32_t addr, uint16_t size);
UINT file_writeblock(void* buf, uint32_t addr, uint16_t size);
#endif

273
src/filetypes.c Normal file
View File

@ -0,0 +1,273 @@
/* sd2snes - SD card based universal cartridge for the SNES
Copyright (C) 2009-2010 Maximilian Rehkopf <otakon@gmx.net>
AVR firmware portion
Inspired by and based on code from sd2iec, written by Ingo Korb et al.
See sdcard.c|h, config.h.
FAT file system access based on code by ChaN, Jim Brain, Ingo Korb,
see ff.c|h.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License only.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
filetypes.c: directory scanning and file type detection
*/
#include <stdio.h>
#include <string.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include "config.h"
#include "uart.h"
#include "filetypes.h"
#include "ff.h"
#include "smc.h"
#include "fileops.h"
#include "crc16.h"
#include "memory.h"
#include "led.h"
uint16_t scan_flat(const char* path) {
DIR dir;
FRESULT res;
FILINFO fno;
fno.lfn = NULL;
res = f_opendir(&dir, (unsigned char*)path);
uint16_t numentries = 0;
if (res == FR_OK) {
for (;;) {
res = f_readdir(&dir, &fno);
if(res != FR_OK || fno.fname[0] == 0)break;
numentries++;
}
}
return numentries;
}
uint16_t scan_dir(char* path, char mkdb, uint32_t this_dir_tgt) {
DIR dir;
FILINFO fno;
FRESULT res;
uint8_t len;
unsigned char* fn;
static unsigned char depth = 0;
static uint16_t crc;
static uint32_t db_tgt;
static uint32_t next_subdir_tgt;
static uint32_t parent_tgt;
static uint32_t dir_end = 0;
static uint8_t was_empty = 0;
uint32_t dir_tgt;
uint16_t numentries;
uint32_t dirsize;
uint8_t pass = 0;
dir_tgt = this_dir_tgt;
if(depth==0) {
crc = 0;
db_tgt = SRAM_DB_ADDR+0x10;
dir_tgt = SRAM_DIR_ADDR;
next_subdir_tgt = SRAM_DIR_ADDR;
this_dir_tgt = SRAM_DIR_ADDR;
parent_tgt = 0;
dprintf("root dir @%lx\n", dir_tgt);
}
fno.lfn = file_lfn;
numentries=0;
for(pass = 0; pass < 2; pass++) {
if(pass) {
dirsize = 4*(numentries);
// dir_tgt_next = dir_tgt + dirsize + 4; // number of entries + end marker
next_subdir_tgt += dirsize + 4;
if(parent_tgt) next_subdir_tgt += 4;
if(next_subdir_tgt > dir_end) {
dir_end = next_subdir_tgt;
}
dprintf("path=%s depth=%d ptr=%lx entries=%d parent=%lx next subdir @%lx\n", path, depth, db_tgt, numentries, parent_tgt, next_subdir_tgt /*dir_tgt_next*/);
// _delay_ms(50);
if(mkdb) {
dprintf("d=%d Saving %lX to Address %lX [end]\n", depth, 0L, next_subdir_tgt - 4);
// _delay_ms(50);
sram_writelong(0L, next_subdir_tgt - 4);
}
}
res = f_opendir(&dir, (unsigned char*)path);
if (res == FR_OK) {
if(pass && parent_tgt && mkdb) {
// write backlink to parent dir
// switch to next bank if record does not fit in current bank
if((db_tgt&0xffff) > ((0x10000-(sizeof(next_subdir_tgt)+sizeof(len)+4))&0xffff)) {
dprintf("switch! old=%lx ", db_tgt);
db_tgt &= 0xffff0000;
db_tgt += 0x00010000;
dprintf("new=%lx\n", db_tgt);
}
sram_writelong((parent_tgt-SRAM_MENU_ADDR), db_tgt);
sram_writebyte(0, db_tgt+sizeof(next_subdir_tgt));
sram_writeblock("../\0", db_tgt+sizeof(next_subdir_tgt)+sizeof(len), 4);
sram_writelong((db_tgt-SRAM_MENU_ADDR)|((uint32_t)0x80<<24), dir_tgt);
db_tgt += sizeof(next_subdir_tgt)+sizeof(len)+4;
dir_tgt += 4;
}
len = strlen((char*)path);
for (;;) {
toggle_busy_led();
res = f_readdir(&dir, &fno);
if (res != FR_OK || fno.fname[0] == 0) {
if(pass) {
if(!numentries) was_empty=1;
}
break;
}
fn = *fno.lfn ? fno.lfn : fno.fname;
// dprintf("%s\n", fn);
// _delay_ms(100);
if (*fn == '.') continue;
if (fno.fattrib & AM_DIR) {
numentries++;
if(pass) {
path[len]='/';
strncpy(path+len+1, (char*)fn, sizeof(fs_path)-len);
depth++;
if(mkdb) {
uint16_t pathlen = strlen(path);
// write element pointer to current dir structure
dprintf("d=%d Saving %lX to Address %lX [dir]\n", depth, db_tgt, dir_tgt);
// _delay_ms(50);
sram_writelong((db_tgt-SRAM_MENU_ADDR)|((uint32_t)0x80<<24), dir_tgt);
// sram_writeblock((uint8_t*)&db_tgt, dir_tgt_save, sizeof(dir_tgt_save));
// save element:
// - path name
// - pointer to sub dir structure
if((db_tgt&0xffff) > ((0x10000-(sizeof(next_subdir_tgt) + sizeof(len) + pathlen + 2))&0xffff)) {
dprintf("switch! old=%lx ", db_tgt);
db_tgt &= 0xffff0000;
db_tgt += 0x00010000;
dprintf("new=%lx\n", db_tgt);
}
dprintf(" Saving dir descriptor to %lX, tgt=%lX, path=%s\n", db_tgt, next_subdir_tgt, path);
// _delay_ms(100);
sram_writelong((next_subdir_tgt-SRAM_MENU_ADDR), db_tgt);
sram_writebyte(len+1, db_tgt+sizeof(next_subdir_tgt));
sram_writeblock(path, db_tgt+sizeof(next_subdir_tgt)+sizeof(len), pathlen);
sram_writeblock("/\0", db_tgt + sizeof(next_subdir_tgt) + sizeof(len) + pathlen, 2);
// sram_writeblock((uint8_t*)&dir_tgt, db_tgt+256, sizeof(dir_tgt));
db_tgt += sizeof(next_subdir_tgt) + sizeof(len) + pathlen + 2;
}
parent_tgt = this_dir_tgt;
scan_dir(path, mkdb, next_subdir_tgt);
dir_tgt += 4;
// if(was_empty)dir_tgt_next += 4;
was_empty = 0;
depth--;
path[len]=0;
}
} else {
SNES_FTYPE type = determine_filetype((char*)fn);
if(type != TYPE_UNKNOWN) {
numentries++;
if(pass) {
if(mkdb) {
snes_romprops_t romprops;
path[len]='/';
strncpy(path+len+1, (char*)fn, sizeof(fs_path)-len);
uint16_t pathlen = strlen(path);
switch(type) {
case TYPE_SMC:
// XXX file_open_by_filinfo(&fno);
// XXX if(file_res){
// XXX dprintf("ZOMG NOOOO %d\n", file_res);
// XXX _delay_ms(30);
// XXX }
// XXX smc_id(&romprops);
// XXX file_close();
// _delay_ms(30);
// write element pointer to current dir structure
// dprintf("d=%d Saving %lX to Address %lX [file]\n", depth, db_tgt, dir_tgt);
// _delay_ms(50);
if((db_tgt&0xffff) > ((0x10000-(sizeof(romprops) + sizeof(len) + pathlen + 1))&0xffff)) {
dprintf("switch! old=%lx ", db_tgt);
db_tgt &= 0xffff0000;
db_tgt += 0x00010000;
dprintf("new=%lx\n", db_tgt);
}
sram_writelong((db_tgt-SRAM_MENU_ADDR), dir_tgt);
// sram_writeblock((uint8_t*)&db_tgt, dir_tgt, sizeof(db_tgt));
dir_tgt += 4;
// save element:
// - SNES header information
// - file name
sram_writeblock((uint8_t*)&romprops, db_tgt, sizeof(romprops));
sram_writebyte(len+1, db_tgt + sizeof(romprops));
sram_writeblock(path, db_tgt + sizeof(romprops) + sizeof(len), pathlen + 1);
db_tgt += sizeof(romprops) + sizeof(len) + pathlen + 1;
break;
case TYPE_UNKNOWN:
default:
break;
}
path[len]=0;
// dprintf("%s ", path);
// _delay_ms(30);
}
} else {
unsigned char* sfn = fno.fname;
while(*sfn != 0) {
crc += crc16_update(crc, sfn++, 1);
}
}
}
// dprintf("%s/%s\n", path, fn);
// _delay_ms(50);
}
}
} else uart_putc(0x30+res);
}
// dprintf("%x\n", crc);
// _delay_ms(50);
sram_writelong(db_tgt, SRAM_DB_ADDR+4);
sram_writelong(dir_end, SRAM_DB_ADDR+8);
return crc;
}
SNES_FTYPE determine_filetype(char* filename) {
char* ext = strrchr(filename, '.');
if(ext == NULL)
return TYPE_UNKNOWN;
if(!strcasecmp_P(ext+1, PSTR("SMC"))) {
return TYPE_SMC;
}/* later
if(!strcasecmp_P(ext+1, PSTR("SRM"))) {
return TYPE_SRM;
}
if(!strcasecmp_P(ext+1, PSTR("SPC"))) {
return TYPE_SPC;
}*/
return TYPE_UNKNOWN;
}
FRESULT get_db_id(uint16_t* id) {
file_open((uint8_t*)"/sd2snes/sd2snes.db", FA_READ);
if(file_res == FR_OK) {
file_readblock(id, 0, 2);
/* XXX */// *id=0xdead;
file_close();
} else {
*id=0xdead;
}
return file_res;
}

45
src/filetypes.h Normal file
View File

@ -0,0 +1,45 @@
/* sd2snes - SD card based universal cartridge for the SNES
Copyright (C) 2009-2010 Maximilian Rehkopf <otakon@gmx.net>
AVR firmware portion
Inspired by and based on code from sd2iec, written by Ingo Korb et al.
See sdcard.c|h, config.h.
FAT file system access based on code by ChaN, Jim Brain, Ingo Korb,
see ff.c|h.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License only.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
filetypes.h: directory scanning and file type detection
*/
#ifndef FILETYPES_H
#define FILETYPES_H
#include "ff.h"
typedef enum {
TYPE_UNKNOWN = 0, /* 0 */
TYPE_SMC, /* 1 */
TYPE_SRM, /* 2 */
TYPE_SPC /* 3 */
} SNES_FTYPE;
char fs_path[256];
SNES_FTYPE determine_filetype(char* filename);
//uint32_t scan_fs();
uint16_t scan_dir(char* path, char mkdb, uint32_t this_subdir_tgt);
FRESULT get_db_id(uint16_t*);
#endif

View File

@ -7,7 +7,6 @@
reset init
flash write_image erase unlock obj/sd2snes.bin 0 bin
sleep 200
reset run
shutdown

4
src/init.gdb Normal file
View File

@ -0,0 +1,4 @@
target remote localhost:3333
add-symbol-file obj/sd2snes.elf 0x0
load obj/sd2snes.elf

24
src/led.c Normal file
View File

@ -0,0 +1,24 @@
/* ___DISCLAIMER___ */
#include <arm/NXP/LPC17xx/LPC17xx.h>
#include "bits.h"
#include "timer.h"
void rdyled(unsigned int state) {
BITBAND(LPC_GPIO2->FIODIR, 0) = state;
}
void readled(unsigned int state) {
BITBAND(LPC_GPIO2->FIODIR, 1) = state;
}
void led_clkout32(uint32_t val) {
while(1) {
rdyled(1);
delay_ms(400);
readled((val & BV(31))>>31);
rdyled(0);
val<<=1;
delay_ms(400);
}
}

10
src/led.h Normal file
View File

@ -0,0 +1,10 @@
/* ___DISCLAIMER___ */
#ifndef _LED_H
#define _LED_H
void readled(unsigned int state);
void rdyled(unsigned int state);
void led_clkout32(uint32_t val);
#endif

View File

@ -1,8 +0,0 @@
#ifndef _LPC_H
#define _LPC_H
#define BV(x) (1<<(x))
#define BITBAND(addr,bit) (*((volatile unsigned long *)(((unsigned long)&(addr)-0x20000000)*32 + bit*4 + 0x22000000)))
#endif

View File

@ -1,35 +1,67 @@
#include <arm/NXP/LPC17xx/LPC17xx.h>
#include "clock.h"
#include "uart.h"
#include "lpc.h"
#include "bits.h"
#include "power.h"
#include "timer.h"
#include "ff.h"
#include "diskio.h"
#include "spi.h"
#include "sdcard.h"
#include "fileops.h"
#define EMC0TOGGLE (3<<4)
#define MR0R (1<<1)
#define PCTIM3 (1<<23)
int i;
/* FIXME HACK */
volatile enum diskstates disk_state;
int main(void) {
LPC_GPIO2->FIODIR = BV(0) | BV(1) | BV(2);
LPC_GPIO1->FIODIR = 0;
uint32_t p1;
/* connect UART3 on P0[25:26] + SSP1 on P0[6:9] */
LPC_PINCON->PINSEL1=(0xf<<18);
LPC_PINCON->PINSEL0=BV(13) | BV(15) | BV(17) | BV(19);
clock_init();
clock_disconnect();
power_init();
timer_init();
uart_init();
delay_ms(10);
spi_init(SPI_SPEED_SLOW);
sd_init();
/* do this last because the peripheral init()s change PCLK dividers */
clock_init();
file_init();
printf("fileres: %d diskstate: %d\n", file_res, disk_state);
file_open((uint8_t*)"/mon.smc", FA_READ);
spi_set_speed(SPI_SPEED_FAST);
printf("fileres: %d diskstate: %d\n", file_res, disk_state);
uart_putc('S');
for(p1=0; p1<2048; p1++) {
file_read();
}
uart_putc('E');
uart_putcrlf();
printf("sizeof(struct FIL): %d\n", sizeof(file_handle));
uart_trace(file_buf, 0, 512);
/* setup timer (fpga clk) */
LPC_SC->PCONP |= PCTIM3; /* enable power */
LPC_TIM3->CTCR=0;
LPC_TIM3->EMR=EMC0TOGGLE;
LPC_PINCON->PINSEL0=(0x3<<20);
LPC_TIM3->MCR=MR0R;
LPC_TIM3->MR0=1;
LPC_TIM3->TCR=1;
uart_puts("hurr durr derpderpderp\n");
while (1) {
p1 = LPC_GPIO1->FIOPIN;
BITBAND(LPC_GPIO2->FIOPIN, 0) = (p1 & BV(29))>>29;
BITBAND(LPC_GPIO2->FIOPIN, 1) = (p1 & BV(29))>>29;
}
}

10
src/power.c Normal file
View File

@ -0,0 +1,10 @@
/* ___DISCLAIMER___ */
#include <arm/NXP/LPC17xx/LPC17xx.h>
#include "bits.h"
#include "power.h"
void power_init() {
LPC_SC->PCONP |= (BV(PCTIM3) | BV(PCUART3));
}

14
src/power.h Normal file
View File

@ -0,0 +1,14 @@
/* ___DISCLAIMER___ */
#ifndef _POWER_H
#define _POWER_H
#include "bits.h"
#define PCUART3 (25)
#define PCUART0 (3)
#define PCTIM3 (23)
void power_init(void);
#endif

290
src/printf.c Normal file
View File

@ -0,0 +1,290 @@
/* Small, noncompliant, not-full-featured printf implementation
*
*
* Copyright (c) 2010, Ingo Korb
* 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 Ingo Korb nor the
* names of the 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 <COPYRIGHT HOLDER> 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.
*
*
* FIXME: Selection of output function should be more flexible
*/
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include "config.h"
#include "uart.h"
#define outfunc(x) uart_putc(x)
#define FLAG_ZEROPAD 1
#define FLAG_LEFTADJ 2
#define FLAG_BLANK 4
#define FLAG_FORCESIGN 8
#define FLAG_WIDTH 16
#define FLAG_LONG 32
#define FLAG_UNSIGNED 64
#define FLAG_NEGATIVE 128
/* Digits used for conversion */
static const char hexdigits[] = "0123456789abcdef";
/* Temporary buffer used for numbers - just large enough for 32 bit in octal */
static char buffer[12];
/* Output string length */
static unsigned int outlength;
/* Output pointer */
static char *outptr;
static int maxlen;
/* printf */
static void outchar(char x) {
if (maxlen) {
maxlen--;
outfunc(x);
outlength++;
}
}
/* sprintf */
static void outstr(char x) {
if (maxlen) {
maxlen--;
*outptr++ = x;
outlength++;
}
}
static int internal_nprintf(void (*output_function)(char c), const char *fmt, va_list ap) {
unsigned int width;
unsigned int flags;
unsigned int base = 0;
char *ptr = NULL;
outlength = 0;
while (*fmt) {
while (1) {
if (*fmt == 0)
goto end;
if (*fmt == '%') {
fmt++;
if (*fmt != '%')
break;
}
output_function(*fmt++);
}
flags = 0;
width = 0;
/* read all flags */
do {
if (flags < FLAG_WIDTH) {
switch (*fmt) {
case '0':
flags |= FLAG_ZEROPAD;
continue;
case '-':
flags |= FLAG_LEFTADJ;
continue;
case ' ':
flags |= FLAG_BLANK;
continue;
case '+':
flags |= FLAG_FORCESIGN;
continue;
}
}
if (flags < FLAG_LONG) {
if (*fmt >= '0' && *fmt <= '9') {
unsigned char tmp = *fmt - '0';
width = 10*width + tmp;
flags |= FLAG_WIDTH;
continue;
}
if (*fmt == 'h')
continue;
if (*fmt == 'l') {
flags |= FLAG_LONG;
continue;
}
}
break;
} while (*fmt++);
/* Strings */
if (*fmt == 'c' || *fmt == 's') {
switch (*fmt) {
case 'c':
buffer[0] = va_arg(ap, int);
ptr = buffer;
break;
case 's':
ptr = va_arg(ap, char *);
break;
}
goto output;
}
/* Numbers */
switch (*fmt) {
case 'u':
flags |= FLAG_UNSIGNED;
case 'd':
base = 10;
break;
case 'o':
base = 8;
flags |= FLAG_UNSIGNED;
break;
case 'p': // pointer
output_function('0');
output_function('x');
width -= 2;
case 'x':
base = 16;
flags |= FLAG_UNSIGNED;
break;
}
unsigned int num;
if (!(flags & FLAG_UNSIGNED)) {
int tmp = va_arg(ap, int);
if (tmp < 0) {
num = -tmp;
flags |= FLAG_NEGATIVE;
} else
num = tmp;
} else {
num = va_arg(ap, unsigned int);
}
/* Convert number into buffer */
ptr = buffer + sizeof(buffer);
*--ptr = 0;
do {
*--ptr = hexdigits[num % base];
num /= base;
} while (num != 0);
/* Sign */
if (flags & FLAG_NEGATIVE) {
output_function('-');
width--;
} else if (flags & FLAG_FORCESIGN) {
output_function('+');
width--;
} else if (flags & FLAG_BLANK) {
output_function(' ');
width--;
}
output:
/* left padding */
if ((flags & FLAG_WIDTH) && !(flags & FLAG_LEFTADJ)) {
while (strlen(ptr) < width) {
if (flags & FLAG_ZEROPAD)
output_function('0');
else
output_function(' ');
width--;
}
}
/* data */
while (*ptr) {
output_function(*ptr++);
if (width)
width--;
}
/* right padding */
if (flags & FLAG_WIDTH) {
while (width) {
output_function(' ');
width--;
}
}
fmt++;
}
end:
return outlength;
}
int printf(const char *format, ...) {
va_list ap;
int res;
maxlen = -1;
va_start(ap, format);
res = internal_nprintf(outchar, format, ap);
va_end(ap);
return res;
}
int snprintf(char *str, size_t size, const char *format, ...) {
va_list ap;
int res;
maxlen = size;
outptr = str;
va_start(ap, format);
res = internal_nprintf(outstr, format, ap);
va_end(ap);
if (res < size)
str[res] = 0;
return res;
}
/* Required for gcc compatibility */
int puts(const char *str) {
uart_puts(str);
uart_putc('\n');
return 0;
}
#undef putchar
int putchar(int c) {
uart_putc(c);
return 0;
}

54
src/rtc.c Normal file
View File

@ -0,0 +1,54 @@
#include <arm/NXP/LPC17xx/LPC17xx.h>
#include <arm/bits.h>
#include "config.h"
#include "rtc.h"
rtcstate_t rtc_state;
#define CLKEN 0
#define CTCRST 1
void rtc_init(void) {
if (LPC_RTC->CCR & BV(CLKEN)) {
rtc_state = RTC_OK;
} else {
rtc_state = RTC_INVALID;
}
}
void read_rtc(struct tm *time) {
do {
time->tm_sec = LPC_RTC->SEC;
time->tm_min = LPC_RTC->MIN;
time->tm_hour = LPC_RTC->HOUR;
time->tm_mday = LPC_RTC->DOM;
time->tm_mon = LPC_RTC->MONTH;
time->tm_year = LPC_RTC->YEAR - 1900;
time->tm_wday = LPC_RTC->DOW;
} while (time->tm_sec != LPC_RTC->SEC);
}
void set_rtc(struct tm *time) {
LPC_RTC->CCR = BV(CTCRST);
LPC_RTC->SEC = time->tm_sec;
LPC_RTC->MIN = time->tm_min;
LPC_RTC->HOUR = time->tm_hour;
LPC_RTC->DOM = time->tm_mday;
LPC_RTC->MONTH = time->tm_mon;
LPC_RTC->YEAR = time->tm_year + 1900;
LPC_RTC->DOW = time->tm_wday;
LPC_RTC->CCR = BV(CLKEN);
}
uint32_t get_fattime(void) {
struct tm time;
read_rtc(&time);
return ((uint32_t)time.tm_year-80) << 25 |
((uint32_t)time.tm_mon+1) << 21 |
((uint32_t)time.tm_mday) << 16 |
((uint32_t)time.tm_hour) << 11 |
((uint32_t)time.tm_min) << 5 |
((uint32_t)time.tm_sec) >> 1;
}

62
src/rtc.h Normal file
View File

@ -0,0 +1,62 @@
/* sd2iec - SD/MMC to Commodore serial bus interface/controller
Copyright (C) 2007-2010 Ingo Korb <ingo@akana.de>
Inspiration and low-level SD/MMC access based on code from MMC2IEC
by Lars Pontoppidan et al., see sdcard.c|h and config.h.
FAT filesystem access based on code from ChaN and Jim Brain, see ff.c|h.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License only.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
rtc.h: Definitions for RTC support
There is no rtc.c, the functions defined here are implemented by a
device-specific .c file, e.g. pcf8583.c.
*/
#ifndef RTC_H
#define RTC_H
#include <stdint.h>
typedef enum {
RTC_NOT_FOUND, /* No RTC present */
RTC_INVALID, /* RTC present, but contents invalid */
RTC_OK /* RTC present and working */
} rtcstate_t;
struct tm {
uint8_t tm_sec; // 0..59
uint8_t tm_min; // 0..59
uint8_t tm_hour; // 0..23
uint8_t tm_mday; // 1..[28..31]
uint8_t tm_mon; // 0..11
uint8_t tm_year; // since 1900, i.e. 2000 is 100
uint8_t tm_wday; // 0 to 6, sunday is 6
// A Unix struct tm has a few more fields we don't need in this application
};
extern rtcstate_t rtc_state;
void rtc_init(void);
/* Return current time in struct tm */
void read_rtc(struct tm *time);
/* Set time from struct tm */
void set_rtc(struct tm *time);
#endif

750
src/sdcard.c Normal file
View File

@ -0,0 +1,750 @@
/* sd2iec - SD/MMC to Commodore serial bus interface/controller
Copyright (C) 2007-2010 Ingo Korb <ingo@akana.de>
Inspiration and low-level SD/MMC access based on code from MMC2IEC
by Lars Pontoppidan et al., see sdcard.c|h and config.h.
FAT filesystem access based on code from ChaN and Jim Brain, see ff.c|h.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License only.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
sdcard.c: SD/MMC access routines
Extended, optimized and cleaned version of code from MMC2IEC,
original copyright header follows:
//
// Title : SD/MMC Card driver
// Author : Lars Pontoppidan, Aske Olsson, Pascal Dufour,
// Date : Jan. 2006
// Version : 0.42
// Target MCU : Atmel AVR Series
//
// CREDITS:
// This module is developed as part of a project at the technical univerisity of
// Denmark, DTU.
//
// DESCRIPTION:
// This SD card driver implements the fundamental communication with a SD card.
// The driver is confirmed working on 8 MHz and 14.7456 MHz AtMega32 and has
// been tested successfully with a large number of different SD and MMC cards.
//
// DISCLAIMER:
// The author is in no way responsible for any problems or damage caused by
// using this code. Use at your own risk.
//
// LICENSE:
// This code is distributed under the GNU Public License
// which can be found at http://www.gnu.org/licenses/gpl.txt
//
The exported functions in this file are weak-aliased to their corresponding
versions defined in diskio.h so when this file is the only diskio provider
compiled in they will be automatically used by the linker.
*/
#include <arm/NXP/LPC17xx/LPC17xx.h>
#include <arm/bits.h>
#include "config.h"
#include "crc.h"
#include "diskio.h"
#include "spi.h"
#include "timer.h"
#include "uart.h"
#include "sdcard.h"
// FIXME: Move, make configurable
static void set_sd_led(uint8_t state) {
BITBAND(LPC_GPIO2->FIODIR, 2) = state;
}
// FIXME: Move, add generic C or AVR ASM version
static uint32_t swap_word(uint32_t input) {
uint32_t result;
asm("rev %[result], %[input]" : [result] "=r" (result) : [input] "r" (input));
return result;
}
#ifdef CONFIG_TWINSD
# define MAX_CARDS 2
#else
# define MAX_CARDS 1
#endif
// SD/MMC commands
#define GO_IDLE_STATE 0
#define SEND_OP_COND 1
#define SWITCH_FUNC 6
#define SEND_IF_COND 8
#define SEND_CSD 9
#define SEND_CID 10
#define STOP_TRANSMISSION 12
#define SEND_STATUS 13
#define SET_BLOCKLEN 16
#define READ_SINGLE_BLOCK 17
#define READ_MULTIPLE_BLOCK 18
#define WRITE_BLOCK 24
#define WRITE_MULTIPLE_BLOCK 25
#define PROGRAM_CSD 27
#define SET_WRITE_PROT 28
#define CLR_WRITE_PROT 29
#define SEND_WRITE_PROT 30
#define ERASE_WR_BLK_STAR_ADDR 32
#define ERASE_WR_BLK_END_ADDR 33
#define ERASE 38
#define LOCK_UNLOCK 42
#define APP_CMD 55
#define GEN_CMD 56
#define READ_OCR 58
#define CRC_ON_OFF 59
// SD ACMDs
#define SD_STATUS 13
#define SD_SEND_NUM_WR_BLOCKS 22
#define SD_SET_WR_BLK_ERASE_COUNT 23
#define SD_SEND_OP_COND 41
#define SD_SET_CLR_CARD_DETECT 42
#define SD_SEND_SCR 51
// R1 status bits
#define STATUS_IN_IDLE 1
#define STATUS_ERASE_RESET 2
#define STATUS_ILLEGAL_COMMAND 4
#define STATUS_CRC_ERROR 8
#define STATUS_ERASE_SEQ_ERROR 16
#define STATUS_ADDRESS_ERROR 32
#define STATUS_PARAMETER_ERROR 64
/* Card types - cardtype == 0 is MMC */
#define CARD_SD (1<<0)
#define CARD_SDHC (1<<1)
static uint8_t cardtype[MAX_CARDS];
/**
* getbits - read value from bit buffer
* @buffer: pointer to the data buffer
* @start : index of the first bit in the value
* @bits : number of bits in the value
*
* This function returns a value from the memory region passed as
* buffer, starting with bit "start" and "bits" bit long. The buffer
* is assumed to be MSB first, passing 0 for start will read starting
* from the highest-value bit of the first byte of the buffer.
*/
static uint32_t getbits(void *buffer, uint16_t start, int8_t bits) {
uint8_t *buf = buffer;
uint32_t result = 0;
if ((start % 8) != 0) {
/* Unaligned start */
result += buf[start / 8] & (0xff >> (start % 8));
bits -= 8 - (start % 8);
start += 8 - (start % 8);
}
while (bits >= 8) {
result = (result << 8) + buf[start / 8];
start += 8;
bits -= 8;
}
if (bits > 0) {
result = result << bits;
result = result + (buf[start / 8] >> (8-bits));
} else if (bits < 0) {
/* Fraction of a single byte */
result = result >> -bits;
}
return result;
}
/**
* wait_for_response - waits for a response from the SD card
* @expected: expected data byte (0 for anything != 0)
*
* This function waits until reading from the SD card returns the
* byte in expected or until reading returns a non-zero byte if
* expected is 0. Returns false if the expected response wasn't
* received within 500ms or true if it was.
*/
static uint8_t wait_for_response(uint8_t expected) {
tick_t timeout = getticks() + HZ/2;
while (time_before(getticks(), timeout)) {
uint8_t byte = spi_rx_byte();
if (expected == 0 && byte != 0)
return 1;
if (expected != 0 && byte == expected)
return 1;
}
return 0;
}
static void deselectCard(uint8_t card) {
// Send 8 clock cycles
set_sd_led(0);
spi_rx_byte();
}
/**
* sendCommand - send a command to the SD card
* @card : card number to be accessed
* @command : command to be sent
* @parameter: parameter to be sent
* @deselect : Flags if the card should be deselected afterwards
*
* This function calculates the correct CRC7 for the command and
* parameter and transmits all of it to the SD card. If requested
* the card will be deselected afterwards.
*/
static int sendCommand(const uint8_t card,
const uint8_t command,
const uint32_t parameter,
const uint8_t deselect) {
union {
uint32_t l;
uint8_t c[4];
} long2char;
uint8_t i,crc,errorcount;
tick_t timeout;
long2char.l = parameter;
crc = crc7update(0 , 0x40+command);
crc = crc7update(crc, long2char.c[3]);
crc = crc7update(crc, long2char.c[2]);
crc = crc7update(crc, long2char.c[1]);
crc = crc7update(crc, long2char.c[0]);
crc = (crc << 1) | 1;
errorcount = 0;
while (errorcount < CONFIG_SD_AUTO_RETRIES) {
// Select card
set_sd_led(1);
#ifdef CONFIG_TWINSD
if (card == 0 && command == GO_IDLE_STATE)
/* Force both cards to SPI mode simultaneously */
SPI_SS_LOW(1);
#endif
// Transfer command
spi_tx_byte(0x40+command);
uint32_t tmp = swap_word(parameter);
spi_tx_block(&tmp, 4);
spi_tx_byte(crc);
// Wait for a valid response
timeout = getticks() + HZ/2;
do {
i = spi_rx_byte();
} while (i & 0x80 && time_before(getticks(), timeout));
#ifdef CONFIG_TWINSD
if (card == 0 && command == GO_IDLE_STATE)
SPI_SS_HIGH(1);
#endif
// Check for CRC error
// can't reliably retry unless deselect is allowed
if (deselect && (i & STATUS_CRC_ERROR)) {
uart_putc('x');
deselectCard(card);
errorcount++;
continue;
}
if (deselect) deselectCard(card);
break;
}
return i;
}
// Extended init sequence for SDHC support
static uint8_t extendedInit(const uint8_t card) {
uint8_t i;
uint32_t answer;
// Send CMD8: SEND_IF_COND
// 0b000110101010 == 2.7-3.6V supply, check pattern 0xAA
i = sendCommand(card, SEND_IF_COND, 0b000110101010, 0);
if (i > 1) {
// Card returned an error, ok (MMC or SD1.x) but not SDHC
deselectCard(card);
return 1;
}
// No error, continue SDHC initialization
spi_rx_block(&answer, 4);
answer = swap_word(answer);
deselectCard(card);
if (((answer >> 8) & 0x0f) != 0b0001) {
// Card didn't accept our voltage specification
return 0;
}
// Verify echo-back of check pattern
if ((answer & 0xff) != 0b10101010) {
// Check pattern mismatch, working but not SD2.0 compliant
// The specs say we should not use the card, but let's try anyway.
return 1;
}
return 1;
}
// SD common initialisation
static void sdInit(const uint8_t card) {
uint8_t i;
uint16_t counter;
printf("sdInit\n");
counter = 0xffff;
do {
// Prepare for ACMD, send CMD55: APP_CMD
i = sendCommand(card, APP_CMD, 0, 1);
if (i > 1) {
// Command not accepted, could be MMC
return;
}
// Send ACMD41: SD_SEND_OP_COND
// 1L<<30 == Host has High Capacity Support
i = sendCommand(card, SD_SEND_OP_COND, 1L<<30, 1);
// Repeat while card card accepts command but isn't ready
} while (i == 1 && --counter > 0);
// Ignore failures, there is at least one Sandisk MMC card
// that accepts CMD55, but not ACMD41.
if (i == 0)
/* We know that a card is SD if ACMD41 was accepted. */
cardtype[card] |= CARD_SD;
}
/* Detect changes of SD card 0 */
#ifdef SD_CHANGE_VECT
ISR(SD_CHANGE_VECT) {
if (SDCARD_DETECT)
disk_state = DISK_CHANGED;
else
disk_state = DISK_REMOVED;
}
#endif
#ifdef CONFIG_TWINSD
/* Detect changes of SD card 1 */
ISR(SD2_CHANGE_VECT) {
if (SD2_DETECT)
disk_state = DISK_CHANGED;
else
disk_state = DISK_REMOVED;
}
#endif
//
// Public functions
//
void sd_init(void) {
/*
SDCARD_DETECT_SETUP();
SDCARD_WP_SETUP();
SD_CHANGE_SETUP();
*/
#ifdef CONFIG_TWINSD
/* Initialize the control lines for card 2 */
SD2_SETUP();
SD2_CHANGE_SETUP();
#endif
}
void disk_init(void) __attribute__ ((weak, alias("sd_init")));
DSTATUS sd_status(BYTE drv) {
#ifdef CONFIG_TWINSD
if (drv != 0) {
if (SD2_DETECT) {
if (SD2_PIN & SD2_WP) {
return STA_PROTECT;
} else {
return RES_OK;
}
} else {
return STA_NOINIT|STA_NODISK;
}
} else
#endif
if (SDCARD_DETECT)
if (SDCARD_WP)
return STA_PROTECT;
else
return RES_OK;
else
return STA_NOINIT|STA_NODISK;
}
DSTATUS disk_status(BYTE drv) __attribute__ ((weak, alias("sd_status")));
/**
* sd_initialize - initialize SD card
* @drv : drive
*
* This function tries to initialize the selected SD card.
*/
DSTATUS sd_initialize(BYTE drv) {
uint8_t i;
uint16_t counter;
uint32_t answer;
if (drv >= MAX_CARDS)
return STA_NOINIT|STA_NODISK;
/* Don't bother initializing a card that isn't there */
if (sd_status(drv) & STA_NODISK)
return sd_status(drv);
/* JLB: Should be in sd_init, but some uIEC versions have
* IEC lines tied to SPI, so I moved it here to resolve the
* conflict.
*/
spi_init(SPI_SPEED_SLOW);
disk_state = DISK_ERROR;
cardtype[drv] = 0;
set_sd_led(0);
// Send 80 clks
for (counter=0; counter<1000; counter++) {
spi_tx_byte(0xff);
}
// Reset card
i = sendCommand(drv, GO_IDLE_STATE, 0, 1);
if (i != 1) {
return STA_NOINIT | STA_NODISK;
}
if (!extendedInit(drv)) {
return STA_NOINIT | STA_NODISK;
}
sdInit(drv);
counter = 0xffff;
// According to the spec READ_OCR should work at this point
// without retries. One of my Sandisk-cards thinks otherwise.
do {
// Send CMD58: READ_OCR
i = sendCommand(drv, READ_OCR, 0, 0);
if (i > 1)
deselectCard(drv);
} while (i > 1 && counter-- > 0);
if (counter > 0) {
spi_rx_block(&answer, 4);
answer = swap_word(answer);
// See if the card likes our supply voltage
if (!(answer & SD_SUPPLY_VOLTAGE)) {
// The code isn't set up to completely ignore the card,
// but at least report it as nonworking
deselectCard(drv);
return STA_NOINIT | STA_NODISK;
}
// See what card we've got
if (answer & 0x40000000) {
cardtype[drv] |= CARD_SDHC;
}
}
// Keep sending CMD1 (SEND_OP_COND) command until zero response
counter = 0xffff;
do {
i = sendCommand(drv, SEND_OP_COND, 1L<<30, 1);
counter--;
} while (i != 0 && counter > 0);
if (counter==0) {
return STA_NOINIT | STA_NODISK;
}
#ifdef CONFIG_SD_DATACRC
// Enable CRC checking
// The SD spec says that the host "should" send CRC_ON_OFF before ACMD_SEND_OP_COND.
// The MMC manual I have says that CRC_ON_OFF isn't allowed before SEND_OP_COND.
// Let's just hope that all SD cards work with this order. =(
i = sendCommand(drv, CRC_ON_OFF, 1, 1);
if (i > 1) {
return STA_NOINIT | STA_NODISK;
}
#endif
// Send MMC CMD16(SET_BLOCKLEN) to 512 bytes
i = sendCommand(drv, SET_BLOCKLEN, 512, 1);
if (i != 0) {
return STA_NOINIT | STA_NODISK;
}
// Thats it!
spi_set_speed(SPI_SPEED_FAST);
disk_state = DISK_OK;
return sd_status(drv);
}
DSTATUS disk_initialize(BYTE drv) __attribute__ ((weak, alias("sd_initialize")));
/**
* sd_read - reads sectors from the SD card to buffer
* @drv : drive
* @buffer: pointer to the buffer
* @sector: first sector to be read
* @count : number of sectors to be read
*
* This function reads count sectors from the SD card starting
* at sector to buffer. Returns RES_ERROR if an error occured or
* RES_OK if successful. Up to SD_AUTO_RETRIES will be made if
* the calculated data CRC does not match the one sent by the
* card. If there were errors during the command transmission
* disk_state will be set to DISK_ERROR and no retries are made.
*/
DRESULT sd_read(BYTE drv, BYTE *buffer, DWORD sector, BYTE count) {
uint8_t sec,res,errorcount;
uint16_t crc,recvcrc;
if (drv >= MAX_CARDS)
return RES_PARERR;
for (sec=0;sec<count;sec++) {
errorcount = 0;
while (errorcount < CONFIG_SD_AUTO_RETRIES) {
if (cardtype[drv] & CARD_SDHC)
res = sendCommand(drv, READ_SINGLE_BLOCK, sector+sec, 0);
else
res = sendCommand(drv, READ_SINGLE_BLOCK, (sector+sec) << 9, 0);
if (res != 0) {
set_sd_led(0);
disk_state = DISK_ERROR;
return RES_ERROR;
}
// Wait for data token
if (!wait_for_response(0xFE)) {
set_sd_led(0);
disk_state = DISK_ERROR;
return RES_ERROR;
}
// Get data
crc = 0;
#ifdef CONFIG_SD_BLOCKTRANSFER
/* Transfer data first, calculate CRC afterwards */
spi_rx_block(buffer, 512);
recvcrc = spi_rx_byte() << 8 | spi_rx_byte();
#ifdef CONFIG_SD_DATACRC
crc = crc_xmodem_block(0, buffer, 512);
#endif
#else
/* Interleave transfer/CRC calculation, AVR-specific */
// Initiate data exchange over SPI
SPDR = 0xff;
uint8_t tmp;
for (i=0; i<512; i++) {
// Wait until data has been received
loop_until_bit_is_set(SPSR, SPIF);
tmp = SPDR;
// Transmit the next byte while we store the current one
SPDR = 0xff;
*(buffer++) = tmp;
#ifdef CONFIG_SD_DATACRC
crc = _crc_xmodem_update(crc, tmp);
#endif
}
// Wait until the first CRC byte is received
loop_until_bit_is_set(SPSR, SPIF);
// Check CRC
recvcrc = (SPDR << 8) + spiTransferByte(0xff);
#endif
#ifdef CONFIG_SD_DATACRC
if (recvcrc != crc) {
uart_putc('X');
deselectCard(drv);
errorcount++;
continue;
}
#endif
break;
}
deselectCard(drv);
if (errorcount >= CONFIG_SD_AUTO_RETRIES) return RES_ERROR;
}
return RES_OK;
}
DRESULT disk_read(BYTE drv, BYTE *buffer, DWORD sector, BYTE count) __attribute__ ((weak, alias("sd_read")));
/**
* sd_write - writes sectors from buffer to the SD card
* @drv : drive
* @buffer: pointer to the buffer
* @sector: first sector to be written
* @count : number of sectors to be written
*
* This function writes count sectors from buffer to the SD card
* starting at sector. Returns RES_ERROR if an error occured,
* RES_WPRT if the card is currently write-protected or RES_OK
* if successful. Up to SD_AUTO_RETRIES will be made if the card
* signals a CRC error. If there were errors during the command
* transmission disk_state will be set to DISK_ERROR and no retries
* are made.
*/
DRESULT sd_write(BYTE drv, const BYTE *buffer, DWORD sector, BYTE count) {
uint8_t res,sec,errorcount,status;
uint16_t crc;
if (drv >= MAX_CARDS)
return RES_PARERR;
#ifdef CONFIG_TWINSD
if (drv != 0) {
if (SD2_PIN & SD2_WP)
return RES_WRPRT;
} else
#endif
if (SDCARD_WP) return RES_WRPRT;
for (sec=0;sec<count;sec++) {
errorcount = 0;
while (errorcount < CONFIG_SD_AUTO_RETRIES) {
if (cardtype[drv] & CARD_SDHC)
res = sendCommand(drv, WRITE_BLOCK, sector+sec, 0);
else
res = sendCommand(drv, WRITE_BLOCK, (sector+sec)<<9, 0);
if (res != 0) {
set_sd_led(0);
disk_state = DISK_ERROR;
return RES_ERROR;
}
// Send data token
spi_tx_byte(0xfe);
// Send data
spi_tx_block(buffer, 512);
#ifdef CONFIG_SD_DATACRC
crc = crc_xmodem_block(0, buffer, 512);
#else
crc = 0;
#endif
// Send CRC
spi_tx_byte(crc >> 8);
spi_tx_byte(crc & 0xff);
// Get and check status feedback
status = spi_rx_byte();
// Retry if neccessary
if ((status & 0x0F) != 0x05) {
uart_putc('X');
deselectCard(drv);
errorcount++;
continue;
}
// Wait for write finish
if (!wait_for_response(0)) {
set_sd_led(0);
disk_state = DISK_ERROR;
return RES_ERROR;
}
break;
}
deselectCard(drv);
if (errorcount >= CONFIG_SD_AUTO_RETRIES) {
if (!(status & STATUS_CRC_ERROR))
disk_state = DISK_ERROR;
return RES_ERROR;
}
}
return RES_OK;
}
DRESULT disk_write(BYTE drv, const BYTE *buffer, DWORD sector, BYTE count) __attribute__ ((weak, alias("sd_write")));
DRESULT sd_getinfo(BYTE drv, BYTE page, void *buffer) {
uint8_t buf[18];
uint32_t capacity;
if (drv >= MAX_CARDS)
return RES_NOTRDY;
if (sd_status(drv) & STA_NODISK)
return RES_NOTRDY;
if (page != 0)
return RES_ERROR;
/* Try to calculate the total number of sectors on the card */
/* FIXME: Write a generic data read function and merge with sd_read */
if (sendCommand(drv, SEND_CSD, 0, 0) != 0) {
deselectCard(drv);
return RES_ERROR;
}
/* Wait for data token */
if (!wait_for_response(0xfe)) {
deselectCard(drv);
return RES_ERROR;
}
spi_rx_block(buf, 18);
deselectCard(drv);
if (cardtype[drv] & CARD_SDHC) {
/* Special CSD for SDHC cards */
capacity = (1 + getbits(buf,127-69,22)) * 1024;
} else {
/* Assume that MMC-CSD 1.0/1.1/1.2 and SD-CSD 1.1 are the same... */
uint8_t exponent = 2 + getbits(buf, 127-49, 3);
capacity = 1 + getbits(buf, 127-73, 12);
exponent += getbits(buf, 127-83,4) - 9;
while (exponent--) capacity *= 2;
}
diskinfo0_t *di = buffer;
di->validbytes = sizeof(diskinfo0_t);
di->disktype = DISK_TYPE_SD;
di->sectorsize = 2;
di->sectorcount = capacity;
return RES_OK;
}
DRESULT disk_getinfo(BYTE drv, BYTE page, void *buffer) __attribute__ ((weak, alias("sd_getinfo")));

40
src/sdcard.h Normal file
View File

@ -0,0 +1,40 @@
/* sd2iec - SD/MMC to Commodore serial bus interface/controller
Copyright (C) 2007-2010 Ingo Korb <ingo@akana.de>
Inspiration and low-level SD/MMC access based on code from MMC2IEC
by Lars Pontoppidan et al., see sdcard.c|h and config.h.
FAT filesystem access based on code from ChaN and Jim Brain, see ff.c|h.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License only.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
sdcard.h: Definitions for the SD/MMC access routines
*/
#ifndef SDCARD_H
#define SDCARD_H
#include "diskio.h"
/* These functions are weak-aliased to disk_... */
void sd_init(void);
DSTATUS sd_status(BYTE drv);
DSTATUS sd_initialize(BYTE drv);
DRESULT sd_read(BYTE drv, BYTE *buffer, DWORD sector, BYTE count);
DRESULT sd_write(BYTE drv, const BYTE *buffer, DWORD sector, BYTE count);
DRESULT sd_getinfo(BYTE drv, BYTE page, void *buffer);
#endif

146
src/snes.c Normal file
View File

@ -0,0 +1,146 @@
/* sd2snes - SD card based universal cartridge for the SNES
Copyright (C) 2009-2010 Maximilian Rehkopf <otakon@gmx.net>
AVR firmware portion
Inspired by and based on code from sd2iec, written by Ingo Korb et al.
See sdcard.c|h, config.h.
FAT file system access based on code by ChaN, Jim Brain, Ingo Korb,
see ff.c|h.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License only.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
snes.c: SNES hardware control and monitoring
*/
#include <avr/io.h>
#include "avrcompat.h"
#include "config.h"
#include "uart.h"
#include "snes.h"
#include "memory.h"
#include "fileops.h"
#include "ff.h"
#include "led.h"
#include "smc.h"
uint8_t initloop=1;
uint32_t saveram_crc, saveram_crc_old;
void snes_init() {
DDRD |= _BV(PD5); // PD5 = RESET_DIR
DDRD |= _BV(PD6); // PD6 = RESET
snes_reset(1);
}
/*
* sets the SNES reset state.
*
* state: put SNES in reset state when 1, release when 0
*/
void snes_reset(int state) {
if(state) {
DDRD |= _BV(PD6); // /RESET pin -> out
PORTD &= ~_BV(PD6); // /RESET = 0
PORTD |= _BV(PD5); // RESET_DIR = 1;
} else {
PORTD &= ~_BV(PD5); // RESET_DIR = 0;
DDRD &= ~_BV(PD6); // /RESET pin -> in
PORTD |= _BV(PD6); // /RESET = pullup
}
}
/*
* gets the SNES reset state.
*
* returns: 1 when reset, 0 when not reset
*/
uint8_t get_snes_reset() {
// DDRD &= ~_BV(PD6); // /RESET pin -> in
// PORTD &= ~_BV(PD5); // RESET_DIR (external buffer) = 0
return !(PIND & _BV(PD6));
}
/*
* SD2SNES main loop.
* monitors SRAM changes and other things
*/
uint32_t diffcount = 0, samecount = 0, didnotsave = 0;
uint8_t sram_valid = 0;
void snes_main_loop() {
if(!romprops.ramsize_bytes)return;
if(initloop) {
saveram_crc_old = calc_sram_crc(SRAM_SAVE_ADDR, romprops.ramsize_bytes);
initloop=0;
}
saveram_crc = calc_sram_crc(SRAM_SAVE_ADDR, romprops.ramsize_bytes);
sram_valid = sram_reliable();
if(crc_valid && sram_valid) {
if(saveram_crc != saveram_crc_old) {
if(samecount) {
diffcount=1;
} else {
diffcount++;
didnotsave++;
}
samecount=0;
}
if(saveram_crc == saveram_crc_old) {
samecount++;
}
if(diffcount>=1 && samecount==5) {
uart_putc('U');
uart_puthexshort(saveram_crc);
uart_putcrlf();
set_busy_led(1);
save_sram(file_lfn, romprops.ramsize_bytes, SRAM_SAVE_ADDR);
set_busy_led(0);
didnotsave=0;
}
if(didnotsave>50) {
diffcount=0;
uart_putc('V');
set_busy_led(1);
save_sram(file_lfn, romprops.ramsize_bytes, SRAM_SAVE_ADDR);
didnotsave=0;
set_busy_led(0);
}
saveram_crc_old = saveram_crc;
}
dprintf("crc_valid=%d sram_valid=%d diffcount=%ld samecount=%ld, didnotsave=%ld\n", crc_valid, sram_valid, diffcount, samecount, didnotsave);
}
/*
* SD2SNES menu loop.
* monitors menu selection. return when selection was made.
*/
uint8_t menu_main_loop() {
uint8_t cmd = 0;
sram_writebyte(0, SRAM_CMD_ADDR);
while(!cmd) {
if(!get_snes_reset()) {
while(!sram_reliable());
cmd = sram_readbyte(SRAM_CMD_ADDR);
}
if(get_snes_reset()) {
cmd = 0;
}
}
return cmd;
}
void get_selected_name(uint8_t* fn) {
uint32_t addr = sram_readlong(SRAM_FD_ADDR);
dprintf("fd addr=%lX\n", addr);
sram_readblock(fn, addr+0x41+SRAM_MENU_ADDR, 256);
}

37
src/snes.h Normal file
View File

@ -0,0 +1,37 @@
/* sd2snes - SD card based universal cartridge for the SNES
Copyright (C) 2009-2010 Maximilian Rehkopf <otakon@gmx.net>
AVR firmware portion
Inspired by and based on code from sd2iec, written by Ingo Korb et al.
See sdcard.c|h, config.h.
FAT file system access based on code by ChaN, Jim Brain, Ingo Korb,
see ff.c|h.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License only.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
snes.h: SNES hardware control and monitoring
*/
#ifndef SNES_H
#define SNES_H
uint8_t crc_valid;
void snes_init(void);
void snes_reset(int state);
uint8_t get_snes_reset(void);
void snes_main_loop(void);
uint8_t menu_main_loop(void);
void get_selected_name(uint8_t* lfn);
#endif

202
src/spi.c Normal file
View File

@ -0,0 +1,202 @@
/* Sd2iec - SD/MMC to Commodore serial bus interface/controller
Copyright (C) 2007-2010 Ingo Korb <ingo@akana.de>
Inspiration and low-level SD/MMC access based on code from MMC2IEC
by Lars Pontoppidan et al., see sdcard.c|h and config.h.
FAT filesystem access based on code from ChaN and Jim Brain, see ff.c|h.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License only.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
spi.c: Low-level SPI routines
*/
#include <arm/NXP/LPC17xx/LPC17xx.h>
#include <arm/bits.h>
#include "config.h"
#include "spi.h"
#define SSP_TFE 0 // Transmit FIFO empty
#define SSP_TNF 1 // Transmit FIFO not full
#define SSP_RNE 2 // Receive FIFO not empty
#define SSP_RFF 3 // Receive FIFO full
#define SSP_BSY 4 // Busy
// FIXME: Move to config.h!
#define SSP_CLK_DIVISOR_FAST 4
#define SSP_CLK_DIVISOR_SLOW 250
#define SSP_REGS LPC_SSP1
#define SSP_PCLKREG PCLKSEL0
/* SSP0: PCLKSEL1
SSP1: PCLKSEL0 */
#define SSP_PCLKBIT 20
/* SSP0: 10
SSP1: 20 */
#define SSP_DMAID_TX 2
/* SSP0: 0
SSP1: 2 */
#define SSP_DMAID_RX 3
/* SSP0: 1
SSP1: 3 */
void spi_init(spi_speed_t speed) {
/* Set clock prescaler to 1:1 */
BITBAND(LPC_SC->SSP_PCLKREG, SSP_PCLKBIT) = 1;
/* configure data format - 8 bits, SPI, CPOL=0, CPHA=0, 1 clock per bit */
SSP_REGS->CR0 = (8-1);
/* set clock prescaler */
if (speed == SPI_SPEED_FAST) {
SSP_REGS->CPSR = SSP_CLK_DIVISOR_FAST;
} else {
SSP_REGS->CPSR = SSP_CLK_DIVISOR_SLOW;
}
/* Enable SSP */
SSP_REGS->CR1 = BV(1);
/* Enable DMA controller, little-endian mode */
BITBAND(LPC_SC->PCONP, 29) = 1;
LPC_GPDMA->DMACConfig = 1;
}
void spi_tx_byte(uint8_t data) {
/* Wait until TX fifo can accept data */
while (!BITBAND(SSP_REGS->SR, SSP_TNF)) ;
/* Send byte */
SSP_REGS->DR = data;
}
uint8_t spi_rx_byte(void) {
/* Wait until SSP is not busy */
while (BITBAND(SSP_REGS->SR, SSP_BSY)) ;
/* Clear RX fifo */
while (BITBAND(SSP_REGS->SR, SSP_RNE))
(void) SSP_REGS->DR;
/* Transmit a single dummy byte */
SSP_REGS->DR = 0xff;
/* Wait until answer has been received */
while (!BITBAND(SSP_REGS->SR, SSP_RNE)) ;
return SSP_REGS->DR;
}
void spi_tx_block(const void *ptr, unsigned int length) {
const uint8_t *data = (const uint8_t *)ptr;
while (length--) {
/* Wait until TX fifo can accept data */
while (!BITBAND(SSP_REGS->SR, SSP_TNF)) ;
SSP_REGS->DR = *data++;
}
}
void spi_rx_block(void *ptr, unsigned int length) {
uint8_t *data = (uint8_t *)ptr;
unsigned int txlen = length;
/* Wait until SSP is not busy */
while (BITBAND(SSP_REGS->SR, SSP_BSY)) ;
/* Clear RX fifo */
while (BITBAND(SSP_REGS->SR, SSP_RNE))
(void) SSP_REGS->DR;
if ((length & 3) != 0 || ((uint32_t)ptr & 3) != 0) {
/* Odd length or unaligned buffer */
while (length > 0) {
/* Wait until TX or RX FIFO are ready */
while (txlen > 0 && !BITBAND(SSP_REGS->SR, SSP_TNF) &&
!BITBAND(SSP_REGS->SR, SSP_RNE)) ;
/* Try to receive data */
while (length > 0 && BITBAND(SSP_REGS->SR, SSP_RNE)) {
*data++ = SSP_REGS->DR;
length--;
}
/* Send dummy data until TX full or RX ready */
while (txlen > 0 && BITBAND(SSP_REGS->SR, SSP_TNF) && !BITBAND(SSP_REGS->SR, SSP_RNE)) {
txlen--;
SSP_REGS->DR = 0xff;
}
}
} else {
/* Clear interrupt flags of DMA channels 0 */
LPC_GPDMA->DMACIntTCClear = BV(0);
LPC_GPDMA->DMACIntErrClr = BV(0);
/* Set up RX DMA channel */
LPC_GPDMACH0->DMACCSrcAddr = (uint32_t)&SSP_REGS->DR;
LPC_GPDMACH0->DMACCDestAddr = (uint32_t)ptr;
LPC_GPDMACH0->DMACCLLI = 0; // no linked list
LPC_GPDMACH0->DMACCControl = length
| (0 << 12) // source burst size 1 (FIXME: Check if larger possible/useful)
| (0 << 15) // destination burst size 1
| (0 << 18) // source transfer width 1 byte
| (2 << 21) // destination transfer width 4 bytes
| (0 << 26) // source address not incremented
| (1 << 27) // destination address incremented
;
LPC_GPDMACH0->DMACCConfig = 1 // enable channel
| (SSP_DMAID_RX << 1) // data source SSP RX
| (2 << 11) // transfer from peripheral to memory
;
/* Enable RX FIFO DMA */
SSP_REGS->DMACR = 1;
/* Write <length> bytes into TX FIFO */
// FIXME: Any value in doing this using DMA too?
while (txlen > 0) {
while (txlen > 0 && BITBAND(SSP_REGS->SR, SSP_TNF)) {
txlen--;
SSP_REGS->DR = 0xff;
}
}
/* Wait until DMA channel disables itself */
while (LPC_GPDMACH0->DMACCConfig & 1) ;
/* Disable RX FIFO DMA */
SSP_REGS->DMACR = 0;
}
}
void spi_set_speed(spi_speed_t speed) {
/* Wait until TX fifo is empty */
while (!BITBAND(SSP_REGS->SR, 0)) ;
/* Disable SSP (FIXME: Is this required?) */
SSP_REGS->CR1 = 0;
/* Change clock divisor */
if (speed == SPI_SPEED_FAST) {
SSP_REGS->CPSR = SSP_CLK_DIVISOR_FAST;
} else {
SSP_REGS->CPSR = SSP_CLK_DIVISOR_SLOW;
}
/* Enable SSP */
SSP_REGS->CR1 = BV(1);
}

53
src/spi.h Normal file
View File

@ -0,0 +1,53 @@
/* sd2iec - SD/MMC to Commodore serial bus interface/controller
Copyright (C) 2007-2010 Ingo Korb <ingo@akana.de>
Inspiration and low-level SD/MMC access based on code from MMC2IEC
by Lars Pontoppidan et al., see sdcard.c|h and config.h.
FAT filesystem access based on code from ChaN and Jim Brain, see ff.c|h.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License only.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
spi.h: Definitions for the low-level SPI routines
Based on original code by Lars Pontoppidan et al., see spi.c
for full copyright details.
*/
#ifndef SPI_H
#define SPI_H
/* Low speed 400kHz for init, fast speed <=20MHz (MMC limit) */
typedef enum { SPI_SPEED_FAST, SPI_SPEED_SLOW } spi_speed_t;
/* Initialize SPI interface */
void spi_init(spi_speed_t speed);
/* Transmit a single byte */
void spi_tx_byte(uint8_t data);
/* Transmit a data block */
void spi_tx_block(const void *data, unsigned int length);
/* Receive a single byte */
uint8_t spi_rx_byte(void);
/* Receive a data block */
void spi_rx_block(void *data, unsigned int length);
/* Switch speed of SPI interface */
void spi_set_speed(spi_speed_t speed);
#endif

69
src/timer.c Normal file
View File

@ -0,0 +1,69 @@
/* ___INGO___ */
#include <arm/NXP/LPC17xx/LPC17xx.h>
#include "bits.h"
#include "config.h"
#include "timer.h"
#include "clock.h"
/* bit definitions */
#define RITINT 0
#define RITEN 3
#define PCRIT 16
volatile tick_t ticks;
extern uint32_t f_cpu;
void __attribute__((weak,noinline)) SysTick_Hook(void) {
// Empty function for hooking the systick handler
}
/* Systick interrupt handler */
void SysTick_Handler(void) {
ticks++;
SysTick_Hook();
}
void timer_init(void) {
/* turn on power to RIT */
BITBAND(LPC_SC->PCONP, PCRIT) = 1;
/* clear RIT mask */
LPC_RIT->RIMASK = 0; //xffffffff;
/* PCLK = CCLK */
BITBAND(LPC_SC->PCLKSEL1, 26) = 1;
BITBAND(LPC_SC->PCLKSEL1, PCLK_TIMER3) = 1;
/* enable SysTick */
SysTick_Config(SysTick->CALIB & SysTick_CALIB_TENMS_Msk);
}
extern int testval;
void delay_us(unsigned int time) {
/* Prepare RIT */
LPC_RIT->RICOUNTER = 0;
LPC_RIT->RICOMPVAL = (CONFIG_CPU_FREQUENCY / 1000000) * time;
LPC_RIT->RICTRL = BV(RITEN) | BV(RITINT);
/* Wait until RIT signals an interrupt */
while (!(BITBAND(LPC_RIT->RICTRL, RITINT))) ;
/* Disable RIT */
LPC_RIT->RICTRL = 0;
}
void delay_ms(unsigned int time) {
/* Prepare RIT */
LPC_RIT->RICOUNTER = 0;
LPC_RIT->RICTRL = BV(RITEN) | BV(RITINT);
LPC_RIT->RICOMPVAL = (f_cpu / 1000) * time;
/* Wait until RIT signals an interrupt */
while (!(BITBAND(LPC_RIT->RICTRL, RITINT))) ;
/* Disable RIT */
LPC_RIT->RICTRL = 0;
}

50
src/timer.h Normal file
View File

@ -0,0 +1,50 @@
#ifndef TIMER_H
#define TIMER_H
#include <stdint.h>
typedef unsigned int tick_t;
extern volatile tick_t ticks;
#define HZ 100
/**
* getticks - return the current system tick count
*
* This inline function returns the current system tick count.
*/
static inline tick_t getticks(void) {
return ticks;
}
#define MS_TO_TICKS(x) (x/10)
/* Adapted from Linux 2.6 include/linux/jiffies.h:
*
* These inlines deal with timer wrapping correctly. You are
* strongly encouraged to use them
* 1. Because people otherwise forget
* 2. Because if the timer wrap changes in future you won't have to
* alter your driver code.
*
* time_after(a,b) returns true if the time a is after time b.
*
* Do this with "<0" and ">=0" to only test the sign of the result. A
* good compiler would generate better code (and a really good compiler
* wouldn't care). Gcc is currently neither.
* (">=0" refers to the time_after_eq macro which wasn't copied)
*/
#define time_after(a,b) \
((int)(b) - (int)(a) < 0)
#define time_before(a,b) time_after(b,a)
void timer_init(void);
/* delay for "time" microseconds - uses the RIT */
void delay_us(unsigned int time);
/* delay for "time" milliseconds - uses the RIT */
void delay_ms(unsigned int time);
#endif

View File

@ -5,9 +5,10 @@
*/
#include <arm/NXP/LPC17xx/LPC17xx.h>
#include <arm/bits.h>
#include "bits.h"
#include "config.h"
#include "uart.h"
#include "led.h"
/* A few symbols to make this code work for all four UARTs */
#if defined(CONFIG_UART_NUM) && CONFIG_UART_NUM == 0
@ -51,14 +52,14 @@ static uint8_t uart_lookupratio(float f_fr) {
750,769,778,786,800,818,833,846,857,
867,875,889,900,909,917,923,929,933};
uint8_t ratios[72]={0x01,0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18,
0x2f,0x17,0x2d,0x16,0x2b,0x15,0x3e,0x29,0x3d,
0x14,0x4f,0x3b,0x27,0x3a,0x4d,0x13,0x5e,0x4b,
0x38,0x5d,0x25,0x5c,0x37,0x49,0x5b,0x6d,0x7f,
0x12,0x8f,0x7d,0x6b,0x59,0x47,0x7c,0x35,0x8d,
0x58,0x7b,0x9e,0x23,0x9d,0x7a,0x57,0x8b,0xbf,
0x34,0xad,0x79,0xbe,0x45,0x9b,0x56,0xbd,0x67,
0xdf,0x78,0x89,0x9a,0xab,0xbc,0xcd,0xde,0xef};
uint8_t ratios[72]={0x10,0xf1,0xe1,0xd1,0xc1,0xb1,0xa1,0x91,0x81,
0xf2,0x71,0xd2,0x61,0xb2,0x51,0xe3,0x92,0xd3,
0x41,0xf4,0xb3,0x72,0xa3,0xd4,0x31,0xe5,0xb4,
0x83,0xd5,0x52,0xc5,0x73,0x94,0xb5,0xd6,0xf7,
0x21,0xf8,0xd7,0xb6,0x95,0x74,0xc7,0x53,0xd8,
0x85,0xb7,0xe9,0x32,0xd9,0xa7,0x75,0xb8,0xfb,
0x43,0xda,0x97,0xeb,0x54,0xb9,0x65,0xdb,0x76,
0xfd,0x87,0x98,0xa9,0xba,0xcb,0xdc,0xed,0xfe};
int fr = (f_fr-1)*1000;
int i=0, i_result=0;
@ -78,10 +79,10 @@ static uint8_t uart_lookupratio(float f_fr) {
}
static uint32_t baud2divisor(unsigned int baudrate) {
float f_ratio;
uint32_t int_ratio;
uint32_t error;
uint32_t dl=0;
float f_ratio;
float f_fr;
float f_dl;
float f_pclk = (float)CONFIG_CPU_FREQUENCY / CONFIG_UART_PCLKDIV;
@ -207,10 +208,11 @@ void uart_init(void) {
UART_REGS->DLL = div & 0xff;
UART_REGS->DLM = (div >> 8) & 0xff;
BITBAND(UART_REGS->LCR, 7) = 0;
if (div & 0xff0000) {
UART_REGS->FDR = (div >> 16) & 0xff;
}
BITBAND(UART_REGS->LCR, 7) = 0;
/* reset and enable FIFO */
UART_REGS->FCR = BV(0);