mk2 fw wip
This commit is contained in:
parent
96e57b4f76
commit
40248e61af
@ -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
14
src/bits.h
Normal 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
540
src/ccsbcs.c
Normal 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;
|
||||
}
|
||||
14
src/clock.c
14
src/clock.c
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
14
src/config.h
14
src/config.h
@ -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
91
src/crc.S
Normal 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
11
src/crc.h
Normal 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
|
||||
36
src/diskio.h
36
src/diskio.h
@ -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) */
|
||||
|
||||
6
src/ff.c
6
src/ff.c
@ -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) */
|
||||
|
||||
@ -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
80
src/fileops.c
Normal 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
45
src/fileops.h
Normal 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
273
src/filetypes.c
Normal 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
45
src/filetypes.h
Normal 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
|
||||
@ -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
4
src/init.gdb
Normal 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
24
src/led.c
Normal 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
10
src/led.h
Normal 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
|
||||
@ -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
|
||||
|
||||
46
src/main.c
46
src/main.c
@ -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
10
src/power.c
Normal 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
14
src/power.h
Normal 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
290
src/printf.c
Normal 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
54
src/rtc.c
Normal 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
62
src/rtc.h
Normal 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
750
src/sdcard.c
Normal 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
40
src/sdcard.h
Normal 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
146
src/snes.c
Normal 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
37
src/snes.h
Normal 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
202
src/spi.c
Normal 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
53
src/spi.h
Normal 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
69
src/timer.c
Normal 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
50
src/timer.h
Normal 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
|
||||
24
src/uart.c
24
src/uart.c
@ -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);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user