archive MK1 AVR source

This commit is contained in:
ikari
2010-09-06 23:51:48 +02:00
parent a6d66e7a8b
commit a9b84c3e0b
54 changed files with 1220 additions and 793 deletions

View File

@@ -1,14 +1,5 @@
# Hey Emacs, this is a -*- makefile -*-
# Define version number
MAJOR = 0
MINOR = 0
PATCHLEVEL = 1
FIX =
# Forces bootloader version to 0, comment out for release
#PRERELEASE =
#----------------------------------------------------------------------------
# WinAVR Makefile Template written by Eric B. Weddington, Joerg Wunsch, et al.
#
@@ -25,7 +16,7 @@ FIX =
# Carlos Lamas
#
#
# Extensively modified for sd2iec by Ingo Korb
# Extensively modified for sd2iec and later adapted for ARM by Ingo Korb
#
# To rebuild project do "make clean" then "make all".
#----------------------------------------------------------------------------
@@ -50,62 +41,22 @@ endif
# Include the configuration file
include $(CONFIG)
# Set MCU name and length of binary for bootloader
# WARNING: Fuse settings not tested!
MCU := $(CONFIG_MCU)
ifeq ($(MCU),atmega128)
BINARY_LENGTH = 0x1f000
# EFUSE = 0xff
# HFUSE = 0x91
# LFUSE = 0xaf
else ifeq ($(MCU),atmega1281)
BINARY_LENGTH = 0x1f000
BOOTLDRSIZE = 0x0800
EFUSE = 0xff
HFUSE = 0xd2
LFUSE = 0xfc
else ifeq ($(MCU),atmega2561)
BINARY_LENGTH = 0x3f000
EFUSE = 0xfd
HFUSE = 0x93
LFUSE = 0xef
else ifeq ($(MCU),atmega644)
BINARY_LENGTH = 0xf000
EFUSE = 0xfd
HFUSE = 0x91
# LFUSE = 0xef
LFUSE = 0xaf
else ifeq ($(MCU),atmega644p)
BINARY_LENGTH = 0xf000
EFUSE = 0xfd
HFUSE = 0x91
LFUSE = 0xef
else
.PHONY: nochip
nochip:
@echo '=============================================================='
@echo 'No known target chip specified.'
@echo
@echo 'Please edit the Makefile.'
@exit 1
endif
# Directory for all generated files
OBJDIR := obj-$(CONFIG_MCU:atmega%=m%)$(CONFIGSUFFIX)
OBJDIR := obj$(CONFIGSUFFIX)
# Output format. (can be srec, ihex, binary)
FORMAT = ihex
FORMAT = binary
# Linker script
LINKERSCRIPT = lpc1754.ld
# Target file name (without extension).
TARGET = $(OBJDIR)/sd2snes
# List C source files here. (C dependencies are automatically generated.)
SRC = main.c ff.c utils.c led.c diskio.c sdcard.c spi.c crc7.c snes.c fpga.c memory.c crc16.c fileops.c fpga_spi.c smc.c filetypes.c
ifeq ($(CONFIG_UART_DEBUG),y)
SRC += uart.c
endif
# List C source files here. (C dependencies are automatically generated.)
SRC = main.c
# List Assembler source files here.
# Make them always end in a capital .S. Files ending in a lowercase .s
@@ -114,19 +65,17 @@ endif
# 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 =
ASRC = startup.S
# Optimization level, can be [0, 1, 2, 3, s].
# 0 = turn off optimization. s = optimize for size.
# (Note: 3 is not always the best optimization level. See avr-libc FAQ.)
# Use s -mcall-prologues when you really need size...
#OPT = 2
OPT = s
#OPT = 3 -finline-functions
# Debugging format.
# Native formats for AVR-GCC's -g are dwarf-2 [default] or stabs.
# AVR Studio 4.10 requires dwarf-2.
# AVR [Extended] COFF format requires stabs, plus an avr-objcopy run.
DEBUG = dwarf-2
@@ -146,52 +95,33 @@ CSTANDARD = -std=gnu99
# Place -D or -U options here
CDEFS = -DF_CPU=$(CONFIG_MCU_FREQ)UL
CDEFS = #-DF_CPU=$(CONFIG_MCU_FREQ)UL
# Calculate bootloader version
ifdef PRERELEASE
BOOT_VERSION := 0
else
BOOT_VERSION := 0x$(MAJOR)$(MINOR)$(PATCHLEVEL)$(FIX)
endif
# Create a version number define
ifdef PATCHLEVEL
ifdef FIX
PROGRAMVERSION := $(MAJOR).$(MINOR).$(PATCHLEVEL).$(FIX)
else
PROGRAMVERSION := $(MAJOR).$(MINOR).$(PATCHLEVEL)
BOOT_VERSION := $(BOOT_VERSION)0
endif
else
PROGRAMVERSION := $(MAJOR).$(MINOR)
BOOT_VERSION := $(BOOT_VERSION)00
endif
ifdef PRERELEASE
PROGRAMVERSION := $(PROGRAMVERSION)$(PRERELEASE)
endif
LONGVERSION := -$(CONFIG_MCU:atmega%=m%)$(CONFIGSUFFIX)
CDEFS += -DVERSION=\"$(PROGRAMVERSION)\" -DLONGVERSION=\"$(LONGVERSION)\"
# Place -I options here
CINCS =
# CPU-specific flags
ifndef CPUFLAGS
CPUFLAGS := -mthumb -mcpu=cortex-m3
endif
ifndef ARCH
ARCH := arm-none-eabi
endif
# Define programs and commands.
# CC must be defined here to generate the correct CFLAGS
SHELL = sh
CC = avr-gcc
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
SIZE = avr-size
NM = avr-nm
AVRDUDE = avrdude
CC = $(ARCH)-gcc
OBJCOPY = $(ARCH)-objcopy
OBJDUMP = $(ARCH)-objdump
SIZE = $(ARCH)-size
NM = $(ARCH)-nm
REMOVE = rm -f
COPY = cp
WINSHELL = cmd
AWK = awk
#---------------- Compiler Options ----------------
@@ -204,34 +134,14 @@ WINSHELL = cmd
CFLAGS = -g$(DEBUG)
CFLAGS += $(CDEFS) $(CINCS)
CFLAGS += -O$(OPT)
CFLAGS += -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
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)
CFLAGS += -ffunction-sections -fdata-sections
#CFLAGS += -mcall-prologues
# these are needed for GCC 4.3.2, which is more aggressive at inlining
# gcc-4.2 knows one of those, but it tends to increase code size
ifeq ($(shell $(CC) --version|gawk -f gcctest.awk),YES)
CFLAGS += --param inline-call-cost=3
CFLAGS += -fno-inline-small-functions
CFLAGS += -fno-move-loop-invariants
CFLAGS += -fno-split-wide-types
# turn these on to keep the functions in the same order as in the source
# this is only useful if you're looking at disassembly
#CFLAGS += -fno-reorder-blocks
#CFLAGS += -fno-reorder-blocks-and-partition
#CFLAGS += -fno-reorder-functions
#CFLAGS += -fno-toplevel-reorder
endif
ifeq ($(CONFIG_STACK_TRACKING),y)
CFLAGS += -finstrument-functions
endif
#---------------- Assembler Options ----------------
@@ -241,50 +151,7 @@ endif
# for use in COFF files, additional information about filenames
# and function names needs to be present in the assembler source
# files -- see avr-libc docs [FIXME: not yet described there]
ASFLAGS = -Wa,-adhlns=$(OBJDIR)/$(<:.S=.lst),-gstabs -I$(OBJDIR)
#---------------- Library Options ----------------
# Minimalistic printf version
PRINTF_LIB_MIN = -Wl,-u,vfprintf -lprintf_min
# Floating point printf version (requires MATH_LIB = -lm below)
PRINTF_LIB_FLOAT = -Wl,-u,vfprintf -lprintf_flt
# If this is left blank, then it will use the Standard printf version.
PRINTF_LIB =
#PRINTF_LIB = $(PRINTF_LIB_MIN)
#PRINTF_LIB = $(PRINTF_LIB_FLOAT)
# Minimalistic scanf version
SCANF_LIB_MIN = -Wl,-u,vfscanf -lscanf_min
# Floating point + %[ scanf version (requires MATH_LIB = -lm below)
SCANF_LIB_FLOAT = -Wl,-u,vfscanf -lscanf_flt
# If this is left blank, then it will use the Standard scanf version.
SCANF_LIB =
#SCANF_LIB = $(SCANF_LIB_MIN)
#SCANF_LIB = $(SCANF_LIB_FLOAT)
MATH_LIB = -lm
#---------------- External Memory Options ----------------
# 64 KB of external RAM, starting after internal RAM (ATmega128!),
# used for variables (.data/.bss) and heap (malloc()).
#EXTMEMOPTS = -Wl,-Tdata=0x801100,--defsym=__heap_end=0x80ffff
# 64 KB of external RAM, starting after internal RAM (ATmega128!),
# only used for heap (malloc()).
#EXTMEMOPTS = -Wl,--defsym=__heap_start=0x801100,--defsym=__heap_end=0x80ffff
EXTMEMOPTS =
ASFLAGS = $(CPUFLAGS) -Wa,-adhlns=$(OBJDIR)/$(<:.S=.lst),-gstabs -I$(OBJDIR)
#---------------- Linker Options ----------------
@@ -292,105 +159,13 @@ EXTMEMOPTS =
# -Map: create map file
# --cref: add cross reference to map file
LDFLAGS = -Wl,-Map=$(TARGET).map,--cref
LDFLAGS += $(EXTMEMOPTS)
LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB)
LDFLAGS += -T$(LINKERSCRIPT)
LDFLAGS += -Wl,--gc-sections
ifeq ($(CONFIG_LINKER_RELAX),y)
LDFLAGS += -Wl,-O9,--relax
endif
#---------------- Programming Options (avrdude) ----------------
# Programming hardware: alf avr910 avrisp bascom bsd
# dt006 pavr picoweb pony-stk200 sp12 stk200 stk500 stk500v2
#
# Type: avrdude -c ?
# to get a full listing.
#
AVRDUDE_PROGRAMMER = dragon_isp
# com1 = serial port. Use lpt1 to connect to parallel port.
AVRDUDE_PORT = usb # programmer connected to serial device
AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex
# AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep
# Allow fuse overrides from the config file
ifdef CONFIG_EFUSE
EFUSE := CONFIG_EFUSE
endif
ifdef CONFIG_HFUSE
HFUSE := CONFIG_HFUSE
endif
ifdef CONFIG_LFUSE
LFUSE := CONFIG_LFUSE
endif
# Calculate command line arguments for fuses
AVRDUDE_WRITE_FUSES :=
ifdef EFUSE
AVRDUDE_WRITE_FUSES += -U efuse:w:$(EFUSE):m
endif
ifdef HFUSE
AVRDUDE_WRITE_FUSES += -U hfuse:w:$(HFUSE):m
endif
ifdef LFUSE
AVRDUDE_WRITE_FUSES += -U lfuse:w:$(LFUSE):m
endif
# Uncomment the following if you want avrdude's erase cycle counter.
# Note that this counter needs to be initialized first using -Yn,
# see avrdude manual.
AVRDUDE_ERASE_COUNTER = -y
# Uncomment the following if you do /not/ wish a verification to be
# performed after programming the device.
#AVRDUDE_NO_VERIFY = -V
# Increase verbosity level. Please use this when submitting bug
# reports about avrdude. See <http://savannah.nongnu.org/projects/avrdude>
# to submit bug reports.
#AVRDUDE_VERBOSE = -v -v
AVRDUDE_FLAGS = -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER)
AVRDUDE_FLAGS += $(AVRDUDE_NO_VERIFY)
AVRDUDE_FLAGS += $(AVRDUDE_VERBOSE)
AVRDUDE_FLAGS += $(AVRDUDE_ERASE_COUNTER)
#---------------- Debugging Options ----------------
# For simulavr only - target MCU frequency.
DEBUG_MFREQ = $(CONFIG_MCU_FREQ)
# Set the DEBUG_UI to either gdb or insight.
# DEBUG_UI = gdb
DEBUG_UI = insight
# Set the debugging back-end to either avarice, simulavr.
DEBUG_BACKEND = avarice
#DEBUG_BACKEND = simulavr
# GDB Init Filename.
GDBINIT_FILE = __avr_gdbinit
# When using avarice settings for the JTAG
JTAG_DEV = /dev/com1
# Debugging port used to communicate between GDB / avarice / simulavr.
DEBUG_PORT = 4242
# Debugging host used to communicate between GDB / avarice / simulavr, normally
# just set to localhost unless doing some sort of crazy debugging when
# avarice is running on a different computer.
DEBUG_HOST = localhost
#============================================================================
@@ -410,8 +185,8 @@ GENDEPFLAGS = -MMD -MP -MF .dep/$(@F).d
# Combine all necessary flags and optional flags.
# Add target processor to flags.
ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) $(GENDEPFLAGS)
ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS) $(CDEFS)
ALL_CFLAGS = -I. $(CFLAGS) $(GENDEPFLAGS)
ALL_ASFLAGS = -I. -x assembler-with-cpp $(ASFLAGS) $(CDEFS)
@@ -431,111 +206,38 @@ eep: $(TARGET).eep
lss: $(TARGET).lss
sym: $(TARGET).sym
# A little helper target for the maintainer =)
copy2card:
mount /mnt
cp $(TARGET).bin /mnt
umount /mnt
sync
# # A little helper target for the maintainer =)
# copy2card:
# cp $(TARGET).bin /mbed/hw_LPC1768.bin
# Doxygen output:
doxygen:
-rm -rf doxyinput
mkdir doxyinput
cp *.h *.c doxyinput
src2doxy.pl doxyinput/*.h doxyinput/*.c
doxygen doxygen.conf
program: bin
utils/lpcchksum $(TARGET).bin
openocd -f openocd-usb.cfg -f lpc1754.cfg -f flash.cfg
debug: bin
openocd -f openocd-usb.cfg -f lpc1754.cfg
# Display size of file.
HEXSIZE = $(SIZE) --target=$(FORMAT) $(TARGET).hex
ELFSIZE = $(SIZE) -A $(TARGET).elf
AVRMEM = avr-mem.sh $(TARGET).elf $(MCU)
# Program the device.
program: bin hex eep
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM)
# Set fuses of the device
fuses: $(CONFIG)
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FUSES)
# Generate avr-gdb config/init file which does the following:
# define the reset signal, load the target file, connect to target, and set
# a breakpoint at main().
gdb-config:
@$(REMOVE) $(GDBINIT_FILE)
@echo define reset >> $(GDBINIT_FILE)
@echo SIGNAL SIGHUP >> $(GDBINIT_FILE)
@echo end >> $(GDBINIT_FILE)
@echo file $(TARGET).elf >> $(GDBINIT_FILE)
@echo target remote $(DEBUG_HOST):$(DEBUG_PORT) >> $(GDBINIT_FILE)
ifeq ($(DEBUG_BACKEND),simulavr)
@echo load >> $(GDBINIT_FILE)
endif
@echo break main >> $(GDBINIT_FILE)
debug: gdb-config $(TARGET).elf
ifeq ($(DEBUG_BACKEND), avarice)
@echo Starting AVaRICE - Press enter when "waiting to connect" message displays.
@$(WINSHELL) /c start avarice --jtag $(JTAG_DEV) --erase --program --file \
$(TARGET).elf $(DEBUG_HOST):$(DEBUG_PORT)
@$(WINSHELL) /c pause
else
@$(WINSHELL) /c start simulavr --gdbserver --device $(MCU) --clock-freq \
$(DEBUG_MFREQ) --port $(DEBUG_PORT)
endif
@$(WINSHELL) /c start avr-$(DEBUG_UI) --command=$(GDBINIT_FILE)
# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.
COFFCONVERT=$(OBJCOPY) --debugging \
--change-section-address .data-0x800000 \
--change-section-address .bss-0x800000 \
--change-section-address .noinit-0x800000 \
--change-section-address .eeprom-0x810000
coff: $(TARGET).elf
$(COFFCONVERT) -O coff-avr $< $(TARGET).cof
extcoff: $(TARGET).elf
$(COFFCONVERT) -O coff-ext-avr $< $(TARGET).cof
# Generate autoconf.h from config
.PRECIOUS : $(OBJDIR)/autoconf.h
$(OBJDIR)/autoconf.h: $(CONFIG) | $(OBJDIR)
$(E) " CONF2H $(CONFIG)"
$(Q)gawk -f conf2h.awk $(CONFIG) > $(OBJDIR)/autoconf.h
$(Q)$(AWK) -f conf2h.awk $(CONFIG) > $(OBJDIR)/autoconf.h
# Create final output files (.hex, .eep) from ELF output file.
ifeq ($(CONFIG_BOOTLOADER),y)
# Create final output files from ELF output file.
$(OBJDIR)/%.bin: $(OBJDIR)/%.elf
$(E) " BIN $@"
$(Q)$(OBJCOPY) -O binary -R .eeprom $< $@
$(E) " CRCGEN $@"
-$(Q)crcgen-new $@ $(BINARY_LENGTH) $(CONFIG_BOOT_DEVID) $(BOOT_VERSION)
$(E) " COPY $(CONFIG_HARDWARE_NAME)-firmware-$(PROGRAMVERSION).bin"
$(Q)$(COPY) $@ $(OBJDIR)/$(CONFIG_HARDWARE_NAME)-firmware-$(PROGRAMVERSION).bin
else
$(OBJDIR)/%.bin: $(OBJDIR)/%.elf
$(E) " BIN $@"
$(Q)$(OBJCOPY) -O binary -R .eeprom $< $@
endif
$(Q)$(OBJCOPY) -O binary $< $@
$(OBJDIR)/%.hex: $(OBJDIR)/%.elf
$(E) " HEX $@"
$(Q)$(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@
$(OBJDIR)/%.eep: $(OBJDIR)/%.elf
-$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \
--change-section-lma .eeprom=0 -O $(FORMAT) $< $@
$(Q)$(OBJCOPY) -O $(FORMAT) $< $@
# Create extended listing file from ELF output file.
$(OBJDIR)/%.lss: $(OBJDIR)/%.elf
@@ -548,7 +250,6 @@ $(OBJDIR)/%.sym: $(OBJDIR)/%.elf
$(E)$(NM) -n $< > $@
# Link: create ELF output file from object files.
.SECONDARY : $(TARGET).elf
.PRECIOUS : $(OBJ)
@@ -589,8 +290,6 @@ clean_list :
$(E) " CLEAN"
$(Q)$(REMOVE) $(TARGET).hex
$(Q)$(REMOVE) $(TARGET).bin
$(Q)$(REMOVE) $(TARGET).eep
$(Q)$(REMOVE) $(TARGET).cof
$(Q)$(REMOVE) $(TARGET).elf
$(Q)$(REMOVE) $(TARGET).map
$(Q)$(REMOVE) $(TARGET).sym
@@ -602,18 +301,11 @@ clean_list :
$(Q)$(REMOVE) $(CSRC:.c=.s)
$(Q)$(REMOVE) $(CSRC:.c=.d)
$(Q)$(REMOVE) .dep/*
$(Q)$(REMOVE) -rf codedoc
$(Q)$(REMOVE) -rf doxyinput
-$(Q)rmdir $(OBJDIR)
# Include the dependency files.
-include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*)
# Manual dependency for the assembler module
# $(OBJDIR)/fastloader-ll.o: config.h $(OBJDIR)/autoconf.h
# Listing of phony targets.
.PHONY : all begin finish end sizebefore sizeafter gccversion \
build elf hex eep lss sym coff extcoff \
clean clean_list program debug gdb-config doxygen
.PHONY : all begin finish end sizebefore sizeafter \
build elf hex lss sym clean clean_list

View File

@@ -1,168 +0,0 @@
/* sd2snes - SD card based universal cartridge for the SNES
Copyright (C) 2009-2010 Maximilian Rehkopf <otakon@gmx.net>
This file was adapted from sd2iec, written by Ingo Korb, original
disclaimer follows:
*/
/* sd2iec - SD/MMC to Commodore serial bus interface/controller
Copyright (C) 2007-2009 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
avrcompat.h: Compatibility defines for multiple target chips
*/
#ifndef AVRCOMPAT_H
#define AVRCOMPAT_H
/* USART */
#if defined __AVR_ATmega644__ || defined __AVR_ATmega644P__ || defined __AVR_ATmega1281__ || defined __AVR_ATmega2561__
# ifdef USE_UART1
# define RXC RXC1
# define RXEN RXEN1
# define TXC TXC1
# define TXEN TXEN1
# define UBRRH UBRR1H
# define UBRRL UBRR1L
# define UCSRA UCSR1A
# define UCSRB UCSR1B
# define UCSRC UCSR1C
# define UCSZ0 UCSZ10
# define UCSZ1 UCSZ11
# define UDR UDR1
# define UDRIE UDRIE1
# define RXCIE RXCIE1
# define USART_UDRE_vect USART1_UDRE_vect
# define USART_RX_vect USART1_RX_vect
# else
/* Default is USART0 */
# define RXC RXC0
# define RXEN RXEN0
# define TXC TXC0
# define TXEN TXEN0
# define UBRRH UBRR0H
# define UBRRL UBRR0L
# define UCSRA UCSR0A
# define UCSRB UCSR0B
# define UCSRC UCSR0C
# define UCSZ0 UCSZ00
# define UCSZ1 UCSZ01
# define UDR UDR0
# define UDRIE UDRIE0
# define RXCIE RXCIE0
# define USART_UDRE_vect USART0_UDRE_vect
# define USART_RX_vect USART0_RX_vect
# endif
#elif defined __AVR_ATmega48__ || defined __AVR_ATmega88__ || defined __AVR_ATmega168__
/* These chips include the USART number in their register names, */
/* but not in the ISR name. */
# define RXC RXC0
# define RXEN RXEN0
# define TXC TXC0
# define TXEN TXEN0
# define UBRRH UBRR0H
# define UBRRL UBRR0L
# define UCSRA UCSR0A
# define UCSRB UCSR0B
# define UCSRC UCSR0C
# define UCSZ0 UCSZ00
# define UCSZ1 UCSZ01
# define UDR UDR0
# define UDRIE UDRIE0
#elif defined __AVR_ATmega32__
# define TIMER2_COMPA_vect TIMER2_COMP_vect
# define TCCR0B TCCR0
# define TCCR2A TCCR2
# define TCCR2B TCCR2
# define TIFR0 TIFR
# define TIMSK2 TIMSK
# define OCIE2A OCIE2
# define OCR2A OCR2
#elif defined __AVR_ATmega128__
# define UBRRH UBRR0H
# define UBRRL UBRR0L
# define UCSRA UCSR0A
# define UCSRB UCSR0B
# define UCSRC UCSR0C
# define UDR UDR0
# define USART_UDRE_vect USART0_UDRE_vect
# define TIMER2_COMPA_vect TIMER2_COMP_vect
# define TCCR0B TCCR0
# define TCCR2A TCCR2
# define TCCR2B TCCR2
# define TIFR0 TIFR
# define TIMSK1 TIMSK
# define TIMSK2 TIMSK
# define OCIE2A OCIE2
# define OCR2A OCR2
#else
# error Unknown chip! (USART)
#endif
/* SPI and I2C */
#if defined __AVR_ATmega32__ || defined __AVR_ATmega644__ || defined __AVR_ATmega644P__
# define SPI_PORT PORTB
# define SPI_DDR DDRB
# define SPI_SS _BV(PB4)
# define SPI_MOSI _BV(PB5)
# define SPI_MISO _BV(PB6)
# define SPI_SCK _BV(PB7)
# define HWI2C_PORT PORTC
# define HWI2C_SDA _BV(PC1)
# define HWI2C_SCL _BV(PC0)
#elif defined __AVR_ATmega128__ || defined __AVR_ATmega1281__ || defined __AVR_ATmega2561__
# define SPI_PORT PORTB
# define SPI_DDR DDRB
# define SPI_SS _BV(PB0)
# define SPI_SCK _BV(PB1)
# define SPI_MOSI _BV(PB2)
# define SPI_MISO _BV(PB3)
# define HWI2C_PORT PORTD
# define HWI2C_SDA _BV(PD1)
# define HWI2C_SCL _BV(PD0)
#elif defined __AVR_ATmega48__ || defined __AVR_ATmega88__ || defined __AVR_ATmega168__
# define SPI_PORT PORTB
# define SPI_DDR DDRB
# define SPI_SS _BV(PB2)
# define SPI_SCK _BV(PB5)
# define SPI_MOSI _BV(PB3)
# define SPI_MISO _BV(PB4)
# define HWI2C_PORT PORTC
# define HWI2C_SDA _BV(PC4)
# define HWI2C_SCL _BV(PC5)
#else
# error Unknown chip! (SPI/TWI)
#endif
#define SPI_MASK (SPI_SS|SPI_MOSI|SPI_MISO|SPI_SCK)
#endif /* AVRCOMPAT_H */

