Initial Commit

This commit is contained in:
ikari 2009-07-02 11:14:04 +02:00
commit e121b34cf4
60 changed files with 9256 additions and 0 deletions

BIN
pcb/DIL-Labels.sch Normal file

Binary file not shown.

BIN
pcb/breakout1.brd Normal file

Binary file not shown.

BIN
pcb/breakout2.brd Normal file

Binary file not shown.

BIN
pcb/breakout2.sch Normal file

Binary file not shown.

BIN
pcb/breakouts1-old.brd Normal file

Binary file not shown.

BIN
pcb/snesbreakout.brd Normal file

Binary file not shown.

BIN
pcb/snesbreakout.sch Normal file

Binary file not shown.

247
pcb/test.brd Normal file
View File

@ -0,0 +1,247 @@
PCBNEW-BOARD Version 1 date 18/5/2009-17:20:42
$GENERAL
LayerCount 2
Ly 1FFF8001
Links 0
NoConn 0
Di 8440 7940 13560 13060
Ndraw 0
Ntrack 0
Nzone 0
Nmodule 2
Nnets 0
$EndGENERAL
$SHEETDESCR
Sheet A4 11700 8267
Title ""
Date "18 may 2009"
Rev ""
Comp ""
Comment1 ""
Comment2 ""
Comment3 ""
Comment4 ""
$EndSHEETDESCR
$SETUP
InternalUnit 0.000100 INCH
UserGridSize 0.010000 0.010000 mm
ZoneGridSize 250
Layers 2
Layer[0] Copper signal
Layer[15] Component signal
TrackWidth 170
TrackWidthHistory 170
TrackClearence 60
ZoneClearence 150
DrawSegmWidth 150
EdgeSegmWidth 150
ViaSize 450
ViaDrill 250
ViaSizeHistory 450
MicroViaSize 200
MicroViaDrill 80
MicroViasAllowed 0
TextPcbWidth 120
TextPcbSize 600 800
EdgeModWidth 150
TextModSize 600 600
TextModWidth 120
PadSize 600 600
PadDrill 320
AuxiliaryAxisOrg 0 0
$EndSETUP
$EQUIPOT
Na 0 ""
St ~
$EndEQUIPOT
$MODULE PIN_ARRAY_5x2
Po 11000 12000 0 15 3FCF2109 4A11978A ~~
Li PIN_ARRAY_5x2
Cd Double rangee de contacts 2 x 5 pins
Kw CONN
Sc 4A11978A
AR /4A11978A
Op 0 0 0
T0 250 -1500 400 400 0 80 N V 21 "P102"
T1 0 -1500 400 400 0 80 N I 21 "CONN_5X2"
DS -2500 -1000 2500 -1000 120 21
DS 2500 -1000 2500 1000 120 21
DS 2500 1000 -2500 1000 120 21
DS -2500 1000 -2500 -1000 120 21
$PAD
Sh "1" R 600 600 0 0 0
Dr 400 0 0
At STD N 00E0FFFF
Ne 0 ""
Po -2000 500
$EndPAD
$PAD
Sh "2" C 600 600 0 0 0
Dr 400 0 0
At STD N 00E0FFFF
Ne 0 ""
Po -2000 -500
$EndPAD
$PAD
Sh "3" C 600 600 0 0 0
Dr 400 0 0
At STD N 00E0FFFF
Ne 0 ""
Po -1000 500
$EndPAD
$PAD
Sh "4" C 600 600 0 0 0
Dr 400 0 0
At STD N 00E0FFFF
Ne 0 ""
Po -1000 -500
$EndPAD
$PAD
Sh "5" C 600 600 0 0 0
Dr 400 0 0
At STD N 00E0FFFF
Ne 0 ""
Po 0 500
$EndPAD
$PAD
Sh "6" C 600 600 0 0 0
Dr 400 0 0
At STD N 00E0FFFF
Ne 0 ""
Po 0 -500
$EndPAD
$PAD
Sh "7" C 600 600 0 0 0
Dr 400 0 0
At STD N 00E0FFFF
Ne 0 ""
Po 1000 500
$EndPAD
$PAD
Sh "8" C 600 600 0 0 0
Dr 400 0 0
At STD N 00E0FFFF
Ne 0 ""
Po 1000 -500
$EndPAD
$PAD
Sh "9" C 600 600 0 0 0
Dr 400 0 0
At STD N 00E0FFFF
Ne 0 ""
Po 2000 500
$EndPAD
$PAD
Sh "10" C 600 600 0 0 0
Dr 400 0 0
At STD N 00E0FFFF
Ne 0 ""
Po 2000 -500
$EndPAD
$SHAPE3D
Na "pin_array/pins_array_5x2.wrl"
Sc 1.000000 1.000000 1.000000
Of 0.000000 0.000000 0.000000
Ro 0.000000 0.000000 0.000000
$EndSHAPE3D
$EndMODULE PIN_ARRAY_5x2
$MODULE PIN_ARRAY_5x2
Po 11000 9000 0 15 3FCF2109 4A119787 ~~
Li PIN_ARRAY_5x2
Cd Double rangee de contacts 2 x 5 pins
Kw CONN
Sc 4A119787
AR /4A119787
Op 0 0 0
T0 250 -1500 400 400 0 80 N V 21 "P101"
T1 0 -1500 400 400 0 80 N I 21 "CONN_5X2"
DS -2500 -1000 2500 -1000 120 21
DS 2500 -1000 2500 1000 120 21
DS 2500 1000 -2500 1000 120 21
DS -2500 1000 -2500 -1000 120 21
$PAD
Sh "1" R 600 600 0 0 0
Dr 400 0 0
At STD N 00E0FFFF
Ne 0 ""
Po -2000 500
$EndPAD
$PAD
Sh "2" C 600 600 0 0 0
Dr 400 0 0
At STD N 00E0FFFF
Ne 0 ""
Po -2000 -500
$EndPAD
$PAD
Sh "3" C 600 600 0 0 0
Dr 400 0 0
At STD N 00E0FFFF
Ne 0 ""
Po -1000 500
$EndPAD
$PAD
Sh "4" C 600 600 0 0 0
Dr 400 0 0
At STD N 00E0FFFF
Ne 0 ""
Po -1000 -500
$EndPAD
$PAD
Sh "5" C 600 600 0 0 0
Dr 400 0 0
At STD N 00E0FFFF
Ne 0 ""
Po 0 500
$EndPAD
$PAD
Sh "6" C 600 600 0 0 0
Dr 400 0 0
At STD N 00E0FFFF
Ne 0 ""
Po 0 -500
$EndPAD
$PAD
Sh "7" C 600 600 0 0 0
Dr 400 0 0
At STD N 00E0FFFF
Ne 0 ""
Po 1000 500
$EndPAD
$PAD
Sh "8" C 600 600 0 0 0
Dr 400 0 0
At STD N 00E0FFFF
Ne 0 ""
Po 1000 -500
$EndPAD
$PAD
Sh "9" C 600 600 0 0 0
Dr 400 0 0
At STD N 00E0FFFF
Ne 0 ""
Po 2000 500
$EndPAD
$PAD
Sh "10" C 600 600 0 0 0
Dr 400 0 0
At STD N 00E0FFFF
Ne 0 ""
Po 2000 -500
$EndPAD
$SHAPE3D
Na "pin_array/pins_array_5x2.wrl"
Sc 1.000000 1.000000 1.000000
Of 0.000000 0.000000 0.000000
Ro 0.000000 0.000000 0.000000
$EndSHAPE3D
$EndMODULE PIN_ARRAY_5x2
$TRACK
$EndTRACK
$ZONE
$EndZONE
$EndBOARD

34
pcb/test.sch Normal file
View File

@ -0,0 +1,34 @@
EESchema Schematic File Version 2
LIBS:power,device,conn,linear,regul,74xx,cmos4000,adc-dac,memory,xilinx,special,microcontrollers,dsp,microchip,analog_switches,motorola,texas,intel,audio,interface,digital-audio,philips,display,cypress,siliconi,contrib,valves
EELAYER 24 0
EELAYER END
$Descr A4 11700 8267
Sheet 1 1
Title ""
Date "18 may 2009"
Rev ""
Comp ""
Comment1 ""
Comment2 ""
Comment3 ""
Comment4 ""
$EndDescr
$Comp
L CONN_5X2 P101
U 1 1 4A119787
P 2100 1250
F 0 "P101" H 2100 1550 60 0000 C C
F 1 "CONN_5X2" V 2100 1250 50 0000 C C
1 2100 1250
1 0 0 -1
$EndComp
$Comp
L CONN_5X2 P102
U 1 1 4A11978A
P 2100 2200
F 0 "P102" H 2100 2500 60 0000 C C
F 1 "CONN_5X2" V 2100 2200 50 0000 C C
1 2100 2200
1 0 0 -1
$EndComp
$EndSCHEMATC

618
src/Makefile Normal file
View File

