Initial Commit
This commit is contained in:
commit
e121b34cf4
BIN
pcb/DIL-Labels.sch
Normal file
BIN
pcb/DIL-Labels.sch
Normal file
Binary file not shown.
BIN
pcb/breakout1.brd
Normal file
BIN
pcb/breakout1.brd
Normal file
Binary file not shown.
BIN
pcb/breakout2.brd
Normal file
BIN
pcb/breakout2.brd
Normal file
Binary file not shown.
BIN
pcb/breakout2.sch
Normal file
BIN
pcb/breakout2.sch
Normal file
Binary file not shown.
BIN
pcb/breakouts1-old.brd
Normal file
BIN
pcb/breakouts1-old.brd
Normal file
Binary file not shown.
BIN
pcb/snesbreakout.brd
Normal file
BIN
pcb/snesbreakout.brd
Normal file
Binary file not shown.
BIN
pcb/snesbreakout.sch
Normal file
BIN
pcb/snesbreakout.sch
Normal file
Binary file not shown.
247
pcb/test.brd
Normal file
247
pcb/test.brd
Normal 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
34
pcb/test.sch
Normal 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
618
src/Makefile
Normal 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
162
src/avrcompat.h
Normal 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
29
src/conf2h.awk
Normal 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
41
src/config
Normal 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
113
src/config.h
Normal 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
51
src/crc16.c
Normal 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
54
src/crc16.h
Normal 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
74
src/crc32.c
Normal 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
85
src/crc32.h
Normal 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
107
src/crc7.c
Normal 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
33
src/crc7.h
Normal 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
85
src/crcgen-new.c
Normal 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
197
src/diskio.c
Normal 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
125
src/diskio.h
Normal 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
170
src/eeprom.c
Normal 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
33
src/eeprom.h
Normal 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
|
||||
547
src/ff.h
Normal file
547
src/ff.h
Normal 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
31
src/fileops.c
Normal 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
18
src/fileops.h
Normal 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
186
src/fpga.c
Normal 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
46
src/fpga.h
Normal 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
15
src/gcctest.awk
Normal 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
30
src/integer.h
Normal 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
43
src/led.c
Normal 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
54
src/led.h
Normal 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
200
src/main.c
Normal 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
121
src/memory.c
Normal 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
10
src/memory.h
Normal 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
749
src/sdcard.c
Normal 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
40
src/sdcard.h
Normal 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
54
src/snes.c
Normal 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
11
src/snes.h
Normal 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
131
src/spi.c
Normal 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
68
src/spi.h
Normal 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
75
src/src2doxy.pl
Executable 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
16
src/time.h
Normal 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
130
src/timer.c
Normal 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
116
src/timer.h
Normal 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
164
src/uart.c
Normal 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
59
src/uart.h
Normal 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
42
src/ustring.h
Normal 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
77
src/utils.c
Normal 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
52
src/utils.h
Normal 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
118
verilog/sd2snes/address.v
Normal 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
83
verilog/sd2snes/data.v
Normal 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
70
verilog/sd2snes/dcm.v
Normal 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
191
verilog/sd2snes/main.ucf
Normal 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
299
verilog/sd2snes/main.v
Normal 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
|
||||
80
verilog/sd2snes/sd2snes.xise
Normal file
80
verilog/sd2snes/sd2snes.xise
Normal 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 & 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
136
verilog/sd2snes/tf_main.v
Normal 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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user