View File

@@ -1,47 +1 @@
# This may not look like it, but it's a -*- makefile -*-
# sd2snes - SD card based universal cartridge for the SNES
# Copyright (C) 2009-2010 Maximilian Rehkopf <otakon@gmx.net>
#
# This file was adapted from sd2iec, written by Ingo Korb.
# Original disclaimer follows:
#
# sd2iec - SD/MMC to Commodore serial bus interface/controller
# Copyright (C) 2007-2009 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, see tff.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
#
#
# This file is included in the main sd2iec Makefile and also parsed
# into autoconf.h.
CONFIG_MCU=atmega644
CONFIG_LINKER_RELAX=n
CONFIG_MCU_FREQ=12288000
CONFIG_BOOTLOADER=y
CONFIG_BOOT_DEVID=0x4e534453
CONFIG_UART_DEBUG=y
CONFIG_UART_BAUDRATE=384000
CONFIG_UART_BUF_SHIFT=7
CONFIG_HARDWARE_NAME=sd2snes
CONFIG_SD_AUTO_RETRIES=10
#CONFIG_SD_DATACRC=y
CONFIG_EEPROM_SIZE=512
CONFIG_EEPROM_OFFSET=512
CONFIG_MAX_PARTITIONS=1
#CONFIG_DEADLOCK_ME_HARDER=y
# empty config file

View File

@@ -1,119 +0,0 @@
/* sd2snes - SD card based universal cartridge for the SNES
Copyright (C) 2009-2010 Maximilian Rehkopf <otakon@gmx.net>
This file was adapted from sd2iec, written by Ingo Korb.
Original copyright header follows:
*/
/*
sd2iec - SD/MMC to Commodore serial bus interface/controller
Copyright (C) 2007-2009 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
config.h: User-configurable options to simplify hardware changes and/or
reduce the code/ram requirements of the code.
Based on MMC2IEC, original copyright header follows:
//
// Title : MMC2IEC - Configuration
// Author : Lars Pontoppidan
// Date : Jan. 2007
// Version : 0.7
// Target MCU : AtMega32(L) at 8 MHz
//
//
// 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
//
*/
#ifndef CONFIG_H
#define CONFIG_H
#include "autoconf.h"
# define HW_NAME "SD2IEC"
# define HAVE_SD
# define SDCARD_DETECT (!(PIND & _BV(PD2)))
# define SDCARD_DETECT_SETUP() do { DDRD &= ~_BV(PD2); PORTD |= _BV(PD2); } while(0)
# if defined __AVR_ATmega32__
# define SD_CHANGE_SETUP() do { MCUCR |= _BV(ISC00); GICR |= _BV(INT0); } while(0)
# elif defined __AVR_ATmega644__ || defined __AVR_ATmega644P__
# define SD_CHANGE_SETUP() do { EICRA |= _BV(ISC00); EIMSK |= _BV(INT0); } while(0)
# else
# error Unknown chip!
# endif
# define SD_CHANGE_VECT INT0_vect
# define SDCARD_WP (PINA & _BV(PA0))
# define SDCARD_WP_SETUP() do { DDRA &= ~ _BV(PA0); PORTA |= _BV(PA0); } while(0)
# define SD_CHANGE_ICR MCUCR
# define SD_SUPPLY_VOLTAGE (1L<<21)
# define DEVICE_SELECT (8+!(PINA & _BV(PA2))+2*!(PINA & _BV(PA3)))
# define DEVICE_SELECT_SETUP() do { \
DDRA &= ~(_BV(PA2)|_BV(PA3)); \
PORTA |= _BV(PA2)|_BV(PA3); \
} while (0)
# define BUSY_LED_SETDDR() DDRA |= _BV(PA0)
# define BUSY_LED_ON() PORTA &= ~_BV(PA0)
# define BUSY_LED_OFF() PORTA |= _BV(PA0)
# define DIRTY_LED_SETDDR() DDRA |= _BV(PA1)
# define DIRTY_LED_ON() PORTA &= ~_BV(PA1)
# define DIRTY_LED_OFF() PORTA |= _BV(PA1)
# define DIRTY_LED_PORT PORTA
# define DIRTY_LED_BIT() _BV(PA1)
# define AUX_LED_SETDDR() do {} while (0)
# define AUX_LED_ON() do {} while (0)
# define AUX_LED_OFF() do {} while (0)
# define BUTTON_PIN PINA
# define BUTTON_PORT PORTA
# define BUTTON_DDR DDRA
# define BUTTON_MASK (_BV(PA4)|_BV(PA5))
# define BUTTON_NEXT _BV(PA4)
# define BUTTON_PREV _BV(PA5)
/* An interrupt for detecting card changes implies hotplugging capability */
#if defined(SD_CHANGE_VECT) || defined (CF_CHANGE_VECT)
# define HAVE_HOTPLUG
#endif
/* Generate dummy functions for the BUSY LED if required */
#ifdef SINGLE_LED
# define BUSY_LED_SETDDR() do {} while(0)
# define BUSY_LED_ON() do {} while(0)
# define BUSY_LED_OFF() do {} while(0)
#endif
/* Create some temporary symbols so we can calculate the number of */
/* enabled storage devices. */
#ifdef HAVE_SD
# define TMP_SD 1
#endif
/* Remove the temporary symbols */
#undef TMP_SD
#endif

View File

@@ -1,51 +0,0 @@
/**
* \file stdout
* Functions and types for CRC checks.
*
* Generated on Tue Jun 30 23:02:59 2009,
* by pycrc v0.7.1, http://www.tty1.net/pycrc/
* using the configuration:
* Width = 16
* Poly = 0x8005
* XorIn = 0x0000
* ReflectIn = True
* XorOut = 0x0000
* ReflectOut = True
* Algorithm = bit-by-bit-fast
* Direct = True
*****************************************************************************/
#include <stdint.h>
#include "crc16.h"
/**
* Update the crc value with new data.
*
* \param crc The current crc value.
* \param data Pointer to a buffer of \a data_len bytes.
* \param data_len Number of bytes in the \a data buffer.
* \return The updated crc value.
*****************************************************************************/
crc_t crc16_update(crc_t crc, const unsigned char *data, size_t data_len)
{
unsigned int i;
uint8_t bit;
unsigned char c;
while (data_len--) {
c = *data++;
for (i = 0x01; i & 0xff; i <<= 1) {
bit = (crc & 0x8000 ? 1 : 0);
if (c & i) {
bit ^= 1;
}
crc <<= 1;
if (bit) {
crc ^= 0x8005;
}
}
crc &= 0xffff;
}
return crc & 0xffff;
}

View File

@@ -1,54 +0,0 @@
/**
* \file stdout
* Functions and types for CRC checks.
*
* Generated on Tue Jun 30 23:02:56 2009,
* by pycrc v0.7.1, http://www.tty1.net/pycrc/
* using the configuration:
* Width = 16
* Poly = 0x8005
* XorIn = 0x0000
* ReflectIn = True
* XorOut = 0x0000
* ReflectOut = True
* Algorithm = bit-by-bit-fast
* Direct = True
*****************************************************************************/
#ifndef __STDOUT__
#define __STDOUT__
#include <stdint.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* The definition of the used algorithm.
*****************************************************************************/
#define CRC_ALGO_BIT_BY_BIT_FAST 1
/**
* The type of the CRC values.
*
* This type must be big enough to contain at least 16 bits.
*****************************************************************************/
typedef uint16_t crc_t;
/**
* Update the crc value with new data.
*
* \param crc The current crc value.
* \param data Pointer to a buffer of \a data_len bytes.
* \param data_len Number of bytes in the \a data buffer.
* \return The updated crc value.
*****************************************************************************/
crc_t crc16_update(crc_t crc, const unsigned char *data, size_t data_len);
#ifdef __cplusplus
} /* closing brace for extern "C" */
#endif
#endif /* __STDOUT__ */

View File

@@ -1,74 +0,0 @@
/**
* \file stdout
* Functions and types for CRC checks.
*
* Generated on Tue Jun 30 21:35:13 2009,
* by pycrc v0.7.1, http://www.tty1.net/pycrc/
* using the configuration:
* Width = 32
* Poly = 0x04c11db7
* XorIn = 0xffffffff
* ReflectIn = True
* XorOut = 0xffffffff
* ReflectOut = True
* Algorithm = bit-by-bit-fast
* Direct = True
*****************************************************************************/
#include <stdint.h>
#include "crc32.h"
/**
* Reflect all bits of a \a data word of \a data_len bytes.
*
* \param data The data word to be reflected.
* \param data_len The width of \a data expressed in number of bits.
* \return The reflected data.
*****************************************************************************/
long crc_reflect(long data, size_t data_len)
{
unsigned int i;
long ret;
ret = data & 0x01;
for (i = 1; i < data_len; i++)
{
data >>= 1;
ret = (ret << 1) | (data & 0x01);
}
return ret;
}
/**
* Update the crc value with new data.
*
* \param crc The current crc value.
* \param data Pointer to a buffer of \a data_len bytes.
* \param data_len Number of bytes in the \a data buffer.
* \return The updated crc value.
*****************************************************************************/
crc_t crc_update(crc_t crc, const unsigned char *data, size_t data_len)
{
unsigned int i;
uint8_t bit;
unsigned char c;
while (data_len--) {
c = *data++;
for (i = 0x01; i & 0xff; i <<= 1) {
bit = ((crc & 0x80000000) ? 1 : 0);
if (c & i) {
bit ^= 1;
}
crc <<= 1;
if (bit) {
crc ^= 0x04c11db7;
}
}
crc &= 0xffffffff;
}
return crc & 0xffffffff;
}

View File

@@ -1,85 +0,0 @@
/**
* \file stdout
* Functions and types for CRC checks.
*
* Generated on Tue Jun 30 21:35:19 2009,
* by pycrc v0.7.1, http://www.tty1.net/pycrc/
* using the configuration:
* Width = 32
* Poly = 0x04c11db7
* XorIn = 0xffffffff
* ReflectIn = True
* XorOut = 0xffffffff
* ReflectOut = True
* Algorithm = bit-by-bit-fast
* Direct = True
*****************************************************************************/
#ifndef __STDOUT__
#define __STDOUT__
#include <stdint.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* The definition of the used algorithm.
*****************************************************************************/
#define CRC_ALGO_BIT_BY_BIT_FAST 1
/**
* The type of the CRC values.
*
* This type must be big enough to contain at least 32 bits.
*****************************************************************************/
typedef uint32_t crc_t;
/**
* Reflect all bits of a \a data word of \a data_len bytes.
*
* \param data The data word to be reflected.
* \param data_len The width of \a data expressed in number of bits.
* \return The reflected data.
*****************************************************************************/
long crc_reflect(long data, size_t data_len);
/**
* Calculate the initial crc value.
*
* \return The initial crc value.
*****************************************************************************/
static inline crc_t crc_init(void)
{
return 0xffffffff;
}
/**
* Update the crc value with new data.
*
* \param crc The current crc value.
* \param data Pointer to a buffer of \a data_len bytes.
* \param data_len Number of bytes in the \a data buffer.
* \return The updated crc value.
*****************************************************************************/
crc_t crc_update(crc_t crc, const unsigned char *data, size_t data_len);
/**
* Calculate the final crc value.
*
* \param crc The current crc value.
* \return The final crc value.
*****************************************************************************/
static inline crc_t crc_finalize(crc_t crc)
{
return crc_reflect(crc, 32) ^ 0xffffffff;
}
#ifdef __cplusplus
} /* closing brace for extern "C" */
#endif
#endif /* __STDOUT__ */

View File