@ -0,0 +1,618 @@
# 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.
#
# Released to the Public Domain
#
# Additional material for this makefile was written by:
# Peter Fleury
# Tim Henigan
# Colin O'Flynn
# Reiner Patommel
# Markus Pfaff
# Sander Pool
# Frederik Rouleau
# Carlos Lamas
#
#
# Extensively modified for sd2iec by Ingo Korb
#
# To rebuild project do "make clean" then "make all".
#----------------------------------------------------------------------------
# Read configuration file
ifdef CONFIG
CONFIGSUFFIX = $(CONFIG:config%=%)
else
CONFIG = config
CONFIGSUFFIX =
endif
# Enable verbose compilation with "make V=1"
ifdef V
Q :=
E := @:
else
Q := @
E := @echo
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
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)
# Output format. (can be srec, ihex, binary)
FORMAT = ihex
# 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 timer.c led.c diskio.c sdcard.c spi.c crc7.c snes.c fpga.c memory.c crc16.c fileops.c
ifeq ($(CONFIG_UART_DEBUG),y)
SRC += uart.c
endif
# List Assembler source files here.
# Make them always end in a capital .S. Files ending in a lowercase .s
# will not be considered source files but generated files (assembler
# output from the compiler), and will be deleted upon "make clean"!
# 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 =
# 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 = 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
# List any extra directories to look for include files here.
# Each directory must be seperated by a space.
# Use forward slashes for directory separators.
# For a directory that has spaces, enclose it in quotes.
EXTRAINCDIRS =
# Compiler flag to set the C Standard level.
# c89 = "ANSI" C
# gnu89 = c89 plus GCC extensions
# c99 = ISO C99 standard (not yet fully implemented)
# gnu99 = c99 plus GCC extensions
CSTANDARD = -std=gnu99
# Place -D or -U options here
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 =
# 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
REMOVE = rm -f
COPY = cp
WINSHELL = cmd
#---------------- Compiler Options ----------------
# -g*: generate debugging information
# -O*: optimization level
# -f...: tuning, see GCC manual and avr-libc documentation
# -Wall...: warning level
# -Wa,...: tell GCC to pass this to the assembler.
# -adhlns...: create assembler listing
CFLAGS = -g$(DEBUG)
CFLAGS += $(CDEFS) $(CINCS)
CFLAGS += -O$(OPT)
CFLAGS += -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
CFLAGS += -Wall -Wstrict-prototypes -Werror
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 ----------------
# -Wa,...: tell GCC to pass this to the assembler.
# -ahlms: create listing
# -gstabs: have the assembler create line number information; note that
# 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 =
#---------------- Linker Options ----------------
# -Wl,...: tell GCC to pass this to linker.
# -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 += -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 = stk200
# com1 = serial port. Use lpt1 to connect to parallel port.
AVRDUDE_PORT = /dev/parport0 # 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
#============================================================================
# De-dupe the list of C source files
CSRC := $(sort $(SRC))
# Define all object files.
OBJ := $(patsubst %,$(OBJDIR)/%,$(CSRC:.c=.o) $(ASRC:.S=.o))
# Define all listing files.
LST := $(patsubst %,$(OBJDIR)/%,$(CSRC:.c=.lst) $(ASRC:.S=.lst))
# Compiler flags to generate dependency files.
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)
# Default target.
all: build
build: elf bin hex
$(E) " SIZE $(TARGET).elf"
$(Q)$(ELFSIZE)|grep -v debug
elf: $(TARGET).elf
bin: $(TARGET).bin
hex: $(TARGET).hex
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
# Doxygen output:
doxygen:
-rm -rf doxyinput
mkdir doxyinput
cp *.h *.c doxyinput
src2doxy.pl doxyinput/*.h doxyinput/*.c
doxygen doxygen.conf
# 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
# Create final output files (.hex, .eep) from ELF output file.
ifeq ($(CONFIG_BOOTLOADER),y)
$(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
$(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) $< $@
# Create extended listing file from ELF output file.
$(OBJDIR)/%.lss: $(OBJDIR)/%.elf
$(E) " LSS $<"
$(Q)$(OBJDUMP) -h -S $< > $@
# Create a symbol table from ELF output file.
$(OBJDIR)/%.sym: $(OBJDIR)/%.elf
$(E) " SYM $<"
$(E)$(NM) -n $< > $@
# Link: create ELF output file from object files.
.SECONDARY : $(TARGET).elf
.PRECIOUS : $(OBJ)
$(OBJDIR)/%.elf: $(OBJ)
$(E) " LINK $@"
$(Q)$(CC) $(ALL_CFLAGS) $^ --output $@ $(LDFLAGS)
# Compile: create object files from C source files.
$(OBJDIR)/%.o : %.c | $(OBJDIR) $(OBJDIR)/autoconf.h
$(E) " CC $<"
$(Q)$(CC) -c $(ALL_CFLAGS) $< -o $@
# Compile: create assembler files from C source files.
$(OBJDIR)/%.s : %.c | $(OBJDIR) $(OBJDIR)/autoconf.h
$(CC) -S $(ALL_CFLAGS) $< -o $@
# Assemble: create object files from assembler source files.
$(OBJDIR)/%.o : %.S | $(OBJDIR) $(OBJDIR)/autoconf.h
$(E) " AS $<"
$(Q)$(CC) -c $(ALL_ASFLAGS) $< -o $@
# Create preprocessed source for use in sending a bug report.
$(OBJDIR)/%.i : %.c | $(OBJDIR) $(OBJDIR)/autoconf.h
$(CC) -E -mmcu=$(MCU) -I. $(CFLAGS) $< -o $@
# Create the output directory
$(OBJDIR):
$(E) " MKDIR $(OBJDIR)"
$(Q)mkdir $(OBJDIR)
# Target: clean project.
clean: begin clean_list end
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
$(Q)$(REMOVE) $(TARGET).lss
$(Q)$(REMOVE) $(OBJ)
$(Q)$(REMOVE) $(OBJDIR)/autoconf.h
$(Q)$(REMOVE) $(OBJDIR)/*.bin
$(Q)$(REMOVE) $(LST)
$(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

162
src/avrcompat.h Normal file
View File

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

29
src/conf2h.awk Normal file
View File

@ -0,0 +1,29 @@
#! /usr/bin/gawk -f
# Trivial little script to convert from a makefile-style configuration
# file to a C header. No copyright claimed.
BEGIN {
print "// autoconf.h generated from " ARGV[1] " at " strftime() "\n" \
"#ifndef AUTOCONF_H\n" \
"#define AUTOCONF_H"
}
/^#/ { sub(/^#/,"//") }
/^CONFIG_.*=/ {
if (/=n$/) {
sub(/^/,"// ");
} else {
sub(/^/,"#define ")
if (/=y$/) {
sub(/=.*$/,"")
} else {
sub(/=/," ")
}
}
}
{ print }
END { print "#endif" }

41
src/config Normal file
View File

@ -0,0 +1,41 @@
# This may not look like it, but it's a -*- makefile -*-
#
# 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=atmega644p
CONFIG_LINKER_RELAX=n
CONFIG_MCU_FREQ=14318180
CONFIG_BOOTLOADER=y
CONFIG_BOOT_DEVID=0x4e534453
CONFIG_UART_DEBUG=y
CONFIG_UART_BAUDRATE=38400
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=2

113
src/config.h Normal file
View File

@ -0,0 +1,113 @@
/* 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 (PIND & _BV(PD6))
# define SDCARD_WP_SETUP() do { DDRD &= ~ _BV(PD6); PORTD |= _BV(PD6); } 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

51
src/crc16.c Normal file
View File

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

54
src/crc16.h Normal file
View File

@ -0,0 +1,54 @@
/**
* \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__ */

74
src/crc32.c Normal file
View File

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

85
src/crc32.h Normal file
View File

@ -0,0 +1,85 @@
/**
* \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__ */

107
src/crc7.c Normal file
View File

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

33
src/crc7.h Normal file
View File

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

85
src/crcgen-new.c Normal file
View File

@ -0,0 +1,85 @@
#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;
}

197
src/diskio.c Normal file
View File

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

125
src/diskio.h Normal file
View File

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

170
src/eeprom.c Normal file
View File

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

33
src/eeprom.h Normal file
View File

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

2936
src/ff.c Normal file

File diff suppressed because it is too large Load Diff

547
src/ff.h Normal file
View File