@@ -1,107 +0,0 @@
/* This file is a modified version of the output of pycrc.
*
* Licensing terms of pycrc:
*
* Copyright (c) 2006-2007, Thomas Pircher <tehpeh@gmx.net>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*
* crc7.c: Calculate CRC7 for SD card commands
*
*/
/*
* Functions and types for CRC checks.
*
* Generated on Thu Nov 8 13:52:05 2007,
* by pycrc v0.6.3, http://www.tty1.net/pycrc/
* using the configuration:
* Width = 7
* Poly = 0x09
* XorIn = 0x00
* ReflectIn = False
* XorOut = 0x00
* ReflectOut = False
* Algorithm = bit-by-bit-fast
*/
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
/**
; MMC/SD CRC Polynom X^7 + X^3 + 1
crc7taba:
mov dptr,#CRC7_TABA ; (2)
clr c ; (1)
rrc a ; (1)
xrl a,crc7ta ; (1)
movc a,@a+dptr ; (2)
jnc crc7m ; (2)
xrl a,#00001001b ; (1)
crc7m: mov crc7ta,a ; (1)
ret ; (2) (LCALL=2)
*/
uint8_t crc7tab[128] = {
0x00,0x12,0x24,0x36,0x48,0x5a,0x6c,0x7e,
0x19,0x0b,0x3d,0x2f,0x51,0x43,0x75,0x67,
0x32,0x20,0x16,0x04,0x7a,0x68,0x5e,0x4c,
0x2b,0x39,0x0f,0x1d,0x63,0x71,0x47,0x55,
0x64,0x76,0x40,0x52,0x2c,0x3e,0x08,0x1a,
0x7d,0x6f,0x59,0x4b,0x35,0x27,0x11,0x03,
0x56,0x44,0x72,0x60,0x1e,0x0c,0x3a,0x28,
0x4f,0x5d,0x6b,0x79,0x07,0x15,0x23,0x31,
0x41,0x53,0x65,0x77,0x09,0x1b,0x2d,0x3f,
0x58,0x4a,0x7c,0x6e,0x10,0x02,0x34,0x26,
0x73,0x61,0x57,0x45,0x3b,0x29,0x1f,0x0d,
0x6a,0x78,0x4e,0x5c,0x22,0x30,0x06,0x14,
0x25,0x37,0x01,0x13,0x6d,0x7f,0x49,0x5b,
0x3c,0x2e,0x18,0x0a,0x74,0x66,0x50,0x42,
0x17,0x05,0x33,0x21,0x5f,0x4d,0x7b,0x69,
0x0e,0x1c,0x2a,0x38,0x46,0x54,0x62,0x70
};
uint8_t crc7update(uint8_t crc, const uint8_t data) {
uint8_t a = data;
uint8_t b = data & 1;
a = crc7tab[(a>>1) ^ crc];
a ^= ((b<<3)|(b));
crc = a;
return a;
}
/*uint8_t crc7update(uint8_t crc, const uint8_t data) {
uint8_t i;
bool bit;
uint8_t c;
c = data;
for (i = 0x80; i > 0; i >>= 1) {
bit = crc & 0x40;
if (c & i) {
bit = !bit;
}
crc <<= 1;
if (bit) {
crc ^= 0x09;
}
}
crc &= 0x7f;
return crc & 0x7f;
}*/

View File

@@ -1,33 +0,0 @@
/* sd2iec - SD/MMC to Commodore serial bus interface/controller
Copyright (C) 2007-2009 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
crc7.h: Definitions for CRC7 calculation routines
*/
#ifndef CRC7_H
#define CRC7_H
uint8_t crc7update(uint8_t crc, const uint8_t data);
#endif

View File

@@ -1,85 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <inttypes.h>
#include <string.h>
#define lo8(x) (x & 0xFF)
#define hi8(x) ((x >> 8) & 0xFF)
#define xhi8(x) ((x >> 16) & 0xff)
#define xxhi8(x) ((x >> 24) & 0xff)
unsigned short crc_ccitt_update (uint16_t crc, uint8_t data)
{
data ^= lo8 (crc);
data ^= data << 4;
return ((((uint16_t)data << 8) | hi8 (crc)) ^ (uint8_t)(data >> 4) ^ ((uint16_t)data << 3));
}
int main(int argc, char *argv[]) {
if (argc != 5) {
printf("Usage: crcgen <filename> <length> <signature> <version>\r\n");
return 1;
}
unsigned long length = strtol(argv[2],NULL,0);
unsigned long devid = strtol(argv[3],NULL,0);
unsigned long version = strtol(argv[4],NULL,0);
if (length > length+8) {
printf("Ha ha, very funny.\n");
return 1;
}
uint8_t *data = malloc(length+8);
if (!data) {
perror("malloc");
return 1;
}
memset(data, 0xff, length);
FILE *f;
f = fopen(argv[1], "rb+");
if (f == 0) {
printf("Unable to open file %s\r\n", argv[1]);
return 1;
}
fread(data, 1, length, f);
data[length-8] = lo8(devid);
data[length-7] = hi8(devid);
data[length-6] = xhi8(devid);
data[length-5] = xxhi8(devid);
data[length-4] = lo8(version);
data[length-3] = hi8(version);
unsigned long l;
unsigned short crc = 0xFFFF;
for (l=0; l < length-2; l++)
crc = crc_ccitt_update(crc, data[l]);
data[length-2] = lo8(crc);
data[length-1] = hi8(crc);
if (fseek(f, 0, SEEK_SET)) {
perror("fseek");
return 1;
}
if (fwrite(data, length, 1, f) != 1) {
perror("fwrite");
return 1;
}
fclose(f);
return 0;
}

View File

@@ -1,202 +0,0 @@
/* sd2snes - SD card based universal cartridge for the SNES
Copyright (C) 2009-2010 Maximilian Rehkopf <otakon@gmx.net>
This file was adapted from sd2iec, written by Ingo Korb.
Original copyright header follows:
*/
/* sd2iec - SD/MMC to Commodore serial bus interface/controller
Copyright (C) 2007-2009 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
diskio.c: Generic disk access routines and supporting stuff
*/
#include "config.h"
#include "diskio.h"
#include "sdcard.h"
volatile enum diskstates disk_state;
#ifdef NEED_DISKMUX
uint32_t drive_config;
/* This function calculates the default drive configuration. */
/* Its result is static after compilation, but doing this in */
/* C in less messy than doing it with the preprocessor. */
uint32_t get_default_driveconfig(void) {
uint32_t result = 0xffffffffL;
/* Order matters: Whatever is checked first will be last in the config */
#ifdef HAVE_DF
result = (result << 4) + (DISK_TYPE_DF << DRIVE_BITS) + 0;
#endif
#ifdef CONFIG_TWINSD
result = (result << 4) + (DISK_TYPE_SD << DRIVE_BITS) + 1;
#endif
#ifdef HAVE_SD
result = (result << 4) + (DISK_TYPE_SD << DRIVE_BITS) + 0;
#endif
#ifdef HAVE_ATA
result = (result << 4) + (DISK_TYPE_ATA << DRIVE_BITS) + 0;
#endif
return result;
}
void disk_init(void) {
#ifdef HAVE_SD
sd_init();
#endif
#ifdef HAVE_ATA
ata_init();
#endif
#ifdef HAVE_DF
df_init();
#endif
}
DSTATUS disk_status(BYTE drv) {
switch(drv >> DRIVE_BITS) {
#ifdef HAVE_DF
case DISK_TYPE_DF:
return df_status(drv & DRIVE_MASK);
#endif
#ifdef HAVE_ATA
case DISK_TYPE_ATA:
return ata_status(drv & DRIVE_MASK);
case DISK_TYPE_ATA2:
return ata_status((drv & DRIVE_MASK) + 2);
#endif
#ifdef HAVE_SD
case DISK_TYPE_SD:
return sd_status(drv & DRIVE_MASK);
#endif
default:
return STA_NOINIT|STA_NODISK;
}
}
DSTATUS disk_initialize(BYTE drv) {
switch(drv >> DRIVE_BITS) {
#ifdef HAVE_DF
case DISK_TYPE_DF:
return df_initialize(drv & DRIVE_MASK);
#endif
#ifdef HAVE_ATA
case DISK_TYPE_ATA:
return ata_initialize(drv & DRIVE_MASK);
case DISK_TYPE_ATA2:
return ata_initialize((drv & DRIVE_MASK) + 2);
#endif
#ifdef HAVE_SD
case DISK_TYPE_SD:
return sd_initialize(drv & DRIVE_MASK);
#endif
default:
return STA_NOINIT|STA_NODISK;
}
}
DRESULT disk_read(BYTE drv, BYTE *buffer, DWORD sector, BYTE count) {
switch(drv >> DRIVE_BITS) {
#ifdef HAVE_DF
case DISK_TYPE_DF:
return df_read(drv & DRIVE_MASK,buffer,sector,count);
#endif
#ifdef HAVE_ATA
case DISK_TYPE_ATA:
return ata_read(drv & DRIVE_MASK,buffer,sector,count);
case DISK_TYPE_ATA2:
return ata_read((drv & DRIVE_MASK) + 2,buffer,sector,count);
#endif
#ifdef HAVE_SD
case DISK_TYPE_SD:
return sd_read(drv & DRIVE_MASK,buffer,sector,count);
#endif
default:
return RES_ERROR;
}
}
DRESULT disk_write(BYTE drv, const BYTE *buffer, DWORD sector, BYTE count) {
switch(drv >> DRIVE_BITS) {
#ifdef HAVE_DF
case DISK_TYPE_DF:
return df_write(drv & DRIVE_MASK,buffer,sector,count);
#endif
#ifdef HAVE_ATA
case DISK_TYPE_ATA:
return ata_write(drv & DRIVE_MASK,buffer,sector,count);
case DISK_TYPE_ATA2:
return ata_write((drv & DRIVE_MASK) + 2,buffer,sector,count);
#endif
#ifdef HAVE_SD
case DISK_TYPE_SD:
return sd_write(drv & DRIVE_MASK,buffer,sector,count);
#endif
default:
return RES_ERROR;
}
}
DRESULT disk_getinfo(BYTE drv, BYTE page, void *buffer) {
switch(drv >> DRIVE_BITS) {
#ifdef HAVE_DF
case DISK_TYPE_DF:
return df_getinfo(drv & DRIVE_MASK,page,buffer);
#endif
#ifdef HAVE_ATA
case DISK_TYPE_ATA:
return ata_getinfo(drv & DRIVE_MASK,page,buffer);
case DISK_TYPE_ATA2:
return ata_getinfo((drv & DRIVE_MASK) + 2,page,buffer);
#endif
#ifdef HAVE_SD
case DISK_TYPE_SD:
return sd_getinfo(drv & DRIVE_MASK,page,buffer);
#endif
default:
return RES_ERROR;
}
}
#endif

View File

@@ -1,132 +0,0 @@
/* sd2snes - SD card based universal cartridge for the SNES
Copyright (C) 2009-2010 Maximilian Rehkopf <otakon@gmx.net>
This file was adapted from sd2iec, written by Ingo Korb.
Original copyright header follows:
*/
/* sd2iec - SD/MMC to Commodore serial bus interface/controller
Copyright (C) 2007-2009 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
diskio.h: Definitions for the disk access routines
Based on diskio.h from FatFS by ChaN, see ff.c for
for full copyright details.
*/
#ifndef DISKIO_H
#define DISKIO_H
#include "integer.h"
/* Status of Disk Functions */
typedef BYTE DSTATUS;
/* Disk Status Bits (DSTATUS) */
#define STA_NOINIT 0x01 /* Drive not initialized */
#define STA_NODISK 0x02 /* No medium in the drive */
#define STA_PROTECT 0x04 /* Write protected */
/* Results of Disk Functions */
typedef enum {
RES_OK = 0, /* 0: Successful */
RES_ERROR, /* 1: R/W Error */
RES_WRPRT, /* 2: Write Protected */
RES_NOTRDY, /* 3: Not Ready */
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 */
DSTATUS disk_initialize (BYTE);
DSTATUS disk_status (BYTE);
DRESULT disk_read (BYTE, BYTE*, DWORD, BYTE);
DRESULT disk_write (BYTE, const BYTE*, DWORD, BYTE);
#define disk_ioctl(a,b,c) RES_OK
DRESULT disk_getinfo(BYTE drv, BYTE page, void *buffer);
void disk_init(void);
uint8_t SD_SPI_OFFLOAD;
/* 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
#ifdef NEED_DISKMUX
/* Disk mux configuration */
extern uint32_t drive_config;
uint32_t get_default_driveconfig(void);
# define set_map_drive(drv,val) (drive_config = \
(drive_config & (0xffffffff - (0x0f << (drv * 4)))) \
| (val << (drv * 4)))
# define map_drive(drv) ((drive_config >> (4 * drv)) & 0x0f)
# define set_drive_config(config) drive_config = config
/* Number of bits used for the drive, the disk type */
/* uses the remainder (4 bits per entry). */
# define DRIVE_BITS 1
/* Calculate mask from the shift value */
# define DRIVE_MASK ((1 << DRIVE_BITS)-1)
#else // NEED_DISKMUX
# define set_map_drive(drv,val) do {} while(0)
# define map_drive(drv) (drv)
# define set_drive_config(conf) do {} while(0)
# define get_default_driveconfig() 0
#endif // NEED_DISKMUX
#endif

View File

@@ -1,175 +0,0 @@
/* sd2snes - SD card based universal cartridge for the SNES
Copyright (C) 2009-2010 Maximilian Rehkopf <otakon@gmx.net>
This file was adapted from sd2iec, written by Ingo Korb.
Original copyright header follows:
*/
/* sd2iec - SD/MMC to Commodore serial bus interface/controller
Copyright (C) 2007-2009 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
eeprom.c: Persistent configuration storage
*/
#include <avr/eeprom.h>
#include <avr/io.h>
#include "config.h"
#include "diskio.h"
#include "fatops.h"
#include "flags.h"
#include "iec.h"
#include "timer.h"
#include "eeprom.h"
#include "uart.h"
/**
* struct storedconfig - in-eeprom data structure
* @dummy : EEPROM position 0 is unused
* @checksum : Checksum over the EEPROM contents
* @structsize : size of the eeprom structure
* @osccal : stored value of OSCCAL
* @globalflags: subset of the globalflags variable
* @address : device address set by software
* @hardaddress: device address set by jumpers
* @fileexts : file extension mapping mode
* @drvflags0 : 16 bits of drv mappings, organized as 4 nybbles.
* @drvflags1 : 16 bits of drv mappings, organized as 4 nybbles.
*
* This is the data structure for the contents of the EEPROM.
*/
static EEMEM struct {
uint8_t dummy;
uint8_t checksum;
uint16_t structsize;
uint8_t osccal;
uint8_t global_flags;
uint8_t address;
uint8_t hardaddress;
uint8_t fileexts;
uint16_t drvconfig0;
uint16_t drvconfig1;
} storedconfig;
/**
* read_configuration - reads configuration from EEPROM
*
* This function reads the stored configuration values from the EEPROM.
* If the stored checksum doesn't match the calculated one nothing will
* be changed.
*/
void read_configuration(void) {
uint16_t i,size;
uint8_t checksum, tmp;
/* Set default values */
globalflags |= JIFFY_ENABLED; /* JiffyDos enabled */
globalflags |= POSTMATCH; /* Post-* matching enabled */
globalflags |= FAT32_FREEBLOCKS; /* Calculate the number of free blocks on FAT32 */
file_extension_mode = 1; /* Store x00 extensions except for PRG */
set_drive_config(get_default_driveconfig()); /* Set the default drive configuration */
/* Use the NEXT button to skip reading the EEPROM configuration */
if (!(BUTTON_PIN & BUTTON_NEXT)) {
ignore_keys();
return;
}
size = eeprom_read_word(&storedconfig.structsize);
/* Calculate checksum of EEPROM contents */
checksum = 0;
for (i=2; i<size; i++)
checksum += eeprom_read_byte((uint8_t *)i);
/* Abort if the checksum doesn't match */
if (checksum != eeprom_read_byte(&storedconfig.checksum)) {
EEAR = 0;
return;
}
/* Read data from EEPROM */
OSCCAL = eeprom_read_byte(&storedconfig.osccal);
tmp = eeprom_read_byte(&storedconfig.global_flags);
globalflags &= (uint8_t)~(JIFFY_ENABLED | POSTMATCH |
EXTENSION_HIDING | FAT32_FREEBLOCKS);
globalflags |= tmp;
if (eeprom_read_byte(&storedconfig.hardaddress) == DEVICE_SELECT)
device_address = eeprom_read_byte(&storedconfig.address);
file_extension_mode = eeprom_read_byte(&storedconfig.fileexts);
#ifdef NEED_DISKMUX
if (size > 9) {
uint32_t tmpconfig;
tmpconfig = eeprom_read_word(&storedconfig.drvconfig0);
tmpconfig |= (uint32_t)eeprom_read_word(&storedconfig.drvconfig1) << 16;
set_drive_config(tmpconfig);
}
/* sanity check. If the user has truly turned off all drives, turn the
* defaults back on
*/
if(drive_config == 0xffffffff)
set_drive_config(get_default_driveconfig());
#endif
/* Paranoia: Set EEPROM address register to the dummy entry */
EEAR = 0;
}
/**
* write_configuration - stores configuration data to EEPROM
*
* This function stores the current configuration values to the EEPROM.
*/
void write_configuration(void) {
uint16_t i;
uint8_t checksum;
/* Write configuration to EEPROM */
eeprom_write_word(&storedconfig.structsize, sizeof(storedconfig));
eeprom_write_byte(&storedconfig.osccal, OSCCAL);
eeprom_write_byte(&storedconfig.global_flags,
globalflags & (JIFFY_ENABLED | POSTMATCH |
EXTENSION_HIDING | FAT32_FREEBLOCKS));
eeprom_write_byte(&storedconfig.address, device_address);
eeprom_write_byte(&storedconfig.hardaddress, DEVICE_SELECT);
eeprom_write_byte(&storedconfig.fileexts, file_extension_mode);
#ifdef NEED_DISKMUX
eeprom_write_word(&storedconfig.drvconfig0, drive_config);
eeprom_write_word(&storedconfig.drvconfig1, drive_config >> 16);
#endif
/* Calculate checksum over EEPROM contents */
checksum = 0;
for (i=2;i<sizeof(storedconfig);i++)
checksum += eeprom_read_byte((uint8_t *) i);
/* Store checksum to EEPROM */
eeprom_write_byte(&storedconfig.checksum, checksum);
/* Paranoia: Set EEPROM address register to the dummy entry */
EEAR = 0;
}

View File

@@ -1,38 +0,0 @@
/* sd2snes - SD card based universal cartridge for the SNES
Copyright (C) 2009-2010 Maximilian Rehkopf <otakon@gmx.net>
This file was adapted from sd2iec, written by Ingo Korb.
Original copyright header follows:
*/
/* sd2iec - SD/MMC to Commodore serial bus interface/controller
Copyright (C) 2007-2009 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
eeprom.h: Persistent configuration storage
*/
#ifndef EEPROM_H
#define EEPROM_H
void read_configuration(void);
void write_configuration(void);
#endif

3066
src/ff.c

File diff suppressed because it is too large Load Diff

448
src/ff.h
View File

@@ -1,448 +0,0 @@
/*--------------------------------------------------------------------------/
/ FatFs - FAT file system module include file R0.06 (C)ChaN, 2008
/---------------------------------------------------------------------------/
/ FatFs module is an experimenal project to implement FAT file system to
/ cheap microcontrollers. This is a free software and is opened for education,
/ research and development under license policy of following trems.
/
/ Copyright (C) 2008, ChaN, all right reserved.
/
/ * The FatFs module is a free software and there is no warranty.
/ * You can use, modify and/or redistribute it for personal, non-profit or
/ * commercial use without any restriction under your responsibility.
/ * Redistributions of source code must retain the above copyright notice.
/
/---------------------------------------------------------------------------*/
#ifndef _FATFS
#define _MCU_ENDIAN 1
/* The _MCU_ENDIAN defines which access method is used to the FAT structure.
/ 1: Enable word access.
/ 2: Disable word access and use byte-by-byte access instead.
/ When the architectural byte order of the MCU is big-endian and/or address
/ miss-aligned access results incorrect behavior, the _MCU_ENDIAN must be set
/ to 2. If it is not the case, it can be set to 1 for good code efficiency. */
#define _FS_READONLY 0
/* Setting _FS_READONLY to 1 defines read only configuration. This removes
/ writing functions, f_write, f_sync, f_unlink, f_mkdir, f_chmod, f_rename,
/ f_truncate and useless f_getfree. */
#define _FS_MINIMIZE 0
/* The _FS_MINIMIZE option defines minimization level to remove some functions.
/ 0: Full function.
/ 1: f_stat, f_getfree, f_unlink, f_mkdir, f_chmod, f_truncate and f_rename are removed.
/ 2: f_opendir and f_readdir are removed in addition to level 1.
/ 3: f_lseek is removed in addition to level 2. */
#define _USE_STRFUNC 0
/* To enable string functions, set _USE_STRFUNC to 1 or 2. */
#define _DRIVES 1
/*MAX_DRIVES*/
/* Number of physical drives to be used. This affects the size of internal
* table. (when using _USE_DRIVE_PREFIX */
#define _USE_MKFS 0
/* When _USE_MKFS is set to 1 and _FS_READONLY is set to 0, f_mkfs function is
/ enabled. */
#define _MULTI_PARTITION 0
/* When _MULTI_PARTITION is set to 0, each logical drive is bound to the same
/ physical drive number and can mount only 1st primary partition.
/
/ When it is set to 1, the low _PARTITION_MASK bits of each partition represent
/ the partition and the high (8-_PARTITION_MASK) bits represent the physical
/ drive */
#define _PARTITION_MASK 4
#define _USE_FSINFO 1
/* To enable FSInfo support on FAT32 volume, set _USE_FSINFO to 1. */
#define _USE_SJIS 0
/* When _USE_SJIS is set to 1, Shift-JIS code transparency is enabled, otherwise
/ only US-ASCII(7bit) code can be accepted as file/directory name. */
#define _USE_NTFLAG 0
/* When _USE_NTFLAG is set to 1, upper/lower case of the file name is preserved.
/ Note that the files are always accessed in case insensitive. */
#define _USE_CHDIR 0
#define _USE_CURR_DIR 1
#define _USE_LFN 1
/* Maximum number of characters to return for a LFN */
/* The buffer used for FILINFO.lfn must be at least */
/* _MAX_LFN_LENGTH+1 characters long! */
/* Note that if _USE_LFN_DBCS is set, this value */
/* represents the characters needed, not bytes */
#define _MAX_LFN_LENGTH 255
/* When _USE_LFN_DBCS is set to 1, FILINFO.lfn will contain a DBCS string, not
/ a simple ASCII string */
#define _USE_LFN_DBCS 0
/* When set to 1, All FIL objects will use the buffer. This reduces memory
/ requirements as open files will only require space for a FIL object, but
/ operate slower. When set, ff.c will behave like tff.c, but will allow
/ multiple filesystems. */
#define _USE_FS_BUF 1
/* When set to 1, All objects will use a static buffer. This reduces memory
/ requirements to the absolute minimum ~512 bytes for the buffer, but will
/ operate slower. This option can only be set if _USE_FS_BUF is set. */
#define _USE_1_BUF 1
/* If set to 1, FatFs will manage the FATFS structures after mounting. If
/ set to 0, the caller must send the correct drive FATFS structure for each
/ call. Normally, this should be set to 1, but if the caller wants to use
/ low level l_* functions or skip sending the drive number in the path string,
/ this must be turned off. */
#define _USE_DRIVE_PREFIX 1
/* If set to 1, FatFS will delay mounting the drive until first use. Normally,
/ this should be turned on. However, it cannot be used with
/ _USE_DRIVE_PREFIX = 0 */
#define _USE_DEFERRED_MOUNT 0
/* New features in 0.05a, not required yet */
#define _USE_TRUNCATE 0
#define _USE_UTIME 0
#include "integer.h"
#if _USE_LFN_DBCS != 0
#define S_LFN_OFFSET 26
#define S_LFN_INCREMENT 2
#else
#define S_LFN_OFFSET 13
#define S_LFN_INCREMENT 1
#endif
/* Definitions corresponds to multiple sector size (not tested) */
#define S_MAX_SIZ 512U /* Do not change */
#if S_MAX_SIZ > 512U
#define SS(fs) ((fs)->s_size)
#else
#define SS(fs) 512U
#endif
#if _USE_1_BUF == 1 && _USE_FS_BUF == 0
#error You can only use 1_BUF with _USE_FS_BUF at present
#define _USE_1_BUF 0
#endif
typedef struct _BUF {
DWORD sect;
BYTE dirty; /* dirty flag (1:must be written back) */
//BYTE pad1;
#if _USE_1_BUF != 0
struct _FATFS *fs;
#endif
BYTE data[S_MAX_SIZ]; /* Disk access window for Directory/FAT */
} BUF;
/* File system object structure */
typedef struct _FATFS {
//WORD id; /* File system mount ID */
WORD n_rootdir; /* Number of root directory entries */
DWORD sects_fat; /* Sectors per fat */
DWORD max_clust; /* Maximum cluster# + 1 */
DWORD fatbase; /* FAT start sector */
DWORD dirbase; /* Root directory start sector (cluster# for FAT32) */
DWORD database; /* Data start sector */
#if _USE_CHDIR != 0 || _USE_CURR_DIR != 0
DWORD curr_dir;
#endif
#if !_FS_READONLY
DWORD last_clust; /* Last allocated cluster */
DWORD free_clust; /* Number of free clusters */
#if _USE_FSINFO
DWORD fsi_sector; /* fsinfo sector */
BYTE fsi_flag; /* fsinfo dirty flag (1:must be written back) */
//BYTE pad2;
#endif
#endif
BYTE fs_type; /* FAT sub type */
BYTE csize; /* Number of sectors per cluster */
#if S_MAX_SIZ > 512U
WORD s_size; /* Sector size */
#endif
BYTE n_fats; /* Number of FAT copies */
BYTE drive; /* Physical drive number */
#if _USE_1_BUF == 0
BUF buf;
#endif
} FATFS;
/* Directory object structure */
typedef struct _DIR {
//WORD id; /* Owner file system mount ID */
WORD index; /* Current index */
FATFS* fs; /* Pointer to the owner file system object */
DWORD sclust; /* Start cluster */
DWORD clust; /* Current cluster */
DWORD sect; /* Current sector */
} DIR;
/* File object structure */
typedef struct _FIL {
//WORD id; /* Owner file system mount ID */
BYTE flag; /* File status flags */
BYTE csect; /* Sector address in the cluster */
FATFS* fs; /* Pointer to the owner file system object */
DWORD fptr; /* File R/W pointer */
DWORD fsize; /* File size */
DWORD org_clust; /* File start cluster */
DWORD curr_clust; /* Current cluster */
DWORD curr_sect; /* Current sector */
#if _FS_READONLY == 0
DWORD dir_sect; /* Sector containing the directory entry */
BYTE* dir_ptr; /* Ponter to the directory entry in the window */
#endif
#if _USE_LESS_BUF == 0 && _USE_1_BUF == 0
BUF buf; /* File R/W buffer */
#endif
} FIL;
/* File status structure */
typedef struct _FILINFO {
DWORD fsize; /* Size */
WORD fdate; /* Date */
WORD ftime; /* Time */
BYTE fattrib; /* Attribute */
DWORD clust; /* Start cluster */
UCHAR fname[8+1+3+1]; /* Name (8.3 format) */
#if _USE_LFN != 0
UCHAR* lfn;
#endif
} FILINFO;
/* Definitions corresponds to multi partition */
#if _MULTI_PARTITION != 0 /* Multiple partition cfg */
#define LD2PD(drv) (drv >> (8-_PARTITION_MASK)) /* Get physical drive# */
#define LD2PT(drv) (drv & ((1<<_PARTITION_MASK)-1)) /* Get partition# */
#define _LOGICAL_DRIVES (_DRIVES * (1<<_PARTITION_MASK))
#else /* Single partition cfg */
#define LD2PD(drv) (drv) /* Physical drive# is equal to logical drive# */
#define LD2PT(drv) 0 /* Always mounts the 1st partition */
#define _LOGICAL_DRIVES _DRIVES
#endif
/* File function return code (FRESULT) */
typedef enum {
FR_OK = 0, /* 0 */
FR_NOT_READY, /* 1 */
FR_NO_FILE, /* 2 */
FR_NO_PATH, /* 3 */
FR_INVALID_NAME, /* 4 */
FR_INVALID_DRIVE, /* 5 */
FR_DENIED, /* 6 */
FR_EXIST, /* 7 */
FR_RW_ERROR, /* 8 */
FR_WRITE_PROTECTED, /* 9 */
FR_NOT_ENABLED, /* 10 */
FR_NO_FILESYSTEM, /* 11 */
FR_INVALID_OBJECT, /* 12 */
FR_MKFS_ABORTED, /* 13 */
FR_IS_DIRECTORY, /* 14 */
FR_IS_READONLY, /* 15 */
FR_DIR_NOT_EMPTY, /* 16 */
FR_NOT_DIRECTORY /* 17 */
} FRESULT;
/*-----------------------------------------------------*/
/* FatFs module application interface */
#if _USE_DRIVE_PREFIX == 0
FRESULT f_mount (BYTE, FATFS*); /* Mount/Unmount a logical drive */
FRESULT f_open (FATFS*, FIL*, const UCHAR*, BYTE); /* Open or create a file */
FRESULT f_read (FIL*, void*, UINT, UINT*); /* Read data from a file */
FRESULT f_write (FIL*, const void*, UINT, UINT*); /* Write data to a file */
FRESULT f_lseek (FIL*, DWORD); /* Move file pointer of a file object */
FRESULT f_close (FIL*); /* Close an open file object */
FRESULT f_opendir (FATFS*, DIR*, const UCHAR*); /* Open an existing directory */
FRESULT f_readdir (DIR*, FILINFO*); /* Read a directory item */
FRESULT f_stat (FATFS*, const UCHAR*, FILINFO*); /* Get file status */
FRESULT f_getfree (FATFS*, const UCHAR*, DWORD*); /* Get number of free clusters on the drive */
FRESULT f_sync (FIL*); /* Flush cached data of a writing file */
FRESULT f_unlink (FATFS*, const UCHAR*); /* Delete an existing file or directory */
FRESULT f_mkdir (FATFS*, const UCHAR*); /* Create a new directory */
FRESULT f_chmod (FATFS*, const UCHAR*, BYTE, BYTE); /* Change file/dir attriburte */
FRESULT f_rename (FATFS*, const UCHAR*, const UCHAR*); /* Rename/Move a file or directory */
FRESULT f_mkfs (BYTE, BYTE, WORD); /* Create a file system on the drive */
FRESULT f_chdir (FATFS*, const UCHAR*); /* Change current directory */
#else
FRESULT f_mount (BYTE, FATFS*); /* Mount/Unmount a logical drive */
FRESULT f_open (FIL*, const UCHAR*, BYTE); /* Open or create a file */
FRESULT f_read (FIL*, void*, UINT, UINT*); /* Read data from a file */
FRESULT f_write (FIL*, const void*, UINT, UINT*); /* Write data to a file */
FRESULT f_lseek (FIL*, DWORD); /* Move file pointer of a file object */
FRESULT f_close (FIL*); /* Close an open file object */
FRESULT f_opendir (DIR*, const UCHAR*); /* Open an existing directory */
FRESULT f_readdir (DIR*, FILINFO*); /* Read a directory item */
FRESULT f_stat (const UCHAR*, FILINFO*); /* Get file status */
FRESULT f_getfree (const UCHAR*, DWORD*, FATFS**); /* Get number of free clusters on the drive */
FRESULT f_sync (FIL*); /* Flush cached data of a writing file */
FRESULT f_unlink (const UCHAR*); /* Delete an existing file or directory */
FRESULT f_mkdir (const UCHAR*); /* Create a new directory */
FRESULT f_chmod (const UCHAR*, BYTE, BYTE); /* Change file/dir attriburte */
FRESULT f_rename (const UCHAR*, const UCHAR*); /* Rename/Move a file or directory */
FRESULT f_mkfs (BYTE, BYTE, WORD); /* Create a file system on the drive */
FRESULT f_chdir (const UCHAR*); /* Change current directory */
#endif
/* Low Level functions */
FRESULT l_opendir(FATFS* fs, DWORD cluster, DIR *dirobj); /* Open an existing directory by its start cluster */
FRESULT l_opencluster(FATFS *fs, FIL *fp, DWORD clust); /* Open a cluster by number as a read-only file */
FRESULT l_openfilebycluster(FATFS *fs, FIL *fp, const UCHAR *path, DWORD clust, DWORD fsize); /* Open a file by its start cluster using supplied file size */
FRESULT l_getfree (FATFS*, const UCHAR*, DWORD*, DWORD); /* Get number of free clusters on the drive, limited */
#if _USE_STRFUNC
#define feof(fp) ((fp)->fptr == (fp)->fsize)
#define EOF -1
int fputc (int, FIL*); /* Put a character to the file */
int fputs (const char*, FIL*); /* Put a string to the file */
int fprintf (FIL*, const char*, ...); /* Put a formatted string to the file */
char* fgets (char*, int, FIL*); /* Get a string from the file */
#endif
/* User defined function to give a current time to fatfs module */
#if CONFIG_RTC_VARIANT > 0
DWORD get_fattime (void); /* 31-25: Year(0-127 org.1980), 24-21: Month(1-12), 20-16: Day(1-31) */
/* 15-11: Hour(0-23), 10-5: Minute(0-59), 4-0: Second(0-29 *2) */
#else
/* Fixed time: 1982-08-31 0:00:00, same month as the introduction of the C64 */
# define get_fattime() 0x51f0000
#endif
/* File access control and file status flags (FIL.flag) */
#define FA_READ 0x01
#define FA_OPEN_EXISTING 0x00
#if _FS_READONLY == 0
#define FA_WRITE 0x02
#define FA_CREATE_NEW 0x04
#define FA_CREATE_ALWAYS 0x08
#define FA_OPEN_ALWAYS 0x10
#define FA__WRITTEN 0x20
#define FA__DIRTY 0x40
#endif
#define FA__ERROR 0x80
/* FAT sub type (FATFS.fs_type) */
#define FS_FAT12 1
#define FS_FAT16 2
#define FS_FAT32 3
/* File attribute bits for directory entry */
#define AM_RDO 0x01 /* Read only */
#define AM_HID 0x02 /* Hidden */
#define AM_SYS 0x04 /* System */
#define AM_VOL 0x08 /* Volume label */
#define AM_LFN 0x0F /* LFN entry */
#define AM_DIR 0x10 /* Directory */
#define AM_ARC 0x20 /* Archive */
/* Offset of FAT structure members */
#define BS_jmpBoot 0
#define BS_OEMName 3
#define BPB_BytsPerSec 11
#define BPB_SecPerClus 13
#define BPB_RsvdSecCnt 14
#define BPB_NumFATs 16
#define BPB_RootEntCnt 17
#define BPB_TotSec16 19
#define BPB_Media 21
#define BPB_FATSz16 22
#define BPB_SecPerTrk 24
#define BPB_NumHeads 26
#define BPB_HiddSec 28
#define BPB_TotSec32 32
#define BS_55AA 510
#define BS_DrvNum 36
#define BS_BootSig 38
#define BS_VolID 39
#define BS_VolLab 43
#define BS_FilSysType 54
#define BPB_FATSz32 36
#define BPB_ExtFlags 40
#define BPB_FSVer 42
#define BPB_RootClus 44
#define BPB_FSInfo 48
#define BPB_BkBootSec 50
#define BS_DrvNum32 64
#define BS_BootSig32 66
#define BS_VolID32 67
#define BS_VolLab32 71
#define BS_FilSysType32 82
#define FSI_LeadSig 0
#define FSI_StrucSig 484
#define FSI_Free_Count 488
#define FSI_Nxt_Free 492
#define MBR_Table 446
#define DIR_Name 0
#define DIR_Attr 11
#define DIR_NTres 12
#define DIR_Chksum 13
#define DIR_CrtTime 14
#define DIR_CrtDate 16
#define DIR_FstClusHI 20
#define DIR_WrtTime 22
#define DIR_WrtDate 24
#define DIR_FstClusLO 26
#define DIR_FileSize 28
/* Multi-byte word access macros */
#if _MCU_ENDIAN == 1 /* Use word access */
#define LD_WORD(ptr) (WORD)(*(WORD*)(BYTE*)(ptr))
#define LD_DWORD(ptr) (DWORD)(*(DWORD*)(BYTE*)(ptr))
#define ST_WORD(ptr,val) *(WORD*)(BYTE*)(ptr)=(WORD)(val)
#define ST_DWORD(ptr,val) *(DWORD*)(BYTE*)(ptr)=(DWORD)(val)
#elif _MCU_ENDIAN == 2 /* Use byte-by-byte access */
#define LD_WORD(ptr) (WORD)(((WORD)*(volatile BYTE*)((ptr)+1)<<8)|(WORD)*(volatile BYTE*)(ptr))
#define LD_DWORD(ptr) (DWORD)(((DWORD)*(volatile BYTE*)((ptr)+3)<<24)|((DWORD)*(volatile BYTE*)((ptr)+2)<<16)|((WORD)*(volatile BYTE*)((ptr)+1)<<8)|*(volatile BYTE*)(ptr))
#define ST_WORD(ptr,val) *(volatile BYTE*)(ptr)=(BYTE)(val); *(volatile BYTE*)((ptr)+1)=(BYTE)((WORD)(val)>>8)
#define ST_DWORD(ptr,val) *(volatile BYTE*)(ptr)=(BYTE)(val); *(volatile BYTE*)((ptr)+1)=(BYTE)((WORD)(val)>>8); *(volatile BYTE*)((ptr)+2)=(BYTE)((DWORD)(val)>>16); *(volatile BYTE*)((ptr)+3)=(BYTE)((DWORD)(val)>>24)
#else
#error Do not forget to set _MCU_ENDIAN properly!
#endif
#define _FATFS
#endif /* _FATFS */