@ -0,0 +1,547 @@
/*---------------------------------------------------------------------------/
/ FatFs - FAT file system module include file R0.07a (C)ChaN, 2009
/----------------------------------------------------------------------------/
/ FatFs module is an open source software to implement FAT file system to
/ small embedded systems. This is a free software and is opened for education,
/ research and commercial developments under license policy of following trems.
/
/ Copyright (C) 2009, ChaN, all right reserved.
/
/ * The FatFs module is a free software and there is NO WARRANTY.
/ * No restriction on use. You can use, modify and redistribute it for
/ personal, non-profit or commercial use UNDER YOUR RESPONSIBILITY.
/ * Redistributions of source code must retain the above copyright notice.
/----------------------------------------------------------------------------*/
#include "integer.h"
/*---------------------------------------------------------------------------/
/ FatFs Configuration Options
/
/ CAUTION! Do not forget to make clean the project after any changes to
/ the configuration options.
/
/----------------------------------------------------------------------------*/
#ifndef _FATFS
#define _FATFS
#define _WORD_ACCESS 0
/* The _WORD_ACCESS option defines which access method is used to the word
/ data in the FAT structure.
/
/ 0: Byte-by-byte access. Always compatible with all platforms.
/ 1: Word access. Do not choose this unless following condition is met.
/
/ When the byte order on the memory is big-endian or address miss-aligned
/ word access results incorrect behavior, the _WORD_ACCESS must be set to 0.
/ If it is not the case, the value can also be set to 1 to improve the
/ performance and code efficiency. */
#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 _FS_TINY 0
/* When _FS_TINY is set to 1, FatFs uses the sector buffer in the file system
/ object instead of the sector buffer in the individual file object for file
/ data transfer. This reduces memory consumption 512 bytes each file object. */
#define _USE_STRFUNC 0
/* To enable string functions, set _USE_STRFUNC to 1 or 2. */
#define _USE_MKFS 0
/* To enable f_mkfs function, set _USE_MKFS to 1 and set _FS_READONLY to 0 */
#define _USE_FORWARD 0
/* To enable f_forward function, set _USE_FORWARD to 1 and set _FS_TINY to 1. */
#define _DRIVES 1
/* Number of volumes (logical drives) to be used. */
#define _MAX_SS 512
/* Maximum sector size to be handled. (512/1024/2048/4096) */
/* 512 for memroy card and hard disk, 1024 for floppy disk, 2048 for MO disk */
#define _MULTI_PARTITION 0
/* When _MULTI_PARTITION is set to 0, each volume is bound to the same physical
/ drive number and can mount only first primaly partition. When it is set to 1,
/ each volume is tied to the partitions listed in Drives[]. */
#define _CODE_PAGE 850
/* The _CODE_PAGE specifies the OEM code page to be used on the target system.
/ When it is non LFN configuration, there is no difference between SBCS code
/ pages. When LFN is enabled, the code page must always be set correctly.
/ 437 - U.S.
/ 720 - Arabic
/ 737 - Greek
/ 775 - Baltic
/ 850 - Multilingual Latin 1
/ 852 - Latin 2
/ 855 - Cyrillic
/ 857 - Turkish
/ 858 - Multilingual Latin 1 + Euro
/ 862 - Hebrew
/ 866 - Russian
/ 874 - Thai
/ 932 - Japanese Shift-JIS (DBCS)
/ 936 - Simplified Chinese GBK (DBCS)
/ 949 - Korean (DBCS)
/ 950 - Traditional Chinese Big5 (DBCS)
/ 1258 - Vietnam
*/
#define _USE_LFN 0
#define _MAX_LFN 255 /* Maximum LFN length to handle (max:255) */
/* The _USE_LFN option switches the LFN support.
/
/ 0: Disable LFN.
/ 1: Enable LFN with static working buffer on the bss. NOT REENTRANT.
/ 2: Enable LFN with dynamic working buffer on the caller's STACK.
/
/ The working buffer occupies (_MAX_LFN + 1) * 2 bytes. When enable LFN,
/ a Unicode - OEM code conversion function ff_convert() must be added to
/ the project. */
#define _FS_REENTRANT 0
#define _TIMEOUT 1000 /* Timeout period in unit of time ticks */
#define _SYNC_t HANDLE /* Type of sync object used on the OS. */
/* e.g. HANDLE, OS_EVENT*, ID and etc.. */
/* To make the FatFs module re-entrant, set _FS_REENTRANT to 1 and add user
/ provided synchronization handlers, ff_req_grant, ff_rel_grant,
/ ff_del_syncobj and ff_cre_syncobj function to the project. */
/* End of configuration options. Do not change followings without care. */
/*--------------------------------------------------------------------------*/
/* Definitions corresponds to multiple sector size */
#if _MAX_SS == 512
#define SS(fs) 512
#else
#if _MAX_SS == 1024 || _MAX_SS == 2048 || _MAX_SS == 4096
#define SS(fs) ((fs)->s_size)
#else
#error Sector size must be 512, 1024, 2048 or 4096.
#endif
#endif
/* File system object structure */
typedef struct _FATFS {
BYTE fs_type; /* FAT sub type */
BYTE drive; /* Physical drive number */
BYTE csize; /* Number of sectors per cluster */
BYTE n_fats; /* Number of FAT copies */
BYTE wflag; /* win[] dirty flag (1:must be written back) */
BYTE pad1;
WORD id; /* File system mount ID */
WORD n_rootdir; /* Number of root directory entries (0 on FAT32) */
#if _FS_REENTRANT
_SYNC_t sobj; /* Identifier of sync object */
#endif
#if _MAX_SS != 512U
WORD s_size; /* Sector size */
#endif
#if !_FS_READONLY
BYTE fsi_flag; /* fsinfo dirty flag (1:must be written back) */
BYTE pad2;
DWORD last_clust; /* Last allocated cluster */
DWORD free_clust; /* Number of free clusters */
DWORD fsi_sector; /* fsinfo sector */
#endif
DWORD sects_fat; /* Sectors per fat */
DWORD max_clust; /* Maximum cluster# + 1. Number of clusters is max_clust - 2 */
DWORD fatbase; /* FAT start sector */
DWORD dirbase; /* Root directory start sector (Cluster# on FAT32) */
DWORD database; /* Data start sector */
DWORD winsect; /* Current sector appearing in the win[] */
BYTE win[_MAX_SS];/* Disk access window for Directory/FAT */
} FATFS;
/* Directory object structure */
typedef struct _DIR {
WORD id; /* Owner file system mount ID */
WORD index; /* Current index number */
FATFS* fs; /* Pointer to the owner file system object */
DWORD sclust; /* Table start cluster (0:Static table) */
DWORD clust; /* Current cluster */
DWORD sect; /* Current sector */
BYTE* dir; /* Pointer to the current SFN entry in the win[] */
BYTE* fn; /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */
#if _USE_LFN
WCHAR* lfn; /* Pointer to the LFN working buffer */
WORD lfn_idx; /* Last matched LFN index (0xFFFF:No LFN) */
#endif
} DIR;
/* File object structure */
typedef struct _FIL {
FATFS* fs; /* Pointer to the owner file system object */
WORD id; /* Owner file system mount ID */
BYTE flag; /* File status flags */
BYTE csect; /* Sector address in the cluster */
DWORD fptr; /* File R/W pointer */
DWORD fsize; /* File size */
DWORD org_clust; /* File start cluster */
DWORD curr_clust; /* Current cluster */
DWORD dsect; /* Current data sector */
#if !_FS_READONLY
DWORD dir_sect; /* Sector containing the directory entry */
BYTE* dir_ptr; /* Ponter to the directory entry in the window */
#endif
#if !_FS_TINY
BYTE buf[_MAX_SS];/* File R/W buffer */
#endif
} FIL;
/* File status structure */
typedef struct _FILINFO {
DWORD fsize; /* File size */
WORD fdate; /* Last modified date */
WORD ftime; /* Last modified time */
BYTE fattrib; /* Attribute */
char fname[13]; /* Short file name (8.3 format) */
#if _USE_LFN
char *lfname; /* Pointer to the LFN buffer */
int lfsize; /* Size of LFN buffer [bytes] */
#endif
} FILINFO;
/* DBCS code ranges */
#if _CODE_PAGE == 932 /* CP932 (Japanese Shift-JIS) */
#define _DF1S 0x81 /* DBC 1st byte range 1 start */
#define _DF1E 0x9F /* DBC 1st byte range 1 end */
#define _DF2S 0xE0 /* DBC 1st byte range 2 start */
#define _DF2E 0xFC /* DBC 1st byte range 2 end */
#define _DS1S 0x40 /* DBC 2nd byte range 1 start */
#define _DS1E 0x7E /* DBC 2nd byte range 1 end */
#define _DS2S 0x80 /* DBC 2nd byte range 2 start */
#define _DS2E 0xFC /* DBC 2nd byte range 2 end */
#elif _CODE_PAGE == 936 /* CP936 (Simplified Chinese GBK) */
#define _DF1S 0x81
#define _DF1E 0xFE
#define _DS1S 0x40
#define _DS1E 0x7E
#define _DS2S 0x80
#define _DS2E 0xFE
#elif _CODE_PAGE == 949 /* CP949 (Korean) */
#define _DF1S 0x81
#define _DF1E 0xFE
#define _DS1S 0x41
#define _DS1E 0x5A
#define _DS2S 0x61
#define _DS2E 0x7A
#define _DS3S 0x81
#define _DS3E 0xFE
#elif _CODE_PAGE == 950 /* CP950 (Traditional Chinese Big5) */
#define _DF1S 0x81
#define _DF1E 0xFE
#define _DS1S 0x40
#define _DS1E 0x7E
#define _DS2S 0xA1
#define _DS2E 0xFE
#else /* SBCS code pages */
#define _DF1S 0
#endif
/* Character code support macros */
#define IsUpper(c) (((c)>='A')&&((c)<='Z'))
#define IsLower(c) (((c)>='a')&&((c)<='z'))
#define IsDigit(c) (((c)>='0')&&((c)<='9'))
#if _DF1S /* DBCS configuration */
#if _DF2S /* Two 1st byte areas */
#define IsDBCS1(c) (((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) || ((BYTE)(c) >= _DF2S && (BYTE)(c) <= _DF2E))
#else /* One 1st byte area */
#define IsDBCS1(c) ((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E)
#endif
#if _DS3S /* Three 2nd byte areas */
#define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E) || ((BYTE)(c) >= _DS3S && (BYTE)(c) <= _DS3E))
#else /* Two 2nd byte areas */
#define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E))
#endif
#else /* SBCS configuration */
#define IsDBCS1(c) 0
#define IsDBCS2(c) 0
#endif /* _DF1S */
/* Definitions corresponds to multi partition */
#if _MULTI_PARTITION /* Multiple partition configuration */
typedef struct _PARTITION {
BYTE pd; /* Physical drive# */
BYTE pt; /* Partition # (0-3) */
} PARTITION;
extern
const PARTITION Drives[]; /* Logical drive# to physical location conversion table */
#define LD2PD(drv) (Drives[drv].pd) /* Get physical drive# */
#define LD2PT(drv) (Drives[drv].pt) /* Get partition# */
#else /* Single partition configuration */
#define LD2PD(drv) (drv) /* Physical drive# is equal to the logical drive# */
#define LD2PT(drv) 0 /* Always mounts the 1st partition */
#endif
/* File function return code (FRESULT) */
typedef enum {
FR_OK = 0, /* 0 */
FR_DISK_ERR, /* 1 */
FR_INT_ERR, /* 2 */
FR_NOT_READY, /* 3 */
FR_NO_FILE, /* 4 */
FR_NO_PATH, /* 5 */
FR_INVALID_NAME, /* 6 */
FR_DENIED, /* 7 */
FR_EXIST, /* 8 */
FR_INVALID_OBJECT, /* 9 */
FR_WRITE_PROTECTED, /* 10 */
FR_INVALID_DRIVE, /* 11 */
FR_NOT_ENABLED, /* 12 */
FR_NO_FILESYSTEM, /* 13 */
FR_MKFS_ABORTED, /* 14 */
FR_TIMEOUT /* 15 */
} FRESULT;
/*--------------------------------------------------------------*/
/* FatFs module application interface */
FRESULT f_mount (BYTE, FATFS*); /* Mount/Unmount a logical drive */
FRESULT f_open (FIL*, const char*, 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 char*); /* Open an existing directory */
FRESULT f_readdir (DIR*, FILINFO*); /* Read a directory item */
FRESULT f_stat (const char*, FILINFO*); /* Get file status */
FRESULT f_getfree (const char*, DWORD*, FATFS**); /* Get number of free clusters on the drive */
FRESULT f_truncate (FIL*); /* Truncate file */
FRESULT f_sync (FIL*); /* Flush cached data of a writing file */
FRESULT f_unlink (const char*); /* Delete an existing file or directory */
FRESULT f_mkdir (const char*); /* Create a new directory */
FRESULT f_chmod (const char*, BYTE, BYTE); /* Change attriburte of the file/dir */
FRESULT f_utime (const char*, const FILINFO*); /* Change timestamp of the file/dir */
FRESULT f_rename (const char*, const char*); /* Rename/Move a file or directory */
FRESULT f_forward (FIL*, UINT(*)(const BYTE*,UINT), UINT, UINT*); /* Forward data to the stream */
FRESULT f_mkfs (BYTE, BYTE, WORD); /* Create a file system on the drive */
#if _USE_STRFUNC
int f_putc (int, FIL*); /* Put a character to the file */
int f_puts (const char*, FIL*); /* Put a string to the file */
int f_printf (FIL*, const char*, ...); /* Put a formatted string to the file */
char* f_gets (char*, int, FIL*); /* Get a string from the file */
#define f_eof(fp) (((fp)->fptr == (fp)->fsize) ? 1 : 0)
#define f_error(fp) (((fp)->flag & FA__ERROR) ? 1 : 0)
#ifndef EOF
#define EOF -1
#endif
#endif
/*--------------------------------------------------------------*/
/* User defined functions */
/* Real time clock */
#if !_FS_READONLY
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) */
#endif
/* Unicode - OEM code conversion */
#if _USE_LFN
WCHAR ff_convert (WCHAR, UINT);
#endif
/* Sync functions */
#if _FS_REENTRANT
BOOL ff_cre_syncobj(BYTE, _SYNC_t*);
BOOL ff_del_syncobj(_SYNC_t);
BOOL ff_req_grant(_SYNC_t);
void ff_rel_grant(_SYNC_t);
#endif
/*--------------------------------------------------------------*/
/* Flags and offset address */
/* 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 */
#define AM_MASK 0x3F /* Mask of defined bits */
/* FatFs refers the members in the FAT structures with byte offset instead
/ of structure member because there are incompatibility of the packing option
/ between various compilers. */
#define BS_jmpBoot 0
#define BS_OEMName 3
#define BPB_BytsPerSec 11
#define BPB_SecPerClus 13
#define BPB_RsvdSecCnt 14
#define BPB_NumFATs 16
#define BPB_RootEntCnt 17
#define BPB_TotSec16 19
#define BPB_Media 21
#define BPB_FATSz16 22
#define BPB_SecPerTrk 24
#define BPB_NumHeads 26
#define BPB_HiddSec 28
#define BPB_TotSec32 32
#define BS_55AA 510
#define BS_DrvNum 36
#define BS_BootSig 38
#define BS_VolID 39
#define BS_VolLab 43
#define BS_FilSysType 54
#define BPB_FATSz32 36
#define BPB_ExtFlags 40
#define BPB_FSVer 42
#define BPB_RootClus 44
#define BPB_FSInfo 48
#define BPB_BkBootSec 50
#define BS_DrvNum32 64
#define BS_BootSig32 66
#define BS_VolID32 67
#define BS_VolLab32 71
#define BS_FilSysType32 82
#define 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_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
#define LDIR_Ord 0
#define LDIR_Attr 11
#define LDIR_Type 12
#define LDIR_Chksum 13
#define LDIR_FstClusLO 26
/*--------------------------------*/
/* Multi-byte word access macros */
#if _WORD_ACCESS == 1 /* Enable word access to the FAT structure */
#define LD_WORD(ptr) (WORD)(*(WORD*)(BYTE*)(ptr))
#define LD_DWORD(ptr) (DWORD)(*(DWORD*)(BYTE*)(ptr))
#define ST_WORD(ptr,val) *(WORD*)(BYTE*)(ptr)=(WORD)(val)
#define ST_DWORD(ptr,val) *(DWORD*)(BYTE*)(ptr)=(DWORD)(val)
#else /* Use byte-by-byte access to the FAT structure */
#define LD_WORD(ptr) (WORD)(((WORD)*(BYTE*)((ptr)+1)<<8)|(WORD)*(BYTE*)(ptr))
#define LD_DWORD(ptr) (DWORD)(((DWORD)*(BYTE*)((ptr)+3)<<24)|((DWORD)*(BYTE*)((ptr)+2)<<16)|((WORD)*(BYTE*)((ptr)+1)<<8)|*(BYTE*)(ptr))
#define ST_WORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *(BYTE*)((ptr)+1)=(BYTE)((WORD)(val)>>8)
#define ST_DWORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *(BYTE*)((ptr)+1)=(BYTE)((WORD)(val)>>8); *(BYTE*)((ptr)+2)=(BYTE)((DWORD)(val)>>16); *(BYTE*)((ptr)+3)=(BYTE)((DWORD)(val)>>24)
#endif
#endif /* _FATFS */

31
src/fileops.c Normal file
View File