View File

@@ -1,80 +0,0 @@
/* 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 <util/delay.h>
#include "config.h"
#include "uart.h"
#include "ff.h"
#include "fileops.h"
WCHAR ff_convert(WCHAR w, UINT dir) {
return w;
}
void file_init() {
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, (unsigned char*)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;
}

View File

@@ -1,45 +0,0 @@
/* 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[512];
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

View File

@@ -1,273 +0,0 @@
/* 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;
}

View File

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

View File

@@ -1,181 +0,0 @@
/* 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
fpga.c: FPGA (re)configuration
*/
/*
FPGA pin mapping
================
PROG_B PD3 OUT
CCLK PD4 OUT
INIT_B PD7 IN
DIN PC7 OUT
DONE PA3 IN
*/
#include <avr/pgmspace.h>
#include <util/delay.h>
#include "fpga.h"
#include "config.h"
#include "uart.h"
#include "sdcard.h"
#include "diskio.h"
#include "integer.h"
#include "ff.h"
#include "fileops.h"
#include "fpga_spi.h"
#include "spi.h"
#include "avrcompat.h"
#include "led.h"
/*DWORD get_fattime(void) {
return 0L;
}*/
void set_prog_b(uint8_t val) {
if(val) {
PORTD |= _BV(PD3);
} else {
PORTD &= ~_BV(PD3);
}
}
void set_cclk(uint8_t val) {
if(val) {
PORTD |= _BV(PD4);
} else {
PORTD &= ~_BV(PD4);
}
}
void fpga_init() {
DDRD &= ~_BV(PD7); // PD7 is input
DDRC = _BV(PC7); // for FPGA config, PC7 is output
DDRD |= _BV(PD3) | _BV(PD4); // PD3, PD4 are outputs
DDRA = ~_BV(PA3); // PA3 is input <- DONE
DDRB |= _BV(PB2); // DMA_CTRL preinit
PORTB |= _BV(PB2);
SPI_OFFLOAD=0;
set_cclk(0); // initial clk=0
}
int fpga_get_done(void) {
return PINA & _BV(PA3);
}
void fpga_postinit() {
DDRA |= _BV(PA0) | _BV(PA1) | _BV(PA2) | _BV(PA4) | _BV(PA5) | _BV(PA6); // MAPPER+NEXTADDR output
DDRB |= _BV(PB1) | _BV(PB0); // turn PB2 into output, enable AVR_BANK
DDRD |= _BV(PD7); // turn PD7 into output
}
void fpga_pgm(uint8_t* filename) {
int MAXRETRIES = 10;
int retries = MAXRETRIES;
int j=0;
do {
set_prog_b(0);
uart_putc('P');
set_prog_b(1);
loop_until_bit_is_set(PIND, PD7);
uart_putc('p');
UINT bytes_read;
// open configware file
file_open(filename, FA_READ);
if(file_res) {
uart_putc('?');
uart_putc(0x30+file_res);
return;
}
for (;;) {
if(!(j++ % 8)) {
toggle_pwr_led();
}
bytes_read = file_read();
if (file_res || bytes_read == 0) break; // error or eof
for(int i=0; i<bytes_read; i++) {
FPGA_SEND_BYTE_SERIAL(file_buf[i]);
}
}
file_close();
_delay_ms(100);
} while (!fpga_get_done() && retries--);
if(!fpga_get_done()) {
dprintf("FPGA failed to configure after %d tries.\n", MAXRETRIES);
_delay_ms(50);
led_panic();
}
fpga_postinit();
}
void set_avr_ena(uint8_t val) {
if(val) { // shared mode
PORTD |= _BV(PD7);
// Disable SPI double speed mode -> clock = f/4
SPSR = 0;
dprintf("SPI slow\n");
} else { // avr only
PORTD &= ~_BV(PD7);
// Enable SPI double speed mode -> clock = f/2
SPSR = _BV(SPI2X);
dprintf("SPI fast\n");
}
}
void set_avr_mapper(uint8_t val) {
SPI_SS_HIGH();
FPGA_SS_LOW();
spiTransferByte(0x30 | (val & 0x0f));
FPGA_SS_HIGH();
SPI_SS_LOW();
}
void set_avr_bank(uint8_t val) {
SPI_SS_HIGH();
FPGA_SS_LOW();
spiTransferByte(0x00); // SET ADDRESS
spiTransferByte(val * 0x20); // select chip
spiTransferByte(0x00); // select chip
spiTransferByte(0x00); // select chip
FPGA_SS_HIGH();
SPI_SS_LOW();
}
uint8_t fpga_test() {
spi_fpga();
spiTransferByte(0xF0); // TEST
spiTransferByte(0x00); // dummy
uint8_t result = spiTransferByte(0x00);
spi_none();
return result;
}

View File

@@ -1,78 +0,0 @@
/* 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
fpga.h: FPGA (re)configuration
*/
#ifndef FPGA_H
#define FPGA_H
void fpga_init(void);
uint8_t fpga_test(void);
void fpga_postinit(void);
void fpga_pgm(uint8_t* filename);
void set_avr_read(uint8_t val);
void set_avr_write(uint8_t val);
void set_avr_ena(uint8_t val);
void set_avr_nextaddr(uint8_t val);
void set_avr_addr_reset(uint8_t val);
void set_avr_data(uint8_t data);
void set_avr_addr_en(uint8_t val);
void set_avr_mapper(uint8_t val);
void set_avr_bank(uint8_t val);
uint8_t SPI_OFFLOAD;
#define FPGA_TEST_TOKEN (0xa5)
// some macros for bulk transfers (faster)
#define FPGA_SEND_BYTE(data) do {SET_AVR_DATA(data); CCLK();} while (0)
#define FPGA_SEND_BYTE_SERIAL(data) do {SET_AVR_DATA(data); CCLK();\
SET_AVR_DATA(data<<1); CCLK(); SET_AVR_DATA(data<<2); CCLK();\
SET_AVR_DATA(data<<3); CCLK(); SET_AVR_DATA(data<<4); CCLK();\
SET_AVR_DATA(data<<5); CCLK(); SET_AVR_DATA(data<<6); CCLK();\
SET_AVR_DATA(data<<7); CCLK();} while (0)
#define SET_CCLK() do {PORTD |= _BV(PD4);} while (0)
#define CLR_CCLK() do {PORTD &= ~_BV(PD4);} while (0)
#define CCLK() do {SET_CCLK(); CLR_CCLK();} while (0)
#define SET_AVR_READ() do {PORTB |= _BV(PB3);} while (0)
#define CLR_AVR_READ() do {PORTB &= ~_BV(PB3);} while (0)
#define SET_AVR_WRITE() do {PORTB |= _BV(PB2);} while (0)
#define CLR_AVR_WRITE() do {PORTB &= ~_BV(PB2);} while (0)
#define SET_AVR_EXCL() do {PORTD |= _BV(PD7);} while (0)
#define CLR_AVR_EXCL() do {PORTD &= ~_BV(PD7);} while (0)
#define SET_AVR_NEXTADDR() do {PORTA |= _BV(PA4);} while (0)
#define CLR_AVR_NEXTADDR() do {PORTA &= ~_BV(PA4);} while (0)
#define SET_AVR_ADDR_RESET() do {PORTA |= _BV(PA5);} while (0)
#define CLR_AVR_ADDR_RESET() do {PORTA &= ~_BV(PA5);} while (0)
#define SET_AVR_ADDR_EN() do {PORTA |= _BV(PA6);} while (0)
#define CLR_AVR_ADDR_EN() do {PORTA &= ~_BV(PA6);} while (0)
#define AVR_NEXTADDR() do {SET_AVR_NEXTADDR(); CLR_AVR_NEXTADDR();} while (0)
#define AVR_ADDR_RESET() do {CLR_AVR_ADDR_RESET();\
AVR_NEXTADDR();SET_AVR_ADDR_RESET();} while (0)
#define SET_AVR_DATA(data) do {PORTC = (uint8_t)data;} while (0)
#define AVR_READ() do {CLR_AVR_READ(); SET_AVR_READ();} while (0)
#define AVR_WRITE() do {CLR_AVR_WRITE(); SET_AVR_WRITE();} while (0)
#define AVR_DATA (PINC)
#endif

View File

@@ -1,99 +0,0 @@
/* 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
fpga_spi.h: functions for SPI ctrl, SRAM interfacing and feature configuration
*/
/*
SPI commands
cmd param function
=============================================
00 bb[hh[ll]] set address to 0xbb0000, 0xbbhh00, or 0xbbhhll
10 bbhhll set SNES input address mask to 0xbbhhll
20 bbhhll set SRAM address mask to 0xbbhhll
3m - set mapper to m
0=HiROM, 1=LoROM, 2=ExHiROM, 7=Menu
80 - read with increment
81 - read w/o increment
90 {xx}* write xx with increment
91 {xx}* write xx w/o increment
F0 - receive test token (to see if FPGA is alive)
*/
#include <avr/pgmspace.h>
#include <util/delay.h>
#include "avrcompat.h"
#include "fpga.h"
#include "config.h"
#include "uart.h"
#include "spi.h"
#include "fpga_spi.h"
void spi_fpga(void) {
SPI_SS_HIGH();
FPGA_SS_LOW();
}
void spi_sd(void) {
FPGA_SS_HIGH();
SPI_SS_LOW();
}
void spi_none(void) {
FPGA_SS_HIGH();
SPI_SS_HIGH();
}
void fpga_spi_init(void) {
DDRC = _BV(PC7);
FPGA_SS_HIGH();
}
void set_avr_addr(uint32_t address) {
spi_fpga();
spiTransferByte(0x00);
spiTransferByte((address>>16)&0xff);
spiTransferByte((address>>8)&0xff);
spiTransferByte((address)&0xff);
spi_none();
}
void set_saveram_mask(uint32_t mask) {
spi_fpga();
spiTransferByte(0x20);
spiTransferByte((mask>>16)&0xff);
spiTransferByte((mask>>8)&0xff);
spiTransferByte((mask)&0xff);
spi_none();
}
void set_rom_mask(uint32_t mask) {
spi_fpga();
spiTransferByte(0x10);
spiTransferByte((mask>>16)&0xff);
spiTransferByte((mask>>8)&0xff);
spiTransferByte((mask)&0xff);
spi_none();
}

View File

@@ -1,38 +0,0 @@
/* 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
fpga_spi.h: functions for SPI ctrl, SRAM interfacing and feature configuration
*/
#define FPGA_SS_HIGH() do {PORTC |= _BV(PC7);} while (0)
#define FPGA_SS_LOW() do {PORTC &= ~_BV(PC7);} while (0)
void fpga_spi_init(void);
void fpga_spi_test(void);
void spi_fpga(void);
void spi_sd(void);
void spi_none(void);
void set_avr_addr(uint32_t);
void set_saveram_mask(uint32_t);
void set_rom_mask(uint32_t);

View File

@@ -1,15 +0,0 @@
#! /usr/bin/gawk -f
#
# Parse the output of (avr-)gcc --version for the version number
# and output YES if it is at least 4.3.
{
match($0, /\) ([0-9]+)\.([0-9]+)\./, ver);
if (RLENGTH > 0) {
major = 0+ver[1];
minor = 0+ver[2];
if (major > 4 || (major == 4 && minor > 2)) {
print "YES";
}
}
}

View File

@@ -1,31 +0,0 @@
/* Integer definitions for ff, based on example code from ChaN */
#ifndef _INTEGER
#include <stdint.h>
/* These types are assumed as 16-bit or larger integer */
typedef int16_t INT;
typedef uint16_t UINT;
/* These types are assumed as 8-bit integer */
typedef int8_t CHAR;
typedef uint8_t UCHAR;
typedef uint8_t BYTE;
/* These types are assumed as 16-bit integer */
typedef int16_t SHORT;
typedef uint16_t USHORT;
typedef uint16_t WORD;
typedef uint16_t WCHAR;
/* These types are assumed as 32-bit integer */
typedef int32_t LONG;
typedef uint32_t ULONG;
typedef uint32_t DWORD;
/* Boolean type */
typedef enum { FALSE = 0, TRUE } BOOL;
#define _INTEGER
#endif

110
src/led.c
View File

@@ -1,110 +0,0 @@
/* 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
led.c: LED control
*/
#include <avr/io.h>
#include <util/delay.h>
#include "config.h"
#include "led.h"
static uint8_t led_bright[16]={255,253,252,251,249,247,244,239,232,223,210,191,165,127,74,0};
static uint8_t curr_bright = 15;
static uint8_t led_bounce_dir = 1;
volatile uint8_t led_state;
void led_panic(void) {
led_std();
while(1) {
set_pwr_led(1);
set_busy_led(1);
_delay_ms(150);
set_pwr_led(0);
set_busy_led(0);
_delay_ms(150);
}
}
void toggle_busy_led(void) {
PORTB &= ~_BV(PB3);
DDRB ^= _BV(PB3);
}
void toggle_pwr_led(void) {
PORTB &= ~_BV(PB0);
DDRB ^= _BV(PB0);
}
void set_busy_led(uint8_t state) {
PORTB &= ~_BV(PB3);
if(state) {
DDRB |= _BV(PB3);
} else {
DDRB &= ~_BV(PB3);
}
}
void set_pwr_led(uint8_t state) {
PORTB &= ~_BV(PB0);
if(state) {
DDRB |= _BV(PB0);
} else {
DDRB &= ~_BV(PB0);
}
}
void set_busy_pwm(uint8_t brightness) {
OCR0A = led_bright[brightness];
set_busy_led(1);
}
void bounce_busy_led() {
set_busy_pwm(curr_bright);
if(led_bounce_dir) {
curr_bright--;
if(curr_bright==0) {
led_bounce_dir = 0;
}
} else {
curr_bright++;
if(curr_bright==15) {
led_bounce_dir = 1;
}
}
}
void led_pwm() {
set_busy_led(1);
TCCR0A = 0x83;
TCCR0B = 0x01;
}
void led_std() {
set_busy_led(0);
TCCR0A = 0;
TCCR0B = 0;
}

View File

@@ -1,50 +0,0 @@
/* 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
led.c: LED control
*/
#ifndef LED_H
#define LED_H
#include "config.h"
#include "uart.h"
/* LED-to-bit mapping - BUSY/DIRTY are only used for SINGLE_LED */
#define LED_ERROR 1
#define LED_BUSY 2
#define LED_DIRTY 4
extern volatile uint8_t led_state;
/* Update the LEDs to match the buffer state */
void toggle_busy_led(void);
void toggle_pwr_led(void);
void set_busy_led(uint8_t);
void set_pwr_led(uint8_t);
void set_busy_pwm(uint8_t brightness);
void bounce_busy_led(void);
void led_pwm(void);
void led_std(void);
void led_panic(void);
#endif

View File