@ -0,0 +1,31 @@
// insert cool lenghty disclaimer here
// fileops.c: fatfs wrapping for convenience
#include "config.h"
#include "uart.h"
#include "ff.h"
#include "fileops.h"
void file_init() {
f_mount(0, &fatfs);
}
void file_open(char* filename, BYTE flags) {
file_res = f_open(&file_handle, 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;
}

18
src/fileops.h Normal file
View File

@ -0,0 +1,18 @@
// insert cool lenghty disclaimer here
// fileops.h
#ifndef FILEOPS_H
#define FILEOPS_H
#include "ff.h"
BYTE file_buf[512];
FATFS fatfs;
FIL file_handle;
FRESULT file_res;
void file_init(void);
void file_open(char* filename, BYTE flags);
void file_close(void);
UINT file_read(void);
UINT file_write(void);
#endif

186
src/fpga.c Normal file
View File

@ -0,0 +1,186 @@
// insert cool lenghty disclaimer here
// fpga.c: FPGA (re)programming
/*
FPGA pin mapping
================
FPGA AVR dir
------------------------
PROG_B PD3 OUT
CCLK PD4 OUT
CS_B PD7 OUT
INIT_B PB2 IN
RDWR_B PB3 OUT
D7 PC0 OUT
D6 PC1 OUT
D5 PC2 OUT
D4 PC3 OUT
D3 PC4 OUT
D2 PC5 OUT
D1 PC6 OUT
D0 PC7 OUT
*/
#include <avr/pgmspace.h>
#include "fpga.h"
#include "config.h"
#include "uart.h"
#include "sdcard.h"
#include "diskio.h"
#include "ff.h"
#include "fileops.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_cs_b(uint8_t val) {
if(val) {
PORTD |= _BV(PD7);
} else {
PORTD &= ~_BV(PD7);
}
}
void set_rdwr_b(uint8_t val) {
if(val) {
PORTB |= _BV(PB3);
} else {
PORTB &= ~_BV(PB3);
}
}
void set_cclk(uint8_t val) {
if(val) {
PORTD |= _BV(PD4);
} else {
PORTD &= ~_BV(PD4);
}
}
void fpga_init() {
DDRB |= _BV(PB3); // PB3 is output
DDRB &= ~_BV(PB2); // PB2 is input
DDRC = 0xff; // for FPGA config, all PORTC pins are outputs
DDRD |= _BV(PD3) | _BV(PD4) | _BV(PD7); // PD3, PD4, PD7 are outputs
set_cclk(0); // initial clk=0
}
int fpga_get_done(void) {
return 0;
}
void fpga_postinit() {
DDRA |= _BV(PA0) | _BV(PA1) | _BV(PA2) | _BV(PA4) | _BV(PA5) | _BV(PA6); // MAPPER+NEXTADDR output
DDRB |= _BV(PB2) | _BV(PB1) | _BV(PB0); // turn PB2 into output, enable AVR_BANK
}
void fpga_pgm(char* filename) {
set_prog_b(0);
uart_putc('P');
set_prog_b(1);
loop_until_bit_is_set(PINB, PB2);
uart_putc('p');
FIL in;
FRESULT res;
UINT bytes_read;
// open configware file
res=f_open(&in, filename, FA_READ);
if(res) {
uart_putc('?');
return;
}
// file open successful
set_cs_b(0);
set_rdwr_b(0);
for (;;) {
res = f_read(&in, file_buf, sizeof(file_buf), &bytes_read);
if (res || bytes_read == 0) break; // error or eof
for(int i=0; i<bytes_read; i++) {
FPGA_SEND_BYTE(file_buf[i]);
}
}
f_close(&in);
fpga_postinit();
}
void set_avr_read(uint8_t val) {
if(val) {
PORTB |= _BV(PB3);
} else {
PORTB &= ~_BV(PB3);
}
}
void set_avr_write(uint8_t val) {
if(val) {
PORTB |= _BV(PB2);
} else {
PORTB &= ~_BV(PB2);
}
}
void set_avr_ena(uint8_t val) {
if(val) {
PORTD |= _BV(PD7);
} else {
PORTD &= ~_BV(PD7);
}
}
void set_avr_nextaddr(uint8_t val) {
if(val) {
PORTA |= _BV(PA4);
} else {
PORTA &= ~_BV(PA4);
}
}
void set_avr_addr_reset(uint8_t val) {
if(val) {
PORTA |= _BV(PA5);
} else {
PORTA &= ~_BV(PA5);
}
}
void set_avr_data(uint8_t data) {
PORTC = data;
}
void set_avr_addr_en(uint8_t val) {
if(val) {
PORTA |= _BV(PA6);
} else {
PORTA &= ~_BV(PA6);
}
}
void set_avr_mapper(uint8_t val) {
PORTA &= 0xF0;
PORTA |= val&0x07;
}
void set_avr_bank(uint8_t val) {
PORTB &= 0xFC;
PORTB |= val&0x03;
}

46
src/fpga.h Normal file
View File

@ -0,0 +1,46 @@
// insert cool lenghty disclaimer here
// fpga.h
#ifndef FPGA_H
#define FPGA_H
void fpga_init(void);
void fpga_postinit(void);
void fpga_pgm(char* 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);
// some macros for bulk transfers (faster)
#define FPGA_SEND_BYTE(data) do {SET_AVR_DATA(data); 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

15
src/gcctest.awk Normal file
View File

@ -0,0 +1,15 @@
#! /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";
}
}
}

30
src/integer.h Normal file
View File

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

43
src/led.c Normal file
View File

@ -0,0 +1,43 @@
/* 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
led.c: Overdesigned LED handling
*/
#include <avr/io.h>
#include "config.h"
#include "led.h"
volatile uint8_t led_state;
/**
* update_leds - set LEDs to correspond to the buffer status
*
* This function sets the busy/dirty LEDs to correspond to the current state
* of the buffers, i.e. busy on of at least one non-system buffer is
* allocated and dirty on if at least one buffer is allocated for writing.
* Call if you have manually changed the LEDs and you want to restore the
* "default" state.
*/
void update_leds(void) {
}

54
src/led.h Normal file
View File

@ -0,0 +1,54 @@
/* 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
led.h: Definitions for the LEDs
*/
#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 update_leds(void);
/* Wrapped in do..while to avoid "ambigious else" warnings */
#ifdef SINGLE_LED
# define set_dirty_led(x) do{if (x) { led_state |= LED_DIRTY; } else { led_state &= (uint8_t)~LED_DIRTY; }}while(0)
# define set_busy_led(x) do{if (x) { led_state |= LED_BUSY ; } else { led_state &= (uint8_t)~LED_BUSY ; }}while(0)
# define set_error_led(x) do{if (x) { led_state |= LED_ERROR; } else { led_state &= (uint8_t)~LED_ERROR; }}while(0)
#else
# define set_dirty_led(x) do{if (x) { DIRTY_LED_ON(); } else { DIRTY_LED_OFF(); }}while(0)
# define set_busy_led(x) do{if (x) { BUSY_LED_ON(); } else { BUSY_LED_OFF(); }}while(0)
# define set_error_led(x) do{if (x) { led_state |= LED_ERROR; } else { led_state &= (uint8_t)~LED_ERROR; update_leds(); }}while(0)
#endif
#endif

200
src/main.c Normal file
View File

@ -0,0 +1,200 @@
/* 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
main.c: Lots of init calls for the submodules
*/
#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"
char stringbuf[100];
/* 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;
}
}
#endif
void avr_goto_addr(const uint32_t val) {
AVR_ADDR_RESET();
for(uint32_t i=0; i<val; i++) {
AVR_NEXTADDR();
}
}
#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
/* BUSY_LED_SETDDR();
DIRTY_LED_SETDDR();
AUX_LED_SETDDR();
AUX_LED_OFF();
set_busy_led(1);
set_dirty_led(0);
*/
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);
set_busy_led(0);
uart_putc('W');
fpga_init();
fpga_pgm("/sd2snes/main.bit");
uart_putc('!');
_delay_ms(100);
set_avr_bank(0);
set_avr_ena(0);
set_avr_read(1);
set_avr_write(1);
AVR_ADDR_RESET();
set_avr_addr_en(0);
snes_reset(1);
uart_putc('(');
load_rom("/test.smc");
uart_putc(')');
uart_putc('[');
load_sram("/test.srm");
uart_putc(']');
AVR_ADDR_RESET();
set_avr_mapper(0);
set_avr_ena(1);
set_avr_read(0);
set_avr_bank(0);
_delay_ms(100);
uart_puts_P(PSTR("SNES GO!"));
snes_reset(0);
DDRC = 0x00;
while(1) {
snes_main_loop();
}
while(1) {
uint8_t data=PINC;
_delay_ms(2);
if(data>=0x20 && data <= 0x7a) {
uart_putc(data);
} else {
uart_putc('.');
}
SET_AVR_NEXTADDR();
CLR_AVR_NEXTADDR();
// set_avr_bank(3);
}
while(1);
}

121
src/memory.c Normal file
View File

@ -0,0 +1,121 @@
// insert cool lenghty disclaimer here
// memory.c: ROM+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"
char* hex = "0123456789ABCDEF";
uint32_t load_rom(char* filename) {
// TODO Mapper, Mirroring, Bankselect
// snes_rom_properties_t romprops;
set_avr_bank(0);
AVR_ADDR_RESET();
SET_AVR_READ();
UINT bytes_read;
DWORD filesize;
file_open(filename, FA_READ);
filesize = file_handle.fsize;
if(file_res) return 0;
// snes_rom_id(&romprops, &file_handle);
for(;;) {
bytes_read = file_read();
if (file_res || !bytes_read) break;
for(int j=0; j<bytes_read; j++) {
SET_AVR_DATA(file_buf[j]);
AVR_WRITE();
AVR_NEXTADDR();
}
}
file_close();
return (uint32_t)filesize;
}
uint32_t load_sram(char* filename) {
set_avr_bank(3);
AVR_ADDR_RESET();
SET_AVR_READ();
UINT bytes_read;
DWORD filesize;
file_open(filename, FA_READ);
filesize = file_handle.fsize;
if(file_res) return 0;
for(;;) {
bytes_read = file_read();
if (file_res || !bytes_read) break;
for(int j=0; j<bytes_read; j++) {
SET_AVR_DATA(file_buf[j]);
AVR_WRITE();
AVR_NEXTADDR();
}
}
file_close();
return (uint32_t)filesize;
}
void save_sram(char* filename, uint32_t sram_size) {
uint32_t count = 0;
uint32_t num = 0;
set_avr_bank(3);
_delay_us(100);
AVR_ADDR_RESET();
CLR_AVR_READ();
SET_AVR_WRITE();
file_open(filename, FA_CREATE_ALWAYS | FA_WRITE);
while(count<sram_size) {
for(int j=0; j<sizeof(file_buf); j++) {
_delay_us(5);
file_buf[j] = AVR_DATA;
CLR_AVR_ADDR_EN();
SET_AVR_NEXTADDR();
_delay_us(5);
CLR_AVR_NEXTADDR();
SET_AVR_ADDR_EN();
count++;
}
num = file_write();
}
file_close();
}
uint32_t calc_sram_crc(uint32_t size) {
uint8_t data;
set_avr_bank(3);
_delay_us(100);
AVR_ADDR_RESET();
SET_AVR_WRITE();
CLR_AVR_READ();
uint32_t count;
uint16_t crc;
crc=0;
for(count=0; count<size; count++) {
_delay_us(5);
data = AVR_DATA;
crc += crc16_update(crc, &data, 1);
CLR_AVR_ADDR_EN();
SET_AVR_NEXTADDR();
_delay_us(5);
CLR_AVR_NEXTADDR();
SET_AVR_ADDR_EN();
}
/* uart_putc(hex[(crc>>28)&0xf]);
uart_putc(hex[(crc>>24)&0xf]);
uart_putc(hex[(crc>>20)&0xf]);
uart_putc(hex[(crc>>16)&0xf]); */
uart_putc(hex[(crc>>12)&0xf]);
uart_putc(hex[(crc>>8)&0xf]);
uart_putc(hex[(crc>>4)&0xf]);
uart_putc(hex[(crc)&0xf]);
uart_putcrlf();
return crc;
}

10
src/memory.h Normal file
View File

@ -0,0 +1,10 @@
// insert cool lengthy disclaimer here
// memory.h
#ifndef MEMORY_H
#define MEMORY_H
uint32_t load_rom(char* filename);
uint32_t load_sram(char* filename);
void save_sram(char* filename, uint32_t sram_size);
uint32_t calc_sram_crc(uint32_t size);
#endif

749
src/sdcard.c Normal file
View File

@ -0,0 +1,749 @@
/* 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 "config.h"
#include "avrcompat.h"
#include "crc7.h"
#include "diskio.h"
#include "spi.h"
#include "uart.h"
#include "sdcard.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)
{
unsigned short count = 0xFFFF; // 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;
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) {
SPI_SS_HIGH(drv);
disk_state = DISK_ERROR;
return RES_ERROR;
}
// Wait for data token
if (!sdResponse(0xFE)) {
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;
// 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) {
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()) {
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")));

40
src/sdcard.h Normal file
View File

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

54
src/snes.c Normal file
View File

@ -0,0 +1,54 @@
// insert cool lengthy disclaimer here
// snes.c: SNES hardware control (resetting)
#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"
uint8_t initloop=1;
uint32_t sram_crc, sram_crc_old;
uint32_t sram_size = 8192; // sane default
void snes_init() {
DDRD |= _BV(PD5); // PD5 = OUTPUT
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) {
PORTD &= ~ _BV(PD5);
} else {
PORTD |= _BV(PD5);
}
}
/*
* SD2SNES main loop.
* monitors SRAM changes, menu selections and other things
*/
void snes_main_loop() {
if(initloop) {
sram_crc_old = calc_sram_crc(sram_size);
initloop=0;
}
sram_crc = calc_sram_crc(sram_size);
if(sram_crc != sram_crc_old) {
uart_putc('U');
uart_putcrlf();
save_sram("/test.srm", sram_size);
}
sram_crc_old = sram_crc;
uart_putc('.');
}

11
src/snes.h Normal file
View File

@ -0,0 +1,11 @@
// insert cool lenghty disclaimer here
// snes.h
#ifndef SNES_H
#define SNES_H
void snes_init(void);
void snes_reset(int state);
void snes_main_loop(void);
#endif

131
src/spi.c Normal file
View File