@@ -1,400 +1,84 @@
/* sd2snes - SD card based universal cartridge for the SNES
Copyright (C) 2009-2010 Maximilian Rehkopf <otakon@gmx.net>
AVR firmware portion
/* The classic embedded version of "Hello World": A blinking LED */
#include <arm/NXP/LPC17xx/LPC17xx.h>
Inspired by and based on code from sd2iec, written by Ingo Korb et al.
See sdcard.c|h, config.h.
#define BV(x) (1<<(x))
#define BITBAND(addr,bit) (*((volatile unsigned long *)(((unsigned long)&(addr)-0x20000000)*32 + bit*4 + 0x22000000)))
#define PLL_MULT(x) ((x)&0x7fff)
#define PLL_PREDIV(x) (((x)<<16)&0xff0000)
#define CLKSRC_MAINOSC (1)
#define PLLE0 (1<<0)
#define PLLC0 (1<<1)
#define PLOCK0 (1<<26)
#define OSCEN (1<<5)
#define OSCSTAT (1<<6)
#define EMC0TOGGLE (3<<4)
#define MR0R (1<<1)
#define FLASH5C (0x403A)
#define PCTIM3 (1<<23)
FAT file system access based on code by ChaN, Jim Brain, Ingo Korb,
see ff.c|h.
#define PCLK_CCLK(x) (1<<(x))
#define PCLK_CCLK4(x) (0)
#define PCLK_CCLK8(x) (3<<(x))
#define PCLK_CCLK2(x) (2<<(x))
#define PCLK_TIMER3 (14)
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.
int i;
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.
int main(void) {
LPC_GPIO2->FIODIR = BV(0) | BV(1) | BV(2);
LPC_GPIO1->FIODIR = 0;
uint32_t p1;
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
/* setup PLL0 */
LPC_SC->FLASHCFG=FLASH5C;
LPC_SC->PLL0CON &= ~PLLC0;
LPC_SC->PLL0FEED=0xaa;
LPC_SC->PLL0FEED=0x55;
LPC_SC->PLL0CON &= ~PLLE0;
LPC_SC->PLL0FEED=0xaa;
LPC_SC->PLL0FEED=0x55;
main.c: initialization and flow
/* 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);
/* continue with PLL0 setup */
LPC_SC->SCS=OSCEN;
while(!(LPC_SC->SCS&OSCSTAT));
LPC_SC->CLKSRCSEL=CLKSRC_MAINOSC;
LPC_SC->PLL0CFG=PLL_MULT(428)|PLL_PREDIV(18);
LPC_SC->PLL0FEED=0xaa;
LPC_SC->PLL0FEED=0x55;
LPC_SC->PLL0CON |= PLLE0;
LPC_SC->PLL0FEED=0xaa;
LPC_SC->PLL0FEED=0x55;
LPC_SC->CCLKCFG=5;
while(!(LPC_SC->PLL0STAT&PLOCK0));
LPC_SC->PLL0CON |= PLLC0;
LPC_SC->PLL0FEED=0xaa;
LPC_SC->PLL0FEED=0x55;
#include <stdio.h>
#include <string.h>
#include <avr/boot.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <avr/power.h>
#include <avr/wdt.h>
#include <util/delay.h>
#include "config.h"
#include "diskio.h"
#include "ff.h"
#include "led.h"
/* #include "timer.h" */
#include "fpga.h"
#include "uart.h"
#include "ustring.h"
#include "utils.h"
#include "snes.h"
#include "fileops.h"
#include "memory.h"
#include "fpga_spi.h"
#include "spi.h"
#include "avrcompat.h"
#include "filetypes.h"
#include "sdcard.h"
/* 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;
void writetest(void) {
// HERE BE LIONS, GET IN THE CAR
char teststring[58];
while(1) {
sram_writeblock((void*)"Testtext of DOOM!!1! 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ", SRAM_SCRATCHPAD+0x20, 58);
sram_readblock((void*)teststring, SRAM_SCRATCHPAD+0x20, 58);
teststring[57]=0;
dprintf("%s\n", teststring);
}
// END OF LIONS
}
void memtest(void) {
/* HERE BE DRAGONS */
uint32_t dbg_i;
for(dbg_i=0; dbg_i < 65536; dbg_i++) {
sram_writeshort((uint16_t)dbg_i&0xffff, dbg_i*2);
}
save_sram((uint8_t*)"/sd2snes/memtest", 0x20000, 0);
set_pwr_led(0);
while(1);
/* END OF DRAGONS */
}
/* Make sure the watchdog is disabled as soon as possible */
/* Copy this code to your bootloader if you use one and your */
/* MCU doesn't disable the WDT after reset! */
void get_mcusr(void) \
__attribute__((naked)) \
__attribute__((section(".init3")));
void get_mcusr(void)
{
MCUSR = 0;
wdt_disable();
}
#ifdef CONFIG_MEMPOISON
void poison_memory(void) \
__attribute__((naked)) \
__attribute__((section(".init1")));
void poison_memory(void) {
register uint16_t i;
register uint8_t *ptr;
asm("clr r1\n");
/* There is no RAMSTARt variable =( */
if (RAMEND > 2048 && RAMEND < 4096) {
/* 2K memory */
ptr = (void *)RAMEND-2047;
for (i=0;i<2048;i++)
ptr[i] = 0x55;
} else if (RAMEND > 4096 && RAMEND < 8192) {
/* 4K memory */
ptr = (void *)RAMEND-4095;
for (i=0;i<4096;i++)
ptr[i] = 0x55;
} else {
/* Assume 8K memory */
ptr = (void *)RAMEND-8191;
for (i=0;i<8192;i++)
ptr[i] = 0x55;
while (1) {
p1 = LPC_GPIO1->FIOPIN;
BITBAND(LPC_GPIO2->FIOPIN, 0) = (p1 & BV(29))>>29;
BITBAND(LPC_GPIO2->FIOSET, 2) = 1;
for (i=0;i<100000;i++)
__NOP();
BITBAND(LPC_GPIO2->FIOCLR, 2) = 1;
for (i=0;i<100000;i++)
__NOP();
}
}
#endif
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 1)
int main(void) __attribute__((OS_main));
#endif
int main(void) {
#if defined __AVR_ATmega644__ || defined __AVR_ATmega644P__ || defined __AVR_ATmega2561__
asm volatile("in r24, %0\n"
"ori r24, 0x80\n"
"out %0, r24\n"
"out %0, r24\n"
:
: "I" (_SFR_IO_ADDR(MCUCR))
: "r24"
);
#elif defined __AVR_ATmega32__
asm volatile ("in r24, %0\n"
"ori r24, 0x80\n"
"out %0, r24\n"
"out %0, r24\n"
:
: "I" (_SFR_IO_ADDR(MCUCSR))
: "r24"
);
#elif defined __AVR_ATmega128__ || defined __AVR_ATmega1281__
/* Just assume that JTAG doesn't hurt us on the m128 */
#else
# error Unknown chip!
#endif
#ifdef CLOCK_PRESCALE
clock_prescale_set(CLOCK_PRESCALE);
#endif
set_pwr_led(0);
set_busy_led(1);
spi_none();
snes_reset(1);
uart_init();
sei();
_delay_ms(100);
disk_init();
snes_init();
/* timer_init(); */
uart_puts_P(PSTR("\nsd2snes " VERSION));
uart_putcrlf();
file_init();
FATFS fatfs;
f_mount(0,&fatfs);
uart_putc('W');
fpga_init();
fpga_pgm((uint8_t*)"/sd2snes/main.bit");
_delay_ms(100);
set_pwr_led(1);
fpga_spi_init();
uart_putc('!');
_delay_ms(100);
restart:
set_avr_ena(0);
snes_reset(1);
*fs_path=0;
uint16_t saved_dir_id;
get_db_id(&saved_dir_id);
uint16_t mem_dir_id = sram_readshort(SRAM_DIRID);
uint32_t mem_magic = sram_readlong(SRAM_SCRATCHPAD);
while(0) {
SD_SPI_OFFLOAD=0;
set_avr_addr(0L);
sd_read(0, file_buf, 0L, 1);
uart_trace((void*)file_buf, 0, 0x200);
// sram_writeblock((void*)file_buf, 0, 0x200);
// sram_hexdump(0,0x200);
uart_putc('+');
}
/* here be strange monsters */
while(0){
// uint16_t hurdur1 = 0, hurdur2 = 0;
spiTransferByte(0x00);
spiTransferByte(0x00);
spiTransferByte(0x00);
spiTransferByte(0x00);
spiTransferByte(0x00);
spiTransferByte(0x00);
spiTransferByte(0x00);
spiTransferByte(0x00);
spiTransferByte(0x00);
spiTransferByte(0x00);
spiTransferByte(0x00);
spiTransferByte(0x00);
spiTransferByte(0x00);
PORTB |= _BV(PB2);
DDRB |= _BV(PB2);
PORTB &= ~_BV(PB2);
DDRB &= ~_BV(PB7); // tristate SCK
PORTB |= _BV(PB2);
DDRB &= ~_BV(PB2);
while(!(PINB & _BV(PB2))) {
}
DDRB |= _BV(PB7);
_delay_ms(1);
// dprintf("hurdur1=%d hurdur2=%d\n", hurdur1, hurdur2);
}
if((mem_magic != 0x12345678) || (mem_dir_id != saved_dir_id)) {
uint16_t curr_dir_id = scan_dir(fs_path, 0, 0); // generate files footprint
dprintf("curr dir id = %x\n", curr_dir_id);
if((get_db_id(&saved_dir_id) != FR_OK) // no database?
|| saved_dir_id != curr_dir_id) { // files changed? // XXX
dprintf("saved dir id = %x\n", saved_dir_id);
dprintf("rebuilding database...");
_delay_ms(50);
curr_dir_id = scan_dir(fs_path, 1, 0); // then rebuild database
sram_writeblock(&curr_dir_id, SRAM_DB_ADDR, 2);
uint32_t endaddr, direndaddr;
sram_readblock(&endaddr, SRAM_DB_ADDR+4, 4);
sram_readblock(&direndaddr, SRAM_DB_ADDR+8, 4);
dprintf("%lx %lx\n", endaddr, direndaddr);
save_sram((uint8_t*)"/sd2snes/sd2snes.db", endaddr-SRAM_DB_ADDR, SRAM_DB_ADDR);
save_sram((uint8_t*)"/sd2snes/sd2snes.dir", direndaddr-(SRAM_DIR_ADDR), SRAM_DIR_ADDR);
dprintf("done\n");
// sram_hexdump(SRAM_DB_ADDR, 0x400);
} else {
dprintf("saved dir id = %x\n", saved_dir_id);
dprintf("different card, consistent db, loading db...\n");
load_sram((uint8_t*)"/sd2snes/sd2snes.db", SRAM_DB_ADDR);
load_sram((uint8_t*)"/sd2snes/sd2snes.dir", SRAM_DIR_ADDR);
}
// save_sram((uint8_t*)"/debug.smc", 0x400000, 0);
// uart_putc('[');
// load_sram((uint8_t*)"/test.srm", SRAM_SAVE_ADDR);
// uart_putc(']');
sram_writeshort(curr_dir_id, SRAM_DIRID);
sram_writelong(0x12345678, SRAM_SCRATCHPAD);
} else {
dprintf("same card, loading db...\n");
load_sram((uint8_t*)"/sd2snes/sd2snes.db", SRAM_DB_ADDR);
load_sram((uint8_t*)"/sd2snes/sd2snes.dir", SRAM_DIR_ADDR);
}
led_pwm();
// sram_hexdump(0, 0x200);
uart_putc('(');
load_rom((uint8_t*)"/sd2snes/menu.bin", SRAM_MENU_ADDR);
set_rom_mask(0x3fffff); // force mirroring off
set_avr_mapper(0x7); // menu mapper XXX
uart_putc(')');
uart_putcrlf();
// sram_hexdump(0x7ffff0, 0x10);
// sram_hexdump(0, 0x400);
// save_sram((uint8_t*)"/sd2snes/dump", 65536, 0);
sram_writebyte(0, SRAM_CMD_ADDR);
set_busy_led(0);
set_avr_ena(1);
_delay_ms(100);
uart_puts_P(PSTR("SNES GO!\r\n"));
snes_reset(0);
// writetest();
/* snes_reset(1);
set_avr_ena(0);
led_std();
set_busy_led(1);
save_sram((uint8_t*)"/sd2snes/dump", 65536, SRAM_MENU_ADDR);
set_busy_led(0);
set_avr_ena(1);
snes_reset(0); */
uint8_t cmd = 0;
while(!sram_reliable());
while(!cmd) {
cmd=menu_main_loop();
switch(cmd) {
case 0x01: // SNES_CMD_LOADROM:
get_selected_name(file_lfn);
_delay_ms(100);
// snes_reset(1);
set_avr_ena(0);
dprintf("Selected name: %s\n", file_lfn);
load_rom(file_lfn, SRAM_ROM_ADDR);
// save_sram((uint8_t*)"/sd2snes/test.smc", romprops.romsize_bytes, 0);
if(romprops.ramsize_bytes) {
strcpy(strrchr((char*)file_lfn, (int)'.'), ".srm");
dprintf("SRM file: %s\n", file_lfn);
load_sram(file_lfn, SRAM_SAVE_ADDR);
} else {
dprintf("No SRAM\n");
}
set_avr_ena(1);
snes_reset(1);
_delay_ms(100);
snes_reset(0);
break;
default:
dprintf("unknown cmd: %d\n", cmd);
cmd=0; // unknown cmd: stay in loop
break;
}
}
dprintf("cmd was %x, going to snes main loop\n", cmd);
led_std();
cmd=0;
uint8_t snes_reset_prev=0, snes_reset_now=0, snes_reset_state=0;
uint16_t reset_count=0;
while(fpga_test() == FPGA_TEST_TOKEN) {
snes_reset_now=get_snes_reset();
if(snes_reset_now) {
if(!snes_reset_prev) {
dprintf("RESET BUTTON DOWN\n");
snes_reset_state=1;
// reset reset counter
reset_count=0;
}
} else {
if(snes_reset_prev) {
dprintf("RESET BUTTON UP\n");
snes_reset_state=0;
}
}
if(snes_reset_state) {
_delay_ms(10);
reset_count++;
} else {
sram_reliable();
snes_main_loop();
}
if(reset_count>100) {
reset_count=0;
led_std();
set_avr_ena(0);
snes_reset(1);
_delay_ms(100);
if(romprops.ramsize_bytes && fpga_test() == 0xa5) {
set_busy_led(1);
save_sram(file_lfn, romprops.ramsize_bytes, SRAM_SAVE_ADDR);
set_busy_led(0);
}
_delay_ms(1000);
set_busy_led(1);
goto restart;
}
snes_reset_prev = snes_reset_now;
}
// FPGA TEST FAIL. PANIC.
led_panic();
/* HERE BE LIONS */
while(1) {
set_avr_addr(0x600000);
spi_fpga();
spiTransferByte(0x81); // read w/ increment... hopefully
spiTransferByte(0x00); // 1 dummy read
uart_putcrlf();
uint8_t buff[21];
for(uint8_t cnt=0; cnt<21; cnt++) {
uint8_t data=spiTransferByte(0x00);
buff[cnt]=data;
}
for(uint8_t cnt=0; cnt<21; cnt++) {
uint8_t data = buff[cnt];
_delay_ms(2);
if(data>=0x20 && data <= 0x7a) {
uart_putc(data);
} else {
// uart_putc('.');
uart_putc("0123456789ABCDEF"[data>>4]);
uart_putc("0123456789ABCDEF"[data&15]);
uart_putc(' ');
}
// set_avr_bank(3);
}
spi_none();
}
while(1);
}

View File

@@ -1,335 +0,0 @@
/* 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
memory.c: RAM operations
*/
#include <stdint.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include "config.h"
#include "uart.h"
#include "fpga.h"
#include "crc16.h"
#include "ff.h"
#include "fileops.h"
#include "spi.h"
#include "fpga_spi.h"
#include "avrcompat.h"
#include "led.h"
#include "smc.h"
#include "fpga_spi.h"
#include "memory.h"
#include "snes.h"
char* hex = "0123456789ABCDEF";
void sram_hexdump(uint32_t addr, uint32_t len) {
static uint8_t buf[16];
uint32_t ptr;
for(ptr=0; ptr < len; ptr += 16) {
sram_readblock((void*)buf, ptr+addr, 16);
uart_trace(buf, 0, 16);
}
}
void sram_writebyte(uint8_t val, uint32_t addr) {
set_avr_addr(addr);
spi_fpga();
spiTransferByte(0x91); // WRITE
spiTransferByte(val);
spiTransferByte(0x00); // dummy
spi_none();
}
uint8_t sram_readbyte(uint32_t addr) {
set_avr_addr(addr);
spi_fpga();
spiTransferByte(0x81); // READ
spiTransferByte(0x00); // dummy
uint8_t val = spiTransferByte(0x00);
spi_none();
return val;
}
void sram_writeshort(uint16_t val, uint32_t addr) {
set_avr_addr(addr);
spi_fpga();
spiTransferByte(0x91); // WRITE
spiTransferByte(val&0xff); // 7-0
spiTransferByte((val>>8)&0xff); // 15-8
spiTransferByte(0x00); // dummy
spi_none();
}
void sram_writelong(uint32_t val, uint32_t addr) {
set_avr_addr(addr);
spi_fpga();
spiTransferByte(0x91); // WRITE
spiTransferByte(val&0xff); // 7-0
spiTransferByte((val>>8)&0xff); // 15-8
spiTransferByte((val>>16)&0xff); // 23-15
spiTransferByte((val>>24)&0xff); // 31-24
spiTransferByte(0x00); // dummy
spi_none();
}
uint16_t sram_readshort(uint32_t addr) {
set_avr_addr(addr);
spi_fpga();
spiTransferByte(0x81);
spiTransferByte(0x00);
uint32_t val = spiTransferByte(0x00);
val |= ((uint32_t)spiTransferByte(0x00)<<8);
spi_none();
return val;
}
uint32_t sram_readlong(uint32_t addr) {
set_avr_addr(addr);
spi_fpga();
spiTransferByte(0x81);
spiTransferByte(0x00);
uint32_t count=0;
uint32_t val = spiTransferByte(count & 0xff);
count++;
val |= ((uint32_t)spiTransferByte(count & val)<<8);
count++;
val |= ((uint32_t)spiTransferByte(count & val)<<16);
count++;
val |= ((uint32_t)spiTransferByte(count & val)<<24);
count++;
spi_none();
return val;
}
void sram_readblock(void* buf, uint32_t addr, uint16_t size) {
uint16_t count=size;
uint8_t* tgt = buf;
set_avr_addr(addr);
spi_fpga();
spiTransferByte(0x81); // READ
spiTransferByte(0x00); // dummy
while(count--) {
*(tgt++) = spiTransferByte(0x00);
}
spi_none();
}
void sram_writeblock(void* buf, uint32_t addr, uint16_t size) {
uint16_t count=size;
uint8_t* src = buf;
set_avr_addr(addr);
spi_fpga();
spiTransferByte(0x91); // WRITE
while(count--) {
spiTransferByte(*src++);
}
spiTransferByte(0x00); // dummy
spi_none();
}
uint32_t load_rom(uint8_t* filename, uint32_t base_addr) {
// uint8_t dummy;
UINT bytes_read;
DWORD filesize;
UINT count=0;
file_open(filename, FA_READ);
filesize = file_handle.fsize;
smc_id(&romprops);
set_avr_addr(base_addr);
dprintf("no nervous breakdown beyond this point! or else!\n");
if(file_res) {
uart_putc('?');
uart_putc(0x30+file_res);
return 0;
}
f_lseek(&file_handle, romprops.offset);
spi_none();
for(;;) {
SPI_OFFLOAD=1;
spi_none();
bytes_read = file_read();
if (file_res || !bytes_read) break;
if(!(count++ % 8)) {
// toggle_busy_led();
bounce_busy_led();
uart_putc('.');
}
/* spi_fpga();
spiTransferByte(0x91); // write w/ increment
if(!(count++ % 8)) {
// toggle_busy_led();
bounce_busy_led();
uart_putc('.');
}
for(int j=0; j<bytes_read; j++) {
// spiTransferByte(file_buf[j]);
SPDR = file_buf[j];
loop_until_bit_is_set(SPSR, SPIF);
dummy = SPDR;
}
spiTransferByte(0x00); // dummy tx for increment+write pulse */
}
file_close();
spi_none();
set_avr_mapper(romprops.mapper_id);
uart_puthex(romprops.header.map);
uart_putc(0x30+romprops.mapper_id);
uint32_t rammask;
uint32_t rommask;
if(filesize > (romprops.romsize_bytes + romprops.offset)) {
romprops.romsize_bytes <<= 1;
}
if(romprops.header.ramsize == 0) {
rammask = 0;
} else {
rammask = romprops.ramsize_bytes - 1;
}
rommask = romprops.romsize_bytes - 1;
uart_putc(' ');
uart_puthex(romprops.header.ramsize);
uart_putc('-');
uart_puthexlong(rammask);
uart_putc(' ');
uart_puthex(romprops.header.romsize);
uart_putc('-');
uart_puthexlong(rommask);
set_saveram_mask(rammask);
set_rom_mask(rommask);
return (uint32_t)filesize;
}
uint32_t load_sram(uint8_t* filename, uint32_t base_addr) {
set_avr_addr(base_addr);
UINT bytes_read;
DWORD filesize;
file_open(filename, FA_READ);
filesize = file_handle.fsize;
if(file_res) return 0;
for(;;) {
// FPGA_SS_HIGH();
// SPI_SS_LOW();
SPI_OFFLOAD=1;
bytes_read = file_read();
// SPI_SS_HIGH();
if (file_res || !bytes_read) break;
// FPGA_SS_LOW();
/* spiTransferByte(0x91);
for(int j=0; j<bytes_read; j++) {
spiTransferByte(file_buf[j]);
}
spiTransferByte(0x00); // dummy tx
FPGA_SS_HIGH(); // */
}
file_close();
return (uint32_t)filesize;
}
void save_sram(uint8_t* filename, uint32_t sram_size, uint32_t base_addr) {
uint32_t count = 0;
uint32_t num = 0;
spi_none();
file_open(filename, FA_CREATE_ALWAYS | FA_WRITE);
if(file_res) {
uart_putc(0x30+file_res);
}
while(count<sram_size) {
set_avr_addr(base_addr+count);
spi_fpga();
spiTransferByte(0x81); // read
spiTransferByte(0); // dummy
for(int j=0; j<sizeof(file_buf); j++) {
file_buf[j] = spiTransferByte(0x00);
count++;
}
spi_none();
num = file_write();
if(file_res) {
uart_putc(0x30+file_res);
}
}
file_close();
}
uint32_t calc_sram_crc(uint32_t base_addr, uint32_t size) {
uint8_t data;
uint32_t count;
uint16_t crc;
crc=0;
crc_valid=1;
set_avr_addr(base_addr);
spi_fpga();
spiTransferByte(0x81);
spiTransferByte(0x00);
for(count=0; count<size; count++) {
data = spiTransferByte(0);
if(get_snes_reset()) {
crc_valid = 0;
break;
}
crc += crc16_update(crc, &data, 1);
}
spi_none();
return crc;
}
uint8_t sram_reliable() {
uint16_t score=0;
uint32_t val;
// uint32_t val = sram_readlong(SRAM_SCRATCHPAD);
uint8_t result = 0;
/* while(score<SRAM_RELIABILITY_SCORE) {
if(sram_readlong(SRAM_SCRATCHPAD)==val) {
score++;
} else {
set_pwr_led(0);
score=0;
}
}*/
for(uint16_t i = 0; i < SRAM_RELIABILITY_SCORE; i++) {
val=sram_readlong(SRAM_SCRATCHPAD);
if(val==0x12345678) {
score++;
// } else {
// dprintf("i=%d val=%08lX\n", i, val);
}
}
if(score<SRAM_RELIABILITY_SCORE) {
result = 0;
// dprintf("score=%d\n", score);
} else {
result = 1;
}
set_pwr_led(result);
return result;
}

View File

@@ -1,60 +0,0 @@
/* 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
memory.h: RAM operations
*/
#ifndef MEMORY_H
#define MEMORY_H
#define SRAM_ROM_ADDR (0x000000L)
#define SRAM_SAVE_ADDR (0x600000L)
#define SRAM_MENU_ADDR (0x600000L)
#define SRAM_DB_ADDR (0x620000L)
#define SRAM_DIR_ADDR (0x610000L)
#define SRAM_CMD_ADDR (0x7F1004L)
#define SRAM_FD_ADDR (0x7F1000L)
#define SRAM_MENU_SAVE_ADDR (0x7F0000L)
#define SRAM_SCRATCHPAD (0x7FFF00L)
#define SRAM_DIRID (0x7FFFF0L)
#define SRAM_RELIABILITY_SCORE (0x100)
uint32_t load_rom(uint8_t* filename, uint32_t base_addr);
uint32_t load_sram(uint8_t* filename, uint32_t base_addr);
void sram_hexdump(uint32_t addr, uint32_t len);
uint8_t sram_readbyte(uint32_t addr);
uint16_t sram_readshort(uint32_t addr);
uint32_t sram_readlong(uint32_t addr);
void sram_writebyte(uint8_t val, uint32_t addr);
void sram_writeshort(uint16_t val, uint32_t addr);
void sram_writelong(uint32_t val, uint32_t addr);
void sram_readblock(void* buf, uint32_t addr, uint16_t size);
void sram_writeblock(void* buf, uint32_t addr, uint16_t size);
void save_sram(uint8_t* filename, uint32_t sram_size, uint32_t base_addr);
uint32_t calc_sram_crc(uint32_t base_addr, uint32_t size);
uint8_t sram_reliable(void);
#include "smc.h"
snes_romprops_t romprops;
#endif

View File

@@ -1,773 +0,0 @@
/* sd2iec - SD/MMC to Commodore serial bus interface/controller
Copyright (C) 2007-2009 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 <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <util/crc16.h>
#include <util/delay.h>
#include "config.h"
#include "avrcompat.h"
#include "crc7.h"
#include "diskio.h"
#include "spi.h"
#include "uart.h"
#include "sdcard.h"
#include "fpga_spi.h"
#ifndef TRUE
#define TRUE -1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#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;
}
static uint8_t sdResponse(uint8_t expected)
{
unsigned short count = 0x0FFF;
while ((spiTransferByte(0xFF) != expected) && count )
count--;
// If count didn't run out, return success
return (count != 0);
}
static uint8_t sdWaitWriteFinish(void)
{
uint32_t count = 0x1FFFF; // wait for quite some time
while ((spiTransferByte(0xFF) == 0) && count )
count--;
// If count didn't run out, return success
return (count != 0);
}
static void deselectCard(uint8_t card) {
// Send 8 clock cycles
SPI_SS_HIGH(card);
spiTransferByte(0xff);
}
/**
* 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=0,errorcount;
uint16_t counter;
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
SPI_SS_LOW(card);
#ifdef CONFIG_TWINSD
if (card == 0 && command == GO_IDLE_STATE)
/* Force both cards to SPI mode simultaneously */
SPI_SS_LOW(1);
#endif
// Transfer command
spiTransferByte(0x40+command);
spiTransferLong(parameter);
spiTransferByte(crc);
// Wait for a valid response
counter = 0;
do {
i = spiTransferByte(0xff);
counter++;
} while (i & 0x80 && counter < 0x1000);
#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 oder SD1.x) but not SDHC
deselectCard(card);
return TRUE;
}
// No error, continue SDHC initialization
answer = spiTransferLong(0);
deselectCard(card);
if (((answer >> 8) & 0x0f) != 0b0001) {
// Card didn't accept our voltage specification
return FALSE;
}
// 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 TRUE;
}
return TRUE;
}
// SD common initialisation
static void sdInit(const uint8_t card) {
uint8_t i;
uint16_t counter;
SD_SPI_OFFLOAD = 0;
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) {
// uart_putc('0');
if (SDCARD_WP) {
// uart_putc('1');
return STA_PROTECT;
} else {
// uart_putc('2');
return RES_OK;
}
} else {
// uart_putc('3');
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 */
// uart_putc('#');
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.
*/
spiInit();
disk_state = DISK_ERROR;
cardtype[drv] = 0;
SPI_SS_HIGH(drv);
// Send 80 clks
for (i=0; i<10; i++) {
spiTransferByte(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) {
answer = spiTransferLong(0);
// 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!
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,tmp,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) {
uart_putc('?');
dprintf("SD error: %02x\n", res);
SPI_SS_HIGH(drv);
disk_state = DISK_ERROR;
return RES_ERROR;
}
// Wait for data token
if (!sdResponse(0xFE)) {
uart_putc('-');
SPI_SS_HIGH(drv);
disk_state = DISK_ERROR;
return RES_ERROR;
}
uint16_t i;
#ifdef CONFIG_SD_DATACRC
BYTE *oldbuffer = buffer;
#endif
// Get data
crc = 0;
if(SD_SPI_OFFLOAD) {
// uart_putc('O');
PORTB |= _BV(PB2);
DDRB |= _BV(PB2);
_delay_us(1);
PORTB &= ~_BV(PB2);
DDRB &= ~_BV(PB7); // tristate SCK
PORTB |= _BV(PB2);
DDRB &= ~_BV(PB2);
_delay_us(1);
while(!(PINB & _BV(PB2)));
DDRB |= _BV(PB7);
DDRB |= _BV(PB2);
// _delay_us(1);
deselectCard(drv);
SD_SPI_OFFLOAD = 0;
return RES_OK;
SPDR = 0xff;
} else {
// Initiate data exchange over SPI
SPDR = 0xff;
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);
#ifdef CONFIG_SD_DATACRC
if (recvcrc != crc) {
uart_putc('X');
deselectCard(drv);
errorcount++;
buffer = oldbuffer;
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) {
uart_putc('C');
SPI_SS_HIGH(drv);
disk_state = DISK_ERROR;
return RES_ERROR;
}
// Send data token
spiTransferByte(0xFE);
uint16_t i;
const BYTE *oldbuffer = buffer;
// Send data
crc = 0;
for (i=0; i<512; i++) {
#ifdef CONFIG_SD_DATACRC
crc = _crc_xmodem_update(crc, *buffer);
#endif
spiTransferByte(*(buffer++));
}
// Send CRC
spiTransferByte(crc >> 8);
spiTransferByte(crc & 0xff);
// Get and check status feedback
status = spiTransferByte(0xFF);
// Retry if neccessary
if ((status & 0x0F) != 0x05) {
uart_putc('X');
deselectCard(drv);
errorcount++;
buffer = oldbuffer;
continue;
}
// Wait for write finish
if (!sdWaitWriteFinish()) {
uart_putc('W');
SPI_SS_HIGH(drv);
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 i;
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 (!sdResponse(0xfe)) {
deselectCard(drv);
return RES_ERROR;
}
for (i=0;i<18;i++) {
buf[i] = spiTransferByte(0xff);
}
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")));

View File

@@ -1,40 +0,0 @@
/* sd2iec - SD/MMC to Commodore serial bus interface/controller
Copyright (C) 2007-2009 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

175
src/smc.c
View File

@@ -1,175 +0,0 @@
/* 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
smc.c: SMC file related operations
*/
#include <avr/io.h>
#include <util/delay.h>
#include "fileops.h"
#include "config.h"
#include "uart.h"
#include "smc.h"
uint32_t hdr_addr[6] = {0xffb0, 0x101b0, 0x7fb0, 0x81b0, 0x40ffb0, 0x4101b0};
uint8_t countAllASCII(uint8_t* data, int size) {
uint8_t res = 0;
do {
size--;
if(data[size] >= 0x20 && data[size] <= 0x7e) {
res++;
}
} while (size);
return res;
}
uint8_t countAllJISX0201(uint8_t* data, int size) {
uint8_t res = 0;
do {
size--;
if((data[size] >= 0x20 && data[size] <= 0x7e)
||(data[size] >= 0xa1 && data[size] <= 0xdf)) {
res++;
}
} while (size);
return res;
}
uint8_t isFixed(uint8_t* data, int size, uint8_t value) {
uint8_t res = 1;
do {
size--;
if(data[size] != value) {
res = 0;
}
} while (size);
return res;
}
uint8_t checkChksum(uint16_t cchk, uint16_t chk) {
uint32_t sum = cchk + chk;
uint8_t res = 0;
if(sum==0x0000ffff) {
res = 0x10;
}
return res;
}
void smc_id(snes_romprops_t* props) {
uint8_t score, maxscore=1, score_idx=2; // assume LoROM
snes_header_t* header = &(props->header);
for(uint8_t num = 0; num < 6; num++) {
if(!file_readblock(header, hdr_addr[num], sizeof(snes_header_t))
|| file_res) {
// dprintf("uh oh... %d\n", file_res);
// _delay_ms(30);
score = 0;
} else {
score = smc_headerscore(header)/(1+(num&1));
if((file_handle.fsize & 0x2ff) == 0x200) {
if(num&1) {
score+=20;
} else {
score=0;
}
} else {
if(!(num&1)) {
score+=20;
} else {
score=0;
}
}
}
// dprintf("%d: offset = %lX; score = %d\n", num, hdr_addr[num], score);
// _delay_ms(100);
if(score>=maxscore) {
score_idx=num;
maxscore=score;
}
}
if(score_idx & 1) {
props->offset = 0x200;
} else {
props->offset = 0;
}
// restore the chosen one
// dprintf("winner is %d\n", score_idx);
// _delay_ms(30);
file_readblock(header, hdr_addr[score_idx], sizeof(snes_header_t));
switch(header->map & 0xef) {
case 0x20:
props->mapper_id = 1;
break;
case 0x21:
props->mapper_id = 0;
break;
case 0x25:
props->mapper_id = 2;
break;
default: // invalid/unsupported mapper, use header location
switch(score_idx) {
case 0:
case 1:
props->mapper_id = 0;
break;
case 2:
case 3:
props->mapper_id = 1;
break;
case 4:
case 5:
props->mapper_id = 2;
break;
default:
props->mapper_id = 1; // whatever
}
}
if(header->romsize == 0 || header->romsize > 13) {
header->romsize = 13;
}
props->ramsize_bytes = (uint32_t)1024 << header->ramsize;
props->romsize_bytes = (uint32_t)1024 << header->romsize;
props->expramsize_bytes = (uint32_t)1024 << header->expramsize;
// dprintf("ramsize_bytes: %ld\n", props->ramsize_bytes);
if(props->ramsize_bytes > 32768 || props->ramsize_bytes < 2048) {
props->ramsize_bytes = 0;
}
// dprintf("ramsize_bytes: %ld\n", props->ramsize_bytes);
f_lseek(&file_handle, 0);
}
uint8_t smc_headerscore(snes_header_t* header) {
uint8_t score=0;
score += countAllASCII(header->maker, sizeof(header->maker));
score += countAllASCII(header->gamecode, sizeof(header->gamecode));
score += isFixed(header->fixed_00, sizeof(header->fixed_00), 0x00);
score += countAllJISX0201(header->name, sizeof(header->name));
score += 3*isFixed(&header->fixed_33, sizeof(header->fixed_33), 0x33);
score += checkChksum(header->cchk, header->chk);
return score;
}

View File

@@ -1,62 +0,0 @@
/* 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
smc.h: SMC file structures
*/
#ifndef SMC_H
#define SMC_H
typedef struct _snes_header {
uint8_t maker[2]; // 0xB0
uint8_t gamecode[4]; // 0xB2
uint8_t fixed_00[7]; // 0xB6
uint8_t expramsize; // 0xBD
uint8_t specver; // 0xBE
uint8_t carttype2; // 0xBF
uint8_t name[21]; // 0xC0
uint8_t map; // 0xD5
uint8_t carttype; // 0xD6
uint8_t romsize; // 0xD7
uint8_t ramsize; // 0xD8
uint8_t destcode; // 0xD9
uint8_t fixed_33; // 0xDA
uint8_t ver; // 0xDB
uint16_t cchk; // 0xDC
uint16_t chk; // 0xDE
} snes_header_t;
typedef struct _snes_romprops {
uint16_t offset; // start of actual ROM image
uint8_t mapper_id; // FPGA mapper
uint8_t pad1; // for alignment
uint32_t expramsize_bytes; // ExpRAM size in bytes
uint32_t ramsize_bytes; // CartRAM size in bytes
uint32_t romsize_bytes; // ROM size in bytes (rounded up)
snes_header_t header; // original header from ROM image
} snes_romprops_t;
void smc_id(snes_romprops_t*);
uint8_t smc_headerscore(snes_header_t*);
#endif

View File

@@ -1,146 +0,0 @@
/* 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);
}

View File

@@ -1,37 +0,0 @@
/* 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

136
src/spi.c
View File

@@ -1,136 +0,0 @@
/* sd2snes - SD card based universal cartridge for the SNES
Copyright (C) 2009-2010 Maximilian Rehkopf <otakon@gmx.net>
This file was adapted from sd2iec, written by Ingo Korb.
Original copyright header follows:
*/
/* sd2iec - SD/MMC to Commodore serial bus interface/controller
Copyright (C) 2007-2009 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 access
Extended, optimized and cleaned version of code from MMC2IEC,
original copyright header follows:
//
// Title : SPI module
// Author : Lars Pontoppidan
// Date : January, 2007
// Version : 1.03
// Target MCU : Atmel AVR Series
//
// DESCRIPTION:
// This module implements initialization, sending and receiving bytes using
// hardware SPI on an AVR.
//
// 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
//
*/
// FIXME: Integrate into sdcard.c
#include <avr/io.h>
#include "avrcompat.h"
#include "spi.h"
// access routines
void spiInit(void)
{
volatile uint8_t dummy;
// setup SPI I/O pins
SPI_PORT = (SPI_PORT & ~SPI_MASK) | SPI_SCK | SPI_SS | SPI_MISO;
SPI_DDR = (SPI_DDR & ~SPI_MASK) | SPI_SCK | SPI_SS | SPI_MOSI;
// setup SPI interface:
// interrupts disabled, SPI enabled, MSB first, master mode,
// leading edge rising, sample on leading edge, clock = f/4
SPCR = 0b01010000;
// Enable SPI double speed mode -> clock = f/2
SPSR = _BV(SPI2X);
// clear status
dummy = SPSR;
// clear receive buffer
dummy = SPDR;
}
inline uint8_t spiTransferByte(uint8_t data)
{
// send the given data
SPDR = data;
// wait for transfer to complete
loop_until_bit_is_set(SPSR, SPIF);
// *** reading of the SPSR and SPDR are crucial
// *** to the clearing of the SPIF flag
// *** in non-interrupt mode
// return the received data
return SPDR;
}
inline uint32_t spiTransferLong(const uint32_t data)
{
// It seems to be necessary to use the union in order to get efficient
// assembler code.
// Beware, endian unsafe union
union {
uint32_t l;
uint8_t c[4];
} long2char;
long2char.l = data;
// send the given data
SPDR = long2char.c[3];
// wait for transfer to complete
loop_until_bit_is_set(SPSR, SPIF);
long2char.c[3] = SPDR;
SPDR = long2char.c[2];
// wait for transfer to complete
loop_until_bit_is_set(SPSR, SPIF);
long2char.c[2] = SPDR;
SPDR = long2char.c[1];
// wait for transfer to complete
loop_until_bit_is_set(SPSR, SPIF);
long2char.c[1] = SPDR;
SPDR = long2char.c[0];
// wait for transfer to complete
loop_until_bit_is_set(SPSR, SPIF);
long2char.c[0] = SPDR;
return long2char.l;
}

View File

@@ -1,73 +0,0 @@
/* sd2snes - SD card based universal cartridge for the SNES
Copyright (C) 2009-2010 Maximilian Rehkopf <otakon@gmx.net>
This file was adapted from sd2iec, written by Ingo Korb.
Original copyright header follows:
*/
/* sd2iec - SD/MMC to Commodore serial bus interface/controller
Copyright (C) 2007-2009 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
// function prototypes
// SPI interface initializer
void spiInit(void);
// spiTransferByte(u08 data) waits until the SPI interface is ready
// and then sends a single byte over the SPI port. The function also
// returns the byte that was received during transmission.
uint8_t spiTransferByte(uint8_t data);
// spiTransferLong(u08 data) waits until the SPI interface is ready
// and then sends the long with MSB first over the SPI port.
uint32_t spiTransferLong(uint32_t data);
// Macros for setting slave select:
#ifdef CONFIG_TWINSD
# define SPI_SS_HIGH(card) do { \
if (card == 0) { \
SPI_PORT |= SPI_SS; \
} else { \
SD2_PORT |= SD2_CS; \
} \
} while (0)
#define SPI_SS_LOW(card) do { \
if (card == 0) { \
SPI_PORT &= (uint8_t)~SPI_SS; \
} else { \
SD2_PORT &= (uint8_t)~SD2_CS; \
} \
} while (0)
#else
# define SPI_SS_HIGH(card) SPI_PORT |= SPI_SS
# define SPI_SS_LOW(card) SPI_PORT &= (uint8_t)~SPI_SS
#endif
#endif

View File

@@ -1,75 +0,0 @@
#!/usr/bin/perl -w -i~
# src2doxy.pl - create doxygen-compatible comments from readable C source
# Copyright (C) 2008 Ingo Korb <ingo@akana.de>
#
# 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
#
# This script parses a subset of kernel-doc style comments and rewrites
# them as something doxygen will understand.
use strict;
my $incomment = 0;
my $inspecialcomment = 0;
my @postcomment = ();
my @outputstack;
while (<>) {
my $filename;
($filename = $ARGV) =~ s!.*/!!;
chomp;
s/\r$//;
s/\s+$//;
# doxygen is too stupid to understand after-the-variable comments
# without external help. WARNING: Will substitute within strings!
s!([^ \t]\s+)/// !$1///< !;
$incomment = 1 if m!^/\*!;
if (m!^/\*\*$!) {
$inspecialcomment = 1;
# Kill output
$_ = "";
next;
}
if ($incomment) {
if (m!\*/$!) {
# End of comment
$incomment = 0;
$inspecialcomment = 0;
@outputstack = @postcomment;
@postcomment = ();
} elsif (/$filename:\s+(.*).?\s*$/) {
# Add file description
push @postcomment, "\n/*! \\file $ARGV\n * \\brief $1. */\n";
}
if ($inspecialcomment == 1) {
# First line of special comment: Brief description
$inspecialcomment = 2;
m/^\s*\*\s*((struct |union )?[^: \t]+):?\s+-?\s*(.*)\s*$/;
$_ = "/*! \\brief $3\n *";
} elsif ($inspecialcomment == 2) {
# Modify parameters
s/\@([^: \t]+)\s*:\s+(.*)\s*$/\\param $1 $2/;
}
}
} continue {
print "$_\n";
while (scalar(@outputstack)) {
print shift @outputstack,"\n";
}
}

View File

@@ -1,16 +0,0 @@
#ifndef TIME_H
#define TIME_H
typedef uint32_t time_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
};
#endif /* TIME_H */

View File

@@ -1,135 +0,0 @@
/* sd2snes - SD card based universal cartridge for the SNES
Copyright (C) 2009-2010 Maximilian Rehkopf <otakon@gmx.net>
This file was adapted from sd2iec, written by Ingo Korb.
Original copyright header follows:
*/
/* sd2iec - SD/MMC to Commodore serial bus interface/controller
Copyright (C) 2007-2009 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
timer.c: System timer (and button debouncer)
*/
#include "config.h"
#include <avr/interrupt.h>
#include <avr/io.h>
#include "avrcompat.h"
#include "led.h"
#include "timer.h"
volatile tick_t ticks;
// Logical buttons
volatile uint8_t active_keys;
// Physical buttons
uint8_t buttonstate;
tick_t lastbuttonchange;
/* Called by the timer interrupt when the button state has changed */
static void buttons_changed(void) {
/* Check if the previous state was stable for two ticks */
if (time_after(ticks, lastbuttonchange+2)) {
if (active_keys & IGNORE_KEYS) {
active_keys &= ~IGNORE_KEYS;
} else if (!(buttonstate & (BUTTON_PREV|BUTTON_NEXT))) {
/* Both buttons held down */
active_keys |= KEY_HOME;
} else if (!(buttonstate & BUTTON_NEXT) &&
(BUTTON_PIN & BUTTON_NEXT)) {
/* "Next" button released */
active_keys |= KEY_NEXT;
} else if (!(buttonstate & BUTTON_PREV) &&
(BUTTON_PIN & BUTTON_NEXT)) {
active_keys |= KEY_PREV;
}
}
lastbuttonchange = ticks;
buttonstate = BUTTON_PIN & BUTTON_MASK;
}
/* The main timer interrupt */
ISR(TIMER1_COMPA_vect) {
uint8_t tmp = BUTTON_PIN & BUTTON_MASK;
if (tmp != buttonstate) {
buttons_changed();
}
ticks++;
#ifdef SINGLE_LED
if (led_state & LED_ERROR) {
if ((ticks & 15) == 0)
DIRTY_LED_PORT ^= DIRTY_LED_BIT();
} else {
if ((led_state & LED_BUSY) || (led_state & LED_DIRTY)) {
DIRTY_LED_ON();
} else {
DIRTY_LED_OFF();
}
}
#else
if (led_state & LED_ERROR)
if ((ticks & 15) == 0)
DIRTY_LED_PORT ^= DIRTY_LED_BIT();
#endif
/* Sleep button triggers when held down for 2sec */
if (time_after(ticks, lastbuttonchange+2)) {
if (!(buttonstate & BUTTON_NEXT) &&
(buttonstate & BUTTON_PREV) &&
time_after(ticks, lastbuttonchange+2*HZ) &&
!key_pressed(KEY_SLEEP)) {
/* Set ignore flag so the release doesn't trigger KEY_NEXT */
active_keys |= KEY_SLEEP | IGNORE_KEYS;
/* Avoid triggering for the next two seconds */
lastbuttonchange = ticks;
}
}
#if CONFIG_RTC_VARIANT == 1
increment_rtc();
#endif
#ifdef CONFIG_REMOTE_DISPLAY
/* Check if the display wants to be queried */
if (!(SOFTI2C_PIN & _BV(SOFTI2C_BIT_INTRQ))) {
active_keys |= KEY_DISPLAY;
}
#endif
}
void timer_init(void) {
/* Count F_CPU/8 in timer 0 */
TCCR0B = _BV(CS01);
/* Set up a 100Hz interrupt using timer 1 */
OCR1A = 1249;
TCNT1 = 0;
TCCR1A = 0;
TCCR1B = _BV(WGM12) | _BV(CS10) | _BV(CS11);
TIMSK1 |= _BV(OCIE1A);
/* Buttons */
BUTTON_DDR &= (uint8_t)~BUTTON_MASK;
BUTTON_PORT |= BUTTON_MASK;
}

View File

@@ -1,121 +0,0 @@
/* sd2snes - SD card based universal cartridge for the SNES
Copyright (C) 2009-2010 Maximilian Rehkopf <otakon@gmx.net>
This file was adapted from sd2iec, written by Ingo Korb.
Original copyright header follows:
*/
/* sd2iec - SD/MMC to Commodore serial bus interface/controller
Copyright (C) 2007-2009 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
timer.h: System timer (and button-debouncer)
*/
#ifndef TIMER_H
#define TIMER_H
#include <util/atomic.h>
// Bit masks for the (simulated) keys
#define KEY_NEXT (1<<0)
#define KEY_PREV (1<<1)
#define KEY_HOME (1<<2)
#define KEY_SLEEP (1<<3)
/* Remote display service request */
#define KEY_DISPLAY (1<<4)
#define IGNORE_KEYS (1<<7)
/// Logical keys that were pressed - must be reset by the reader.
extern volatile uint8_t active_keys;
#define key_pressed(x) (active_keys & (x))
#define reset_key(x) active_keys &= (uint8_t)~(x)
#define ignore_keys() active_keys = IGNORE_KEYS;
typedef uint16_t tick_t;
/// Global timing variable, 100 ticks per second
/// Use atomic access or getticks() !
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) {
tick_t tmp;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
tmp = ticks;
}
return tmp;
}
#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) \
((int16_t)(b) - (int16_t)(a) < 0)
#define time_before(a,b) time_after(b,a)
/// Calculate timer start value for given timeout in microseconds
#define TIMEOUT_US(x) (256-((float)F_CPU/10000000.0)*x)
/**
* start_timeout - start a timeout using timer0
* @startval: starting value for timer
*
* This function sets timer 0 to the specified value and clears its overflow
* flag. Use in conjunction with TIMEOUT_US to cause a timer overflow after
* a specified number of microseconds. DON'T use a variable as a parameter to
* the TIMEOUT_US macro because that would require run-time float calculations.
*/
#define start_timeout(startval) do { TCNT0 = startval; TIFR0 |= _BV(TOV0); } while (0)
/**
* has_timed_out - returns true if timeout was reached
*
* This function returns true if the overflow flag of timer 0 is set which
* (together with start_timeout and TIMEOUT_US) will happen when the
* specified time has elapsed.
*/
#define has_timed_out() (TIFR0 & _BV(TOV0))
void timer_init(void);
#endif