@ -0,0 +1,131 @@
/* 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)
{
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/8
SPSR = _BV(SPI2X);
// clear status
dummy = SPSR;
// clear receive buffer
dummy = SPDR;
}
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;
}
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;
}

68
src/spi.h Normal file
View File

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

75
src/src2doxy.pl Executable file
View File

@ -0,0 +1,75 @@
#!/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";
}
}

16
src/time.h Normal file
View File

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

130
src/timer.c Normal file
View File

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

116
src/timer.h Normal file
View File

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

164
src/uart.c Normal file
View File

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

59
src/uart.h Normal file
View File

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

42
src/ustring.h Normal file
View File

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

77
src/utils.c Normal file
View File

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

52
src/utils.h Normal file
View File

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

118
verilog/sd2snes/address.v Normal file
View File

@ -0,0 +1,118 @@
`timescale 1 ns / 1 ns
//////////////////////////////////////////////////////////////////////////////////
// Company: Rehkopf
// Engineer: Rehkopf
//
// Create Date: 01:13:46 05/09/2009
// Design Name:
// Module Name: address
// Project Name:
// Target Devices:
// Tool versions:
// Description: Address logic w/ SaveRAM masking
//
// Dependencies:
//
// Revision:
// Revision 0.02 - All new combinatorial glory. fucking slow.
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module address(
input CLK,
input [2:0] MAPPER, // AVR detected mapper
input [23:0] SNES_ADDR, // requested address from SNES
input SNES_CS, // "CART" pin from SNES (active low)
output [20:0] SRAM_ADDR, // Address to request from SRAM
output [3:0] ROM_SEL, // which SRAM unit to access (active low)
input AVR_ADDR_RESET, // reset AVR sequence (active low)
input AVR_NEXTADDR, // next byte request from AVR
input AVR_ENA, // enable AVR master mode (active low)
input AVR_ADDR_EN, // enable address counter (active low)
input [1:0] AVR_BANK, // which bank does the AVR want
input MODE, // AVR(1) or SNES(0) ("bus phase")
output IS_SAVERAM, // address/CS mapped as SRAM?
output IS_ROM, // address mapped as ROM?
input AVR_NEXTADDR_CURR,
input AVR_NEXTADDR_PREV
);
reg [22:0] SRAM_ADDR_BUF;
reg [3:0] ROM_SEL_BUF;
reg [3:0] AVR_ROM_SEL_BUF;
reg [20:0] AVR_ADDR;
reg [3:0] CS_ARRAY[3:0];
wire [3:0] CURRENT_ROM_SEL;
wire [22:0] SRAM_ADDR_FULL;
initial begin
AVR_ADDR = 21'b0;
CS_ARRAY[0] = 4'b1110;
CS_ARRAY[1] = 4'b1101;
CS_ARRAY[2] = 4'b1011;
CS_ARRAY[3] = 4'b0111;
end
/* currently supported mappers:
Index Mapper
000 HiROM
001 LoROM
*/
/* HiROM: SRAM @ Bank 0x20-0x3f, 0xa0-0xbf
Offset 6000-7fff */
assign IS_SAVERAM = ((MAPPER == 3'b000) ? (!SNES_ADDR[22]
& SNES_ADDR[21]
& &SNES_ADDR[14:13]
& !SNES_ADDR[15]
)
/* LoROM: SRAM @ Bank 0x70-0x7f, 0xf0-0xff
Offset 0000-7fff */
:(MAPPER == 3'b001) ? (&SNES_ADDR[22:20]
& !SNES_ADDR[15]
& !SNES_CS)
: 1'b0);
assign IS_ROM = ((MAPPER == 3'b000) ? ( (!SNES_ADDR[22]
& SNES_ADDR[15])
|(SNES_ADDR[22]))
:(MAPPER == 3'b001) ? ( (SNES_ADDR[15]) )
: 1'b0);
assign SRAM_ADDR_FULL = (MODE) ? AVR_ADDR
: ((MAPPER == 3'b000) ?
(IS_SAVERAM ? SNES_ADDR[14:0] - 15'h6000
: SNES_ADDR[22:0])
:(MAPPER == 3'b001) ?
(IS_SAVERAM ? SNES_ADDR[14:0]
: {1'b0, SNES_ADDR[22:16], SNES_ADDR[14:0]})
: 21'b0);
assign SRAM_BANK = SRAM_ADDR_FULL[22:21];
assign SRAM_ADDR = SRAM_ADDR_FULL[20:0];
assign ROM_SEL = (MODE) ? CS_ARRAY[AVR_BANK] : IS_SAVERAM ? 4'b0111 : 4'b1110; // CS_ARRAY[SRAM_BANK];
//assign ROM_SEL = 4'b1110;
always @(posedge CLK) begin
if(AVR_NEXTADDR_CURR) begin
if(!AVR_NEXTADDR_PREV) begin
if(!AVR_ADDR_RESET)
AVR_ADDR <= 21'b0;
else if (!AVR_ADDR_EN)
AVR_ADDR <= AVR_ADDR + 1;
end
end
end
/*
always @(posedge AVR_NEXTADDR) begin
if (!AVR_ADDR_RESET)
AVR_ADDR <= 21'b0;
else if (!AVR_ADDR_EN)
AVR_ADDR <= AVR_ADDR + 1;
end
*/
endmodule

83
verilog/sd2snes/data.v Normal file
View File

@ -0,0 +1,83 @@
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 23:03:06 05/13/2009
// Design Name:
// Module Name: data
// Project Name:
// Target Devices:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module data(
input CLK,
input SNES_READ,
input SNES_WRITE,
input AVR_READ,
input AVR_WRITE,
inout [7:0] SNES_DATA,
inout [7:0] SRAM_DATA,
inout [7:0] AVR_DATA,
input MODE,
input SNES_DATA_TO_MEM,
input AVR_DATA_TO_MEM,
input SRAM_DATA_TO_SNES_MEM,
input SRAM_DATA_TO_AVR_MEM,
input AVR_ENA,
input AVR_NEXTADDR_PREV,
input AVR_NEXTADDR_CURR
);
reg [7:0] SNES_IN_MEM;
reg [7:0] SNES_OUT_MEM;
reg [7:0] AVR_IN_MEM;
reg [7:0] AVR_OUT_MEM;
assign SNES_DATA = SNES_READ ? 8'bZ : SNES_OUT_MEM;
assign AVR_DATA = !AVR_ENA ? (!AVR_READ ? SRAM_DATA : 8'bZ)
: (AVR_READ ? 8'bZ : AVR_OUT_MEM);
assign SRAM_DATA = !AVR_ENA ? (!AVR_WRITE ? AVR_DATA : 8'bZ)// /**/ : 8'bZ;
: MODE ? (!AVR_WRITE ? AVR_IN_MEM : 8'bZ)
: (!SNES_WRITE ? SNES_IN_MEM : 8'bZ);
always @(posedge CLK) begin
if(SNES_DATA_TO_MEM)
SNES_IN_MEM <= SNES_DATA;
if(AVR_DATA_TO_MEM)
AVR_IN_MEM <= AVR_DATA;
if(SRAM_DATA_TO_SNES_MEM)
SNES_OUT_MEM <= SRAM_DATA;
if(SRAM_DATA_TO_AVR_MEM)
AVR_OUT_MEM <= SRAM_DATA;
end
/*
always @(posedge SNES_DATA_TO_MEM) begin
SNES_IN_MEM <= SNES_DATA;
end
always @(posedge AVR_DATA_TO_MEM) begin
AVR_IN_MEM <= AVR_DATA;
end
always @(posedge SRAM_DATA_TO_SNES_MEM) begin
SNES_OUT_MEM <= SRAM_DATA;
end
always @(posedge SRAM_DATA_TO_AVR_MEM) begin
AVR_OUT_MEM <= SRAM_DATA;
end
*/
endmodule

70
verilog/sd2snes/dcm.v Normal file
View File

@ -0,0 +1,70 @@
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 13:06:52 06/28/2009
// Design Name:
// Module Name: dcm
// Project Name:
// Target Devices:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module my_dcm (
input CLKIN,
input CLKFB,
output CLK2X
);
// DCM: Digital Clock Manager Circuit
// Spartan-3
// Xilinx HDL Language Template, version 11.1
DCM #(
.SIM_MODE("SAFE"), // Simulation: "SAFE" vs. "FAST", see "Synthesis and Simulation Design Guide" for details
.CLKDV_DIVIDE(2.0), // Divide by: 1.5,2.0,2.5,3.0,3.5,4.0,4.5,5.0,5.5,6.0,6.5
// 7.0,7.5,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0 or 16.0
.CLKFX_DIVIDE(1), // Can be any integer from 1 to 32
.CLKFX_MULTIPLY(16), // Can be any integer from 2 to 32
.CLKIN_DIVIDE_BY_2("FALSE"), // TRUE/FALSE to enable CLKIN divide by two feature
.CLKIN_PERIOD(0.0), // Specify period of input clock
.CLKOUT_PHASE_SHIFT("NONE"), // Specify phase shift of NONE, FIXED or VARIABLE
.CLK_FEEDBACK("2X"), // Specify clock feedback of NONE, 1X or 2X
.DESKEW_ADJUST("SYSTEM_SYNCHRONOUS"), // SOURCE_SYNCHRONOUS, SYSTEM_SYNCHRONOUS or
// an integer from 0 to 15
.DFS_FREQUENCY_MODE("LOW"), // HIGH or LOW frequency mode for frequency synthesis
.DLL_FREQUENCY_MODE("LOW"), // HIGH or LOW frequency mode for DLL
.DUTY_CYCLE_CORRECTION("TRUE"), // Duty cycle correction, TRUE or FALSE
.FACTORY_JF(16'hC080), // FACTORY JF values
.PHASE_SHIFT(0), // Amount of fixed phase shift from -255 to 255
.STARTUP_WAIT("FALSE") // Delay configuration DONE until DCM LOCK, TRUE/FALSE
) DCM_inst (
.CLK0(CLK0), // 0 degree DCM CLK output
.CLK180(CLK180), // 180 degree DCM CLK output
.CLK270(CLK270), // 270 degree DCM CLK output
.CLK2X(CLK2X), // 2X DCM CLK output
.CLK2X180(CLK2X180), // 2X, 180 degree DCM CLK out
.CLK90(CLK90), // 90 degree DCM CLK output
.CLKDV(CLKDV), // Divided DCM CLK out (CLKDV_DIVIDE)
.CLKFX(CLKFX), // DCM CLK synthesis out (M/D)
.CLKFX180(CLKFX180), // 180 degree CLK synthesis out
.LOCKED(LOCKED), // DCM LOCK status output
.PSDONE(PSDONE), // Dynamic phase adjust done output
.STATUS(STATUS), // 8-bit DCM status bits output
.CLKFB(CLKFB), // DCM clock feedback
.CLKIN(CLKIN), // Clock input (from IBUFG, BUFG or DCM)
.PSCLK(PSCLK), // Dynamic phase adjust clock input
.PSEN(PSEN), // Dynamic phase adjust enable input
.PSINCDEC(PSINCDEC), // Dynamic phase adjust increment/decrement
.RST(RST) // DCM asynchronous reset input
);
assign RST=0;
endmodule

191
verilog/sd2snes/main.ucf Normal file
View File

@ -0,0 +1,191 @@
# INST "AVR_NEXTADDR_BUFGP" LOC = BUFGMUX7;
# INST "CLK_BUFGP" LOC = BUFGMUX0;
NET "AVR_BANK[0]" LOC = P56;
NET "AVR_BANK[1]" LOC = P57;
NET "AVR_ENA" LOC = P40;
NET "AVR_READ" LOC = P41;
NET "MAPPER[0]" LOC = P68;
NET "MAPPER[1]" LOC = P69;
NET "MAPPER[2]" LOC = P70;
NET "ROM_SEL[0]" LOC = P124;
NET "ROM_SEL[1]" LOC = P125;
NET "ROM_SEL[2]" LOC = P122;
NET "ROM_SEL[3]" LOC = P123;
NET "SNES_ADDR[0]" LOC = P1;
NET "SNES_ADDR[10]" LOC = P13;
NET "SNES_ADDR[11]" LOC = P14;
NET "SNES_ADDR[12]" LOC = P15;
NET "SNES_ADDR[13]" LOC = P17;
NET "SNES_ADDR[14]" LOC = P18;
NET "SNES_ADDR[15]" LOC = P20;
NET "SNES_ADDR[16]" LOC = P21;
NET "SNES_ADDR[17]" LOC = P23;
NET "SNES_ADDR[18]" LOC = P24;
NET "SNES_ADDR[19]" LOC = P25;
NET "SNES_ADDR[1]" LOC = P2;
NET "SNES_ADDR[20]" LOC = P26;
NET "SNES_ADDR[21]" LOC = P27;
NET "SNES_ADDR[22]" LOC = P28;
NET "SNES_ADDR[23]" LOC = P30;
NET "SNES_ADDR[2]" LOC = P4;
NET "SNES_ADDR[3]" LOC = P5;
NET "SNES_ADDR[4]" LOC = P6;
NET "SNES_ADDR[5]" LOC = P7;
NET "SNES_ADDR[6]" LOC = P8;
NET "SNES_ADDR[7]" LOC = P10;
NET "SNES_ADDR[8]" LOC = P11;
NET "SNES_ADDR[9]" LOC = P12;
NET "SRAM_ADDR[0]" LOC = P92;
NET "SRAM_ADDR[10]" LOC = P104;
NET "SRAM_ADDR[11]" LOC = P105;
NET "SRAM_ADDR[12]" LOC = P107;
NET "SRAM_ADDR[13]" LOC = P108;
NET "SRAM_ADDR[14]" LOC = P73;
NET "SRAM_ADDR[15]" LOC = P74;
NET "SRAM_ADDR[16]" LOC = P76;
NET "SRAM_ADDR[17]" LOC = P77;
NET "SRAM_ADDR[18]" LOC = P78;
NET "SRAM_ADDR[19]" LOC = P79;
NET "SRAM_ADDR[1]" LOC = P93;
NET "SRAM_ADDR[20]" LOC = P80;
NET "SRAM_ADDR[2]" LOC = P95;
NET "SRAM_ADDR[3]" LOC = P96;
NET "SRAM_ADDR[4]" LOC = P97;
NET "SRAM_ADDR[5]" LOC = P98;
NET "SRAM_ADDR[6]" LOC = P99;
NET "SRAM_ADDR[7]" LOC = P100;
NET "SRAM_ADDR[8]" LOC = P102;
NET "SRAM_ADDR[9]" LOC = P103;
NET "SRAM_DATA[0]" LOC = P82;
NET "SRAM_DATA[1]" LOC = P83;
NET "SRAM_DATA[2]" LOC = P84;
NET "SRAM_DATA[3]" LOC = P85;
NET "SRAM_DATA[4]" LOC = P86;
NET "SRAM_DATA[5]" LOC = P87;
NET "SRAM_DATA[6]" LOC = P89;
NET "SRAM_DATA[7]" LOC = P90;
NET "SRAM_OE" LOC = P118;
NET "SRAM_WE" LOC = P119;
NET "AVR_ADDR_RESET" LOC = P44;
NET "CLKIN" LOC = P55;
NET "AVR_NEXTADDR" LOC = P128;
NET "SNES_READ" LOC = P31;
NET "SNES_WRITE" LOC = P32;
NET "AVR_WRITE" LOC = P58;
NET "SNES_CS" LOC = P52;
NET "AVR_ADDR_EN" LOC = P53;
NET "CLK" TNM_NET = CLK;
NET "AVR_DATA[0]" LOC = P46;
NET "AVR_DATA[1]" LOC = P47;
NET "AVR_DATA[2]" LOC = P50;
NET "AVR_DATA[3]" LOC = P51;
NET "AVR_DATA[4]" LOC = P59;
NET "AVR_DATA[5]" LOC = P60;
NET "AVR_DATA[6]" LOC = P63;
NET "AVR_DATA[7]" LOC = P65;
NET "SNES_DATA[0]" LOC = P129;
NET "SNES_DATA[1]" LOC = P130;
NET "SNES_DATA[2]" LOC = P131;
NET "SNES_DATA[3]" LOC = P132;
NET "SNES_DATA[4]" LOC = P135;
NET "SNES_DATA[5]" LOC = P137;
NET "SNES_DATA[6]" LOC = P140;
NET "SNES_DATA[7]" LOC = P141;
NET "SNES_DATABUS_DIR" LOC = P35;
NET "SNES_DATABUS_OE" LOC = P33;
NET "MODE" LOC = P112;
NET "CLKIN" TNM_NET = CLKIN;
TIMESPEC TS_CLKIN = PERIOD "CLKIN" 30 MHz HIGH 50 %;
NET "AVR_ADDR_EN" IOSTANDARD = LVCMOS33;
NET "AVR_ADDR_RESET" IOSTANDARD = LVCMOS33;
NET "AVR_BANK[0]" IOSTANDARD = LVCMOS33;
NET "AVR_BANK[1]" IOSTANDARD = LVCMOS33;
NET "AVR_DATA[0]" IOSTANDARD = LVCMOS33;
NET "AVR_DATA[1]" IOSTANDARD = LVCMOS33;
NET "AVR_DATA[2]" IOSTANDARD = LVCMOS33;
NET "AVR_DATA[3]" IOSTANDARD = LVCMOS33;
NET "AVR_DATA[4]" IOSTANDARD = LVCMOS33;
NET "AVR_DATA[5]" IOSTANDARD = LVCMOS33;
NET "AVR_DATA[6]" IOSTANDARD = LVCMOS33;
NET "AVR_DATA[7]" IOSTANDARD = LVCMOS33;
NET "AVR_ENA" IOSTANDARD = LVCMOS33;
NET "AVR_NEXTADDR" IOSTANDARD = LVCMOS33;
NET "AVR_READ" IOSTANDARD = LVCMOS33;
NET "AVR_WRITE" IOSTANDARD = LVCMOS33;
NET "CLKIN" IOSTANDARD = LVCMOS33;
NET "MAPPER[0]" IOSTANDARD = LVCMOS33;
NET "MAPPER[1]" IOSTANDARD = LVCMOS33;
NET "MAPPER[2]" IOSTANDARD = LVCMOS33;
NET "MODE" IOSTANDARD = LVCMOS33;
NET "ROM_SEL[0]" IOSTANDARD = LVCMOS33;
NET "ROM_SEL[1]" IOSTANDARD = LVCMOS33;
NET "ROM_SEL[2]" IOSTANDARD = LVCMOS33;
NET "ROM_SEL[3]" IOSTANDARD = LVCMOS33;
NET "SNES_ADDR[0]" IOSTANDARD = LVCMOS33;
NET "SNES_ADDR[10]" IOSTANDARD = LVCMOS33;
NET "SNES_ADDR[11]" IOSTANDARD = LVCMOS33;
NET "SNES_ADDR[12]" IOSTANDARD = LVCMOS33;
NET "SNES_ADDR[13]" IOSTANDARD = LVCMOS33;
NET "SNES_ADDR[14]" IOSTANDARD = LVCMOS33;
NET "SNES_ADDR[15]" IOSTANDARD = LVCMOS33;
NET "SNES_ADDR[16]" IOSTANDARD = LVCMOS33;
NET "SNES_ADDR[17]" IOSTANDARD = LVCMOS33;
NET "SNES_ADDR[18]" IOSTANDARD = LVCMOS33;
NET "SNES_ADDR[19]" IOSTANDARD = LVCMOS33;
NET "SNES_ADDR[1]" IOSTANDARD = LVCMOS33;
NET "SNES_ADDR[20]" IOSTANDARD = LVCMOS33;
NET "SNES_ADDR[21]" IOSTANDARD = LVCMOS33;
NET "SNES_ADDR[22]" IOSTANDARD = LVCMOS33;
NET "SNES_ADDR[23]" IOSTANDARD = LVCMOS33;
NET "SNES_ADDR[2]" IOSTANDARD = LVCMOS33;
NET "SNES_ADDR[3]" IOSTANDARD = LVCMOS33;
NET "SNES_ADDR[4]" IOSTANDARD = LVCMOS33;
NET "SNES_ADDR[5]" IOSTANDARD = LVCMOS33;
NET "SNES_ADDR[6]" IOSTANDARD = LVCMOS33;
NET "SNES_ADDR[7]" IOSTANDARD = LVCMOS33;
NET "SNES_ADDR[8]" IOSTANDARD = LVCMOS33;
NET "SNES_ADDR[9]" IOSTANDARD = LVCMOS33;
NET "SNES_CS" IOSTANDARD = LVCMOS33;
NET "SNES_DATABUS_DIR" IOSTANDARD = LVCMOS33;
NET "SNES_DATABUS_OE" IOSTANDARD = LVCMOS33;
NET "SNES_DATA[0]" IOSTANDARD = LVCMOS33;
NET "SNES_DATA[1]" IOSTANDARD = LVCMOS33;
NET "SNES_DATA[2]" IOSTANDARD = LVCMOS33;
NET "SNES_DATA[3]" IOSTANDARD = LVCMOS33;
NET "SNES_DATA[4]" IOSTANDARD = LVCMOS33;
NET "SNES_DATA[5]" IOSTANDARD = LVCMOS33;
NET "SNES_DATA[6]" IOSTANDARD = LVCMOS33;
NET "SNES_DATA[7]" IOSTANDARD = LVCMOS33;
NET "SNES_READ" IOSTANDARD = LVCMOS33;
NET "SNES_WRITE" IOSTANDARD = LVCMOS33;
NET "SRAM_ADDR[0]" IOSTANDARD = LVCMOS33;
NET "SRAM_ADDR[10]" IOSTANDARD = LVCMOS33;
NET "SRAM_ADDR[11]" IOSTANDARD = LVCMOS33;
NET "SRAM_ADDR[12]" IOSTANDARD = LVCMOS33;
NET "SRAM_ADDR[13]" IOSTANDARD = LVCMOS33;
NET "SRAM_ADDR[14]" IOSTANDARD = LVCMOS33;
NET "SRAM_ADDR[15]" IOSTANDARD = LVCMOS33;
NET "SRAM_ADDR[16]" IOSTANDARD = LVCMOS33;
NET "SRAM_ADDR[17]" IOSTANDARD = LVCMOS33;
NET "SRAM_ADDR[18]" IOSTANDARD = LVCMOS33;
NET "SRAM_ADDR[19]" IOSTANDARD = LVCMOS33;
NET "SRAM_ADDR[1]" IOSTANDARD = LVCMOS33;
NET "SRAM_ADDR[20]" IOSTANDARD = LVCMOS33;
NET "SRAM_ADDR[2]" IOSTANDARD = LVCMOS33;
NET "SRAM_ADDR[3]" IOSTANDARD = LVCMOS33;
NET "SRAM_ADDR[4]" IOSTANDARD = LVCMOS33;
NET "SRAM_ADDR[5]" IOSTANDARD = LVCMOS33;
NET "SRAM_ADDR[6]" IOSTANDARD = LVCMOS33;
NET "SRAM_ADDR[7]" IOSTANDARD = LVCMOS33;
NET "SRAM_ADDR[8]" IOSTANDARD = LVCMOS33;
NET "SRAM_ADDR[9]" IOSTANDARD = LVCMOS33;
NET "SRAM_DATA[0]" IOSTANDARD = LVCMOS33;
NET "SRAM_DATA[1]" IOSTANDARD = LVCMOS33;
NET "SRAM_DATA[2]" IOSTANDARD = LVCMOS33;
NET "SRAM_DATA[3]" IOSTANDARD = LVCMOS33;
NET "SRAM_DATA[4]" IOSTANDARD = LVCMOS33;
NET "SRAM_DATA[5]" IOSTANDARD = LVCMOS33;
NET "SRAM_DATA[6]" IOSTANDARD = LVCMOS33;
NET "SRAM_DATA[7]" IOSTANDARD = LVCMOS33;
NET "SRAM_OE" IOSTANDARD = LVCMOS33;
NET "SRAM_WE" IOSTANDARD = LVCMOS33;

299
verilog/sd2snes/main.v Normal file
View File

@ -0,0 +1,299 @@
`timescale 1 ns / 1 ns
//////////////////////////////////////////////////////////////////////////////////
// Company: Rehkopf
// Engineer: Rehkopf
//
// Create Date: 01:13:46 05/09/2009
// Design Name:
// Module Name: main
// Project Name:
// Target Devices:
// Tool versions:
// Description: Master Control FSM
//
// Dependencies: address
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module main(
input CLKIN,
input [2:0] MAPPER,
input [23:0] SNES_ADDR,
input SNES_READ,
input SNES_WRITE,
input SNES_CS,
inout [7:0] SNES_DATA,
inout [7:0] SRAM_DATA,
inout [7:0] AVR_DATA,
output [20:0] SRAM_ADDR,
output [3:0] ROM_SEL,
output SRAM_OE,
output SRAM_WE,
output SNES_DATABUS_OE,
output SNES_DATABUS_DIR,
input AVR_ADDR_RESET,
input AVR_ADDR_EN,
input AVR_READ,
input AVR_WRITE,
input AVR_NEXTADDR,
input AVR_ENA,
input [1:0] AVR_BANK,
output MODE
);
my_dcm snes_dcm(.CLKIN(CLKIN),
.CLK2X(CLK),
.CLKFB(CLKFB)
);
assign CLKFB = CLK;
address snes_addr(
.CLK(CLK),
.MAPPER(MAPPER),
.SNES_ADDR(SNES_ADDR), // requested address from SNES
.SNES_CS(SNES_CS), // "CART" pin from SNES (active low)
.SRAM_ADDR(SRAM_ADDR), // Address to request from SRAM (active low)
.ROM_SEL(ROM_SEL), // which SRAM unit to access
.AVR_ADDR_RESET(AVR_ADDR_RESET), // reset AVR sequence (active low)
.AVR_NEXTADDR(AVR_NEXTADDR), // next byte request from AVR
.AVR_ENA(AVR_ENA), // enable AVR mode (active low)
.AVR_ADDR_EN(AVR_ADDR_EN), // enable AVR address counter (active low)
.AVR_BANK(AVR_BANK), // which bank does the AVR want
.MODE(MODE), // AVR(1) or SNES(0) ("bus phase")
.IS_SAVERAM(IS_SAVERAM),
.IS_ROM(IS_ROM),
.AVR_NEXTADDR_PREV(AVR_NEXTADDR_PREV),
.AVR_NEXTADDR_CURR(AVR_NEXTADDR_CURR)
);
data snes_data(.CLK(CLK),
.SNES_READ(SNES_READ),
.SNES_WRITE(SNES_WRITE),
.AVR_READ(AVR_READ),
.AVR_WRITE(AVR_WRITE),
.SNES_DATA(SNES_DATA),
.SRAM_DATA(SRAM_DATA),
.AVR_DATA(AVR_DATA),
.MODE(MODE),
.SNES_DATA_TO_MEM(SNES_DATA_TO_MEM),
.AVR_DATA_TO_MEM(AVR_DATA_TO_MEM),
.SRAM_DATA_TO_SNES_MEM(SRAM_DATA_TO_SNES_MEM),
.SRAM_DATA_TO_AVR_MEM(SRAM_DATA_TO_AVR_MEM),
.AVR_ENA(AVR_ENA),
.AVR_NEXTADDR_PREV(AVR_NEXTADDR_PREV),
.AVR_NEXTADDR_CURR(AVR_NEXTADDR_CURR)
);
parameter MODE_SNES = 1'b0;
parameter MODE_AVR = 1'b1;
parameter STATE_0 = 8'b00000001;
parameter STATE_1 = 8'b00000010;
parameter STATE_2 = 8'b00000100;
parameter STATE_3 = 8'b00001000;
parameter STATE_4 = 8'b00010000;
parameter STATE_5 = 8'b00100000;
parameter STATE_6 = 8'b01000000;
parameter STATE_7 = 8'b10000000;
reg [7:0] STATE;
reg [2:0] STATEIDX;
reg STATE_RESET, CYCLE_RESET, CYCLE_RESET_ACK;
reg SRAM_WE_MASK;
reg SRAM_OE_MASK;
reg [7:0] SRAM_WE_ARRAY [3:0];
reg [7:0] SRAM_OE_ARRAY [3:0];
reg [7:0] SNES_DATA_TO_MEM_ARRAY[1:0];
reg [7:0] AVR_DATA_TO_MEM_ARRAY[1:0];
reg [7:0] SRAM_DATA_TO_SNES_MEM_ARRAY[1:0];
reg [7:0] SRAM_DATA_TO_AVR_MEM_ARRAY[1:0];
reg [7:0] MODE_ARRAY;
reg SNES_READ_CYCLE;
reg SNES_WRITE_CYCLE;
reg AVR_READ_CYCLE;
reg AVR_WRITE_CYCLE;
reg SNES_DATABUS_OE_BUF;
reg SNES_DATABUS_DIR_BUF;
reg AVR_NEXTADDR_PREV_BUF;
reg AVR_NEXTADDR_CURR_BUF;
wire SNES_RW;
assign MODE = !AVR_ENA ? MODE_AVR : MODE_ARRAY[STATEIDX];
assign SNES_RW = (SNES_READ & SNES_WRITE);
initial begin
CYCLE_RESET = 0;
CYCLE_RESET_ACK = 0;
STATE = STATE_7;
STATEIDX = 7;
SRAM_WE_MASK = 1'b1;
SRAM_OE_MASK = 1'b1;
SNES_READ_CYCLE = 1'b1;
SNES_WRITE_CYCLE = 1'b1;
AVR_READ_CYCLE = 1'b1;
AVR_WRITE_CYCLE = 1'b1;
MODE_ARRAY = 8'b00011111;
SRAM_WE_ARRAY[2'b00] = 8'b10010011;
SRAM_WE_ARRAY[2'b01] = 8'b10011111;
SRAM_WE_ARRAY[2'b10] = 8'b11110011;
SRAM_WE_ARRAY[2'b11] = 8'b11111111;
SRAM_OE_ARRAY[2'b00] = 8'b11111111;
SRAM_OE_ARRAY[2'b01] = 8'b11100000;
SRAM_OE_ARRAY[2'b10] = 8'b00011111;
SRAM_OE_ARRAY[2'b11] = 8'b00000000;
SNES_DATA_TO_MEM_ARRAY[1'b0] = 8'b10000000;
SNES_DATA_TO_MEM_ARRAY[1'b1] = 8'b00000000;
AVR_DATA_TO_MEM_ARRAY[1'b0] = 8'b00010000;
AVR_DATA_TO_MEM_ARRAY[1'b1] = 8'b00000000;
SRAM_DATA_TO_SNES_MEM_ARRAY[1'b0] = 8'b00000000;
SRAM_DATA_TO_SNES_MEM_ARRAY[1'b1] = 8'b00100000;
SRAM_DATA_TO_AVR_MEM_ARRAY[1'b0] = 8'b00000000;
SRAM_DATA_TO_AVR_MEM_ARRAY[1'b1] = 8'b00000010;
AVR_NEXTADDR_PREV_BUF = 0;
AVR_NEXTADDR_CURR_BUF = 0;
end
// falling edge of SNES /RD or /WR marks the beginning of a new cycle
// SNES READ or WRITE always starts @posedge CLK !!
// CPU cycle can be 6, 8 or 12 CLK cycles so we must satisfy
// the minimum of 6 cycles to get everything done.
always @(posedge CLK) begin
if (!SNES_RW) begin
if (!CYCLE_RESET_ACK)
CYCLE_RESET <= 1;
else
CYCLE_RESET <= 0;
end
end
always @(posedge CLK) begin
if (CYCLE_RESET && !CYCLE_RESET_ACK) begin
CYCLE_RESET_ACK <= 1;
STATE <= STATE_0;
end else begin
case (STATE)
STATE_0:
STATE <= STATE_1;
STATE_1:
STATE <= STATE_2;
STATE_2:
STATE <= STATE_3;
STATE_3:
STATE <= STATE_4;
STATE_4:
STATE <= STATE_5;
STATE_5:
STATE <= STATE_6;
STATE_6:
STATE <= STATE_7;
STATE_7: begin
if (SNES_RW) // check for end of SNES cycle to avoid looping
CYCLE_RESET_ACK <= 0; // ready for new cycle
STATE <= STATE_7;
end
default:
STATE <= STATE_7;
endcase
end
end
always @(posedge CLK) begin
case (STATE)
STATE_7: begin
SNES_READ_CYCLE <= SNES_READ;
SNES_WRITE_CYCLE <= SNES_WRITE;
AVR_READ_CYCLE <= AVR_READ;
AVR_WRITE_CYCLE <= AVR_WRITE;
STATEIDX <= 7;
end
STATE_0: begin
STATEIDX <= 6;
end
STATE_1: begin
STATEIDX <= 5;
end
STATE_2: begin
STATEIDX <= 4;
end
STATE_3: begin
STATEIDX <= 3;
end
STATE_4: begin
STATEIDX <= 2;
end
STATE_5: begin
STATEIDX <= 1;
end
STATE_6: begin
STATEIDX <= 0;
end
endcase
end
// When in AVR mode, enable SRAM_WE according to AVR programming
// else enable SRAM_WE according to state&cycle
assign SRAM_WE = !AVR_ENA ? AVR_WRITE
: ((!IS_SAVERAM & !MODE) | SRAM_WE_ARRAY[{SNES_WRITE_CYCLE, AVR_WRITE_CYCLE}][STATEIDX]);
// When in AVR mode, enable SRAM_OE whenever not writing
// else enable SRAM_OE according to state&cycle
assign SRAM_OE = !AVR_ENA ? AVR_READ
: SRAM_OE_ARRAY[{SNES_WRITE_CYCLE, AVR_WRITE_CYCLE}][STATEIDX];
// dumb version
//assign SRAM_OE = !AVR_ENA ? AVR_READ : SNES_READ;
//assign SRAM_WE = !AVR_ENA ? AVR_WRITE : 1'b1;
always @(posedge CLK) begin
SNES_DATABUS_OE_BUF <= SNES_CS | (SNES_READ & SNES_WRITE);
end
always @(posedge CLK) begin
AVR_NEXTADDR_PREV_BUF <= AVR_NEXTADDR_CURR_BUF;
AVR_NEXTADDR_CURR_BUF <= AVR_NEXTADDR;
end
assign AVR_NEXTADDR_PREV = AVR_NEXTADDR_PREV_BUF;
assign AVR_NEXTADDR_CURR = AVR_NEXTADDR_CURR_BUF;
//assign SNES_DATABUS_OE = (!IS_SAVERAM & SNES_CS) | (SNES_READ & SNES_WRITE);
assign SNES_DATABUS_OE = (IS_ROM & SNES_CS) | (!IS_ROM & !IS_SAVERAM) | (SNES_READ & SNES_WRITE);
assign SNES_DATABUS_DIR = !SNES_WRITE ? 1'b0 : 1'b1;
assign SNES_DATA_TO_MEM = SNES_DATA_TO_MEM_ARRAY[SNES_WRITE_CYCLE][STATEIDX];
assign AVR_DATA_TO_MEM = AVR_DATA_TO_MEM_ARRAY[AVR_WRITE_CYCLE][STATEIDX];
assign SRAM_DATA_TO_SNES_MEM = SRAM_DATA_TO_SNES_MEM_ARRAY[SNES_WRITE_CYCLE][STATEIDX];
assign SRAM_DATA_TO_AVR_MEM = SRAM_DATA_TO_AVR_MEM_ARRAY[AVR_WRITE_CYCLE][STATEIDX];
endmodule

View File

@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<project xmlns="http://www.xilinx.com/XMLSchema" xmlns:xil_pn="http://www.xilinx.com/XMLSchema">
<header>
<!-- ISE source project file created by Project Navigator. -->
<!-- -->
<!-- This file contains project source information including a list of -->
<!-- project source files, project and process properties. This file, -->
<!-- along with the project source files, is sufficient to open and -->
<!-- implement in ISE Project Navigator. -->
<!-- -->
<!-- Copyright (c) 1995-2009 Xilinx, Inc. All rights reserved. -->
</header>
<version xil_pn:ise_version="11.1" xil_pn:schema_version="2"/>
<files>
<file xil_pn:name="address.v" xil_pn:type="FILE_VERILOG">
<association xil_pn:name="BehavioralSimulation"/>
<association xil_pn:name="Implementation"/>
</file>
<file xil_pn:name="data.v" xil_pn:type="FILE_VERILOG">
<association xil_pn:name="BehavioralSimulation"/>
<association xil_pn:name="Implementation"/>
</file>
<file xil_pn:name="main.ucf" xil_pn:type="FILE_UCF">
<association xil_pn:name="Implementation"/>
</file>
<file xil_pn:name="main.v" xil_pn:type="FILE_VERILOG">
<association xil_pn:name="BehavioralSimulation"/>
<association xil_pn:name="Implementation"/>
</file>
<file xil_pn:name="tf_main.v" xil_pn:type="FILE_VERILOG">
<association xil_pn:name="BehavioralSimulation"/>
<association xil_pn:name="PostRouteSimulation"/>
<association xil_pn:name="PostMapSimulation"/>
<association xil_pn:name="PostTranslateSimulation"/>
</file>
<file xil_pn:name="dcm.v" xil_pn:type="FILE_VERILOG">
<association xil_pn:name="BehavioralSimulation"/>
<association xil_pn:name="Implementation"/>
</file>
</files>
<properties>
<property xil_pn:name="Constraints Entry" xil_pn:value="Constraints Editor"/>
<property xil_pn:name="Device" xil_pn:value="xc3s200"/>
<property xil_pn:name="Device Family" xil_pn:value="Spartan3"/>
<property xil_pn:name="Extra Effort (Highest PAR level only)" xil_pn:value="Normal"/>
<property xil_pn:name="Fitter Report Format" xil_pn:value="HTML"/>
<property xil_pn:name="Implementation Top" xil_pn:value="Module|main"/>
<property xil_pn:name="Implementation Top Instance Path" xil_pn:value="/main"/>
<property xil_pn:name="PROP_BehavioralSimTop" xil_pn:value="Module|tf_main"/>
<property xil_pn:name="PROP_DesignName" xil_pn:value="sd2snes"/>
<property xil_pn:name="PROP_PostParSimTop" xil_pn:value="Module|tf_main"/>
<property xil_pn:name="Package" xil_pn:value="tq144"/>
<property xil_pn:name="Place &amp; Route Effort Level (Overall)" xil_pn:value="High"/>
<property xil_pn:name="Placer Effort Level (Overrides Overall Level)" xil_pn:value="High"/>
<property xil_pn:name="Preferred Language" xil_pn:value="Verilog"/>
<property xil_pn:name="Project Description" xil_pn:value="sd2snes"/>
<property xil_pn:name="Router Effort Level (Overrides Overall Level)" xil_pn:value="High"/>
<property xil_pn:name="Selected Simulation Root Source Node Behavioral" xil_pn:value="Module|tf_main"/>
<property xil_pn:name="Selected Simulation Root Source Node Post-Route" xil_pn:value="Module|tf_main"/>
<property xil_pn:name="Selected Simulation Source Node" xil_pn:value="uut"/>
<property xil_pn:name="Simulator" xil_pn:value="ISim (VHDL/Verilog)"/>
<property xil_pn:name="Speed Grade" xil_pn:value="-4"/>
<property xil_pn:name="Synthesis Tool" xil_pn:value="XST (VHDL/Verilog)"/>
<property xil_pn:name="Top-Level Source Type" xil_pn:value="HDL"/>
<property xil_pn:name="Verbose Property Persistence" xil_pn:value="false"/>
</properties>
<bindings/>
<libraries/>
<partitions>
<partition xil_pn:name="/main"/>
</partitions>
</project>

136
verilog/sd2snes/tf_main.v Normal file
View File

@ -0,0 +1,136 @@
`timescale 1ns / 1ps
////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 23:11:58 05/13/2009
// Design Name: main
// Module Name: /home/ikari/prj/sd2snes/verilog/sd2snes/tf_main.v
// Project Name: sd2snes
// Target Device:
// Tool versions:
// Description:
//
// Verilog Test Fixture created by ISE for module: main
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
////////////////////////////////////////////////////////////////////////////////
module tf_main;
// Inputs
reg CLK;
reg [2:0] MAPPER;
reg [23:0] SNES_ADDR;
reg SNES_READ;
reg SNES_WRITE;
reg SNES_CS;
reg AVR_ADDR_RESET;
reg AVR_WRITE;
reg AVR_READ;
reg AVR_NEXTADDR;
reg AVR_ENA;
reg [1:0] AVR_BANK;
reg AVR_ADDR_EN;
// Outputs
wire [20:0] SRAM_ADDR;
wire [3:0] ROM_SEL;
wire SRAM_OE;
wire SRAM_WE;
wire SNES_DATABUS_OE;
wire SNES_DATABUS_DIR;
wire MODE;
// Bidirs
wire [7:0] SNES_DATA;
wire [7:0] SRAM_DATA;
wire [7:0] AVR_DATA;
reg [7:0] SRAM_DATA_BUF;
reg [7:0] SNES_DATA_BUF;
// Instantiate the Unit Under Test (UUT)
main uut (
.CLKIN(CLK),
.MAPPER(MAPPER),
.SNES_ADDR(SNES_ADDR),
.SNES_READ(SNES_READ),
.SNES_WRITE(SNES_WRITE),
.SNES_CS(SNES_CS),
.SNES_DATA(SNES_DATA),
.SRAM_DATA(SRAM_DATA),
.AVR_DATA(AVR_DATA),
.SRAM_ADDR(SRAM_ADDR),
.ROM_SEL(ROM_SEL),
.SRAM_OE(SRAM_OE),
.SRAM_WE(SRAM_WE),
.AVR_ADDR_RESET(AVR_ADDR_RESET),
.AVR_WRITE(AVR_WRITE),
.AVR_NEXTADDR(AVR_NEXTADDR),
.AVR_ENA(AVR_ENA),
.AVR_BANK(AVR_BANK),
.AVR_READ(AVR_READ),
.AVR_ADDR_EN(AVR_ADDR_EN),
.SNES_DATABUS_OE(SNES_DATABUS_OE),
.SNES_DATABUS_DIR(SNES_DATABUS_DIR),
.MODE(MODE)
);
assign SRAM_DATA = SRAM_DATA_BUF;
initial begin
// Initialize Inputs
CLK = 1;
MAPPER = 0;
SNES_ADDR = 24'h223456;
SNES_READ = 1;
SNES_WRITE = 1;
SNES_CS = 0;
AVR_ADDR_RESET = 1;
AVR_WRITE = 1;
AVR_READ = 0;
AVR_NEXTADDR = 0;
AVR_ENA = 1;
AVR_BANK = 0;
AVR_ADDR_EN = 0;
SRAM_DATA_BUF = 8'hff;
// Wait for global reset to finish
#276;
#276 AVR_NEXTADDR <= ~AVR_NEXTADDR;
#276 AVR_NEXTADDR <= ~AVR_NEXTADDR;
#276 AVR_NEXTADDR <= ~AVR_NEXTADDR;
#276 AVR_NEXTADDR <= ~AVR_NEXTADDR;
#276 AVR_NEXTADDR <= ~AVR_NEXTADDR;
#276 AVR_NEXTADDR <= ~AVR_NEXTADDR;
#276 AVR_NEXTADDR <= ~AVR_NEXTADDR;
#276 AVR_NEXTADDR <= ~AVR_NEXTADDR;
SNES_ADDR <= 24'h123456;
SNES_READ <= 0;
#176;
SNES_READ <= 1;
#100;
SNES_WRITE <= 0;
#176;
SNES_WRITE <= 1;
#100;
AVR_WRITE <= 0;
SNES_READ <= 0;
#276;
// AVR_READ <= 1;
// Add stimulus here
end
always
#23 CLK <= ~CLK;
// always begin
// #234 AVR_NEXTADDR <= ~AVR_NEXTADDR;
// end
endmodule