View File

@@ -1,187 +0,0 @@
/* sd2snes - SD card based universal cartridge for the SNES
Copyright (C) 2009-2010 Maximilian Rehkopf <otakon@gmx.net>
This file was adapted from sd2iec, written by Ingo Korb.
Original copyright header follows:
*/
/* sd2iec - SD/MMC to Commodore serial bus interface/controller
Copyright (C) 2007-2009 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
uart.c: UART access routines
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <stdio.h>
#include "config.h"
#include "avrcompat.h"
#include "uart.h"
static uint8_t txbuf[1 << CONFIG_UART_BUF_SHIFT];
static volatile uint16_t read_idx;
static volatile uint16_t write_idx;
ISR(USART_UDRE_vect) {
if (read_idx == write_idx) return;
UDR = txbuf[read_idx];
read_idx = (read_idx+1) & (sizeof(txbuf)-1);
if (read_idx == write_idx)
UCSRB &= ~ _BV(UDRIE);
}
void uart_putc(char c) {
uint16_t t=(write_idx+1) & (sizeof(txbuf)-1);
#ifndef CONFIG_DEADLOCK_ME_HARDER // :-)
UCSRB &= ~ _BV(UDRIE); // turn off RS232 irq
#else
while (t == read_idx); // wait for free space
#endif
txbuf[write_idx] = c;
write_idx = t;
//if (read_idx == write_idx) PORTD |= _BV(PD7);
UCSRB |= _BV(UDRIE);
}
void uart_puthex(uint8_t num) {
uint8_t tmp;
tmp = (num & 0xf0) >> 4;
if (tmp < 10)
uart_putc('0'+tmp);
else
uart_putc('a'+tmp-10);
tmp = num & 0x0f;
if (tmp < 10)
uart_putc('0'+tmp);
else
uart_putc('a'+tmp-10);
}
void uart_puthexlong(uint32_t num) {
uart_puthex((num>>24)&0xff);
uart_puthex((num>>16)&0xff);
uart_puthex((num>>8)&0xff);
uart_puthex(num&0xff);
}
void uart_puthexshort(uint16_t num) {
uart_puthex((num>>8)&0xff);
uart_puthex(num&0xff);
}
void uart_trace(void *ptr, uint16_t start, uint16_t len) {
uint16_t i;
uint8_t j;
uint8_t ch;
uint8_t *data = ptr;
data+=start;
for(i=0;i<len;i+=16) {
uart_puthex(start>>8);
uart_puthex(start&0xff);
uart_putc('|');
uart_putc(' ');
for(j=0;j<16;j++) {
if(i+j<len) {
ch=*(data + j);
uart_puthex(ch);
} else {
uart_putc(' ');
uart_putc(' ');
}
uart_putc(' ');
}
uart_putc('|');
for(j=0;j<16;j++) {
if(i+j<len) {
ch=*(data++);
if(ch<32 || ch>0x7e)
ch='.';
uart_putc(ch);
} else {
uart_putc(' ');
}
}
uart_putc('|');
uart_putcrlf();
start+=16;
}
}
static int ioputc(char c, FILE *stream) {
if (c == '\n') uart_putc('\r');
uart_putc(c);
return 0;
}
uint8_t uart_getc(void) {
loop_until_bit_is_set(UCSRA,RXC);
return UDR;
}
void uart_flush(void) {
while (read_idx != write_idx) ;
}
void uart_puts_P(prog_char *text) {
uint8_t ch;
while ((ch = pgm_read_byte(text++))) {
uart_putc(ch);
}
}
void uart_putcrlf(void) {
uart_putc(13);
uart_putc(10);
}
static FILE mystdout = FDEV_SETUP_STREAM(ioputc, NULL, _FDEV_SETUP_WRITE);
void uart_init(void) {
/* Seriellen Port konfigurieren */
/* UBRRH = (int)((double)F_CPU/(16.0*CONFIG_UART_BAUDRATE)-1) >> 8;
UBRRL = (int)((double)F_CPU/(16.0*CONFIG_UART_BAUDRATE)-1) & 0xff;*/
UBRRH = (int)((double)F_CPU/(8.0*CONFIG_UART_BAUDRATE)-1) >> 8;
UBRRL = (int)((double)F_CPU/(8.0*CONFIG_UART_BAUDRATE)-1) & 0xff;
UCSRA |= _BV(U2X0);
UCSRB = _BV(RXEN) | _BV(TXEN);
// I really don't like random #ifdefs in the code =(
#if defined __AVR_ATmega32__
UCSRC = _BV(URSEL) | _BV(UCSZ1) | _BV(UCSZ0);
#else
UCSRC = _BV(UCSZ1) | _BV(UCSZ0);
#endif
stdout = &mystdout;
//UCSRB |= _BV(UDRIE);
read_idx = 0;
write_idx = 0;
}

View File

@@ -1,66 +0,0 @@
/* sd2snes - SD card based universal cartridge for the SNES
Copyright (C) 2009-2010 Maximilian Rehkopf <otakon@gmx.net>
This file was adapted from sd2iec, written by Ingo Korb.
Original copyright header follows:
*/
/* sd2iec - SD/MMC to Commodore serial bus interface/controller
Copyright (C) 2007-2009 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
uart.h: Definitions for the UART access routines
*/
#ifndef UART_H
#define UART_H
#ifdef CONFIG_UART_DEBUG
#include <avr/pgmspace.h>
void uart_init(void);
unsigned char uart_getc(void);
void uart_putc(char c);
void uart_puthex(uint8_t num);
void uart_puthexlong(uint32_t num);
void uart_puthexshort(uint16_t num);
void uart_trace(void *ptr, uint16_t start, uint16_t len);
void uart_flush(void);
void uart_puts_P(prog_char *text);
void uart_putcrlf(void);
#include <stdio.h>
#define dprintf(str,...) printf_P(PSTR(str), ##__VA_ARGS__)
#else
#define uart_init() do {} while(0)
#define uart_getc() 0
#define uart_putc(x) do {} while(0)
#define uart_puthex(x) do {} while(0)
#define uart_flush() do {} while(0)
#define uart_puts_P(x) do {} while(0)
#define uart_putcrlf() do {} while(0)
#define uart_trace(a,b,c) do {} while(0)
#endif
#endif

View File

@@ -1,47 +0,0 @@
/* sd2snes - SD card based universal cartridge for the SNES
Copyright (C) 2009-2010 Maximilian Rehkopf <otakon@gmx.net>
This file was adapted from sd2iec, written by Ingo Korb.
Original copyright header follows:
*/
/* sd2iec - SD/MMC to Commodore serial bus interface/controller
Copyright (C) 2007-2009 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
ustring.h: uint8_t wrappers for string.h-functions
*/
#ifndef USTRING_H
#define USTRING_H
#include <string.h>
#define ustrcasecmp_P(s1,s2) (strcasecmp_P((char *)(s1), (s2)))
#define ustrchr(s,c) ((uint8_t *)strchr((char *)(s), (c)))
#define ustrcmp(s1,s2) (strcmp((char *)(s1), (char *)(s2)))
#define ustrcmp_P(s1,s2) (strcmp_P((char *)(s1), (s2)))
#define ustrcpy(s1,s2) (strcpy((char *)(s1), (char *)(s2)))
#define ustrcpy_P(s1,s2) (strcpy_P((char *)(s1), (s2)))
#define ustrncpy(s1,s2,n) (strncpy((char *)(s1), (char *)(s2),(n)))
#define ustrlen(s) (strlen((char *)(s)))
#define ustrrchr(s,c) ((uint8_t *)strrchr((char *)(s), (c)))
#endif

View File

@@ -1,82 +0,0 @@
/* sd2snes - SD card based universal cartridge for the SNES
Copyright (C) 2009-2010 Maximilian Rehkopf <otakon@gmx.net>
This file was adapted from sd2iec, written by Ingo Korb.
Original copyright header follows:
*/
/* sd2iec - SD/MMC to Commodore serial bus interface/controller
Copyright (C) 2007-2009 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
utils.c: Misc. utility functions that didn't fit elsewhere
*/
#include <stdint.h>
#include "ustring.h"
uint8_t *appendnumber(uint8_t *msg, uint8_t value) {
if (value >= 100) {
*msg++ = '0' + value/100;
value %= 100;
}
*msg++ = '0' + value/10;
*msg++ = '0' + value%10;
return msg;
}
/* Convert a one-byte BCD value to a normal integer */
uint8_t bcd2int(uint8_t value) {
return (value & 0x0f) + 10*(value >> 4);
}
/* Convert a uint8_t into a BCD value */
uint8_t int2bcd(uint8_t value) {
return (value % 10) + 16*(value/10);
}
/* Similiar to strtok_r, but only a single delimiting character */
uint8_t *ustr1tok(uint8_t *str, const uint8_t delim, uint8_t **saveptr) {
uint8_t *tmp;
if (str == NULL)
str = *saveptr;
/* Skip leading delimiters */
while (*str == delim) str++;
/* If there is anything left... */
if (*str) {
/* Search for the next delimiter */
tmp = str;
while (*tmp && *tmp != delim) tmp++;
/* Terminate the string there */
if (*tmp != 0)
*tmp++ = 0;
*saveptr = tmp;
return str;
} else
return NULL;
}

View File

@@ -1,57 +0,0 @@
/* sd2snes - SD card based universal cartridge for the SNES
Copyright (C) 2009-2010 Maximilian Rehkopf <otakon@gmx.net>
This file was adapted from sd2iec, written by Ingo Korb.
Original copyright header follows:
*/
/* sd2iec - SD/MMC to Commodore serial bus interface/controller
Copyright (C) 2007-2009 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
utils.c: Misc. utility functions that didn't fit elsewhere
*/
#ifndef UTILS_H
#define UTILS_H
/* Side-effect safe min/max */
#define max(a,b) \
({ typeof (a) _a = (a); \
typeof (b) _b = (b); \
_a > _b ? _a : _b; })
#define min(a,b) \
({ typeof (a) _a = (a); \
typeof (b) _b = (b); \
_a < _b ? _a : _b; })
/* Write a number to a string as ASCII */
uint8_t *appendnumber(uint8_t *msg, uint8_t value);
/* Convert between integer and BCD */
uint8_t bcd2int(uint8_t value);
uint8_t int2bcd(uint8_t value);
/* Tokenize a string like strtok_r, but with a single delimiter character only */
uint8_t *ustr1tok(uint8_t *str, const uint8_t delim, uint8_t **saveptr);
#endif