├── .gitignore ├── CMakeLists.txt ├── Makefile ├── README.md ├── res ├── IP.BIN ├── boot_loader_devkit.bios ├── boot_loader_devkit_32mb.bios ├── boot_loader_devkit_nogdrom.bios ├── boot_loader_devkit_nogdrom_32mb.bios ├── boot_loader_retail.bios ├── boot_loader_retail_32mb.bios ├── boot_loader_retail_nogdrom.bios ├── boot_loader_retail_nogdrom_32mb.bios ├── future.bmfc ├── future.fnt ├── future_0.png ├── future_0.tex └── screen1.png ├── romdisk ├── dcload-ip.bin ├── dcload-serial.bin ├── future.fnt ├── future_0.tex └── syscalls.bin ├── src ├── dc │ ├── bmfont.c │ ├── bmfont.h │ ├── descramble.c │ ├── drawing.c │ ├── dreamfs.c │ ├── input.c │ └── utility.c ├── drawing.h ├── dreamfs.h ├── ds │ ├── include │ │ ├── drivers │ │ │ ├── g1_ide.h │ │ │ ├── rtc.h │ │ │ ├── sd.h │ │ │ ├── sh7750_regs.h │ │ │ └── spi.h │ │ ├── fatfs │ │ │ ├── diskio.h │ │ │ ├── ff.h │ │ │ ├── ff_utils.h │ │ │ ├── ffconf.h │ │ │ └── integer.h │ │ ├── fs.h │ │ └── utils.h │ └── src │ │ ├── drivers │ │ ├── rtc.c │ │ ├── sd.c │ │ └── spi.c │ │ ├── fs │ │ ├── fat │ │ │ ├── dc.c │ │ │ ├── ff.c │ │ │ ├── option │ │ │ │ ├── ccsbcs.c │ │ │ │ └── syscall.c │ │ │ └── utils.c │ │ └── fs.c │ │ └── utils │ │ ├── asm.h │ │ ├── memcpy.S │ │ └── memset.S ├── input.h ├── linux │ ├── SDL_FontCache.c │ ├── SDL_FontCache.h │ ├── drawing.c │ ├── input.c │ └── utility.c ├── main.c ├── menu.c ├── menu.h ├── retrodream.h ├── retrolog.c ├── retrolog.h ├── uthash │ ├── LICENSE │ ├── utarray.h │ ├── uthash.h │ ├── utlist.h │ ├── utringbuffer.h │ ├── utstack.h │ └── utstring.h ├── utility.c └── utility.h ├── targets.cmake └── toolchain.cmake /.gitignore: -------------------------------------------------------------------------------- 1 | cmake-build-* 2 | .idea* 3 | 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | #set(CMAKE_VERBOSE_MAKEFILE ON) 3 | 4 | option(PLATFORM_LINUX "Linux platform target" OFF) 5 | option(DEBUG_EMU "Enable emulator debug" OFF) 6 | 7 | # toolchain: https://github.com/PacBrew/pacbrew-packages/blob/master/README.md 8 | if (NOT DEFINED CMAKE_TOOLCHAIN_FILE) 9 | include(toolchain.cmake) 10 | endif () 11 | 12 | ############# 13 | # ds loader 14 | ############# 15 | project(dreamboot) 16 | enable_language(ASM) 17 | 18 | set(VERSION "1.1.0") 19 | 20 | ############# 21 | # code 22 | ############# 23 | 24 | file(GLOB SOURCES src/*.c) 25 | set(INCLUDES src src/uthash) 26 | set(CFLAGS -D__DB_VERSION__="${VERSION}") 27 | 28 | if (PLATFORM_LINUX) 29 | file(GLOB_RECURSE CROSS_SOURCES src/linux/*.c) 30 | list(APPEND SOURCES ${CROSS_SOURCES}) 31 | list(APPEND CFLAGS -D__LINUX__) 32 | set(LDFLAGS SDL2 SDL2_ttf freetype) 33 | else () 34 | file(GLOB_RECURSE CROSS_SOURCES src/dc/*.c) 35 | file(GLOB_RECURSE DS_SOURCES src/ds/*.*) 36 | list(APPEND SOURCES ${CROSS_SOURCES} ${DS_SOURCES}) 37 | list(APPEND INCLUDES src/ds/include src/ds/include/fatfs) 38 | list(APPEND CFLAGS -D__DC__) 39 | if (DEBUG_EMU) 40 | list(APPEND CFLAGS -D__DEBUG_EMU__) 41 | endif () 42 | set(LDFLAGS kosext2fs ${KOS_LIBS}) 43 | endif () 44 | 45 | ############# 46 | # executable 47 | ############# 48 | add_executable(${PROJECT_NAME} ${SOURCES}) 49 | target_include_directories(${PROJECT_NAME} PRIVATE ${INCLUDES}) 50 | target_compile_options(${PROJECT_NAME} PRIVATE ${CFLAGS}) 51 | target_link_libraries(${PROJECT_NAME} ${LDFLAGS}) 52 | set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS_RELEASE -s) 53 | 54 | include(targets.cmake) -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # DreamShell boot loader 3 | # (c)2011-2016 SWAT 4 | # 5 | 6 | TARGET = loader 7 | VERSION = 2.4 8 | TARGET_NAME = DreamShell_boot_$(TARGET)_v$(VERSION) 9 | TARGET_CD = cd/1DS_BOOT.BIN 10 | 11 | all: rm-elf $(TARGET).elf 12 | 13 | clean: rm-elf 14 | -rm -f $(OBJS) 15 | 16 | rm-elf: 17 | -rm -f $(TARGET).elf $(TARGET).bin $(TARGET_CD) romdisk.* 18 | 19 | include ../../sdk/Makefile.cfg 20 | 21 | FATFS = $(DS_BASE)/src/fs/fat 22 | DRIVERS = $(DS_BASE)/src/drivers 23 | UTILS = $(DS_BASE)/src/utils 24 | 25 | OBJS = src/main.o src/spiral.o src/menu.o src/descramble.o \ 26 | $(DRIVERS)/spi.o $(DRIVERS)/sd.o $(DRIVERS)/rtc.o \ 27 | $(FATFS)/utils.o $(FATFS)/option/ccsbcs.o $(FATFS)/option/syscall.o \ 28 | $(FATFS)/ff.o $(FATFS)/dc.o $(FATFS)/../fs.o \ 29 | $(UTILS)/memcpy.op $(UTILS)/memset.op 30 | 31 | KOS_CFLAGS += -I$(DS_BASE)/include -I$(DS_BASE)/include/fatfs -I./include -DVERSION="$(VERSION)" 32 | 33 | $(TARGET).bin: $(TARGET).elf 34 | $(TARGET).elf: $(OBJS) romdisk.o 35 | $(KOS_CC) $(KOS_CFLAGS) $(KOS_LDFLAGS) -o $(TARGET).elf \ 36 | $(OBJS) romdisk.o $(OBJEXTRA) -lkosext2fs -lz -lkmg $(KOS_LIBS) 37 | $(KOS_STRIP) $(TARGET).elf 38 | $(KOS_OBJCOPY) -R .stack -O binary $(TARGET).elf $(TARGET).bin 39 | 40 | %.op: %.S 41 | kos-cc $(CFLAGS) -c $< -o $@ 42 | 43 | romdisk.img: 44 | $(KOS_GENROMFS) -f romdisk.img -d romdisk -v 45 | 46 | romdisk.o: romdisk.img 47 | $(KOS_BASE)/utils/bin2o/bin2o romdisk.img romdisk romdisk.o 48 | 49 | $(TARGET_CD): $(TARGET).bin 50 | 51 | cdi: $(TARGET_CD) 52 | @mkdir -p ./cd 53 | @$(DS_SDK)/bin/scramble $(TARGET).bin $(TARGET_CD) 54 | @$(DS_SDK)/bin/mkisofs -V DreamShell -G res/IP.BIN -joliet -rock -l -o $(TARGET).iso ./cd 55 | @echo Convert ISO to CDI... 56 | @-rm -f $(TARGET).cdi 57 | @$(DS_SDK)/bin/cdi4dc $(TARGET).iso $(TARGET).cdi -d > cdi4dc.out 58 | @-rm -f $(TARGET).iso 59 | 60 | #@$(DS_SDK)/bin/mkisofs -V DreamShell -C 0,11702 -G res/IP.BIN -joliet -rock -l -o $(TARGET).iso ./cd 61 | #@$(DS_SDK)/bin/cdi4dc $(TARGET).iso $(TARGET).cdi > cdi4dc.out 62 | 63 | release: all cdi 64 | rm -f $(TARGET_NAME).elf $(TARGET_NAME).bin $(TARGET_NAME).cdi 65 | mv $(TARGET).elf $(TARGET_NAME).elf 66 | mv $(TARGET).bin $(TARGET_NAME).bin 67 | mv $(TARGET).cdi $(TARGET_NAME).cdi 68 | 69 | nulldc: all cdi 70 | @echo Running... 71 | @-rm -f $(DS_BASE)/DS.cdi 72 | @cp $(TARGET).cdi $(DS_BASE)/DS.cdi 73 | @run $(DS_BASE)/emu/nullDC.exe -serial "debug.log" 74 | 75 | lxdream: all cdi 76 | @echo Running... 77 | @lxdream -p $(TARGET).cdi 78 | 79 | lxelf: $(TARGET).elf 80 | lxdream -u -p -e $(TARGET).elf 81 | 82 | run: $(TARGET).elf 83 | $(DS_SDK)/bin/dc-tool -t $(DC_IP) -x $(TARGET).elf 84 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dreamboot 2 | 3 | A custom bios for the dreamcast. 4 | 5 | ![](https://github.com/Cpasjuste/dreamboot/raw/master/res/screen1.png) 6 | 7 | #### How does it works ? 8 | The bios will try to boot stuff in this order: 9 | - If the text file "/sd/boot.cfg" exists, the bios will try to boot the defined binary path in this file. 10 | - If the text file "/ide/boot.cfg" exists, the bios will try to boot the defined binary path in this file. 11 | - If the file "/sd/RD/retrodream.bin" exists, the bios will boot that. 12 | - If the file "/ide/RD/retrodream.bin" exists, the bios will boot that. 13 | - If the file "/sd/DS/DS_CORE.BIN" exists, the bios will boot that. 14 | - If the file "/ide/DS/DS_CORE.BIN" exists, the bios will boot that. 15 | #### More options ? 16 | - If none of the previous cases succeed, the bios will enter the boot menu 17 | - If "START" is pressed during boot up, the boot menu will be displayed 18 | - If "A" + "B" is pressed during boot up, dc-load-serial will be launched 19 | - If "X" + "Y" is pressed during boot up, dc-load-ip will be launched 20 | #### Building 21 | - install dreamcast (KallistiOS) sdk with "[pacbrew-pacman](https://github.com/PacBrew/pacbrew-packages/blob/master/README.md)" 22 | - add toolchain file to your cmake build command or ide: 23 | - `-DCMAKE_TOOLCHAIN_FILE=/opt/pacbrew/dc/target/sh-elf/usr/lib/cmake/dc-toolchain.cmake` -------------------------------------------------------------------------------- /res/IP.BIN: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cpasjuste/dreamboot/5f40f46e65032e5e170501a82d8ddf720bf96a95/res/IP.BIN -------------------------------------------------------------------------------- /res/boot_loader_devkit.bios: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cpasjuste/dreamboot/5f40f46e65032e5e170501a82d8ddf720bf96a95/res/boot_loader_devkit.bios -------------------------------------------------------------------------------- /res/boot_loader_devkit_32mb.bios: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cpasjuste/dreamboot/5f40f46e65032e5e170501a82d8ddf720bf96a95/res/boot_loader_devkit_32mb.bios -------------------------------------------------------------------------------- /res/boot_loader_devkit_nogdrom.bios: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cpasjuste/dreamboot/5f40f46e65032e5e170501a82d8ddf720bf96a95/res/boot_loader_devkit_nogdrom.bios -------------------------------------------------------------------------------- /res/boot_loader_devkit_nogdrom_32mb.bios: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cpasjuste/dreamboot/5f40f46e65032e5e170501a82d8ddf720bf96a95/res/boot_loader_devkit_nogdrom_32mb.bios -------------------------------------------------------------------------------- /res/boot_loader_retail.bios: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cpasjuste/dreamboot/5f40f46e65032e5e170501a82d8ddf720bf96a95/res/boot_loader_retail.bios -------------------------------------------------------------------------------- /res/boot_loader_retail_32mb.bios: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cpasjuste/dreamboot/5f40f46e65032e5e170501a82d8ddf720bf96a95/res/boot_loader_retail_32mb.bios -------------------------------------------------------------------------------- /res/boot_loader_retail_nogdrom.bios: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cpasjuste/dreamboot/5f40f46e65032e5e170501a82d8ddf720bf96a95/res/boot_loader_retail_nogdrom.bios -------------------------------------------------------------------------------- /res/boot_loader_retail_nogdrom_32mb.bios: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cpasjuste/dreamboot/5f40f46e65032e5e170501a82d8ddf720bf96a95/res/boot_loader_retail_nogdrom_32mb.bios -------------------------------------------------------------------------------- /res/future.bmfc: -------------------------------------------------------------------------------- 1 | # AngelCode Bitmap Font Generator configuration file 2 | fileVersion=1 3 | 4 | # font settings 5 | fontName=This Is The Future 6 | fontFile= 7 | charSet=0 8 | fontSize=24 9 | aa=1 10 | scaleH=100 11 | useSmoothing=1 12 | isBold=0 13 | isItalic=0 14 | useUnicode=1 15 | disableBoxChars=1 16 | outputInvalidCharGlyph=0 17 | dontIncludeKerningPairs=0 18 | useHinting=1 19 | renderFromOutline=0 20 | useClearType=1 21 | autoFitNumPages=0 22 | autoFitFontSizeMin=0 23 | autoFitFontSizeMax=0 24 | 25 | # character alignment 26 | paddingDown=0 27 | paddingUp=0 28 | paddingRight=0 29 | paddingLeft=0 30 | spacingHoriz=1 31 | spacingVert=1 32 | useFixedHeight=0 33 | forceZero=0 34 | widthPaddingFactor=0.00 35 | 36 | # output file 37 | outWidth=256 38 | outHeight=256 39 | outBitDepth=32 40 | fontDescFormat=0 41 | fourChnlPacked=0 42 | textureFormat=png 43 | textureCompression=0 44 | alphaChnl=1 45 | redChnl=0 46 | greenChnl=0 47 | blueChnl=0 48 | invA=0 49 | invR=0 50 | invG=0 51 | invB=0 52 | 53 | # outline 54 | outlineThickness=0 55 | 56 | # selected chars 57 | chars=0-0,29,32-126,160,163,165,173,180,247 58 | 59 | # imported icon images 60 | -------------------------------------------------------------------------------- /res/future_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cpasjuste/dreamboot/5f40f46e65032e5e170501a82d8ddf720bf96a95/res/future_0.png -------------------------------------------------------------------------------- /res/future_0.tex: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cpasjuste/dreamboot/5f40f46e65032e5e170501a82d8ddf720bf96a95/res/future_0.tex -------------------------------------------------------------------------------- /res/screen1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cpasjuste/dreamboot/5f40f46e65032e5e170501a82d8ddf720bf96a95/res/screen1.png -------------------------------------------------------------------------------- /romdisk/dcload-ip.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cpasjuste/dreamboot/5f40f46e65032e5e170501a82d8ddf720bf96a95/romdisk/dcload-ip.bin -------------------------------------------------------------------------------- /romdisk/dcload-serial.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cpasjuste/dreamboot/5f40f46e65032e5e170501a82d8ddf720bf96a95/romdisk/dcload-serial.bin -------------------------------------------------------------------------------- /romdisk/future.fnt: -------------------------------------------------------------------------------- 1 | info face="This Is The Future" size=24 bold=0 italic=0 charset="unicode" unicode=1 stretchH=100 smooth=1 aa=1 padding=0,0,0,0 spacing=1,1 outline=0 2 | common lineHeight=25 base=21 scaleW=256 scaleH=256 pages=1 packed=0 alphaChnl=1 redChnl=0 greenChnl=0 blueChnl=0 3 | page id=0 file="future_0.png" 4 | chars count=103 5 | char id=0 x=16 y=44 width=3 height=1 xoffset=-1 yoffset=24 xadvance=0 page=0 chnl=15 6 | char id=29 x=20 y=44 width=3 height=1 xoffset=-1 yoffset=24 xadvance=0 page=0 chnl=15 7 | char id=32 x=24 y=44 width=3 height=1 xoffset=-1 yoffset=24 xadvance=5 page=0 chnl=15 8 | char id=33 x=113 y=88 width=7 height=21 xoffset=0 yoffset=1 xadvance=6 page=0 chnl=15 9 | char id=34 x=20 y=112 width=11 height=6 xoffset=0 yoffset=1 xadvance=11 page=0 chnl=15 10 | char id=35 x=133 y=0 width=16 height=21 xoffset=0 yoffset=1 xadvance=16 page=0 chnl=15 11 | char id=36 x=0 y=0 width=14 height=23 xoffset=0 yoffset=0 xadvance=13 page=0 chnl=15 12 | char id=37 x=150 y=0 width=16 height=21 xoffset=0 yoffset=1 xadvance=15 page=0 chnl=15 13 | char id=38 x=99 y=0 width=16 height=21 xoffset=0 yoffset=1 xadvance=15 page=0 chnl=15 14 | char id=39 x=249 y=22 width=6 height=6 xoffset=0 yoffset=1 xadvance=6 page=0 chnl=15 15 | char id=40 x=76 y=88 width=9 height=21 xoffset=0 yoffset=1 xadvance=9 page=0 chnl=15 16 | char id=41 x=66 y=88 width=9 height=21 xoffset=0 yoffset=1 xadvance=8 page=0 chnl=15 17 | char id=42 x=0 y=112 width=10 height=8 xoffset=-1 yoffset=1 xadvance=8 page=0 chnl=15 18 | char id=43 x=203 y=88 width=13 height=11 xoffset=0 yoffset=6 xadvance=13 page=0 chnl=15 19 | char id=44 x=11 y=112 width=8 height=7 xoffset=0 yoffset=18 xadvance=7 page=0 chnl=15 20 | char id=45 x=57 y=110 width=9 height=5 xoffset=0 yoffset=9 xadvance=9 page=0 chnl=15 21 | char id=46 x=77 y=110 width=7 height=5 xoffset=0 yoffset=17 xadvance=6 page=0 chnl=15 22 | char id=47 x=128 y=22 width=15 height=21 xoffset=0 yoffset=1 xadvance=15 page=0 chnl=15 23 | char id=48 x=45 y=44 width=14 height=21 xoffset=0 yoffset=1 xadvance=13 page=0 chnl=15 24 | char id=49 x=96 y=88 width=8 height=21 xoffset=-1 yoffset=1 xadvance=6 page=0 chnl=15 25 | char id=50 x=60 y=44 width=14 height=21 xoffset=0 yoffset=1 xadvance=13 page=0 chnl=15 26 | char id=51 x=75 y=44 width=14 height=21 xoffset=0 yoffset=1 xadvance=13 page=0 chnl=15 27 | char id=52 x=32 y=22 width=15 height=21 xoffset=-1 yoffset=1 xadvance=14 page=0 chnl=15 28 | char id=53 x=90 y=44 width=14 height=21 xoffset=0 yoffset=1 xadvance=13 page=0 chnl=15 29 | char id=54 x=30 y=44 width=14 height=21 xoffset=0 yoffset=1 xadvance=13 page=0 chnl=15 30 | char id=55 x=162 y=66 width=13 height=21 xoffset=-1 yoffset=1 xadvance=12 page=0 chnl=15 31 | char id=56 x=0 y=68 width=14 height=21 xoffset=0 yoffset=1 xadvance=13 page=0 chnl=15 32 | char id=57 x=135 y=44 width=14 height=21 xoffset=0 yoffset=1 xadvance=13 page=0 chnl=15 33 | char id=58 x=217 y=88 width=7 height=11 xoffset=0 yoffset=11 xadvance=6 page=0 chnl=15 34 | char id=59 x=193 y=88 width=9 height=12 xoffset=-1 yoffset=11 xadvance=7 page=0 chnl=15 35 | char id=60 x=165 y=88 width=13 height=14 xoffset=0 yoffset=7 xadvance=13 page=0 chnl=15 36 | char id=61 x=225 y=88 width=12 height=10 xoffset=0 yoffset=9 xadvance=12 page=0 chnl=15 37 | char id=62 x=179 y=88 width=13 height=14 xoffset=0 yoffset=7 xadvance=13 page=0 chnl=15 38 | char id=63 x=204 y=22 width=14 height=21 xoffset=0 yoffset=1 xadvance=13 page=0 chnl=15 39 | char id=64 x=129 y=88 width=22 height=20 xoffset=0 yoffset=2 xadvance=22 page=0 chnl=15 40 | char id=65 x=217 y=0 width=15 height=21 xoffset=0 yoffset=1 xadvance=15 page=0 chnl=15 41 | char id=66 x=219 y=22 width=14 height=21 xoffset=0 yoffset=1 xadvance=13 page=0 chnl=15 42 | char id=67 x=105 y=44 width=14 height=21 xoffset=0 yoffset=1 xadvance=13 page=0 chnl=15 43 | char id=68 x=120 y=44 width=14 height=21 xoffset=0 yoffset=1 xadvance=13 page=0 chnl=15 44 | char id=69 x=216 y=66 width=12 height=21 xoffset=0 yoffset=1 xadvance=12 page=0 chnl=15 45 | char id=70 x=229 y=66 width=12 height=21 xoffset=0 yoffset=1 xadvance=12 page=0 chnl=15 46 | char id=71 x=165 y=44 width=14 height=21 xoffset=0 yoffset=1 xadvance=13 page=0 chnl=15 47 | char id=72 x=180 y=44 width=14 height=21 xoffset=0 yoffset=1 xadvance=13 page=0 chnl=15 48 | char id=73 x=121 y=88 width=7 height=21 xoffset=0 yoffset=1 xadvance=6 page=0 chnl=15 49 | char id=74 x=34 y=88 width=10 height=21 xoffset=0 yoffset=1 xadvance=9 page=0 chnl=15 50 | char id=75 x=225 y=44 width=14 height=21 xoffset=0 yoffset=1 xadvance=13 page=0 chnl=15 51 | char id=76 x=242 y=66 width=11 height=21 xoffset=0 yoffset=1 xadvance=10 page=0 chnl=15 52 | char id=77 x=80 y=0 width=18 height=21 xoffset=0 yoffset=1 xadvance=17 page=0 chnl=15 53 | char id=78 x=15 y=68 width=14 height=21 xoffset=0 yoffset=1 xadvance=13 page=0 chnl=15 54 | char id=79 x=30 y=66 width=14 height=21 xoffset=0 yoffset=1 xadvance=13 page=0 chnl=15 55 | char id=80 x=240 y=44 width=14 height=21 xoffset=0 yoffset=1 xadvance=13 page=0 chnl=15 56 | char id=81 x=116 y=0 width=16 height=21 xoffset=0 yoffset=1 xadvance=15 page=0 chnl=15 57 | char id=82 x=210 y=44 width=14 height=21 xoffset=0 yoffset=1 xadvance=13 page=0 chnl=15 58 | char id=83 x=195 y=44 width=14 height=21 xoffset=0 yoffset=1 xadvance=13 page=0 chnl=15 59 | char id=84 x=176 y=66 width=13 height=21 xoffset=0 yoffset=1 xadvance=12 page=0 chnl=15 60 | char id=85 x=189 y=22 width=14 height=21 xoffset=0 yoffset=1 xadvance=13 page=0 chnl=15 61 | char id=86 x=96 y=22 width=15 height=21 xoffset=0 yoffset=1 xadvance=15 page=0 chnl=15 62 | char id=87 x=15 y=0 width=22 height=21 xoffset=0 yoffset=1 xadvance=21 page=0 chnl=15 63 | char id=88 x=80 y=22 width=15 height=21 xoffset=0 yoffset=1 xadvance=15 page=0 chnl=15 64 | char id=89 x=64 y=22 width=15 height=21 xoffset=0 yoffset=1 xadvance=15 page=0 chnl=15 65 | char id=90 x=120 y=66 width=13 height=21 xoffset=0 yoffset=1 xadvance=13 page=0 chnl=15 66 | char id=91 x=86 y=88 width=9 height=21 xoffset=0 yoffset=1 xadvance=9 page=0 chnl=15 67 | char id=92 x=233 y=0 width=15 height=21 xoffset=0 yoffset=1 xadvance=15 page=0 chnl=15 68 | char id=93 x=56 y=88 width=9 height=21 xoffset=0 yoffset=1 xadvance=8 page=0 chnl=15 69 | char id=94 x=238 y=88 width=11 height=8 xoffset=0 yoffset=1 xadvance=11 page=0 chnl=15 70 | char id=95 x=42 y=110 width=14 height=5 xoffset=0 yoffset=17 xadvance=14 page=0 chnl=15 71 | char id=96 x=93 y=110 width=7 height=5 xoffset=0 yoffset=1 xadvance=7 page=0 chnl=15 72 | char id=97 x=112 y=22 width=15 height=21 xoffset=0 yoffset=1 xadvance=15 page=0 chnl=15 73 | char id=98 x=15 y=46 width=14 height=21 xoffset=0 yoffset=1 xadvance=13 page=0 chnl=15 74 | char id=99 x=0 y=46 width=14 height=21 xoffset=0 yoffset=1 xadvance=13 page=0 chnl=15 75 | char id=100 x=234 y=22 width=14 height=21 xoffset=0 yoffset=1 xadvance=13 page=0 chnl=15 76 | char id=101 x=203 y=66 width=12 height=21 xoffset=0 yoffset=1 xadvance=12 page=0 chnl=15 77 | char id=102 x=190 y=66 width=12 height=21 xoffset=0 yoffset=1 xadvance=12 page=0 chnl=15 78 | char id=103 x=174 y=22 width=14 height=21 xoffset=0 yoffset=1 xadvance=13 page=0 chnl=15 79 | char id=104 x=159 y=22 width=14 height=21 xoffset=0 yoffset=1 xadvance=13 page=0 chnl=15 80 | char id=105 x=105 y=88 width=7 height=21 xoffset=0 yoffset=1 xadvance=6 page=0 chnl=15 81 | char id=106 x=23 y=90 width=10 height=21 xoffset=0 yoffset=1 xadvance=9 page=0 chnl=15 82 | char id=107 x=144 y=22 width=14 height=21 xoffset=0 yoffset=1 xadvance=13 page=0 chnl=15 83 | char id=108 x=0 y=90 width=11 height=21 xoffset=0 yoffset=1 xadvance=10 page=0 chnl=15 84 | char id=109 x=61 y=0 width=18 height=21 xoffset=0 yoffset=1 xadvance=17 page=0 chnl=15 85 | char id=110 x=45 y=66 width=14 height=21 xoffset=0 yoffset=1 xadvance=13 page=0 chnl=15 86 | char id=111 x=60 y=66 width=14 height=21 xoffset=0 yoffset=1 xadvance=13 page=0 chnl=15 87 | char id=112 x=75 y=66 width=14 height=21 xoffset=0 yoffset=1 xadvance=13 page=0 chnl=15 88 | char id=113 x=184 y=0 width=16 height=21 xoffset=0 yoffset=1 xadvance=15 page=0 chnl=15 89 | char id=114 x=90 y=66 width=14 height=21 xoffset=0 yoffset=1 xadvance=13 page=0 chnl=15 90 | char id=115 x=150 y=44 width=14 height=21 xoffset=0 yoffset=1 xadvance=13 page=0 chnl=15 91 | char id=116 x=134 y=66 width=13 height=21 xoffset=0 yoffset=1 xadvance=12 page=0 chnl=15 92 | char id=117 x=105 y=66 width=14 height=21 xoffset=0 yoffset=1 xadvance=13 page=0 chnl=15 93 | char id=118 x=0 y=24 width=15 height=21 xoffset=0 yoffset=1 xadvance=15 page=0 chnl=15 94 | char id=119 x=38 y=0 width=22 height=21 xoffset=0 yoffset=1 xadvance=21 page=0 chnl=15 95 | char id=120 x=201 y=0 width=15 height=21 xoffset=0 yoffset=1 xadvance=15 page=0 chnl=15 96 | char id=121 x=16 y=22 width=15 height=21 xoffset=0 yoffset=1 xadvance=15 page=0 chnl=15 97 | char id=122 x=148 y=66 width=13 height=21 xoffset=0 yoffset=1 xadvance=13 page=0 chnl=15 98 | char id=123 x=12 y=90 width=10 height=21 xoffset=-1 yoffset=1 xadvance=9 page=0 chnl=15 99 | char id=124 x=249 y=0 width=6 height=21 xoffset=0 yoffset=1 xadvance=6 page=0 chnl=15 100 | char id=125 x=45 y=88 width=10 height=21 xoffset=0 yoffset=1 xadvance=9 page=0 chnl=15 101 | char id=126 x=32 y=112 width=9 height=6 xoffset=0 yoffset=8 xadvance=9 page=0 chnl=15 102 | char id=160 x=249 y=29 width=3 height=1 xoffset=-1 yoffset=24 xadvance=5 page=0 chnl=15 103 | char id=163 x=48 y=22 width=15 height=21 xoffset=0 yoffset=1 xadvance=14 page=0 chnl=15 104 | char id=165 x=167 y=0 width=16 height=21 xoffset=-1 yoffset=1 xadvance=14 page=0 chnl=15 105 | char id=173 x=67 y=110 width=9 height=5 xoffset=0 yoffset=9 xadvance=9 page=0 chnl=15 106 | char id=180 x=85 y=110 width=7 height=5 xoffset=0 yoffset=1 xadvance=7 page=0 chnl=15 107 | char id=247 x=152 y=88 width=12 height=17 xoffset=0 yoffset=4 xadvance=12 page=0 chnl=15 108 | -------------------------------------------------------------------------------- /romdisk/future_0.tex: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cpasjuste/dreamboot/5f40f46e65032e5e170501a82d8ddf720bf96a95/romdisk/future_0.tex -------------------------------------------------------------------------------- /romdisk/syscalls.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cpasjuste/dreamboot/5f40f46e65032e5e170501a82d8ddf720bf96a95/romdisk/syscalls.bin -------------------------------------------------------------------------------- /src/dc/bmfont.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by cpasjuste on 12/02/2020. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include "bmfont.h" 9 | 10 | int bmf_parse(const char *fntPath, BMFont *bmFont) { 11 | 12 | FILE *fd = fopen(fntPath, "r"); 13 | if (fd == NULL) { 14 | return -1; 15 | } 16 | 17 | char *lineBuf = (char *) malloc(BMF_MAX_PATH); 18 | 19 | /// parse info 20 | if (fgets(lineBuf, BMF_MAX_PATH, fd) == NULL) { 21 | fclose(fd); 22 | free(lineBuf); 23 | return -1; 24 | } 25 | // TODO: fix empty "charset" 26 | if (sscanf(lineBuf, 27 | "info face=\"%[^\"]\" size=%d bold=%d italic=%d charset=\"%[^\"]\" unicode=%d stretchH=%d smooth=%d aa=%d padding=%d,%d,%d,%d spacing=%d,%d outline=%d\n", 28 | &bmFont->info.face, &bmFont->info.size, &bmFont->info.bold, &bmFont->info.italic, &bmFont->info.charset, 29 | &bmFont->info.unicode, &bmFont->info.stretchH, &bmFont->info.smooth, &bmFont->info.aa, 30 | &bmFont->info.padding[0], &bmFont->info.padding[1], &bmFont->info.padding[2], &bmFont->info.padding[3], 31 | &bmFont->info.spacing[0], &bmFont->info.spacing[1], &bmFont->info.outline) != 16) { 32 | fclose(fd); 33 | free(lineBuf); 34 | printf("sscanf failed on info\n"); 35 | return -1; 36 | } 37 | 38 | /// parse common 39 | if (fgets(lineBuf, BMF_MAX_PATH, fd) == NULL) { 40 | fclose(fd); 41 | free(lineBuf); 42 | return -1; 43 | } 44 | if (sscanf(lineBuf, 45 | "common lineHeight=%d base=%d scaleW=%d scaleH=%d pages=%d packed=%d alphaChnl=%d redChnl=%d greenChnl=%d blueChnl=%d\n", 46 | &bmFont->common.lineHeight, &bmFont->common.base, 47 | &bmFont->common.scaleW, &bmFont->common.scaleH, 48 | &bmFont->common.pages, &bmFont->common.packed, 49 | &bmFont->common.alphaChnl, 50 | &bmFont->common.redChnl, &bmFont->common.greenChnl, &bmFont->common.blueChnl) != 10) { 51 | fclose(fd); 52 | free(lineBuf); 53 | printf("sscanf failed on common\n"); 54 | return -1; 55 | } 56 | 57 | /// parse page 58 | if (fgets(lineBuf, BMF_MAX_PATH, fd) == NULL) { 59 | fclose(fd); 60 | free(lineBuf); 61 | return -1; 62 | } 63 | if (sscanf(lineBuf, "page id=%d file=\"%[^\"]\"\n", &bmFont->page.id, &bmFont->page.file) != 2) { 64 | fclose(fd); 65 | free(lineBuf); 66 | printf("sscanf failed on page\n"); 67 | return -1; 68 | } 69 | 70 | /// parse chars count 71 | if (fgets(lineBuf, BMF_MAX_PATH, fd) == NULL) { 72 | fclose(fd); 73 | free(lineBuf); 74 | return -1; 75 | } 76 | if (sscanf(lineBuf, "chars count=%d\n", &bmFont->charsCount) != 1) { 77 | fclose(fd); 78 | free(lineBuf); 79 | printf("sscanf failed on chars count\n"); 80 | return -1; 81 | } 82 | 83 | /// parse chars 84 | char str_id[3]; 85 | int id; 86 | 87 | if (bmFont->charsCount > BMF_MAX_CHAR) { 88 | bmFont->charsCount = BMF_MAX_CHAR; 89 | } 90 | 91 | for (int i = 0; i < bmFont->charsCount; i++) { 92 | if (fgets(lineBuf, BMF_MAX_PATH, fd) == NULL) { 93 | fclose(fd); 94 | free(lineBuf); 95 | return -1; 96 | } 97 | // extract for id 98 | char *pos = strchr(lineBuf, '=') + 1; 99 | if (pos == NULL) { 100 | continue; 101 | } 102 | 103 | memset(str_id, 0, 3); 104 | strncpy(str_id, pos, 3); 105 | id = atoi(str_id); 106 | if (id >= BMF_MAX_CHAR) { 107 | continue; 108 | } 109 | 110 | if (sscanf(lineBuf, 111 | "char id=%d x=%d y=%d width=%d height=%d xoffset=%d yoffset=%d xadvance=%d page=%d chnl=%d\n", 112 | &bmFont->chars[id].id, &bmFont->chars[id].x, &bmFont->chars[id].y, 113 | &bmFont->chars[id].width, &bmFont->chars[id].height, 114 | &bmFont->chars[id].xoffset, &bmFont->chars[id].yoffset, &bmFont->chars[id].xadvance, 115 | &bmFont->chars[id].page, &bmFont->chars[id].chnl) != 10) { 116 | fclose(fd); 117 | free(lineBuf); 118 | printf("sscanf failed on char[%i]\n", i); 119 | return -1; 120 | } 121 | } 122 | 123 | fclose(fd); 124 | free(lineBuf); 125 | 126 | return 0; 127 | } 128 | -------------------------------------------------------------------------------- /src/dc/bmfont.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by cpasjuste on 12/02/2020. 3 | // 4 | 5 | #ifndef BMFONTLIB_BMFONT_H 6 | #define BMFONTLIB_BMFONT_H 7 | 8 | #define BMF_MAX_PATH 512 9 | #define BMF_MAX_CHAR 128 10 | 11 | typedef struct bmf_font_info_s { 12 | char face[BMF_MAX_PATH]; 13 | int size; 14 | int bold; 15 | int italic; 16 | char charset[BMF_MAX_PATH]; 17 | int unicode; 18 | int stretchH; 19 | int smooth; 20 | int aa; 21 | int padding[4]; 22 | int spacing[2]; 23 | int outline; 24 | } BMFontInfo; 25 | 26 | typedef struct bmf_font_common_s { 27 | int lineHeight; 28 | int base; 29 | int scaleW; 30 | int scaleH; 31 | int pages; 32 | int packed; 33 | int alphaChnl; 34 | int redChnl; 35 | int greenChnl; 36 | int blueChnl; 37 | } BMFontCommon; 38 | 39 | typedef struct bmf_font_page_s { 40 | int id; 41 | char file[BMF_MAX_PATH]; 42 | 43 | } BMFontPage; 44 | 45 | typedef struct bmf_font_char_s { 46 | int id; 47 | int x; 48 | int y; 49 | int width; 50 | int height; 51 | int xoffset; 52 | int yoffset; 53 | int xadvance; 54 | int page; 55 | int chnl; 56 | } BMFontChar; 57 | 58 | typedef struct bmf_font_kerning_s { 59 | int first; 60 | int second; 61 | int amount; 62 | } BMFontKerning; 63 | 64 | typedef struct bmf_font_s { 65 | BMFontInfo info; 66 | BMFontCommon common; 67 | BMFontPage page; 68 | int charsCount; 69 | BMFontChar chars[BMF_MAX_CHAR]; 70 | //BMFontKerning kernings[4096]; 71 | } BMFont; 72 | 73 | int bmf_parse(const char *fntPath, BMFont *bmFont); 74 | 75 | #endif //BMFONTLIB_BMFONT_H 76 | -------------------------------------------------------------------------------- /src/dc/descramble.c: -------------------------------------------------------------------------------- 1 | /** 2 | * DreamShell boot loader 3 | * Descramble binary 4 | * (c)2011-2016 SWAT 5 | */ 6 | 7 | #include 8 | 9 | #define MAXCHUNK 0x200000 10 | static uint seed; 11 | 12 | static inline void my_srand(uint n) { 13 | seed = n & 0xffff; 14 | } 15 | 16 | static inline uint my_rand(void) { 17 | seed = (seed * 2109 + 9273) & 0x7fff; 18 | return (seed + 0xc000) & 0xffff; 19 | } 20 | 21 | static void load(uint8 *dest, uint32 size) { 22 | 23 | static uint8 *source; 24 | 25 | if (!size) { 26 | source = dest; 27 | return; 28 | } 29 | 30 | memcpy(dest, source, size); 31 | source += size; 32 | } 33 | 34 | static inline void handle_chunk(uint8 *ptr, int sz) { 35 | 36 | int idx[MAXCHUNK / 32]; 37 | int i; 38 | 39 | /* Convert chunk size to number of slices */ 40 | sz /= 32; 41 | 42 | /* Initialize index table with unity, 43 | so that each slice gets loaded exactly once */ 44 | for (i = 0; i < sz; i++) 45 | idx[i] = i; 46 | 47 | for (i = sz - 1; i >= 0; --i) { 48 | /* Select a replacement index */ 49 | int x = (my_rand() * i) >> 16; 50 | 51 | /* Swap */ 52 | int tmp = idx[i]; 53 | idx[i] = idx[x]; 54 | idx[x] = tmp; 55 | 56 | /* Load resulting slice */ 57 | load(ptr + 32 * idx[i], 32); 58 | } 59 | } 60 | 61 | void descramble(uint8 *source, uint8 *dest, uint32 size) { 62 | 63 | load(source, 0); 64 | my_srand(size); 65 | 66 | /* Descramble 2 meg blocks for as long as possible, then 67 | gradually reduce the window down to 32 bytes (1 slice) */ 68 | for (uint32 chunksz = MAXCHUNK; chunksz >= 32; chunksz >>= 1) { 69 | while (size >= chunksz) { 70 | handle_chunk(dest, chunksz); 71 | size -= chunksz; 72 | dest += chunksz; 73 | } 74 | } 75 | 76 | /* !!! Load final incomplete slice */ 77 | if (size) 78 | load(dest, size); 79 | } 80 | 81 | -------------------------------------------------------------------------------- /src/dc/drawing.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by cpasjuste on 28/01/2020. 3 | // 4 | 5 | #include 6 | #include "retrodream.h" 7 | #include "drawing.h" 8 | #include "bmfont.h" 9 | 10 | static BMFont bmf_font; 11 | static pvr_ptr_t bmf_tex = NULL; 12 | 13 | pvr_init_params_t params = { 14 | {PVR_BINSIZE_16, PVR_BINSIZE_0, PVR_BINSIZE_32, PVR_BINSIZE_0, PVR_BINSIZE_0}, 15 | 512 * 1024 16 | }; 17 | 18 | typedef struct { 19 | char id[4]; 20 | short width; 21 | short height; 22 | int type; 23 | int size; 24 | } tex_header_t; 25 | 26 | static void draw_init_font() { 27 | 28 | FILE *fp; 29 | tex_header_t hdr; 30 | 31 | // parse BMFont font information 32 | if (bmf_parse(ROMDISK_PATH"/future.fnt", &bmf_font) != 0) { 33 | return; 34 | } 35 | 36 | // load "texconv" texture 37 | fp = fopen(ROMDISK_PATH"/future_0.tex", "r"); 38 | if (fp == NULL) { 39 | return; 40 | } 41 | // read "texconv" texture header 42 | fread(&hdr, sizeof(hdr), 1, fp); 43 | // allocate pvr mem 44 | bmf_tex = pvr_mem_malloc(hdr.size); 45 | // read "texconv" texture to pvr mem 46 | fread(bmf_tex, hdr.size, 1, fp); 47 | 48 | // all done 49 | fclose(fp); 50 | } 51 | 52 | static void draw_char(float x1, float y1, float z1, Color color, BMFontChar *c) { 53 | 54 | pvr_vertex_t vert; 55 | 56 | vert.flags = PVR_CMD_VERTEX; 57 | vert.x = x1 + (float) c->xoffset; 58 | vert.y = y1 + (float) c->height + (float) c->yoffset; 59 | vert.z = z1; 60 | vert.u = (float) c->x / (float) bmf_font.common.scaleW; 61 | vert.v = (float) (c->y + c->height) / (float) bmf_font.common.scaleH; 62 | vert.argb = DRAW_PACK_COLOR(color.a, color.r, color.g, color.b); 63 | vert.oargb = 0; 64 | pvr_prim(&vert, sizeof(vert)); 65 | 66 | vert.x = x1 + (float) c->xoffset; 67 | vert.y = y1 + (float) c->yoffset; 68 | vert.u = (float) c->x / (float) bmf_font.common.scaleW; 69 | vert.v = (float) c->y / (float) bmf_font.common.scaleH; 70 | pvr_prim(&vert, sizeof(vert)); 71 | 72 | vert.x = x1 + (float) (c->width + c->xoffset); 73 | vert.y = y1 + (float) (c->height + c->yoffset); 74 | vert.u = (float) (c->x + c->width) / (float) bmf_font.common.scaleW; 75 | vert.v = (float) (c->y + c->height) / (float) bmf_font.common.scaleH; 76 | pvr_prim(&vert, sizeof(vert)); 77 | 78 | vert.flags = PVR_CMD_VERTEX_EOL; 79 | vert.x = x1 + (float) (c->width + c->xoffset); 80 | vert.y = y1 + (float) c->yoffset; 81 | vert.u = (float) (c->x + c->width) / (float) bmf_font.common.scaleW; 82 | vert.v = (float) c->y / (float) bmf_font.common.scaleH; 83 | pvr_prim(&vert, sizeof(vert)); 84 | } 85 | 86 | /* draw len chars at string */ 87 | void draw_string(float x, float y, float z, Color color, char *str) { 88 | 89 | int i, len; 90 | pvr_poly_cxt_t cxt; 91 | pvr_poly_hdr_t poly; 92 | 93 | pvr_poly_cxt_txr(&cxt, PVR_LIST_TR_POLY, PVR_TXRFMT_ARGB1555 | PVR_TXRFMT_VQ_ENABLE, 94 | 256, 256, bmf_tex, PVR_FILTER_NONE); 95 | pvr_poly_compile(&poly, &cxt); 96 | pvr_prim(&poly, sizeof(poly)); 97 | 98 | len = strlen(str); 99 | for (i = 0; i < len; i++) { 100 | char c = str[i]; 101 | if (!(c > 31 && c < 127)) { 102 | continue; 103 | } 104 | BMFontChar bmfChar = bmf_font.chars[(int) c]; 105 | draw_char(x, y, z, color, &bmfChar); 106 | x += (float) (bmfChar.xadvance + bmfChar.xoffset); 107 | } 108 | } 109 | 110 | /* draw a box (used by cursor and border, etc) (at 1.0f z coord) */ 111 | void draw_box(float x, float y, float w, float h, float z, Color color) { 112 | pvr_poly_cxt_t cxt; 113 | pvr_poly_hdr_t poly; 114 | pvr_vertex_t vert; 115 | 116 | pvr_poly_cxt_col(&cxt, PVR_LIST_TR_POLY); 117 | pvr_poly_compile(&poly, &cxt); 118 | pvr_prim(&poly, sizeof(poly)); 119 | 120 | vert.flags = PVR_CMD_VERTEX; 121 | vert.x = x; 122 | vert.y = y + h; 123 | vert.z = z; 124 | vert.u = vert.v = 0.0f; 125 | vert.argb = DRAW_PACK_COLOR(color.a, color.r, color.g, color.b); 126 | vert.oargb = 0; 127 | pvr_prim(&vert, sizeof(vert)); 128 | 129 | vert.y -= h; 130 | pvr_prim(&vert, sizeof(vert)); 131 | 132 | vert.y += h; 133 | vert.x += w; 134 | pvr_prim(&vert, sizeof(vert)); 135 | 136 | vert.flags = PVR_CMD_VERTEX_EOL; 137 | vert.y -= h; 138 | pvr_prim(&vert, sizeof(vert)); 139 | } 140 | 141 | void draw_box_outline(float x, float y, float w, float h, float z, Color color, 142 | Color outline_color, float outline_size) { 143 | 144 | draw_box(x - outline_size, y - outline_size, w + (outline_size * 2), h + (outline_size * 2), z - 1, outline_color); 145 | draw_box(x, y, w, h, z, color); 146 | } 147 | 148 | void draw_init() { 149 | pvr_init(¶ms); 150 | draw_init_font(); 151 | } 152 | 153 | void draw_exit() { 154 | if (bmf_tex != NULL) { 155 | pvr_mem_free(bmf_tex); 156 | } 157 | } 158 | 159 | void draw_start() { 160 | pvr_wait_ready(); 161 | pvr_scene_begin(); 162 | pvr_list_begin(PVR_LIST_TR_POLY); 163 | } 164 | 165 | void draw_end() { 166 | pvr_list_finish(); 167 | pvr_scene_finish(); 168 | } 169 | 170 | Vec2 draw_get_screen_size() { 171 | return (Vec2) {640, 480}; 172 | } 173 | 174 | int draw_printf(int level, const char *fmt, ...) { 175 | 176 | if (bmf_tex == NULL) { 177 | return 0; 178 | } 179 | 180 | char buff[512]; 181 | va_list args; 182 | Color color = COL_WHITE; 183 | Vec2 screenSize = draw_get_screen_size(); 184 | 185 | memset(buff, 0, 512); 186 | va_start(args, fmt); 187 | int ret = vsnprintf(buff, 512, fmt, args); 188 | va_end(args); 189 | 190 | switch (level) { 191 | case DBG_DEAD: 192 | case DBG_ERROR: 193 | case DBG_CRITICAL: 194 | color = COL_RED; 195 | break; 196 | case DBG_WARNING: 197 | color = COL_YELLOW; 198 | default: 199 | break; 200 | } 201 | 202 | draw_start(); 203 | draw_string(16, screenSize.y - DRAW_FONT_HEIGHT - 16, 200, color, buff); 204 | draw_end(); 205 | 206 | return ret; 207 | } 208 | -------------------------------------------------------------------------------- /src/dc/dreamfs.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by cpasjuste on 11/02/2020. 3 | // 4 | 5 | #if 0 6 | #ifdef __DREAMCAST__ 7 | 8 | #include 9 | #include 10 | #include 11 | #include "dreamfs.h" 12 | 13 | static Device devices[2] = { 14 | (Device) {"/sd", Sd, 0, -1, -1}, 15 | (Device) {"/ide", Ide, 0, -1, -1} 16 | }; 17 | 18 | void dream_fs_init() { 19 | 20 | fs_ext2_init(); 21 | fs_fat_init(); 22 | 23 | devices[Sd].inited = sd_init(); 24 | dream_fs_mount(Sd); 25 | 26 | devices[Ide].inited = g1_ata_init(); 27 | dream_fs_mount(Ide); 28 | } 29 | 30 | int dream_fs_mount(int dev) { 31 | 32 | kos_blockdev_t deviceBlock; 33 | uint8 deviceType; 34 | 35 | Device *device = &devices[dev]; 36 | if (device->inited != 0) { 37 | return -1; 38 | } 39 | 40 | if (dev == Sd) { 41 | if (sd_blockdev_for_partition(0, &deviceBlock, &deviceType) != 0) { 42 | return -1; 43 | } 44 | } else { 45 | if (g1_ata_blockdev_for_partition(0, 1, &deviceBlock, &deviceType) != 0) { 46 | if (g1_ata_blockdev_for_partition(0, 0, &deviceBlock, &deviceType) != 0) { 47 | return -1; 48 | } 49 | } 50 | } 51 | 52 | if (deviceType == 0x83) { 53 | if (fs_ext2_mount(device->path, &deviceBlock, FS_EXT2_MOUNT_READONLY) != 0) { 54 | return -1; 55 | } 56 | device->format = Ext2; 57 | } else if (deviceType == 0x04 || deviceType == 0x06 || deviceType == 0x0B || deviceType == 0x0C) { 58 | if (fs_fat_mount(device->path, &deviceBlock, FS_FAT_MOUNT_READONLY) != 0) { 59 | return -1; 60 | } 61 | device->format = Fat; 62 | } 63 | 64 | device->mounted = 0; 65 | 66 | return 0; 67 | } 68 | 69 | void dream_fs_unmount(int dev) { 70 | 71 | Device *device = &devices[dev]; 72 | if (device->inited == 0 && device->mounted == 0) { 73 | if (device->format == Ext2) { 74 | fs_ext2_sync(device->path); 75 | fs_ext2_unmount(device->path); 76 | } else { 77 | fs_fat_sync(device->path); 78 | fs_fat_unmount(device->path); 79 | } 80 | device->mounted = -1; 81 | } 82 | } 83 | 84 | void dream_fs_exit() { 85 | 86 | if (devices[Sd].inited == 0) { 87 | dream_fs_unmount(Sd); 88 | sd_shutdown(); 89 | } 90 | 91 | if (devices[Ide].inited == 0) { 92 | dream_fs_unmount(Ide); 93 | g1_ata_shutdown(); 94 | } 95 | 96 | fs_fat_shutdown(); 97 | fs_ext2_shutdown(); 98 | } 99 | 100 | #endif 101 | #endif 102 | -------------------------------------------------------------------------------- /src/dc/input.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by cpasjuste on 03/02/2020. 3 | // 4 | 5 | #include 6 | 7 | static uint32 last_buttons = 0; 8 | 9 | uint32 get_input() { 10 | 11 | maple_device_t *cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER); 12 | if (cont == NULL) { 13 | return 0; 14 | } 15 | 16 | cont_state_t *state = (cont_state_t *) maple_dev_status(cont); 17 | if (state == NULL) { 18 | return 0; 19 | } 20 | 21 | if (last_buttons != state->buttons) { 22 | last_buttons = state->buttons; 23 | return state->buttons; 24 | } 25 | 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /src/dc/utility.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by cpasjuste on 28/01/2020. 3 | // 4 | 5 | #include "uthash/utlist.h" 6 | #include "retrodream.h" 7 | #include "drawing.h" 8 | #include "utility.h" 9 | #include "fs.h" 10 | 11 | KOS_INIT_FLAGS(INIT_DEFAULT); 12 | extern uint8 romdisk[]; 13 | KOS_INIT_ROMDISK(romdisk); 14 | 15 | void get_dir(List *list, const char *path) { 16 | 17 | dirent_t *ent; 18 | file_t fd; 19 | ListItem *entry; 20 | 21 | memset(list, 0, sizeof(List)); 22 | strncpy(list->path, path, MAX_PATH - 1); 23 | 24 | if ((fd = fs_open(path, O_RDONLY | O_DIR)) != FILEHND_INVALID) { 25 | while ((ent = fs_readdir(fd)) != NULL) { 26 | 27 | // skip "." 28 | if (ent->name[0] == '.') { 29 | continue; 30 | } 31 | 32 | if (strncmp(ent->name, "pty", 3) == 0 || strncmp(ent->name, "ram", 3) == 0 33 | || strncmp(ent->name, "pc", 2) == 0 || strncmp(ent->name, "cd", 2) == 0) { 34 | continue; 35 | } 36 | 37 | entry = (ListItem *) malloc(sizeof(ListItem)); 38 | memset(entry, 0, sizeof(ListItem)); 39 | 40 | strncpy(entry->name, ent->name, MAX_PATH - 1); 41 | if (list->path[strlen(list->path) - 1] != '/') { 42 | snprintf(entry->path, MAX_PATH - 1, "%s/%s", list->path, ent->name); 43 | } else { 44 | snprintf(entry->path, MAX_PATH - 1, "%s%s", list->path, ent->name); 45 | } 46 | 47 | entry->type = ent->attr == O_DIR ? TYPE_DIR : TYPE_FILE; 48 | if (entry->type == TYPE_FILE) { 49 | if (strstr(entry->name, ".bin") != NULL || strstr(entry->name, ".BIN") != NULL || 50 | strstr(entry->name, ".elf") != NULL || strstr(entry->name, ".ELF") != NULL) { 51 | entry->type = TYPE_BIN; 52 | } 53 | } 54 | 55 | DL_APPEND(list->head, entry); 56 | list->size++; 57 | } 58 | 59 | DL_SORT(list->head, list_cmp); 60 | fs_close(fd); 61 | } 62 | } 63 | 64 | int file_exists(const char *fn) { 65 | file_t f; 66 | 67 | f = fs_open(fn, O_RDONLY); 68 | 69 | if (f == FILEHND_INVALID) { 70 | return 0; 71 | } 72 | 73 | fs_close(f); 74 | return 1; 75 | } 76 | 77 | int dir_exists(const char *dir) { 78 | file_t f; 79 | 80 | f = fs_open(dir, O_DIR | O_RDONLY); 81 | 82 | if (f == FILEHND_INVALID) { 83 | return 0; 84 | } 85 | 86 | fs_close(f); 87 | return 1; 88 | } 89 | 90 | char *read_file(const char *file, int *size) { 91 | 92 | file_t fd; 93 | ssize_t fsize; 94 | char *buffer = NULL; 95 | 96 | fd = fs_open(file, O_RDONLY); 97 | if (fd == FILEHND_INVALID) { 98 | printf("read_file: can't open %s\n", file); 99 | if (size != NULL) { 100 | *size = 0; 101 | } 102 | return NULL; 103 | } 104 | 105 | fsize = fs_total(fd); 106 | buffer = (char *) malloc(fsize); 107 | memset(buffer, 0, fsize); 108 | 109 | if (fs_read(fd, buffer, fsize) != fsize) { 110 | fs_close(fd); 111 | free(buffer); 112 | printf("read_file: can't read %s\n", file); 113 | if (size != NULL) { 114 | *size = 0; 115 | } 116 | return NULL; 117 | } 118 | 119 | fs_close(fd); 120 | 121 | if (size != NULL) { 122 | *size = fsize; 123 | } 124 | 125 | return buffer; 126 | } 127 | 128 | int flash_get_region() { 129 | 130 | int start, size; 131 | uint8 region[6] = {0}; 132 | region[2] = *(uint8 *) 0x0021A002; 133 | 134 | /* Find the partition */ 135 | if (flashrom_info(FLASHROM_PT_SYSTEM, &start, &size) < 0) { 136 | dbglog(DBG_ERROR, "%s: can't find partition %d\n", __func__, FLASHROM_PT_SYSTEM); 137 | } else { 138 | /* Read the first 5 characters of that partition */ 139 | if (flashrom_read(start, region, 5) < 0) { 140 | dbglog(DBG_ERROR, "%s: can't read partition %d\n", __func__, FLASHROM_PT_SYSTEM); 141 | } 142 | } 143 | 144 | if (region[2] == 0x58 || region[2] == 0x30) { 145 | return FLASHROM_REGION_JAPAN; 146 | } else if (region[2] == 0x59 || region[2] == 0x31) { 147 | return FLASHROM_REGION_US; 148 | } else if (region[2] == 0x5A || region[2] == 0x32) { 149 | return FLASHROM_REGION_EUROPE; 150 | } else { 151 | dbglog(DBG_ERROR, "%s: Unknown region code %02x\n", __func__, region[2]); 152 | return FLASHROM_REGION_UNKNOWN; 153 | } 154 | } 155 | 156 | int is_hacked_bios() { 157 | return (*(uint16 *) 0xa0000000) == 0xe6ff; 158 | } 159 | 160 | int is_custom_bios() { 161 | return (*(uint16 *) 0xa0000004) == 0x4318; 162 | } 163 | 164 | int is_no_syscalls() { 165 | return (*(uint16 *) 0xac000100) != 0x2f06; 166 | } 167 | 168 | int setup_syscalls() { 169 | 170 | file_t fd; 171 | size_t fd_size; 172 | int (*sc)(int, int, int, int); 173 | 174 | dbglog(DBG_INFO, "Loading and setup syscalls...\n"); 175 | fd = fs_open(ROMDISK_PATH"/syscalls.bin", O_RDONLY); 176 | 177 | if (fd != FILEHND_INVALID) { 178 | 179 | fd_size = fs_total(fd); 180 | dbgio_dev_select("null"); 181 | dcache_flush_range(0x8c000000, fd_size); 182 | icache_flush_range(0x8c000000, fd_size); 183 | 184 | if (fs_read(fd, (uint8 *) 0x8c000000, fd_size) < 0) { 185 | fs_close(fd); 186 | //dbgio_dev_select("fb"); 187 | dbglog(DBG_ERROR, "Error at loading syscalls\n"); 188 | return -1; 189 | 190 | } else { 191 | fs_close(fd); 192 | dcache_flush_range(0x8c000000, fd_size); 193 | icache_flush_range(0x8c000000, fd_size); 194 | //dbgio_dev_select("fb"); 195 | *((uint32 *) &sc) = *((uint32 *) 0x8c0000b0); 196 | if (sc(0, 0, 0, 0)) { 197 | dbglog(DBG_ERROR, "Error in sysinfo syscall\n"); 198 | return -1; 199 | } 200 | dbglog(DBG_INFO, "Syscalls successfully installed\n"); 201 | return 0; 202 | } 203 | } else { 204 | dbglog(DBG_ERROR, "Can't open file with syscalls\n"); 205 | } 206 | 207 | return -1; 208 | } 209 | 210 | void exec(const char *path) { 211 | 212 | draw_printf(DBG_INFO, "LOADING: %s\n", path); 213 | 214 | int size = 0; 215 | char *bin = read_file(path, &size); 216 | if (bin == NULL || size < 1) { 217 | retro_log(DBG_ERROR, "EXEC: COULD NOT READ %s\n", path); 218 | return; 219 | } 220 | 221 | arch_exec(bin, size); 222 | } 223 | 224 | void dc_load_serial(void) { 225 | 226 | exec(ROMDISK_PATH"/dcload-serial.bin"); 227 | } 228 | 229 | void dc_load_ip(void) { 230 | 231 | exec(ROMDISK_PATH"/dcload-ip.bin"); 232 | } 233 | 234 | void loader_init() { 235 | 236 | if (is_custom_bios()) { 237 | setup_syscalls(); 238 | } 239 | 240 | #ifndef __DEBUG_EMU__ 241 | InitIDE(); 242 | InitSDCard(); 243 | #endif 244 | } 245 | -------------------------------------------------------------------------------- /src/drawing.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by cpasjuste on 28/01/2020. 3 | // 4 | 5 | #ifndef LOADER_DRAWING_H 6 | #define LOADER_DRAWING_H 7 | 8 | #define DRAW_FONT_WIDTH 12.0f 9 | #define DRAW_FONT_HEIGHT 24.0f 10 | #define DRAW_FONT_LINE_SPACING 4.0f 11 | 12 | #define DRAW_PACK_COLOR(a, r, g, b) ( \ 13 | a << 24 | \ 14 | r << 16 | \ 15 | g << 8 | \ 16 | b << 0 ) 17 | 18 | typedef struct color_t { 19 | uint8 r; 20 | uint8 g; 21 | uint8 b; 22 | uint8 a; 23 | } Color; 24 | 25 | typedef struct rect_t { 26 | float left; 27 | float top; 28 | float width; 29 | float height; 30 | } Rect; 31 | 32 | typedef struct vec2_t { 33 | float x; 34 | float y; 35 | } Vec2; 36 | 37 | #define COL_WHITE (Color) {255, 255, 255, 255} 38 | #define COL_BLUE (Color) {54, 70, 93, 255} 39 | #define COL_RED (Color) {255, 81, 72, 255} 40 | #define COL_BLUE_LIGHT (Color) {178, 226, 249, 255} 41 | #define COL_YELLOW (Color) {240, 226, 107, 255} 42 | 43 | void draw_init(); 44 | 45 | void draw_exit(); 46 | 47 | void draw_start(); 48 | 49 | void draw_end(); 50 | 51 | void draw_string(float x, float y, float z, Color color, char *str); 52 | 53 | void draw_box(float x, float y, float w, float h, float z, Color color); 54 | 55 | void draw_box_outline(float x, float y, float w, float h, float z, 56 | Color color, Color outline_color, float outline_size); 57 | 58 | int draw_printf(int level, const char *fmt, ...); 59 | 60 | Vec2 draw_get_screen_size(); 61 | 62 | #endif //LOADER_DRAWING_H 63 | -------------------------------------------------------------------------------- /src/dreamfs.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by cpasjuste on 11/02/2020. 3 | // 4 | 5 | #ifndef DREAMBOOT_DREAMFS_H 6 | #define DREAMBOOT_DREAMFS_H 7 | 8 | #ifdef __DREAMCAST__ 9 | 10 | enum DeviceType { 11 | Sd = 0, 12 | Ide = 1 13 | }; 14 | 15 | enum DeviceFormat { 16 | Fat = 0, 17 | Ext2 = 1 18 | }; 19 | 20 | typedef struct device_t { 21 | char path[16]; 22 | int type; 23 | int format; 24 | int inited; 25 | int mounted; 26 | } Device; 27 | 28 | int dream_fs_mount(int dev); 29 | 30 | void dream_fs_unmount(int dev); 31 | 32 | #endif 33 | 34 | void dream_fs_init(); 35 | 36 | void dream_fs_exit(); 37 | 38 | #endif //DREAMBOOT_DREAMFS_H 39 | -------------------------------------------------------------------------------- /src/ds/include/drivers/g1_ide.h: -------------------------------------------------------------------------------- 1 | /* DreamShell ##version## 2 | 3 | drivers/g1_ide.h 4 | Copyright (C) 2013-2014 SWAT 5 | 6 | Additional functions for G1-ATA devices 7 | */ 8 | 9 | #ifndef __G1_IDE_H 10 | #define __G1_IDE_H 11 | 12 | #include 13 | __BEGIN_DECLS 14 | 15 | #include 16 | 17 | 18 | /** \brief Retrieve the size of the ATA device. 19 | 20 | \return On succes, max LBA 21 | error, (uint64)-1. 22 | */ 23 | uint64_t g1_ata_max_lba(void); 24 | 25 | 26 | /** \brief Send ATA device to standby mode. 27 | 28 | \retval 0 On success. 29 | \retval -1 On error 30 | */ 31 | int g1_ata_standby(void); 32 | 33 | 34 | /** \brief Checking for DCIO board. 35 | 36 | \retval 1 Is DCIO board 37 | \retval 0 Is NOT 38 | \retval -1 On error 39 | */ 40 | int g1_ata_is_dcio(void); 41 | 42 | 43 | __END_DECLS 44 | #endif /* !__G1_IDE_H */ 45 | -------------------------------------------------------------------------------- /src/ds/include/drivers/rtc.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file rtc.h 3 | * \brief Real time clock 4 | * \date 2015-2016 5 | * \author SWAT www.dc-swat.ru 6 | */ 7 | 8 | #ifndef _DS_RTC_H 9 | #define _DS_RTC_H 10 | 11 | #include 12 | __BEGIN_DECLS 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | /** 19 | * Grabs the current RTC seconds counter and adjusts it to the Unix Epoch. 20 | * 21 | * Return: 22 | * On SUCCESS UNIX Time Stamp 23 | * On ERROR -1 24 | */ 25 | time_t rtc_gettime(); 26 | 27 | /** 28 | * Adjusts the given time value to the AICA Epoch and sets the RTC seconds counter. 29 | * 30 | * Return: 31 | * On SUCCESS 0 32 | * On ERROR -1 33 | */ 34 | int rtc_settime(time_t time); 35 | 36 | /** 37 | * Grabs the current RTC seconds counter and write to struct tm. 38 | * 39 | * Return: 40 | * On SUCCESS 0 41 | * On ERROR -1 42 | */ 43 | int rtc_gettimeutc(struct tm *time); 44 | 45 | /** 46 | * Adjusts the given time value from struct tm to the AICA Epoch and sets the RTC seconds counter. 47 | * 48 | * Return: 49 | * On SUCCESS 0 50 | * On ERROR -1 51 | */ 52 | int rtc_settimeutc(const struct tm *time); 53 | 54 | /** 55 | * Grabs the current RTC seconds counter and write to struct timeval. 56 | */ 57 | void rtc_gettimeofday(struct timeval *tv); 58 | 59 | /** 60 | * Adjusts the given time value from struct timeval to the AICA Epoch and sets the RTC seconds counter. 61 | * 62 | * Return: 63 | * On SUCCESS 0 64 | * On ERROR -1 65 | */ 66 | int rtc_settimeofday(const struct timeval *tv); 67 | 68 | 69 | __END_DECLS 70 | #endif /* _DS_RTC_H */ 71 | -------------------------------------------------------------------------------- /src/ds/include/drivers/sd.h: -------------------------------------------------------------------------------- 1 | /* DreamShell ##version## 2 | 3 | drivers/sd.h 4 | Copyright (C) 2014 SWAT 5 | */ 6 | 7 | #ifndef _SD_H 8 | #define _SD_H 9 | 10 | #include 11 | __BEGIN_DECLS 12 | 13 | #include 14 | #include 15 | 16 | /** 17 | * \file 18 | * SD driver for Sega Dreamcast 19 | * Doxygen comments by Lawrence Sebald 20 | * 21 | * \author SWAT 22 | */ 23 | 24 | /** \brief Initialize the SD card for use. 25 | 26 | This function initializes the SD card for first use. This includes all steps 27 | of the basic initialization sequence for SPI mode, as documented in the SD 28 | card spec and at http://elm-chan.org/docs/mmc/mmc_e.html . This also will 29 | call scif_sd_init() for you, so you don't have to worry about that ahead of 30 | time. 31 | 32 | \retval 0 On success. 33 | \retval -1 On failure. This could indicate any number of 34 | problems, but probably means that no SD card was 35 | detected. 36 | */ 37 | int sdc_init(void); 38 | 39 | /** \brief Shut down SD card support. 40 | 41 | This function shuts down SD card support, and cleans up anything that the 42 | sd_init() function set up. 43 | 44 | \retval 0 On success. 45 | \retval -1 On failure. The only currently defined error is if 46 | the card was never initialized to start with. 47 | */ 48 | int sdc_shutdown(void); 49 | 50 | /** \brief Read one or more blocks from the SD card. 51 | 52 | This function reads the specified number of blocks from the SD card from the 53 | beginning block specified into the buffer passed in. It is your 54 | responsibility to allocate the buffer properly for the number of bytes that 55 | is to be read (512 * the number of blocks requested). 56 | 57 | \param block The starting block number to read from. 58 | \param count The number of 512 byte blocks of data to read. 59 | \param buf The buffer to read into. 60 | \retval 0 On success. 61 | \retval -1 On error, errno will be set as appropriate. 62 | 63 | \par Error Conditions: 64 | \em EIO - an I/O error occurred in reading data \n 65 | \em ENXIO - SD card support was not initialized 66 | */ 67 | int sdc_read_blocks(uint32 block, size_t count, uint8 *buf); 68 | 69 | /** \brief Write one or more blocks to the SD card. 70 | 71 | This function writes the specified number of blocks to the SD card at the 72 | beginning block specified from the buffer passed in. Each block is 512 bytes 73 | in length, and you must write at least one block at a time. You cannot write 74 | partial blocks. 75 | 76 | If this function returns an error, you have quite possibly corrupted 77 | something on the card or have a damaged card in general (unless errno is 78 | ENXIO). 79 | 80 | \param block The starting block number to write to. 81 | \param count The number of 512 byte blocks of data to write. 82 | \param buf The buffer to write from. 83 | \retval 0 On success. 84 | \retval -1 On error, errno will be set as appropriate. 85 | 86 | \par Error Conditions: 87 | \em EIO - an I/O error occurred in reading data \n 88 | \em ENXIO - SD card support was not initialized 89 | */ 90 | int sdc_write_blocks(uint32 block, size_t count, const uint8 *buf); 91 | 92 | /** \brief Retrieve the size of the SD card. 93 | 94 | This function reads the size of the SD card from the card's CSD register. 95 | This is the raw size of the card, not its formatted capacity. To get the 96 | number of blocks from this, divide by 512. 97 | 98 | \return On succes, the raw size of the SD card in bytes. On 99 | error, (uint64)-1. 100 | 101 | \par Error Conditions: 102 | \em EIO - an I/O error occurred in reading data \n 103 | \em ENXIO - SD card support was not initialized 104 | */ 105 | uint64 sdc_get_size(void); 106 | 107 | /** \brief Print identification data of the SD card. 108 | 109 | This function reads the manufacturer info of the SD card from the card's CID register. 110 | 111 | \retval 0 On success. 112 | \retval -1 On error, errno will be set as appropriate. 113 | 114 | \par Error Conditions: 115 | \em EIO - an I/O error occurred in reading data \n 116 | \em ENXIO - SD card support was not initialized 117 | */ 118 | int sdc_print_ident(void); 119 | 120 | /** \brief Get a block device for a given partition on the SD card. 121 | 122 | This function creates a block device descriptor for the given partition on 123 | the attached SD card. This block device is used to interface with various 124 | filesystems on the device. 125 | 126 | \param partition The partition number (0-3) to use. 127 | \param rv Used to return the block device. Must be non-NULL. 128 | \param partition_type Used to return the partition type. Must be non-NULL. 129 | \retval 0 On success. 130 | \retval -1 On error, errno will be set as appropriate. 131 | 132 | \par Error Conditions: 133 | \em ENXIO - SD card support was not initialized \n 134 | \em EIO - an I/O error occurred in reading data \n 135 | \em EINVAL - invalid partition number was given \n 136 | \em EFAULT - rv or partition_type was NULL \n 137 | \em ENOENT - no MBR found \n 138 | \em ENOENT - no partition at the specified position \n 139 | \em ENOMEM - out of memory 140 | 141 | \note This interface currently only supports MBR-formatted SD cards. There 142 | is currently no support for GPT partition tables. 143 | */ 144 | int sdc_blockdev_for_partition(int partition, kos_blockdev_t *rv, 145 | uint8 *partition_type); 146 | 147 | __END_DECLS 148 | 149 | #endif /* _SD_H */ 150 | -------------------------------------------------------------------------------- /src/ds/include/drivers/spi.h: -------------------------------------------------------------------------------- 1 | /* DreamShell ##version## 2 | 3 | drivers/spi.h 4 | Copyright (C) 2011-2014 SWAT 5 | */ 6 | 7 | #ifndef _SPI_H 8 | #define _SPI_H 9 | 10 | #include 11 | 12 | /** 13 | * \file 14 | * SPI interface for Sega Dreamcast SCIF 15 | * 16 | * \author SWAT 17 | */ 18 | 19 | 20 | /** 21 | * \brief Max speed delay 22 | */ 23 | #define SPI_DEFAULT_DELAY -1 24 | 25 | /** 26 | * \brief Some predefined delays 27 | */ 28 | #define SPI_SDC_MMC_DELAY SPI_DEFAULT_DELAY 29 | #define SPI_ENC28J60_DELAY 1000000 30 | 31 | 32 | /** 33 | * \brief Chip select pins 34 | */ 35 | #define SPI_CS_SCIF_RTS 10 36 | #define SPI_CS_GPIO_VGA 8 // This is a real GPIO index 37 | #define SPI_CS_GPIO_RGB 9 38 | 39 | #define SPI_CS_SDC SPI_CS_SCIF_RTS 40 | #define SPI_CS_ENC28J60 SPI_CS_GPIO_VGA 41 | #define SPI_CS_SDC_2 SPI_CS_GPIO_RGB 42 | 43 | 44 | /** 45 | * \brief Initializes the SPI interface 46 | */ 47 | int spi_init(int use_gpio); 48 | 49 | /** 50 | * \brief Shutdown the SPI interface 51 | */ 52 | int spi_shutdown(); 53 | 54 | /** 55 | * \brief Change the SPI delay for clock 56 | * 57 | * \param[in] The SPI delay 58 | */ 59 | void spi_set_delay(int delay); 60 | 61 | /** 62 | * \brief Getting current SPI delay 63 | * 64 | * \returns The SPI delay 65 | */ 66 | int spi_get_delay(); 67 | 68 | /** 69 | * \brief Switch on CS pin and lock SPI bus 70 | * 71 | * \param[in] the CS pin 72 | */ 73 | void spi_cs_on(int cs); 74 | 75 | /** 76 | * \brief Switch off CS pin and unlock SPI bus 77 | * 78 | * \param[in] the CS pin 79 | */ 80 | void spi_cs_off(int cs); 81 | 82 | /** 83 | * \brief Sends a byte over the SPI bus. 84 | * 85 | * \param[in] b The byte to send. 86 | */ 87 | 88 | void spi_send_byte(register uint8 b); 89 | void spi_cc_send_byte(register uint8 b); 90 | 91 | /** 92 | * \brief Receives a byte from the SPI bus. 93 | * 94 | * \returns The received byte. 95 | */ 96 | uint8 spi_rec_byte(); 97 | uint8 spi_cc_rec_byte(); 98 | 99 | /** 100 | * \brief Send and receive a byte to/from the SPI bus. 101 | * 102 | * \param[in] b The byte to send. 103 | * \returns The received byte. 104 | */ 105 | uint8 spi_sr_byte(register uint8 b); 106 | uint8 spi_cc_sr_byte(register uint8 b); 107 | 108 | /** 109 | * \brief Slow send and receive a byte to/from the SPI bus. 110 | * Used for SDC/MMC commands. 111 | * 112 | * \param[in] b The byte to send. 113 | * \returns The received byte. 114 | */ 115 | uint8 spi_slow_sr_byte(register uint8 b); 116 | 117 | /** 118 | * \brief Sends data contained in a buffer over the SPI bus. 119 | * 120 | * \param[in] data A pointer to the buffer which contains the data to send. 121 | * \param[in] len The number of bytes to send. 122 | */ 123 | void spi_send_data(const uint8* data, uint16 data_len); 124 | void spi_cc_send_data(const uint8* data, uint16 data_len); 125 | 126 | /** 127 | * \brief Receives multiple bytes from the SPI bus and writes them to a buffer. 128 | * 129 | * \param[out] buffer A pointer to the buffer into which the data gets written. 130 | * \param[in] len The number of bytes to read. 131 | */ 132 | void spi_rec_data(uint8* buffer, uint16 buffer_len); 133 | void spi_cc_rec_data(uint8* buffer, uint16 buffer_len); 134 | 135 | 136 | #endif /* _SPI_H */ 137 | -------------------------------------------------------------------------------- /src/ds/include/fatfs/diskio.h: -------------------------------------------------------------------------------- 1 | /*-----------------------------------------------------------------------/ 2 | / Low level disk interface modlue include file (C)ChaN, 2014 / 3 | /-----------------------------------------------------------------------*/ 4 | 5 | #ifndef _DISKIO_DEFINED 6 | #define _DISKIO_DEFINED 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | #define _USE_WRITE 1 /* 1: Enable disk_write function */ 13 | #define _USE_IOCTL 1 /* 1: Enable disk_ioctl fucntion */ 14 | 15 | #include "integer.h" 16 | 17 | 18 | /* Status of Disk Functions */ 19 | typedef BYTE DSTATUS; 20 | 21 | /* Results of Disk Functions */ 22 | typedef enum { 23 | RES_OK = 0, /* 0: Successful */ 24 | RES_ERROR, /* 1: R/W Error */ 25 | RES_WRPRT, /* 2: Write Protected */ 26 | RES_NOTRDY, /* 3: Not Ready */ 27 | RES_PARERR /* 4: Invalid Parameter */ 28 | } DRESULT; 29 | 30 | 31 | /*---------------------------------------*/ 32 | /* Prototypes for disk control functions */ 33 | 34 | 35 | DSTATUS disk_initialize (BYTE pdrv); 36 | DSTATUS disk_status (BYTE pdrv); 37 | DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count); 38 | DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count); 39 | DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff); 40 | 41 | 42 | /* Disk Status Bits (DSTATUS) */ 43 | 44 | #define STA_NOINIT 0x01 /* Drive not initialized */ 45 | #define STA_NODISK 0x02 /* No medium in the drive */ 46 | #define STA_PROTECT 0x04 /* Write protected */ 47 | 48 | 49 | /* Command code for disk_ioctrl fucntion */ 50 | 51 | /* Generic command (Used by FatFs) */ 52 | #define CTRL_SYNC 0 /* Complete pending write process (needed at _FS_READONLY == 0) */ 53 | #define GET_SECTOR_COUNT 1 /* Get media size (needed at _USE_MKFS == 1) */ 54 | #define GET_SECTOR_SIZE 2 /* Get sector size (needed at _MAX_SS != _MIN_SS) */ 55 | #define GET_BLOCK_SIZE 3 /* Get erase block size (needed at _USE_MKFS == 1) */ 56 | #define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at _USE_TRIM == 1) */ 57 | 58 | /* Generic command (Not used by FatFs) */ 59 | #define CTRL_POWER 5 /* Get/Set power status */ 60 | #define CTRL_LOCK 6 /* Lock/Unlock media removal */ 61 | #define CTRL_EJECT 7 /* Eject media */ 62 | #define CTRL_FORMAT 8 /* Create physical format on the media */ 63 | 64 | /* MMC/SDC specific ioctl command */ 65 | #define MMC_GET_TYPE 10 /* Get card type */ 66 | #define MMC_GET_CSD 11 /* Get CSD */ 67 | #define MMC_GET_CID 12 /* Get CID */ 68 | #define MMC_GET_OCR 13 /* Get OCR */ 69 | #define MMC_GET_SDSTAT 14 /* Get SD status */ 70 | 71 | /* ATA/CF specific ioctl command */ 72 | #define ATA_GET_REV 20 /* Get F/W revision */ 73 | #define ATA_GET_MODEL 21 /* Get model name */ 74 | #define ATA_GET_SN 22 /* Get serial number */ 75 | 76 | #ifdef __cplusplus 77 | } 78 | #endif 79 | 80 | #endif 81 | -------------------------------------------------------------------------------- /src/ds/include/fatfs/ff.h: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------------/ 2 | / FatFs - FAT file system module include R0.11 (C)ChaN, 2015 3 | /----------------------------------------------------------------------------/ 4 | / FatFs module is a free software that opened under license policy of 5 | / following conditions. 6 | / 7 | / Copyright (C) 2015, ChaN, all right reserved. 8 | / 9 | / 1. Redistributions of source code must retain the above copyright notice, 10 | / this condition and the following disclaimer. 11 | / 12 | / This software is provided by the copyright holder and contributors "AS IS" 13 | / and any warranties related to this software are DISCLAIMED. 14 | / The copyright owner or contributors be NOT LIABLE for any damages caused 15 | / by use of this software. 16 | /---------------------------------------------------------------------------*/ 17 | 18 | 19 | #ifndef _FATFS 20 | #define _FATFS 32020 /* Revision ID */ 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | #include "integer.h" /* Basic integer types */ 27 | #include "ffconf.h" /* FatFs configuration options */ 28 | #if _FATFS != _FFCONF 29 | #error Wrong configuration file (ffconf.h). 30 | #endif 31 | 32 | 33 | 34 | /* Definitions of volume management */ 35 | 36 | #if _MULTI_PARTITION /* Multiple partition configuration */ 37 | typedef struct { 38 | BYTE pd; /* Physical drive number */ 39 | BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */ 40 | } PARTITION; 41 | extern PARTITION VolToPart[]; /* Volume - Partition resolution table */ 42 | #define LD2PD(vol) (VolToPart[vol].pd) /* Get physical drive number */ 43 | #define LD2PT(vol) (VolToPart[vol].pt) /* Get partition index */ 44 | 45 | #else /* Single partition configuration */ 46 | #define LD2PD(vol) (BYTE)(vol) /* Each logical drive is bound to the same physical drive number */ 47 | #define LD2PT(vol) 0 /* Find first valid partition or in SFD */ 48 | 49 | #endif 50 | 51 | 52 | 53 | /* Type of path name strings on FatFs API */ 54 | 55 | #if _LFN_UNICODE /* Unicode string */ 56 | #if !_USE_LFN 57 | #error _LFN_UNICODE must be 0 at non-LFN cfg. 58 | #endif 59 | #ifndef _INC_TCHAR 60 | typedef WCHAR TCHAR; 61 | #define _T(x) L ## x 62 | #define _TEXT(x) L ## x 63 | #endif 64 | 65 | #else /* ANSI/OEM string */ 66 | #ifndef _INC_TCHAR 67 | typedef char TCHAR; 68 | #define _T(x) x 69 | #define _TEXT(x) x 70 | #endif 71 | 72 | #endif 73 | 74 | 75 | 76 | /* File system object structure (FATFS) */ 77 | 78 | typedef struct { 79 | BYTE fs_type; /* FAT sub-type (0:Not mounted) */ 80 | BYTE drv; /* Physical drive number */ 81 | BYTE csize; /* Sectors per cluster (1,2,4...128) */ 82 | BYTE n_fats; /* Number of FAT copies (1 or 2) */ 83 | BYTE wflag; /* win[] flag (b0:dirty) */ 84 | BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */ 85 | WORD id; /* File system mount ID */ 86 | WORD n_rootdir; /* Number of root directory entries (FAT12/16) */ 87 | #if _MAX_SS != _MIN_SS 88 | WORD ssize; /* Bytes per sector (512, 1024, 2048 or 4096) */ 89 | #endif 90 | #if _FS_REENTRANT 91 | _SYNC_t sobj; /* Identifier of sync object */ 92 | #endif 93 | #if !_FS_READONLY 94 | DWORD last_clust; /* Last allocated cluster */ 95 | DWORD free_clust; /* Number of free clusters */ 96 | #endif 97 | #if _FS_RPATH 98 | DWORD cdir; /* Current directory start cluster (0:root) */ 99 | #endif 100 | DWORD n_fatent; /* Number of FAT entries, = number of clusters + 2 */ 101 | DWORD fsize; /* Sectors per FAT */ 102 | DWORD volbase; /* Volume start sector */ 103 | DWORD fatbase; /* FAT start sector */ 104 | DWORD dirbase; /* Root directory start sector (FAT32:Cluster#) */ 105 | DWORD database; /* Data start sector */ 106 | DWORD winsect; /* Current sector appearing in the win[] */ 107 | BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */ 108 | } FATFS; 109 | 110 | 111 | 112 | /* File object structure (FIL) */ 113 | 114 | typedef struct { 115 | FATFS* fs; /* Pointer to the related file system object (**do not change order**) */ 116 | WORD id; /* Owner file system mount ID (**do not change order**) */ 117 | BYTE flag; /* Status flags */ 118 | BYTE err; /* Abort flag (error code) */ 119 | DWORD fptr; /* File read/write pointer (Zeroed on file open) */ 120 | DWORD fsize; /* File size */ 121 | DWORD sclust; /* File start cluster (0:no cluster chain, always 0 when fsize is 0) */ 122 | DWORD clust; /* Current cluster of fpter (not valid when fprt is 0) */ 123 | DWORD dsect; /* Sector number appearing in buf[] (0:invalid) */ 124 | #if !_FS_READONLY 125 | DWORD dir_sect; /* Sector number containing the directory entry */ 126 | BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */ 127 | #endif 128 | #if _USE_FASTSEEK 129 | DWORD* cltbl; /* Pointer to the cluster link map table (Nulled on file open) */ 130 | #endif 131 | #if _FS_LOCK 132 | UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */ 133 | #endif 134 | #if !_FS_TINY 135 | BYTE buf[_MAX_SS]; /* File private data read/write window */ 136 | #endif 137 | } FIL; 138 | 139 | 140 | 141 | /* Directory object structure (DIR) */ 142 | 143 | typedef struct { 144 | FATFS* fs; /* Pointer to the owner file system object (**do not change order**) */ 145 | WORD id; /* Owner file system mount ID (**do not change order**) */ 146 | WORD index; /* Current read/write index number */ 147 | DWORD sclust; /* Table start cluster (0:Root dir) */ 148 | DWORD clust; /* Current cluster */ 149 | DWORD sect; /* Current sector */ 150 | BYTE* dir; /* Pointer to the current SFN entry in the win[] */ 151 | BYTE* fn; /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */ 152 | #if _FS_LOCK 153 | UINT lockid; /* File lock ID (index of file semaphore table Files[]) */ 154 | #endif 155 | #if _USE_LFN 156 | WCHAR* lfn; /* Pointer to the LFN working buffer */ 157 | WORD lfn_idx; /* Last matched LFN index number (0xFFFF:No LFN) */ 158 | #endif 159 | #if _USE_FIND 160 | const TCHAR* pat; /* Pointer to the name matching pattern */ 161 | #endif 162 | } DIR; 163 | 164 | 165 | 166 | /* File information structure (FILINFO) */ 167 | 168 | typedef struct { 169 | DWORD fsize; /* File size */ 170 | WORD fdate; /* Last modified date */ 171 | WORD ftime; /* Last modified time */ 172 | BYTE fattrib; /* Attribute */ 173 | TCHAR fname[13]; /* Short file name (8.3 format) */ 174 | #if _USE_LFN 175 | TCHAR* lfname; /* Pointer to the LFN buffer */ 176 | UINT lfsize; /* Size of LFN buffer in TCHAR */ 177 | #endif 178 | } FILINFO; 179 | 180 | 181 | 182 | /* File function return code (FRESULT) */ 183 | 184 | typedef enum { 185 | FR_OK = 0, /* (0) Succeeded */ 186 | FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */ 187 | FR_INT_ERR, /* (2) Assertion failed */ 188 | FR_NOT_READY, /* (3) The physical drive cannot work */ 189 | FR_NO_FILE, /* (4) Could not find the file */ 190 | FR_NO_PATH, /* (5) Could not find the path */ 191 | FR_INVALID_NAME, /* (6) The path name format is invalid */ 192 | FR_DENIED, /* (7) Access denied due to prohibited access or directory full */ 193 | FR_EXIST, /* (8) Access denied due to prohibited access */ 194 | FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */ 195 | FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */ 196 | FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */ 197 | FR_NOT_ENABLED, /* (12) The volume has no work area */ 198 | FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */ 199 | FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any parameter error */ 200 | FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */ 201 | FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */ 202 | FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */ 203 | FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_SHARE */ 204 | FR_INVALID_PARAMETER /* (19) Given parameter is invalid */ 205 | } FRESULT; 206 | 207 | 208 | 209 | /*--------------------------------------------------------------*/ 210 | /* FatFs module application interface */ 211 | 212 | FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */ 213 | FRESULT f_close (FIL* fp); /* Close an open file object */ 214 | FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from a file */ 215 | FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to a file */ 216 | FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */ 217 | FRESULT f_lseek (FIL* fp, DWORD ofs); /* Move file pointer of a file object */ 218 | FRESULT f_truncate (FIL* fp); /* Truncate file */ 219 | FRESULT f_sync (FIL* fp); /* Flush cached data of a writing file */ 220 | FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */ 221 | FRESULT f_closedir (DIR* dp); /* Close an open directory */ 222 | FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */ 223 | FRESULT f_findfirst (DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */ 224 | FRESULT f_findnext (DIR* dp, FILINFO* fno); /* Find next file */ 225 | FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */ 226 | FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */ 227 | FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */ 228 | FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */ 229 | FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of the file/dir */ 230 | FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change times-tamp of the file/dir */ 231 | FRESULT f_chdir (const TCHAR* path); /* Change current directory */ 232 | FRESULT f_chdrive (const TCHAR* path); /* Change current drive */ 233 | FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */ 234 | FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */ 235 | FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */ 236 | FRESULT f_setlabel (const TCHAR* label); /* Set volume label */ 237 | FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */ 238 | FRESULT f_mkfs (const TCHAR* path, BYTE sfd, UINT au); /* Create a file system on the volume */ 239 | FRESULT f_fdisk (BYTE pdrv, const DWORD szt[], void* work); /* Divide a physical drive into some partitions */ 240 | int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */ 241 | int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */ 242 | int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */ 243 | TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */ 244 | 245 | #define f_eof(fp) ((int)((fp)->fptr == (fp)->fsize)) 246 | #define f_error(fp) ((fp)->err) 247 | #define f_tell(fp) ((fp)->fptr) 248 | #define f_size(fp) ((fp)->fsize) 249 | #define f_rewind(fp) f_lseek((fp), 0) 250 | #define f_rewinddir(dp) f_readdir((dp), 0) 251 | 252 | #ifndef EOF 253 | #define EOF (-1) 254 | #endif 255 | 256 | 257 | 258 | 259 | /*--------------------------------------------------------------*/ 260 | /* Additional user defined functions */ 261 | 262 | /* RTC function */ 263 | #if !_FS_READONLY && !_FS_NORTC 264 | DWORD get_fattime (void); 265 | #endif 266 | 267 | /* Unicode support functions */ 268 | #if _USE_LFN /* Unicode - OEM code conversion */ 269 | WCHAR ff_convert (WCHAR chr, UINT dir); /* OEM-Unicode bidirectional conversion */ 270 | WCHAR ff_wtoupper (WCHAR chr); /* Unicode upper-case conversion */ 271 | #if _USE_LFN == 3 /* Memory functions */ 272 | void* ff_memalloc (UINT msize); /* Allocate memory block */ 273 | void ff_memfree (void* mblock); /* Free memory block */ 274 | #endif 275 | #endif 276 | 277 | /* Sync functions */ 278 | #if _FS_REENTRANT 279 | int ff_cre_syncobj (BYTE vol, _SYNC_t* sobj); /* Create a sync object */ 280 | int ff_req_grant (_SYNC_t sobj); /* Lock sync object */ 281 | void ff_rel_grant (_SYNC_t sobj); /* Unlock sync object */ 282 | int ff_del_syncobj (_SYNC_t sobj); /* Delete a sync object */ 283 | #endif 284 | 285 | 286 | 287 | 288 | /*--------------------------------------------------------------*/ 289 | /* Flags and offset address */ 290 | 291 | 292 | /* File access control and file status flags (FIL.flag) */ 293 | 294 | #define FA_READ 0x01 295 | #define FA_OPEN_EXISTING 0x00 296 | 297 | #if !_FS_READONLY 298 | #define FA_WRITE 0x02 299 | #define FA_CREATE_NEW 0x04 300 | #define FA_CREATE_ALWAYS 0x08 301 | #define FA_OPEN_ALWAYS 0x10 302 | #define FA__WRITTEN 0x20 303 | #define FA__DIRTY 0x40 304 | #endif 305 | 306 | 307 | /* FAT sub type (FATFS.fs_type) */ 308 | 309 | #define FS_FAT12 1 310 | #define FS_FAT16 2 311 | #define FS_FAT32 3 312 | 313 | 314 | /* File attribute bits for directory entry */ 315 | 316 | #define AM_RDO 0x01 /* Read only */ 317 | #define AM_HID 0x02 /* Hidden */ 318 | #define AM_SYS 0x04 /* System */ 319 | #define AM_VOL 0x08 /* Volume label */ 320 | #define AM_LFN 0x0F /* LFN entry */ 321 | #define AM_DIR 0x10 /* Directory */ 322 | #define AM_ARC 0x20 /* Archive */ 323 | #define AM_MASK 0x3F /* Mask of defined bits */ 324 | 325 | 326 | /* Fast seek feature */ 327 | #define CREATE_LINKMAP 0xFFFFFFFF 328 | 329 | 330 | 331 | /*--------------------------------*/ 332 | /* Multi-byte word access macros */ 333 | 334 | #if _WORD_ACCESS == 1 /* Enable word access to the FAT structure */ 335 | #define LD_WORD(ptr) (WORD)(*(WORD*)(BYTE*)(ptr)) 336 | #define LD_DWORD(ptr) (DWORD)(*(DWORD*)(BYTE*)(ptr)) 337 | #define ST_WORD(ptr,val) *(WORD*)(BYTE*)(ptr)=(WORD)(val) 338 | #define ST_DWORD(ptr,val) *(DWORD*)(BYTE*)(ptr)=(DWORD)(val) 339 | #else /* Use byte-by-byte access to the FAT structure */ 340 | #define LD_WORD(ptr) (WORD)(((WORD)*((BYTE*)(ptr)+1)<<8)|(WORD)*(BYTE*)(ptr)) 341 | #define LD_DWORD(ptr) (DWORD)(((DWORD)*((BYTE*)(ptr)+3)<<24)|((DWORD)*((BYTE*)(ptr)+2)<<16)|((WORD)*((BYTE*)(ptr)+1)<<8)|*(BYTE*)(ptr)) 342 | #define ST_WORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8) 343 | #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) 344 | #endif 345 | 346 | #ifdef __cplusplus 347 | } 348 | #endif 349 | 350 | #endif /* _FATFS */ 351 | -------------------------------------------------------------------------------- /src/ds/include/fatfs/ff_utils.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Fatfs utils 3 | */ 4 | #ifndef __FF_UTILS_H__ 5 | #define __FF_UTILS_H__ 6 | 7 | #include "integer.h" 8 | 9 | struct _time_block { 10 | int year; 11 | int mon; 12 | int day; 13 | int hour; 14 | int min; 15 | int sec; 16 | }; 17 | 18 | unsigned long rtc_secs(void); 19 | struct _time_block *conv_gmtime(unsigned long t); 20 | DWORD get_fattime(); 21 | 22 | #endif 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/ds/include/fatfs/ffconf.h: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------------/ 2 | / FatFs - FAT file system module configuration file R0.11 (C)ChaN, 2015 3 | /---------------------------------------------------------------------------*/ 4 | 5 | #define _FFCONF 32020 /* Revision ID */ 6 | 7 | /*---------------------------------------------------------------------------/ 8 | / Functions and Buffer Configurations 9 | /---------------------------------------------------------------------------*/ 10 | 11 | #define _FS_TINY 0 12 | /* This option switches tiny buffer configuration. (0:Normal or 1:Tiny) 13 | / At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS 14 | / bytes. Instead of private sector buffer eliminated from the file object, 15 | / common sector buffer in the file system object (FATFS) is used for the file 16 | / data transfer. */ 17 | 18 | 19 | #define _FS_READONLY 0 20 | /* This option switches read-only configuration. (0:Read/Write or 1:Read-only) 21 | / Read-only configuration removes writing API functions, f_write(), f_sync(), 22 | / f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree() 23 | / and optional writing functions as well. */ 24 | 25 | 26 | #define _FS_MINIMIZE 0 27 | /* This option defines minimization level to remove some basic API functions. 28 | / 29 | / 0: All basic functions are enabled. 30 | / 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_chmod(), f_utime(), 31 | / f_truncate() and f_rename() function are removed. 32 | / 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1. 33 | / 3: f_lseek() function is removed in addition to 2. */ 34 | 35 | 36 | #define _USE_STRFUNC 0 37 | /* This option switches string functions, f_gets(), f_putc(), f_puts() and 38 | / f_printf(). 39 | / 40 | / 0: Disable string functions. 41 | / 1: Enable without LF-CRLF conversion. 42 | / 2: Enable with LF-CRLF conversion. */ 43 | 44 | 45 | #define _USE_FIND 0 46 | /* This option switches filtered directory read feature and related functions, 47 | / f_findfirst() and f_findnext(). (0:Disable or 1:Enable) */ 48 | 49 | 50 | #define _USE_MKFS 1 51 | /* This option switches f_mkfs() function. (0:Disable or 1:Enable) */ 52 | 53 | 54 | #define _USE_FASTSEEK 1 55 | /* This option switches fast seek feature. (0:Disable or 1:Enable) */ 56 | 57 | 58 | #define _USE_LABEL 1 59 | /* This option switches volume label functions, f_getlabel() and f_setlabel(). 60 | / (0:Disable or 1:Enable) */ 61 | 62 | 63 | #define _USE_FORWARD 0 64 | /* This option switches f_forward() function. (0:Disable or 1:Enable) 65 | / To enable it, also _FS_TINY need to be set to 1. */ 66 | 67 | 68 | /*---------------------------------------------------------------------------/ 69 | / Locale and Namespace Configurations 70 | /---------------------------------------------------------------------------*/ 71 | 72 | #define _CODE_PAGE 1251 73 | /* This option specifies the OEM code page to be used on the target system. 74 | / Incorrect setting of the code page can cause a file open failure. 75 | / 76 | / 1 - ASCII (No extended character. Non-LFN cfg. only) 77 | / 437 - U.S. 78 | / 720 - Arabic 79 | / 737 - Greek 80 | / 775 - Baltic 81 | / 850 - Multilingual Latin 1 82 | / 852 - Latin 2 83 | / 855 - Cyrillic 84 | / 857 - Turkish 85 | / 858 - Multilingual Latin 1 + Euro 86 | / 862 - Hebrew 87 | / 866 - Russian 88 | / 874 - Thai 89 | / 932 - Japanese Shift_JIS (DBCS) 90 | / 936 - Simplified Chinese GBK (DBCS) 91 | / 949 - Korean (DBCS) 92 | / 950 - Traditional Chinese Big5 (DBCS) 93 | */ 94 | 95 | 96 | #define _USE_LFN 3 97 | #define _MAX_LFN 255 98 | /* The _USE_LFN option switches the LFN feature. 99 | / 100 | / 0: Disable LFN feature. _MAX_LFN has no effect. 101 | / 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe. 102 | / 2: Enable LFN with dynamic working buffer on the STACK. 103 | / 3: Enable LFN with dynamic working buffer on the HEAP. 104 | / 105 | / When enable the LFN feature, Unicode handling functions (option/unicode.c) must 106 | / be added to the project. The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes. 107 | / When use stack for the working buffer, take care on stack overflow. When use heap 108 | / memory for the working buffer, memory management functions, ff_memalloc() and 109 | / ff_memfree(), must be added to the project. */ 110 | 111 | 112 | #define _LFN_UNICODE 0 113 | /* This option switches character encoding on the API. (0:ANSI/OEM or 1:Unicode) 114 | / To use Unicode string for the path name, enable LFN feature and set _LFN_UNICODE 115 | / to 1. This option also affects behavior of string I/O functions. */ 116 | 117 | 118 | #define _STRF_ENCODE 3 119 | /* When _LFN_UNICODE is 1, this option selects the character encoding on the file to 120 | / be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf(). 121 | / 122 | / 0: ANSI/OEM 123 | / 1: UTF-16LE 124 | / 2: UTF-16BE 125 | / 3: UTF-8 126 | / 127 | / When _LFN_UNICODE is 0, this option has no effect. */ 128 | 129 | 130 | #define _FS_RPATH 2 131 | /* This option configures relative path feature. 132 | / 133 | / 0: Disable relative path feature and remove related functions. 134 | / 1: Enable relative path feature. f_chdir() and f_chdrive() are available. 135 | / 2: f_getcwd() function is available in addition to 1. 136 | / 137 | / Note that directory items read via f_readdir() are affected by this option. */ 138 | 139 | 140 | /*---------------------------------------------------------------------------/ 141 | / Drive/Volume Configurations 142 | /---------------------------------------------------------------------------*/ 143 | 144 | #define _VOLUMES 8 145 | /* Number of volumes (logical drives) to be used. */ 146 | 147 | 148 | #define _STR_VOLUME_ID 0 149 | #define _VOLUME_STRS "SD","SD1","SD2","SD3","IDE","IDE1","IDE2","IDE3" 150 | /* _STR_VOLUME_ID option switches string volume ID feature. 151 | / When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive 152 | / number in the path name. _VOLUME_STRS defines the drive ID strings for each 153 | / logical drives. Number of items must be equal to _VOLUMES. Valid characters for 154 | / the drive ID strings are: A-Z and 0-9. */ 155 | 156 | 157 | #define _MULTI_PARTITION 1 158 | /* This option switches multi-partition feature. By default (0), each logical drive 159 | / number is bound to the same physical drive number and only an FAT volume found on 160 | / the physical drive will be mounted. When multi-partition feature is enabled (1), 161 | / each logical drive number is bound to arbitrary physical drive and partition 162 | / listed in the VolToPart[]. Also f_fdisk() funciton will be available. */ 163 | 164 | 165 | #define _MIN_SS 512 166 | #define _MAX_SS 512 167 | /* These options configure the range of sector size to be supported. (512, 1024, 168 | / 2048 or 4096) Always set both 512 for most systems, all type of memory cards and 169 | / harddisk. But a larger value may be required for on-board flash memory and some 170 | / type of optical media. When _MAX_SS is larger than _MIN_SS, FatFs is configured 171 | / to variable sector size and GET_SECTOR_SIZE command must be implemented to the 172 | / disk_ioctl() function. */ 173 | 174 | 175 | #define _USE_TRIM 0 176 | /* This option switches ATA-TRIM feature. (0:Disable or 1:Enable) 177 | / To enable Trim feature, also CTRL_TRIM command should be implemented to the 178 | / disk_ioctl() function. */ 179 | 180 | 181 | #define _FS_NOFSINFO 0 182 | /* If you need to know correct free space on the FAT32 volume, set bit 0 of this 183 | / option, and f_getfree() function at first time after volume mount will force 184 | / a full FAT scan. Bit 1 controls the use of last allocated cluster number. 185 | / 186 | / bit0=0: Use free cluster count in the FSINFO if available. 187 | / bit0=1: Do not trust free cluster count in the FSINFO. 188 | / bit1=0: Use last allocated cluster number in the FSINFO if available. 189 | / bit1=1: Do not trust last allocated cluster number in the FSINFO. 190 | */ 191 | 192 | 193 | 194 | /*---------------------------------------------------------------------------/ 195 | / System Configurations 196 | /---------------------------------------------------------------------------*/ 197 | 198 | #define _FS_NORTC 0 199 | #define _NORTC_MON 2 200 | #define _NORTC_MDAY 1 201 | #define _NORTC_YEAR 2015 202 | /* The _FS_NORTC option switches timestamp feature. If the system does not have 203 | / an RTC function or valid timestamp is not needed, set _FS_NORTC to 1 to disable 204 | / the timestamp feature. All objects modified by FatFs will have a fixed timestamp 205 | / defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR. 206 | / When timestamp feature is enabled (_FS_NORTC == 0), get_fattime() function need 207 | / to be added to the project to read current time form RTC. _NORTC_MON, 208 | / _NORTC_MDAY and _NORTC_YEAR have no effect. 209 | / These options have no effect at read-only configuration (_FS_READONLY == 1). */ 210 | 211 | 212 | #define _FS_LOCK 0 213 | /* The _FS_LOCK option switches file lock feature to control duplicated file open 214 | / and illegal operation to open objects. This option must be 0 when _FS_READONLY 215 | / is 1. 216 | / 217 | / 0: Disable file lock feature. To avoid volume corruption, application program 218 | / should avoid illegal open, remove and rename to the open objects. 219 | / >0: Enable file lock feature. The value defines how many files/sub-directories 220 | / can be opened simultaneously under file lock control. Note that the file 221 | / lock feature is independent of re-entrancy. */ 222 | 223 | #include 224 | #define _FS_REENTRANT 0 225 | #define _FS_TIMEOUT 1000 226 | #define _SYNC_t mutex_t* 227 | /* The _FS_REENTRANT option switches the re-entrancy (thread safe) of the FatFs 228 | / module itself. Note that regardless of this option, file access to different 229 | / volume is always re-entrant and volume control functions, f_mount(), f_mkfs() 230 | / and f_fdisk() function, are always not re-entrant. Only file/directory access 231 | / to the same volume is under control of this feature. 232 | / 233 | / 0: Disable re-entrancy. _FS_TIMEOUT and _SYNC_t have no effect. 234 | / 1: Enable re-entrancy. Also user provided synchronization handlers, 235 | / ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj() 236 | / function, must be added to the project. Samples are available in 237 | / option/syscall.c. 238 | / 239 | / The _FS_TIMEOUT defines timeout period in unit of time tick. 240 | / The _SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*, 241 | / SemaphoreHandle_t and etc.. A header file for O/S definitions needs to be 242 | / included somewhere in the scope of ff.c. */ 243 | 244 | 245 | #define _WORD_ACCESS 0 246 | /* The _WORD_ACCESS option is an only platform dependent option. It defines 247 | / which access method is used to the word data on the FAT volume. 248 | / 249 | / 0: Byte-by-byte access. Always compatible with all platforms. 250 | / 1: Word access. Do not choose this unless under both the following conditions. 251 | / 252 | / * Address misaligned memory access is always allowed to ALL instructions. 253 | / * Byte order on the memory is little-endian. 254 | / 255 | / If it is the case, _WORD_ACCESS can also be set to 1 to reduce code size. 256 | / Following table shows allowable settings of some processor types. 257 | / 258 | / ARM7TDMI 0 ColdFire 0 V850E 0 259 | / Cortex-M3 0 Z80 0/1 V850ES 0/1 260 | / Cortex-M0 0 x86 0/1 TLCS-870 0/1 261 | / AVR 0/1 RX600(LE) 0/1 TLCS-900 0/1 262 | / AVR32 0 RL78 0 R32C 0 263 | / PIC18 0/1 SH-2 0 M16C 0/1 264 | / PIC24 0 H8S 0 MSP430 0 265 | / PIC32 0 H8/300H 0 8051 0/1 266 | */ 267 | 268 | -------------------------------------------------------------------------------- /src/ds/include/fatfs/integer.h: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------*/ 2 | /* Integer type definitions for FatFs module */ 3 | /*-------------------------------------------*/ 4 | 5 | #ifndef _FF_INTEGER 6 | #define _FF_INTEGER 7 | 8 | #ifdef _WIN32 /* FatFs development platform */ 9 | 10 | #include 11 | #include 12 | 13 | #else /* Embedded platform */ 14 | 15 | /* This type MUST be 8 bit */ 16 | typedef unsigned char BYTE; 17 | 18 | /* These types MUST be 16 bit */ 19 | typedef short SHORT; 20 | typedef unsigned short WORD; 21 | typedef unsigned short WCHAR; 22 | 23 | /* These types MUST be 16 bit or 32 bit */ 24 | typedef int INT; 25 | typedef unsigned int UINT; 26 | 27 | /* These types MUST be 32 bit */ 28 | typedef long LONG; 29 | typedef unsigned long DWORD; 30 | 31 | #endif 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /src/ds/include/fs.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file fs.h 3 | * \brief DreamShell filesystem 4 | * \date 2007-2014 5 | * \author SWAT www.dc-swat.ru 6 | */ 7 | 8 | 9 | #ifndef _DS_FS_H 10 | #define _DS_FS_H 11 | 12 | #include 13 | #include 14 | #include 15 | #include "retrolog.h" 16 | 17 | /** 18 | * Initialize SD Card 19 | * and mount all partitions with FAT or EXT2 filesystems 20 | */ 21 | int InitSDCard(); 22 | 23 | /** 24 | * Initialize G1-ATA device 25 | * and mount all partitions with FAT or EXT2 filesystems 26 | */ 27 | int InitIDE(); 28 | 29 | /** 30 | * Search romdisk images in BIOS ROM and mount it 31 | */ 32 | int InitRomdisk(); 33 | 34 | /** 35 | * Search DreamShell root directory on all usable devices 36 | * pass_cnt is a number of passed devices 37 | */ 38 | int SearchRoot(int pass_cnt); 39 | 40 | 41 | /** 42 | * FAT filesystem API 43 | */ 44 | 45 | typedef enum fatfs_ioctl { 46 | 47 | FATFS_IOCTL_CTRL_SYNC = 0, /* Flush disk cache (for write functions) */ 48 | FATFS_IOCTL_GET_SECTOR_COUNT, /* Get media size (for only f_mkfs()), 4 byte unsigned */ 49 | FATFS_IOCTL_GET_SECTOR_SIZE, /* Get sector size (for multiple sector size (_MAX_SS >= 1024)), 2 byte unsigned */ 50 | FATFS_IOCTL_GET_BLOCK_SIZE, /* Get erase block size (for only f_mkfs()), 2 byte unsigned */ 51 | FATFS_IOCTL_CTRL_ERASE_SECTOR, /* Force erased a block of sectors (for only _USE_ERASE) */ 52 | FATFS_IOCTL_GET_BOOT_SECTOR_DATA, /* Get first sector data, ffconf.h _MAX_SS bytes */ 53 | FATFS_IOCTL_GET_FD_LBA, /* Get file LBA, 4 byte unsigned */ 54 | FATFS_IOCTL_GET_FD_LINK_MAP /* Get file clusters linkmap, 128+ bytes */ 55 | 56 | } fatfs_ioctl_t; 57 | 58 | /** 59 | * Initialize and shutdown FAT filesystem 60 | * return 0 on success, or < 0 if error 61 | */ 62 | int fs_fat_init(void); 63 | int fs_fat_shutdown(void); 64 | 65 | /** 66 | * Mount FAT filesystem on specified partition 67 | * For block device need reset to 0 start_block number 68 | * return 0 on success, or < 0 if error 69 | */ 70 | int fs_fat_mount(const char *mp, kos_blockdev_t *dev, int dma, int partition); 71 | 72 | /** 73 | * Unmount FAT filesystem 74 | * return 0 on success, or < 0 if error 75 | */ 76 | int fs_fat_unmount(const char *mp); 77 | 78 | /** 79 | * Check mount point for FAT filesystem 80 | * return 0 is not FAT 81 | */ 82 | int fs_fat_is_mounted(const char *mp); 83 | 84 | /** 85 | * Check partition type for FAT 86 | * return 0 if not FAT or 16/32 if FAT partition 87 | */ 88 | int is_fat_partition(uint8 partition_type); 89 | 90 | /** 91 | * Check partition type for EXT2 92 | */ 93 | #define is_ext2_partition(partition_type) (partition_type == 0x83) 94 | 95 | 96 | #endif /* _DS_FS_H */ 97 | -------------------------------------------------------------------------------- /src/ds/include/utils.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file utils.h 3 | * \brief DreamShell utils 4 | * \date 2004-2016 5 | * \author SWAT www.dc-swat.ru 6 | */ 7 | 8 | 9 | #ifndef _DS_UTILS_H 10 | #define _DS_UTILS_H 11 | 12 | /* Optimized memory utils */ 13 | void *memcpy_sh4(void *dest, const void *src, size_t count); 14 | void *memmove_sh4(void *dest, const void *src, size_t count); 15 | void *memset_sh4(void *dest, uint32 val, size_t count); 16 | 17 | #define memcpy memcpy_sh4 18 | #define memmove memmove_sh4 19 | #define memset memset_sh4 20 | 21 | #endif /*_DS_UTILS_H */ 22 | -------------------------------------------------------------------------------- /src/ds/src/drivers/rtc.c: -------------------------------------------------------------------------------- 1 | /* DreamShell ##version## 2 | 3 | rtc.c 4 | Copyright (C) 2015-2016 SWAT 5 | Copyright (C) 2016 Megavolt85 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | /* The AICA RTC has an Epoch of 1/1/1950, so we must subtract 20 years (in 13 | seconds to get the standard Unix Epoch when getting the time, and add 20 14 | years when setting the time. */ 15 | #define TWENTY_YEARS ((20 * 365LU + 5) * 86400) 16 | 17 | /* The AICA RTC is represented by a 32-bit seconds counter stored in 2 16-bit 18 | registers.*/ 19 | #define AICA_RTC_SECS_H 0xa0710000 20 | #define AICA_RTC_SECS_L 0xa0710004 21 | #define AICA_RTC_WRITE_EN 0xa0710008 22 | 23 | #define AICA_RTC_ATTEMPTS_COUNT 10 24 | 25 | time_t rtc_gettime() { 26 | 27 | time_t val1, val2; 28 | int i = 0; 29 | 30 | do { 31 | 32 | val1 = ((g2_read_32(AICA_RTC_SECS_H) & 0xffff) << 16) | (g2_read_32(AICA_RTC_SECS_L) & 0xffff); 33 | val2 = ((g2_read_32(AICA_RTC_SECS_H) & 0xffff) << 16) | (g2_read_32(AICA_RTC_SECS_L) & 0xffff); 34 | 35 | if(i++ > AICA_RTC_ATTEMPTS_COUNT) { 36 | return (-1); 37 | } 38 | 39 | } while (val1 != val2); 40 | 41 | return (val1 - TWENTY_YEARS); 42 | } 43 | 44 | 45 | int rtc_settime(time_t time) { 46 | 47 | time_t val1, val2; 48 | time_t secs = time + TWENTY_YEARS; 49 | int i = 0; 50 | 51 | do { 52 | 53 | g2_write_32(1, AICA_RTC_WRITE_EN); 54 | g2_write_32((secs & 0xffff0000) >> 16, AICA_RTC_SECS_H); 55 | g2_write_32((secs & 0xffff), AICA_RTC_SECS_L); 56 | 57 | val1 = ((g2_read_32(AICA_RTC_SECS_H) & 0xffff) << 16) | (g2_read_32(AICA_RTC_SECS_L) & 0xffff); 58 | val2 = ((g2_read_32(AICA_RTC_SECS_H) & 0xffff) << 16) | (g2_read_32(AICA_RTC_SECS_L) & 0xffff); 59 | 60 | if(i++ > AICA_RTC_ATTEMPTS_COUNT) { 61 | return (-1); 62 | } 63 | 64 | } while ((val1 != val2) && ((val1 & 0xffffff80) != (secs & 0xffffff80))); 65 | 66 | return 0; 67 | } 68 | 69 | 70 | int rtc_gettimeutc(struct tm *time) { 71 | 72 | time_t timestamp = rtc_gettime(); 73 | 74 | if(time == NULL || timestamp == -1) { 75 | return -1; 76 | } 77 | 78 | localtime_r(×tamp, time); 79 | return 0; 80 | } 81 | 82 | 83 | int rtc_settimeutc(const struct tm *time) { 84 | 85 | time_t timestamp = mktime((struct tm *)time); 86 | 87 | if(time == NULL || timestamp == -1) { 88 | return -1; 89 | } 90 | 91 | return rtc_settime(timestamp); 92 | } 93 | 94 | 95 | void rtc_gettimeofday(struct timeval *tv) { 96 | tv->tv_sec = rtc_gettime(); 97 | 98 | /* Can't get microseconds with just a seconds counter. */ 99 | tv->tv_usec = 0; 100 | } 101 | 102 | int rtc_settimeofday(const struct timeval *tv) { 103 | return rtc_settime(tv->tv_sec); 104 | } 105 | -------------------------------------------------------------------------------- /src/ds/src/drivers/sd.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014 by SWAT 3 | * 4 | * This file is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License version 2 as 6 | * published by the Free Software Foundation. 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | /* For CRC16-CCITT */ 20 | #include 21 | 22 | #include 23 | #include 24 | #include "retrolog.h" 25 | 26 | //#define SD_DEBUG 1 27 | 28 | #define MAX_RETRIES 500000 29 | #define READ_RETRIES 50000 30 | #define WRITE_RETRIES 150000 31 | #define MAX_RETRY 10 32 | 33 | 34 | /* MMC/SD command (in SPI) */ 35 | #define CMD(n) (n | 0x40) 36 | #define CMD0 (0x40+0) /* GO_IDLE_STATE */ 37 | #define CMD1 (0x40+1) /* SEND_OP_COND */ 38 | #define CMD8 (0x40+8) /* SEND_IF_COND */ 39 | #define CMD9 (0x40+9) /* SEND_CSD */ 40 | #define CMD10 (0x40+10) /* SEND_CID */ 41 | #define CMD12 (0x40+12) /* STOP_TRANSMISSION */ 42 | #define CMD16 (0x40+16) /* SET_BLOCKLEN */ 43 | #define CMD17 (0x40+17) /* READ_SINGLE_BLOCK */ 44 | #define CMD18 (0x40+18) /* READ_MULTIPLE_BLOCK */ 45 | #define CMD23 (0x40+23) /* SET_BLOCK_COUNT */ 46 | #define CMD24 (0x40+24) /* WRITE_BLOCK */ 47 | #define CMD25 (0x40+25) /* WRITE_MULTIPLE_BLOCK */ 48 | #define CMD41 (0x40+41) /* SEND_OP_COND (ACMD) */ 49 | #define CMD55 (0x40+55) /* APP_CMD */ 50 | #define CMD58 (0x40+58) /* READ_OCR */ 51 | #define CMD59 (0x40+59) /* CRC_ON_OFF */ 52 | 53 | 54 | static inline uint16_t sdc_get_uint16( const uint8_t *s) 55 | { 56 | return (uint16_t) ((s [0] << 8) | s [1]); 57 | } 58 | 59 | static inline uint32_t sdc_get_uint32( const uint8_t *s) 60 | { 61 | return ((uint32_t) s [0] << 24) | ((uint32_t) s [1] << 16) | ((uint32_t) s [2] << 8) | (uint32_t) s [3]; 62 | } 63 | 64 | 65 | /** 66 | * @name Card Identification 67 | * @{ 68 | */ 69 | 70 | #define SD_MMC_CID_SIZE 16 71 | 72 | #define SD_MMC_CID_GET_MID( cid) ((cid) [0]) 73 | #define SD_MMC_CID_GET_OID( cid) sdc_get_uint16( cid + 1) 74 | #define SD_MMC_CID_GET_PNM( cid, i) ((char) (cid) [3 + (i)]) 75 | #define SD_MMC_CID_GET_PRV( cid) ((cid) [9]) 76 | #define SD_MMC_CID_GET_PSN( cid) sdc_get_uint32( cid + 10) 77 | #define SD_MMC_CID_GET_MDT( cid) ((cid) [14]) 78 | #define SD_MMC_CID_GET_CRC7( cid) ((cid) [15] >> 1) 79 | 80 | /** @} */ 81 | 82 | 83 | /* The type of the dev_data in the block device structure */ 84 | typedef struct sd_devdata { 85 | uint64_t block_count; 86 | uint64_t start_block; 87 | } sd_devdata_t; 88 | 89 | 90 | //static const int card_spi_delay = SPI_SDC_MMC_DELAY; 91 | //static int old_spi_delay = SPI_SDC_MMC_DELAY; 92 | 93 | static int byte_mode = 0; 94 | static int is_mmc = 0; 95 | static int initted = 0; 96 | 97 | #define SELECT() spi_cs_on(SPI_CS_SDC) 98 | #define DESELECT() spi_cs_off(SPI_CS_SDC) 99 | /* 100 | #define SELECT() do { \ 101 | spi_cs_on(SPI_CS_SDC); \ 102 | old_spi_delay = spi_get_delay(); \ 103 | if(old_spi_delay != card_spi_delay) \ 104 | spi_set_delay(card_spi_delay); \ 105 | } while(0) 106 | 107 | 108 | #define DESELECT() do { \ 109 | if(old_spi_delay != card_spi_delay) \ 110 | spi_set_delay(old_spi_delay); \ 111 | spi_cs_off(SPI_CS_SDC); \ 112 | } while(0) 113 | */ 114 | 115 | static uint8 wait_ready (void) { 116 | int i; 117 | uint8 res; 118 | 119 | (void)spi_sr_byte(0xFF); 120 | i = 0; 121 | do { 122 | res = spi_sr_byte(0xFF); 123 | i++; 124 | } while ((res != 0xFF) && i < MAX_RETRIES); 125 | 126 | return res; 127 | } 128 | 129 | 130 | static uint8 send_cmd ( 131 | uint8 cmd, /* Command byte */ 132 | uint32 arg /* Argument */ 133 | ) 134 | { 135 | uint8 n, res; 136 | uint8 cb[6]; 137 | 138 | if (wait_ready() != 0xFF) { 139 | #ifdef SD_DEBUG 140 | dbglog(DBG_DEBUG, "%s: CMD 0x%02x wait ready error\n", __func__, cmd); 141 | #endif 142 | return 0xFF; 143 | } 144 | 145 | cb[0] = cmd; 146 | cb[1] = (uint8)(arg >> 24); 147 | cb[2] = (uint8)(arg >> 16); 148 | cb[3] = (uint8)(arg >> 8); 149 | cb[4] = (uint8)arg; 150 | cb[5] = sd_crc7(cb, 5, 0); 151 | /* Send command packet */ 152 | 153 | int old = irq_disable(); 154 | spi_send_byte(cmd); /* Command */ 155 | spi_send_byte(cb[1]); /* Argument[31..24] */ 156 | spi_send_byte(cb[2]); /* Argument[23..16] */ 157 | spi_send_byte(cb[3]); /* Argument[15..8] */ 158 | spi_send_byte(cb[4]); /* Argument[7..0] */ 159 | spi_send_byte(cb[5]); // CRC7 160 | 161 | /* Receive command response */ 162 | if (cmd == CMD12) 163 | (void)spi_rec_byte(); /* Skip a stuff byte when stop reading */ 164 | 165 | n = 20; /* Wait for a valid response in timeout of 10 attempts */ 166 | 167 | do { 168 | 169 | res = spi_rec_byte(); 170 | 171 | } while ((res & 0x80) && --n); 172 | 173 | #ifdef SD_DEBUG 174 | dbglog(DBG_DEBUG, "%s: CMD 0x%02x response 0x%02x\n", __func__, cmd, res); 175 | #endif 176 | 177 | irq_restore(old); 178 | return res; /* Return with the response value */ 179 | } 180 | 181 | 182 | static uint8 send_slow_cmd ( 183 | uint8 cmd, /* Command byte */ 184 | uint32 arg /* Argument */ 185 | ) 186 | { 187 | uint8 n, res; 188 | uint8 cb[6]; 189 | int i; 190 | 191 | (void)spi_slow_sr_byte(0xff); 192 | i = 0; 193 | 194 | do { 195 | 196 | res = spi_slow_sr_byte(0xff); 197 | i++; 198 | 199 | } while ((res != 0xFF) && i < 100000); 200 | 201 | if (res != 0xff) { 202 | #ifdef SD_DEBUG 203 | dbglog(DBG_DEBUG, "%s: CMD 0x%02x error\n", __func__, cmd); 204 | #endif 205 | return(0xff); 206 | } 207 | 208 | cb[0] = cmd; 209 | cb[1] = (uint8)(arg >> 24); 210 | cb[2] = (uint8)(arg >> 16); 211 | cb[3] = (uint8)(arg >> 8); 212 | cb[4] = (uint8)arg; 213 | cb[5] = sd_crc7(cb, 5, 0); 214 | /* Send command packet */ 215 | spi_slow_sr_byte(cmd); /* Command */ 216 | spi_slow_sr_byte(cb[1]); /* Argument[31..24] */ 217 | spi_slow_sr_byte(cb[2]); /* Argument[23..16] */ 218 | spi_slow_sr_byte(cb[3]); /* Argument[15..8] */ 219 | spi_slow_sr_byte(cb[4]); /* Argument[7..0] */ 220 | spi_slow_sr_byte(cb[5]); // CRC7 221 | 222 | /* Receive command response */ 223 | if (cmd == CMD12) 224 | (void)spi_slow_sr_byte(0xff);/* Skip a stuff byte when stop reading */ 225 | 226 | n = 20; /* Wait for a valid response in timeout of 10 attempts */ 227 | 228 | do { 229 | res = spi_slow_sr_byte(0xff); 230 | } while ((res & 0x80) && --n); 231 | 232 | #ifdef SD_DEBUG 233 | dbglog(DBG_DEBUG, "%s: CMD 0x%02x response 0x%02x\n", __func__, cmd, res); 234 | #endif 235 | 236 | return res; /* Return with the response value */ 237 | } 238 | 239 | 240 | int sdc_init(void) { 241 | 242 | int i; 243 | uint8 n, ty = 0, ocr[4]; 244 | 245 | if(initted) 246 | return 0; 247 | 248 | if(spi_init(0)) { 249 | return -1; 250 | } 251 | 252 | timer_spin_sleep(20); 253 | SELECT(); 254 | 255 | /* 80 dummy clocks */ 256 | for (n = 10; n; n--) 257 | (void)spi_slow_sr_byte(0xff); 258 | 259 | 260 | if (send_slow_cmd(CMD0, 0) == 1) { /* Enter Idle state */ 261 | 262 | #ifdef SD_DEBUG 263 | dbglog(DBG_DEBUG, "%s: Enter Idle state\n", __func__); 264 | #endif 265 | timer_spin_sleep(20); 266 | // thd_sleep(100); 267 | 268 | i = 0; 269 | 270 | if (send_slow_cmd(CMD8, 0x1AA) == 1) { /* SDC Ver2+ */ 271 | 272 | for (n = 0; n < 4; n++) 273 | ocr[n] = spi_slow_sr_byte(0xff); 274 | 275 | if (ocr[2] == 0x01 && ocr[3] == 0xAA) { /* The card can work at vdd range of 2.7-3.6V */ 276 | 277 | do { 278 | 279 | /* ACMD41 with HCS bit */ 280 | if (send_slow_cmd(CMD55, 0) <= 1 && send_slow_cmd(CMD41, 1UL << 30) == 0) 281 | break; 282 | 283 | ++i; 284 | 285 | } while (i < 300000); 286 | 287 | if (i < 300000 && send_slow_cmd(CMD58, 0) == 0) { /* Check CCS bit */ 288 | 289 | for (n = 0; n < 4; n++) 290 | ocr[n] = spi_slow_sr_byte(0xff); 291 | 292 | ty = (ocr[0] & 0x40) ? 6 : 2; 293 | } 294 | } 295 | 296 | } else { /* SDC Ver1 or MMC */ 297 | 298 | ty = (send_slow_cmd(CMD55, 0) <= 1 && send_slow_cmd(CMD41, 0) <= 1) ? 2 : 1; /* SDC : MMC */ 299 | 300 | do { 301 | 302 | if (ty == 2) { 303 | 304 | if (send_slow_cmd(CMD55, 0) <= 1 && send_slow_cmd(CMD41, 0) == 0) /* ACMD41 */ 305 | break; 306 | 307 | } else { 308 | 309 | if (send_slow_cmd(CMD1, 0) == 0) { /* CMD1 */ 310 | is_mmc = 1; 311 | break; 312 | } 313 | } 314 | 315 | ++i; 316 | 317 | } while (i < 300000); 318 | 319 | if (!(i < 300000) || send_slow_cmd(CMD16, 512) != 0) /* Select R/W block length */ 320 | ty = 0; 321 | } 322 | } 323 | 324 | send_slow_cmd(CMD59, 1); // crc check 325 | 326 | #ifdef SD_DEBUG 327 | dbglog(DBG_DEBUG, "%s: card type = 0x%02x\n", __func__, ty & 0xff); 328 | #endif 329 | 330 | if(!(ty & 4)) { 331 | byte_mode = 1; 332 | } 333 | 334 | DESELECT(); 335 | (void)spi_slow_sr_byte(0xff); /* Idle (Release DO) */ 336 | 337 | if (ty) { /* Initialization succeded */ 338 | // sdc_print_ident(); 339 | initted = 1; 340 | return 0; 341 | } 342 | 343 | /* Initialization failed */ 344 | sdc_shutdown(); 345 | return -1; 346 | } 347 | 348 | 349 | int sdc_shutdown(void) { 350 | 351 | if(!initted) 352 | return -1; 353 | 354 | SELECT(); 355 | wait_ready(); 356 | DESELECT(); 357 | (void)spi_rec_byte(); 358 | 359 | spi_shutdown(); 360 | initted = 0; 361 | return 0; 362 | } 363 | 364 | 365 | static int read_data ( 366 | uint8 *buff, /* Data buffer to store received data */ 367 | size_t len /* Byte count (must be even number) */ 368 | ) 369 | { 370 | uint8 token; 371 | int i, old; 372 | 373 | uint16 crc, crc2; 374 | i = 0; 375 | 376 | do { /* Wait for data packet in timeout of 100ms */ 377 | token = spi_rec_byte(); 378 | ++i; 379 | } while ((token == 0xFF) && i < READ_RETRIES); 380 | 381 | if(token != 0xFE) { 382 | #ifdef SD_DEBUG 383 | dbglog(DBG_DEBUG, "%s: not valid data token: %02x\n", __func__, token); 384 | #endif 385 | return -1; /* If not valid data token, return with error */ 386 | } 387 | 388 | // dcache_alloc_range((uint32)buff, len); 389 | 390 | old = irq_disable(); 391 | 392 | spi_rec_data(buff, len); 393 | crc = (uint16)spi_rec_byte() << 8; 394 | crc |= (uint16)spi_rec_byte(); 395 | 396 | irq_restore(old); 397 | 398 | crc2 = net_crc16ccitt(buff, len, 0); 399 | 400 | // dcache_purge_range((uint32)buff, len); 401 | 402 | if(crc != crc2) { 403 | errno = EIO; 404 | return -1; 405 | } 406 | 407 | return 0; /* Return with success */ 408 | } 409 | 410 | 411 | int sdc_read_blocks(uint32 block, size_t count, uint8 *buf) { 412 | 413 | if(!initted) { 414 | errno = ENXIO; 415 | return -1; 416 | } 417 | 418 | #ifdef SD_DEBUG 419 | dbglog(DBG_DEBUG, "%s: block=%ld count=%d\n", __func__, block, count); 420 | #endif 421 | 422 | uint8 *p; 423 | int retry, cnt; 424 | 425 | if (byte_mode) block <<= 9; /* Convert to byte address if needed */ 426 | 427 | for (retry = 0; retry < MAX_RETRY; retry++) { 428 | p = buf; 429 | cnt = count; 430 | 431 | SELECT(); 432 | 433 | if (cnt == 1) { /* Single block read */ 434 | 435 | if ((send_cmd(CMD17, block) == 0) && !read_data(p, 512)) { 436 | cnt = 0; 437 | } 438 | 439 | } else { /* Multiple block read */ 440 | if (send_cmd(CMD18, block) == 0) { 441 | 442 | do { 443 | 444 | if (read_data(p, 512)) 445 | break; 446 | 447 | p += 512; 448 | 449 | } while (--cnt); 450 | 451 | send_cmd(CMD12, 0); /* STOP_TRANSMISSION */ 452 | } 453 | } 454 | 455 | DESELECT(); 456 | (void)spi_rec_byte(); /* Idle (Release DO) */ 457 | if (cnt == 0) break; 458 | } 459 | 460 | //#ifdef SD_DEBUG 461 | // dbglog(DBG_DEBUG, "%s: retry = %d (MAX=%d) cnt = %d\n", __func__, retry, MAX_RETRY, cnt); 462 | //#endif 463 | 464 | if((retry >= MAX_RETRY || cnt > 0)) { 465 | errno = EIO; 466 | return -1; 467 | } 468 | 469 | return 0; 470 | } 471 | 472 | 473 | static int write_data ( 474 | uint8 *buff, /* 512 byte data block to be transmitted */ 475 | uint8 token /* Data/Stop token */ 476 | ) 477 | { 478 | uint8 resp; 479 | uint16 crc; 480 | int old; 481 | 482 | if (wait_ready() != 0xFF) 483 | return -1; 484 | 485 | spi_send_byte(token); /* Xmit data token */ 486 | 487 | if (token != 0xFD) { /* Is data token */ 488 | 489 | dcache_pref_range((uint32)buff, 512); 490 | crc = net_crc16ccitt(buff, 512, 0); 491 | 492 | old = irq_disable(); 493 | 494 | spi_send_data(buff, 512); 495 | spi_send_byte((uint8)(crc >> 8)); 496 | spi_send_byte((uint8)crc); 497 | 498 | irq_restore(old); 499 | 500 | resp = spi_rec_byte(); /* Reсeive data response */ 501 | 502 | if ((resp & 0x1F) != 0x05) { /* If not accepted, return with error */ 503 | #ifdef SD_DEBUG 504 | dbglog(DBG_DEBUG, "%s: not accepted: %02x\n", __func__, resp); 505 | #endif 506 | errno = EIO; 507 | return -1; 508 | } 509 | } 510 | 511 | return 0; 512 | } 513 | 514 | 515 | int sdc_write_blocks(uint32 block, size_t count, const uint8 *buf) { 516 | 517 | if(!initted) { 518 | errno = ENXIO; 519 | return -1; 520 | } 521 | 522 | #ifdef SD_DEBUG 523 | dbglog(DBG_DEBUG, "%s: block=%ld count=%d\n", __func__, block, count); 524 | #endif 525 | 526 | uint8 cnt, *p; 527 | int retry; 528 | 529 | if (byte_mode) block <<= 9; /* Convert to byte address if needed */ 530 | 531 | for (retry = 0; retry < MAX_RETRY; retry++) { 532 | 533 | p = (uint8 *)buf; 534 | cnt = count; 535 | 536 | SELECT(); /* CS = L */ 537 | 538 | if (count == 1) { /* Single block write */ 539 | if ((send_cmd(CMD24, block) == 0) && !write_data(p, 0xFE)) 540 | cnt = 0; 541 | } 542 | else { /* Multiple block write */ 543 | if (!is_mmc) { 544 | send_cmd(CMD55, 0); 545 | send_cmd(CMD23, cnt); /* ACMD23 */ 546 | } 547 | if (send_cmd(CMD25, block) == 0) { 548 | 549 | do { 550 | 551 | if (write_data(p, 0xFC)) 552 | break; 553 | 554 | p += 512; 555 | 556 | } while (--cnt); 557 | 558 | if (write_data(0, 0xFD)) /* STOP_TRAN token */ 559 | cnt = 1; 560 | } 561 | } 562 | 563 | DESELECT(); /* CS = H */ 564 | (void)spi_rec_byte(); /* Idle (Release DO) */ 565 | if (cnt == 0) break; 566 | } 567 | 568 | //#ifdef SD_DEBUG 569 | // dbglog(DBG_DEBUG, "%s: retry = %d (MAX=%d) cnt = %d\n", __func__, retry, MAX_RETRY, cnt); 570 | //#endif 571 | 572 | if((retry >= MAX_RETRY || cnt > 0)) { 573 | errno = EIO; 574 | return -1; 575 | } 576 | 577 | return 0; 578 | } 579 | 580 | 581 | uint64 sdc_get_size(void) { 582 | 583 | uint8 csd[16]; 584 | int exponent; 585 | uint64 rv = 0; 586 | 587 | if(!initted) { 588 | errno = ENXIO; 589 | return (uint64)-1; 590 | } 591 | 592 | SELECT(); 593 | 594 | if(send_cmd(CMD9, 0)) { 595 | rv = (uint64)-1; 596 | errno = EIO; 597 | goto out; 598 | } 599 | 600 | /* Read back the register */ 601 | if(read_data(csd, 16)) { 602 | rv = (uint64)-1; 603 | errno = EIO; 604 | goto out; 605 | } 606 | 607 | /* Figure out what version of the CSD register we're looking at */ 608 | switch(csd[0] >> 6) { 609 | case 0: 610 | /* CSD version 1.0 (SD) 611 | C_SIZE is bits 62-73 of the CSD, C_SIZE_MULT is bits 47-49, 612 | READ_BL_LEN is bits 80-83. 613 | Card size is calculated as follows: 614 | (C_SIZE + 1) * 2^(C_SIZE_MULT + 2) * 2^(READ_BL_LEN) */ 615 | exponent = (csd[5] & 0x0F) + ((csd[9] & 0x03) << 1) + 616 | (csd[10] >> 7) + 2; 617 | rv = ((csd[8] >> 6) | (csd[7] << 2) | ((csd[6] & 0x03) << 10)) + 1; 618 | rv <<= exponent; 619 | break; 620 | 621 | case 1: 622 | /* CSD version 2.0 (SDHC/SDXC) 623 | C_SIZE is bits 48-69 of the CSD, card size is calculated as 624 | (C_SIZE + 1) * 512KiB */ 625 | rv = ((((uint64)csd[9]) | (uint64)(csd[8] << 8) | 626 | ((uint64)(csd[7] & 0x3F) << 16)) + 1) << 19; 627 | break; 628 | 629 | default: 630 | /* Unknown version, punt. */ 631 | rv = (uint64)-1; 632 | errno = ENODEV; 633 | goto out; 634 | } 635 | 636 | out: 637 | DESELECT(); 638 | (void)spi_rec_byte(); 639 | return rv; 640 | } 641 | 642 | 643 | int sdc_print_ident(void) { 644 | 645 | uint8 cid[SD_MMC_CID_SIZE]; 646 | int rv = 0; 647 | 648 | if(!initted) { 649 | errno = ENXIO; 650 | return -1; 651 | } 652 | 653 | SELECT(); 654 | 655 | if(send_cmd(CMD10, 0)) { 656 | rv = -1; 657 | errno = EIO; 658 | goto out; 659 | } 660 | 661 | memset(cid, 0, SD_MMC_CID_SIZE); 662 | 663 | /* Read back the register */ 664 | if(read_data(cid, SD_MMC_CID_SIZE)) { 665 | rv = -1; 666 | errno = EIO; 667 | goto out; 668 | } 669 | 670 | // dbglog(DBG_DEBUG, "*** Card Identification ***\n"); 671 | dbglog(DBG_DEBUG, "Manufacturer ID : %" PRIu8 "\n", SD_MMC_CID_GET_MID(cid)); 672 | dbglog(DBG_DEBUG, "OEM/Application ID : %" PRIu16 "\n", SD_MMC_CID_GET_OID(cid)); 673 | dbglog(DBG_DEBUG, 674 | "Product name : %c%c%c%c%c%c\n", 675 | SD_MMC_CID_GET_PNM(cid, 0), 676 | SD_MMC_CID_GET_PNM(cid, 1), 677 | SD_MMC_CID_GET_PNM(cid, 2), 678 | SD_MMC_CID_GET_PNM(cid, 3), 679 | SD_MMC_CID_GET_PNM(cid, 4), 680 | SD_MMC_CID_GET_PNM(cid, 5) 681 | ); 682 | dbglog(DBG_DEBUG, "Product revision : %" PRIu8 "\n", SD_MMC_CID_GET_PRV(cid)); 683 | dbglog(DBG_DEBUG, "Product serial number : %" PRIu32 "\n", SD_MMC_CID_GET_PSN(cid)); 684 | dbglog(DBG_DEBUG, "Manufacturing date : %" PRIu8 "\n", SD_MMC_CID_GET_MDT(cid)); 685 | dbglog(DBG_DEBUG, "7-bit CRC checksum : %" PRIu8 "\n", SD_MMC_CID_GET_CRC7(cid)); 686 | 687 | 688 | out: 689 | DESELECT(); 690 | (void)spi_rec_byte(); 691 | return rv; 692 | } 693 | 694 | 695 | static int sdb_init(kos_blockdev_t *d) { 696 | (void)d; 697 | 698 | if(!initted) { 699 | errno = ENODEV; 700 | return -1; 701 | } 702 | 703 | return 0; 704 | } 705 | 706 | static int sdb_shutdown(kos_blockdev_t *d) { 707 | free(d->dev_data); 708 | return 0; 709 | } 710 | 711 | static int sdb_read_blocks(kos_blockdev_t *d, uint64_t block, size_t count, 712 | void *buf) { 713 | sd_devdata_t *data = (sd_devdata_t *)d->dev_data; 714 | 715 | return sdc_read_blocks(block + data->start_block, count, (uint8 *)buf); 716 | } 717 | 718 | static int sdb_write_blocks(kos_blockdev_t *d, uint64_t block, size_t count, 719 | const void *buf) { 720 | sd_devdata_t *data = (sd_devdata_t *)d->dev_data; 721 | 722 | return sdc_write_blocks(block + data->start_block, count, 723 | (const uint8 *)buf); 724 | } 725 | 726 | static uint64_t sdb_count_blocks(kos_blockdev_t *d) { 727 | sd_devdata_t *data = (sd_devdata_t *)d->dev_data; 728 | 729 | return data->block_count; 730 | } 731 | 732 | static int sdb_flush(kos_blockdev_t *d) { 733 | (void)d; 734 | 735 | SELECT(); 736 | wait_ready(); 737 | DESELECT(); 738 | (void)spi_rec_byte(); 739 | 740 | return 0; 741 | } 742 | 743 | static kos_blockdev_t sd_blockdev = { 744 | NULL, /* dev_data */ 745 | 9, /* l_block_size (block size of 512 bytes) */ 746 | &sdb_init, /* init */ 747 | &sdb_shutdown, /* shutdown */ 748 | &sdb_read_blocks, /* read_blocks */ 749 | &sdb_write_blocks, /* write_blocks */ 750 | &sdb_count_blocks, /* count_blocks */ 751 | &sdb_flush /* flush */ 752 | }; 753 | 754 | int sdc_blockdev_for_partition(int partition, kos_blockdev_t *rv, 755 | uint8 *partition_type) { 756 | uint8 buf[512]; 757 | int pval; 758 | sd_devdata_t *ddata; 759 | 760 | if(!initted) { 761 | errno = ENXIO; 762 | return -1; 763 | } 764 | 765 | if(!rv || !partition_type) { 766 | errno = EFAULT; 767 | return -1; 768 | } 769 | 770 | /* Make sure the partition asked for is sane */ 771 | if(partition < 0 || partition > 3) { 772 | dbglog(DBG_DEBUG, "Invalid partition number given: %d\n", partition); 773 | errno = EINVAL; 774 | return -1; 775 | } 776 | 777 | /* Read the MBR from the card */ 778 | if(sdc_read_blocks(0, 1, buf)) { 779 | return -1; 780 | } 781 | 782 | /* Make sure the SD card uses MBR partitions. 783 | TODO: Support GPT partitioning at some point. */ 784 | if(buf[0x01FE] != 0x55 || buf[0x1FF] != 0xAA) { 785 | dbglog(DBG_DEBUG, "SD card doesn't appear to have a MBR\n"); 786 | errno = ENOENT; 787 | return -1; 788 | } 789 | 790 | /* Figure out where the partition record we're concerned with is, and make 791 | sure that the partition actually exists. */ 792 | pval = 16 * partition + 0x01BE; 793 | 794 | if(buf[pval + 4] == 0) { 795 | dbglog(DBG_DEBUG, "Partition %d appears to be empty\n", partition); 796 | errno = ENOENT; 797 | return -1; 798 | } 799 | 800 | /* Allocate the device data */ 801 | if(!(ddata = (sd_devdata_t *)malloc(sizeof(sd_devdata_t)))) { 802 | errno = ENOMEM; 803 | return -1; 804 | } 805 | 806 | /* Copy in the template block device and fill it in */ 807 | memcpy(rv, &sd_blockdev, sizeof(kos_blockdev_t)); 808 | ddata->block_count = buf[pval + 0x0C] | (buf[pval + 0x0D] << 8) | 809 | (buf[pval + 0x0E] << 16) | (buf[pval + 0x0F] << 24); 810 | ddata->start_block = buf[pval + 0x08] | (buf[pval + 0x09] << 8) | 811 | (buf[pval + 0x0A] << 16) | (buf[pval + 0x0B] << 24); 812 | rv->dev_data = ddata; 813 | *partition_type = buf[pval + 4]; 814 | 815 | return 0; 816 | } 817 | 818 | -------------------------------------------------------------------------------- /src/ds/src/fs/fat/option/syscall.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------*/ 2 | /* Sample code of OS dependent controls for FatFs R0.08 */ 3 | /* (C)ChaN, 2010 */ 4 | /*------------------------------------------------------------------------*/ 5 | 6 | #include 7 | #include /* ANSI memory controls */ 8 | #include /* ANSI memory controls */ 9 | 10 | #include "fatfs/ff.h" 11 | #include "fatfs/integer.h" 12 | 13 | #if _FS_REENTRANT 14 | /*------------------------------------------------------------------------ 15 | Create a Synchronization Object 16 | ------------------------------------------------------------------------ 17 | / This function is called in f_mount function to create a new 18 | / synchronization object, such as semaphore and mutex. When a FALSE is 19 | / returned, the f_mount function fails with FR_INT_ERR. 20 | */ 21 | 22 | int ff_cre_syncobj ( /* TRUE:Function succeeded, FALSE:Could not create due to any error */ 23 | BYTE vol, /* Corresponding logical drive being processed */ 24 | _SYNC_t *sobj /* Pointer to return the created sync object */ 25 | ) 26 | { 27 | return mutex_init(*sobj, MUTEX_TYPE_DEFAULT) < 0 ? FALSE : TRUE; /* Dreamcast */ 28 | } 29 | 30 | 31 | 32 | /*------------------------------------------------------------------------*/ 33 | /* Delete a Synchronization Object */ 34 | /*------------------------------------------------------------------------*/ 35 | /* This function is called in f_mount function to delete a synchronization 36 | / object that created with ff_cre_syncobj function. When a FALSE is 37 | / returned, the f_mount function fails with FR_INT_ERR. 38 | */ 39 | 40 | int ff_del_syncobj ( /* TRUE:Function succeeded, FALSE:Could not delete due to any error */ 41 | _SYNC_t sobj /* Sync object tied to the logical drive to be deleted */ 42 | ) 43 | { 44 | 45 | mutex_destroy(sobj); /* Dreamcast */ 46 | return TRUE; 47 | } 48 | 49 | 50 | 51 | /*------------------------------------------------------------------------*/ 52 | /* Request Grant to Access the Volume */ 53 | /*------------------------------------------------------------------------*/ 54 | /* This function is called on entering file functions to lock the volume. 55 | / When a FALSE is returned, the file function fails with FR_TIMEOUT. 56 | */ 57 | 58 | int ff_req_grant ( /* TRUE:Got a grant to access the volume, FALSE:Could not get a grant */ 59 | _SYNC_t sobj /* Sync object to wait */ 60 | ) 61 | { 62 | return (mutex_lock_timed(sobj, _FS_TIMEOUT) < 0) ? FALSE : TRUE; 63 | } 64 | 65 | 66 | 67 | /*------------------------------------------------------------------------*/ 68 | /* Release Grant to Access the Volume */ 69 | /*------------------------------------------------------------------------*/ 70 | /* This function is called on leaving file functions to unlock the volume. 71 | */ 72 | 73 | void ff_rel_grant ( 74 | _SYNC_t sobj /* Sync object to be signaled */ 75 | ) 76 | { 77 | mutex_unlock(sobj); /* Dreamcast */ 78 | } 79 | 80 | #endif 81 | 82 | 83 | 84 | 85 | #if _USE_LFN == 3 /* LFN with a working buffer on the heap */ 86 | /*------------------------------------------------------------------------*/ 87 | /* Allocate a memory block */ 88 | /*------------------------------------------------------------------------*/ 89 | /* If a NULL is returned, the file function fails with FR_NOT_ENOUGH_CORE. 90 | */ 91 | 92 | void* ff_memalloc ( /* Returns pointer to the allocated memory block */ 93 | UINT size /* Number of bytes to allocate */ 94 | ) 95 | { 96 | return malloc(size); 97 | } 98 | 99 | 100 | /*------------------------------------------------------------------------*/ 101 | /* Free a memory block */ 102 | /*------------------------------------------------------------------------*/ 103 | 104 | void ff_memfree( 105 | void* mblock /* Pointer to the memory block to free */ 106 | ) 107 | { 108 | free(mblock); 109 | } 110 | 111 | #endif 112 | -------------------------------------------------------------------------------- /src/ds/src/fs/fat/utils.c: -------------------------------------------------------------------------------- 1 | // $$$ : utils.c -- 2 | 3 | #include "ff_utils.h" 4 | #include 5 | 6 | #define S_P_MIN 60L 7 | #define S_P_HOUR (60L * S_P_MIN) 8 | #define S_P_DAY (24L * S_P_HOUR) 9 | #define S_P_YEAR (365L * S_P_DAY) 10 | #define JAPAN_ADJ (-9L * S_P_HOUR) 11 | 12 | struct _time_block *conv_gmtime(uint32 t) 13 | { 14 | static int day_p_m[] = { 15 | 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 16 | }; 17 | int day, mon, yr, cumday; 18 | static struct _time_block tm; 19 | 20 | tm.sec = t % 60L; 21 | t /= 60L; 22 | tm.min = t % 60L; 23 | t /= 60L; 24 | tm.hour = t % 24L; 25 | day = t / 24L; 26 | yr = 1950; 27 | cumday = 0; 28 | while ((cumday += (yr % 4 ? 365 : 366)) <= day) yr++; 29 | tm.year = yr; 30 | cumday -= yr % 4 ? 365 : 366; 31 | day -= cumday; 32 | cumday = 0; 33 | mon = 0; 34 | day_p_m[1] = (yr % 4) == 0 ? 29 : 28; 35 | while ((cumday += day_p_m[mon]) <= day) mon++; 36 | cumday -= day_p_m[mon]; 37 | day -= cumday; 38 | tm.day = day + 1; 39 | tm.mon = mon + 1; 40 | return &tm; 41 | } 42 | 43 | 44 | DWORD get_fattime() 45 | { 46 | struct timeval tv; 47 | struct _time_block *tm; 48 | DWORD tmr; 49 | 50 | rtc_gettimeofday(&tv); 51 | tm = conv_gmtime(tv.tv_sec); 52 | 53 | tmr = (((DWORD)tm->year - 60) << 25) 54 | | ((DWORD)tm->mon << 21) 55 | | ((DWORD)tm->day << 16) 56 | | (WORD)(tm->hour << 11) 57 | | (WORD)(tm->min << 5) 58 | | (WORD)(tm->sec >> 1); 59 | return tmr; 60 | } 61 | -------------------------------------------------------------------------------- /src/ds/src/fs/fs.c: -------------------------------------------------------------------------------- 1 | /** 2 | * \file fs.c 3 | * \brief Filesystem 4 | * \date 2013-2015 5 | * \author SWAT 6 | * \copyright http://www.dc-swat.ru 7 | */ 8 | 9 | //#include "ds.h" 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "fs.h" 15 | #include "drivers/sd.h" 16 | #include "drivers/g1_ide.h" 17 | 18 | typedef struct romdisk_hdr { 19 | char magic[8]; /* Should be "-rom1fs-" */ 20 | uint32 full_size; /* Full size of the file system */ 21 | uint32 checksum; /* Checksum */ 22 | char volume_name[16]; /* Volume name (zero-terminated) */ 23 | } romdisk_hdr_t; 24 | 25 | typedef struct blockdev_devdata { 26 | uint64_t block_count; 27 | uint64_t start_block; 28 | } sd_devdata_t; 29 | 30 | typedef struct ata_devdata { 31 | uint64_t block_count; 32 | uint64_t start_block; 33 | uint64_t end_block; 34 | } ata_devdata_t; 35 | 36 | #define MAX_PARTITIONS 4 37 | 38 | static kos_blockdev_t sd_dev[MAX_PARTITIONS]; 39 | static kos_blockdev_t g1_dev[MAX_PARTITIONS]; 40 | 41 | static uint32 ntohl_32(const void *data) { 42 | const uint8 *d = (const uint8 *) data; 43 | return (d[0] << 24) | (d[1] << 16) | (d[2] << 8) | (d[3] << 0); 44 | } 45 | 46 | 47 | static int check_partition(uint8 *buf, int partition) { 48 | int pval; 49 | 50 | if (buf[0x01FE] != 0x55 || buf[0x1FF] != 0xAA) { 51 | // dbglog(DBG_DEBUG, "Device doesn't appear to have a MBR\n"); 52 | return -1; 53 | } 54 | 55 | pval = 16 * partition + 0x01BE; 56 | 57 | if (buf[pval + 4] == 0) { 58 | // dbglog(DBG_DEBUG, "Partition empty: 0x%02x\n", buf[pval + 4]); 59 | return -1; 60 | } 61 | 62 | return 0; 63 | } 64 | 65 | 66 | int InitSDCard() { 67 | 68 | dbglog(DBG_INFO, "Checking for SD card...\n"); 69 | uint8 partition_type; 70 | int part = 0, fat_part = 0; 71 | char path[8]; 72 | uint32 sd_block_count = 0; 73 | uint64 sd_capacity = 0; 74 | uint8 buf[512]; 75 | 76 | if (sdc_init()) { 77 | dbglog(DBG_WARNING, "SD card not found.\n"); 78 | return -1; 79 | } 80 | 81 | sd_capacity = sdc_get_size(); 82 | sd_block_count = (uint32) (sd_capacity / 512); 83 | 84 | dbglog(DBG_INFO, "SD card initialized, capacity %" 85 | PRIu32 86 | " MB\n", (uint32) (sd_capacity / 1024 / 1024)); 87 | 88 | // if(sdc_print_ident()) { 89 | // dbglog(DBG_INFO, "SD card read CID error\n"); 90 | // return -1; 91 | // } 92 | 93 | if (sdc_read_blocks(0, 1, buf)) { 94 | dbglog(DBG_ERROR, "Can't read MBR from SD card\n"); 95 | return -1; 96 | } 97 | 98 | for (part = 0; part < MAX_PARTITIONS; part++) { 99 | 100 | if (!check_partition(buf, part) && !sdc_blockdev_for_partition(part, &sd_dev[part], &partition_type)) { 101 | 102 | if (!part) { 103 | strcpy(path, "/sd"); 104 | path[3] = '\0'; 105 | } else { 106 | sprintf(path, "sd%d", part); 107 | path[strlen(path)] = '\0'; 108 | } 109 | 110 | /* Check to see if the MBR says that we have a Linux partition. */ 111 | if (is_ext2_partition(partition_type)) { 112 | 113 | dbglog(DBG_INFO, "Detected EXT2 filesystem on partition %d\n", part); 114 | 115 | if (fs_ext2_init()) { 116 | dbglog(DBG_INFO, "Could not initialize fs_ext2!\n"); 117 | sd_dev[part].shutdown(&sd_dev[part]); 118 | } else { 119 | dbglog(DBG_INFO, "Mounting filesystem...\n"); 120 | 121 | if (fs_ext2_mount(path, &sd_dev[part], FS_EXT2_MOUNT_READWRITE)) { 122 | dbglog(DBG_INFO, "Could not mount device as ext2fs.\n"); 123 | sd_dev[part].shutdown(&sd_dev[part]); 124 | } 125 | } 126 | 127 | } else if ((fat_part = is_fat_partition(partition_type))) { 128 | 129 | dbglog(DBG_INFO, "Detected FAT%d filesystem on partition %d\n", fat_part, part); 130 | 131 | sd_devdata_t *ddata = (sd_devdata_t *) sd_dev[part].dev_data; 132 | // ddata->block_count += ddata->start_block; 133 | ddata->block_count = sd_block_count; 134 | ddata->start_block = 0; 135 | 136 | if (fs_fat_init()) { 137 | dbglog(DBG_ERROR, "Could not initialize fs_fat!\n"); 138 | sd_dev[part].shutdown(&sd_dev[part]); 139 | } else { 140 | 141 | dbglog(DBG_INFO, "Mounting filesystem...\n"); 142 | 143 | if (fs_fat_mount(path, &sd_dev[part], 0, part)) { 144 | dbglog(DBG_ERROR, "Could not mount device as fatfs.\n"); 145 | sd_dev[part].shutdown(&sd_dev[part]); 146 | } 147 | } 148 | 149 | } else { 150 | dbglog(DBG_ERROR, "Unknown filesystem: 0x%02x\n", partition_type); 151 | sd_dev[part].shutdown(&sd_dev[part]); 152 | } 153 | 154 | } else { 155 | // dbglog(DBG_ERROR, "Could not make blockdev for partition %d, error: %d\n", part, errno); 156 | } 157 | } 158 | 159 | return 0; 160 | } 161 | 162 | 163 | int InitIDE() { 164 | 165 | dbglog(DBG_INFO, "Checking for G1 ATA devices...\n"); 166 | uint8 partition_type; 167 | int part = 0, fat_part = 0; 168 | char path[8]; 169 | uint64 ide_block_count = 0; 170 | uint8 buf[512]; 171 | int use_dma = 1; 172 | 173 | if (g1_ata_init()) { 174 | dbglog(DBG_ERROR, "G1 ATA device not found.\n"); 175 | return -1; 176 | } 177 | 178 | dbglog(DBG_INFO, "G1 ATA device initialized\n"); 179 | 180 | /* Read the MBR from the disk */ 181 | if (g1_ata_max_lba() > 0) { 182 | if (g1_ata_read_lba(0, 1, (uint16_t *) buf) < 0) { 183 | dbglog(DBG_ERROR, "Can't read MBR from IDE by LBA\n"); 184 | return -1; 185 | } 186 | } else { 187 | 188 | use_dma = 0; 189 | 190 | if (g1_ata_read_chs(0, 0, 1, 1, (uint16_t *) buf) < 0) { 191 | dbglog(DBG_ERROR, "Can't read MBR from IDE by CHS\n"); 192 | return -1; 193 | } 194 | } 195 | 196 | for (part = 0; part < MAX_PARTITIONS; part++) { 197 | 198 | if (!check_partition(buf, part) && 199 | !g1_ata_blockdev_for_partition(part, use_dma, &g1_dev[part], &partition_type)) { 200 | 201 | if (!part) { 202 | strcpy(path, "/ide"); 203 | path[4] = '\0'; 204 | } else { 205 | sprintf(path, "/ide%d", part); 206 | path[strlen(path)] = '\0'; 207 | } 208 | 209 | /* Check to see if the MBR says that we have a EXT2 or FAT partition. */ 210 | if (is_ext2_partition(partition_type)) { 211 | 212 | dbglog(DBG_INFO, "Detected EXT2 filesystem on partition %d\n", part); 213 | 214 | if (fs_ext2_init()) { 215 | dbglog(DBG_ERROR, "Could not initialize fs_ext2!\n"); 216 | g1_dev[part].shutdown(&g1_dev[part]); 217 | } else { 218 | 219 | /* Only PIO for EXT2 */ 220 | g1_dev[part].shutdown(&g1_dev[part]); 221 | if (g1_ata_blockdev_for_partition(part, 0, &g1_dev[part], &partition_type)) { 222 | continue; 223 | } 224 | 225 | dbglog(DBG_INFO, "Mounting filesystem...\n"); 226 | if (fs_ext2_mount(path, &g1_dev[part], FS_EXT2_MOUNT_READWRITE)) { 227 | dbglog(DBG_ERROR, "Could not mount device as ext2fs.\n"); 228 | } 229 | } 230 | 231 | } else if ((fat_part = is_fat_partition(partition_type))) { 232 | 233 | dbglog(DBG_INFO, "Detected FAT%d filesystem on partition %d\n", fat_part, part); 234 | 235 | if (!ide_block_count) { 236 | ide_block_count = g1_ata_max_lba(); 237 | } 238 | 239 | ata_devdata_t *ddata = (ata_devdata_t *) g1_dev[part].dev_data; 240 | 241 | if (ide_block_count > 0) { 242 | ddata->block_count = ide_block_count; 243 | ddata->end_block = ide_block_count - 1; 244 | } else { 245 | ddata->block_count += ddata->start_block; 246 | ddata->end_block += ddata->start_block; 247 | } 248 | 249 | ddata->start_block = 0; 250 | 251 | if (fs_fat_init()) { 252 | dbglog(DBG_ERROR, "Could not initialize fs_fat!\n"); 253 | g1_dev[part].shutdown(&g1_dev[part]); 254 | } else { 255 | 256 | dbglog(DBG_INFO, "Mounting filesystem...\n"); 257 | 258 | if (fs_fat_mount(path, &g1_dev[part], use_dma, part)) { 259 | dbglog(DBG_ERROR, "Could not mount device as fatfs.\n"); 260 | g1_dev[part].shutdown(&g1_dev[part]); 261 | } 262 | } 263 | 264 | } else { 265 | dbglog(DBG_ERROR, "Unknown filesystem: 0x%02x\n", partition_type); 266 | g1_dev[part].shutdown(&g1_dev[part]); 267 | } 268 | } 269 | } 270 | 271 | return 0; 272 | } 273 | -------------------------------------------------------------------------------- /src/ds/src/utils/asm.h: -------------------------------------------------------------------------------- 1 | #ifdef __STDC__ 2 | # define _C_LABEL(x) _ ## x 3 | #else 4 | # define _C_LABEL(x) _/**/x 5 | #endif 6 | #define _ASM_LABEL(x) x 7 | 8 | #if __SH5__ 9 | # if __SH5__ == 32 && __SHMEDIA__ 10 | # define TEXT .section .text..SHmedia32, "ax" 11 | # else 12 | # define TEXT .text 13 | # endif 14 | 15 | # define _ENTRY(name) \ 16 | TEXT; .balign 8; .globl name; name: 17 | #else 18 | #define _ENTRY(name) \ 19 | .text; .align 2; .globl name; name: 20 | #endif /* __SH5__ */ 21 | 22 | #define ENTRY(name) \ 23 | _ENTRY(_C_LABEL(name)) 24 | 25 | #if (defined (__sh2__) || defined (__SH2E__) || defined (__sh3__) || defined (__SH3E__) \ 26 | || defined (__SH4_SINGLE__) || defined (__SH4__)) \ 27 | || defined (__SH4_SINGLE_ONLY__) || defined (__SH5__) || defined (__SH2A__) 28 | #define DELAYED_BRANCHES 29 | #define SL(branch, dest, in_slot, in_slot_arg2) \ 30 | branch##.s dest; in_slot, in_slot_arg2 31 | #else 32 | #define SL(branch, dest, in_slot, in_slot_arg2) \ 33 | in_slot, in_slot_arg2; branch dest 34 | #endif 35 | 36 | #ifdef __LITTLE_ENDIAN__ 37 | #define SHHI shlld 38 | #define SHLO shlrd 39 | #else 40 | #define SHHI shlrd 41 | #define SHLO shlld 42 | #endif 43 | 44 | #define __ALIGN .balign 4 45 | #define __ALIGN_STR ".balign 4" 46 | -------------------------------------------------------------------------------- /src/ds/src/utils/memset.S: -------------------------------------------------------------------------------- 1 | /* $Id: memset.S,v 1.1 2000/04/14 16:49:01 mjd Exp $ 2 | * 3 | * "memset" implementation of SuperH 4 | * 5 | * Copyright (C) 1999 Niibe Yutaka 6 | * 7 | * Copyright (c) 2009 STMicroelectronics Ltd 8 | * Optimised using 64bit data transfer (via FPU) and the movca.l inst. 9 | * Author: Giuseppe Cavallaro 10 | * 11 | * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. 12 | */ 13 | 14 | /* 15 | * void *memset(void *s, int c, size_t n); 16 | */ 17 | 18 | #include "asm.h" 19 | 20 | #if defined (__LITTLE_ENDIAN__) && defined (__SH_FPU_ANY__) 21 | #define MEMSET_USES_FPU 22 | /* Use paired single precision load or store mode for 64-bit tranfering. 23 | * FPSCR.SZ=1,FPSCR.SZ=0 is well defined on both SH4-200 and SH4-300. 24 | * Currenlty it has been only implemented and tested for little endian mode. */ 25 | .macro FPU_SET_PAIRED_PREC 26 | sts fpscr, r3 27 | mov #0x10, r1 ! PR=0 SZ=1 28 | shll16 r1 29 | lds r1, fpscr 30 | .endm 31 | .macro RESTORE_FPSCR 32 | lds r3, fpscr 33 | .endm 34 | #endif 35 | 36 | ENTRY(memset_sh4) 37 | mov #12,r0 38 | add r6,r4 39 | cmp/gt r6,r0 40 | bt/s 40f ! if it's too small, set a byte at once 41 | mov r4,r0 42 | and #3,r0 43 | cmp/eq #0,r0 44 | bt/s 2f ! It's aligned 45 | sub r0,r6 46 | 1: 47 | dt r0 48 | bf/s 1b 49 | mov.b r5,@-r4 50 | 2: ! make VVVV 51 | extu.b r5,r5 52 | swap.b r5,r0 ! V0 53 | or r0,r5 ! VV 54 | swap.w r5,r0 ! VV00 55 | or r0,r5 ! VVVV 56 | 57 | ! Check if enough bytes need to be copied to be worth the big loop 58 | mov #0x40, r0 ! (MT) 59 | cmp/gt r6,r0 ! (MT) 64 > len => slow loop 60 | 61 | bt/s 22f 62 | mov r6,r0 63 | 64 | ! align the dst to the cache block size if necessary 65 | mov r4, r3 66 | mov #~(0x1f), r1 67 | 68 | and r3, r1 69 | cmp/eq r3, r1 70 | 71 | bt/s 11f ! dst is already aligned 72 | sub r1, r3 ! r3-r1 -> r3 73 | shlr2 r3 ! number of loops 74 | 75 | 10: mov.l r5,@-r4 76 | dt r3 77 | bf/s 10b 78 | add #-4, r6 79 | 80 | 11: ! dst is 32byte aligned 81 | mov r6,r2 82 | mov #-5,r0 83 | shld r0,r2 ! number of loops 84 | 85 | add #-32, r4 86 | mov r5, r0 87 | 88 | #ifdef MEMSET_USES_FPU 89 | lds r5, fpul ! (CO) 90 | fsts fpul, fr0 ! Dr0 will be 'VVVVVVVV' 91 | fsts fpul, fr1 92 | 93 | FPU_SET_PAIRED_PREC 94 | 12: 95 | movca.l r0, @r4 96 | mov.l r5, @(4, r4) 97 | add #32, r4 98 | fmov dr0, @-r4 99 | fmov dr0, @-r4 100 | add #-0x20, r6 101 | fmov dr0, @-r4 102 | dt r2 103 | bf/s 12b 104 | add #-40, r4 105 | 106 | RESTORE_FPSCR 107 | #else 108 | 12: 109 | movca.l r0,@r4 110 | mov.l r5,@(4, r4) 111 | mov.l r5,@(8, r4) 112 | mov.l r5,@(12,r4) 113 | mov.l r5,@(16,r4) 114 | mov.l r5,@(20,r4) 115 | add #-0x20, r6 116 | mov.l r5,@(24,r4) 117 | dt r2 118 | mov.l r5,@(28,r4) 119 | bf/s 12b 120 | add #-32, r4 121 | 122 | #endif 123 | add #32, r4 124 | mov #8, r0 125 | cmp/ge r0, r6 126 | bf 40f 127 | 128 | mov r6,r0 129 | 22: 130 | shlr2 r0 131 | shlr r0 ! r0 = r6 >> 3 132 | 3: 133 | dt r0 134 | mov.l r5,@-r4 ! set 8-byte at once 135 | bf/s 3b 136 | mov.l r5,@-r4 137 | ! 138 | mov #7,r0 139 | and r0,r6 140 | 141 | ! fill bytes (length may be zero) 142 | 40: tst r6,r6 143 | bt 5f 144 | 4: 145 | dt r6 146 | bf/s 4b 147 | mov.b r5,@-r4 148 | 5: 149 | rts 150 | mov r4,r0 151 | -------------------------------------------------------------------------------- /src/input.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by cpasjuste on 03/02/2020. 3 | // 4 | 5 | #ifndef LOADER_INPUT_LINUX_H 6 | #define LOADER_INPUT_LINUX_H 7 | 8 | #define BIT(n) (1U<<(n)) 9 | 10 | #ifdef __LINUX__ 11 | #define INPUT_QUIT BIT(1) 12 | #define INPUT_LEFT BIT(2) 13 | #define INPUT_RIGHT BIT(3) 14 | #define INPUT_UP BIT(4) 15 | #define INPUT_DOWN BIT(5) 16 | #define INPUT_A BIT(6) 17 | #define INPUT_B BIT(7) 18 | #define INPUT_X BIT(8) 19 | #define INPUT_Y BIT(9) 20 | #define INPUT_START BIT(10) 21 | #else 22 | #define INPUT_QUIT BIT(20) 23 | #define INPUT_LEFT CONT_DPAD_LEFT 24 | #define INPUT_RIGHT CONT_DPAD_RIGHT 25 | #define INPUT_UP CONT_DPAD_UP 26 | #define INPUT_DOWN CONT_DPAD_DOWN 27 | #define INPUT_A CONT_A 28 | #define INPUT_B CONT_B 29 | #define INPUT_X CONT_X 30 | #define INPUT_Y CONT_Y 31 | #define INPUT_START CONT_START 32 | #endif 33 | 34 | uint32 get_input(); 35 | 36 | #endif //LOADER_INPUT_LINUX_H 37 | -------------------------------------------------------------------------------- /src/linux/SDL_FontCache.h: -------------------------------------------------------------------------------- 1 | /* 2 | SDL_FontCache v0.10.0: A font cache for SDL and SDL_ttf 3 | by Jonathan Dearborn 4 | Dedicated to the memory of Florian Hufsky 5 | 6 | License: 7 | The short: 8 | Use it however you'd like, but keep the copyright and license notice 9 | whenever these files or parts of them are distributed in uncompiled form. 10 | 11 | The long: 12 | Copyright (c) 2019 Jonathan Dearborn 13 | 14 | Permission is hereby granted, free of charge, to any person obtaining a copy 15 | of this software and associated documentation files (the "Software"), to deal 16 | in the Software without restriction, including without limitation the rights 17 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 18 | copies of the Software, and to permit persons to whom the Software is 19 | furnished to do so, subject to the following conditions: 20 | 21 | The above copyright notice and this permission notice shall be included in 22 | all copies or substantial portions of the Software. 23 | 24 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 27 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 29 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 30 | THE SOFTWARE. 31 | */ 32 | 33 | #ifndef _SDL_FONTCACHE_H__ 34 | #define _SDL_FONTCACHE_H__ 35 | 36 | #include "SDL2/SDL.h" 37 | #include "SDL2/SDL_ttf.h" 38 | 39 | #ifdef FC_USE_SDL_GPU 40 | #include "SDL_gpu.h" 41 | #endif 42 | 43 | 44 | #include 45 | 46 | #ifdef __cplusplus 47 | extern "C" { 48 | #endif 49 | 50 | 51 | // Let's pretend this exists... 52 | #define TTF_STYLE_OUTLINE 16 53 | 54 | 55 | 56 | // Differences between SDL_Renderer and SDL_gpu 57 | #ifdef FC_USE_SDL_GPU 58 | #define FC_Rect GPU_Rect 59 | #define FC_Target GPU_Target 60 | #define FC_Image GPU_Image 61 | #define FC_Log GPU_LogError 62 | #else 63 | #define FC_Rect SDL_Rect 64 | #define FC_Target SDL_Renderer 65 | #define FC_Image SDL_Texture 66 | #define FC_Log SDL_Log 67 | #endif 68 | 69 | 70 | // SDL_FontCache types 71 | 72 | typedef enum 73 | { 74 | FC_ALIGN_LEFT, 75 | FC_ALIGN_CENTER, 76 | FC_ALIGN_RIGHT 77 | } FC_AlignEnum; 78 | 79 | typedef enum 80 | { 81 | FC_FILTER_NEAREST, 82 | FC_FILTER_LINEAR 83 | } FC_FilterEnum; 84 | 85 | typedef struct FC_Scale 86 | { 87 | float x; 88 | float y; 89 | 90 | } FC_Scale; 91 | 92 | typedef struct FC_Effect 93 | { 94 | FC_AlignEnum alignment; 95 | FC_Scale scale; 96 | SDL_Color color; 97 | 98 | } FC_Effect; 99 | 100 | // Opaque type 101 | typedef struct FC_Font FC_Font; 102 | 103 | 104 | typedef struct FC_GlyphData 105 | { 106 | SDL_Rect rect; 107 | int cache_level; 108 | 109 | } FC_GlyphData; 110 | 111 | 112 | 113 | 114 | // Object creation 115 | 116 | FC_Rect FC_MakeRect(float x, float y, float w, float h); 117 | 118 | FC_Scale FC_MakeScale(float x, float y); 119 | 120 | SDL_Color FC_MakeColor(Uint8 r, Uint8 g, Uint8 b, Uint8 a); 121 | 122 | FC_Effect FC_MakeEffect(FC_AlignEnum alignment, FC_Scale scale, SDL_Color color); 123 | 124 | FC_GlyphData FC_MakeGlyphData(int cache_level, Sint16 x, Sint16 y, Uint16 w, Uint16 h); 125 | 126 | 127 | 128 | // Font object 129 | 130 | FC_Font* FC_CreateFont(void); 131 | 132 | #ifdef FC_USE_SDL_GPU 133 | Uint8 FC_LoadFont(FC_Font* font, const char* filename_ttf, Uint32 pointSize, SDL_Color color, int style); 134 | 135 | Uint8 FC_LoadFontFromTTF(FC_Font* font, TTF_Font* ttf, SDL_Color color); 136 | 137 | Uint8 FC_LoadFont_RW(FC_Font* font, SDL_RWops* file_rwops_ttf, Uint8 own_rwops, Uint32 pointSize, SDL_Color color, int style); 138 | #else 139 | Uint8 FC_LoadFont(FC_Font* font, SDL_Renderer* renderer, const char* filename_ttf, Uint32 pointSize, SDL_Color color, int style); 140 | 141 | Uint8 FC_LoadFontFromTTF(FC_Font* font, SDL_Renderer* renderer, TTF_Font* ttf, SDL_Color color); 142 | 143 | Uint8 FC_LoadFont_RW(FC_Font* font, SDL_Renderer* renderer, SDL_RWops* file_rwops_ttf, Uint8 own_rwops, Uint32 pointSize, SDL_Color color, int style); 144 | #endif 145 | 146 | #ifndef FC_USE_SDL_GPU 147 | // note: handle SDL event types SDL_RENDER_TARGETS_RESET(>= SDL 2.0.2) and SDL_RENDER_DEVICE_RESET(>= SDL 2.0.4) 148 | void FC_ResetFontFromRendererReset(FC_Font* font, SDL_Renderer* renderer, Uint32 evType); 149 | #endif 150 | 151 | void FC_ClearFont(FC_Font* font); 152 | 153 | void FC_FreeFont(FC_Font* font); 154 | 155 | 156 | 157 | // Built-in loading strings 158 | 159 | char* FC_GetStringASCII(void); 160 | 161 | char* FC_GetStringLatin1(void); 162 | 163 | char* FC_GetStringASCII_Latin1(void); 164 | 165 | 166 | // UTF-8 to SDL_FontCache codepoint conversion 167 | 168 | /*! 169 | Returns the Uint32 codepoint (not UTF-32) parsed from the given UTF-8 string. 170 | \param c A pointer to a string of proper UTF-8 character values. 171 | \param advance_pointer If true, the source pointer will be incremented to skip the extra bytes from multibyte codepoints. 172 | */ 173 | Uint32 FC_GetCodepointFromUTF8(const char** c, Uint8 advance_pointer); 174 | 175 | /*! 176 | Parses the given codepoint and stores the UTF-8 bytes in 'result'. The result is NULL terminated. 177 | \param result A memory buffer for the UTF-8 values. Must be at least 5 bytes long. 178 | \param codepoint The Uint32 codepoint to parse (not UTF-32). 179 | */ 180 | void FC_GetUTF8FromCodepoint(char* result, Uint32 codepoint); 181 | 182 | 183 | // UTF-8 string operations 184 | 185 | /*! Allocates a new string of 'size' bytes that is already NULL-terminated. The NULL byte counts toward the size limit, as usual. Returns NULL if size is 0. */ 186 | char* U8_alloc(unsigned int size); 187 | 188 | /*! Deallocates the given string. */ 189 | void U8_free(char* string); 190 | 191 | /*! Allocates a copy of the given string. */ 192 | char* U8_strdup(const char* string); 193 | 194 | /*! Returns the number of UTF-8 characters in the given string. */ 195 | int U8_strlen(const char* string); 196 | 197 | /*! Returns the number of bytes in the UTF-8 multibyte character pointed at by 'character'. */ 198 | int U8_charsize(const char* character); 199 | 200 | /*! Copies the source multibyte character into the given buffer without overrunning it. Returns 0 on failure. */ 201 | int U8_charcpy(char* buffer, const char* source, int buffer_size); 202 | 203 | /*! Returns a pointer to the next UTF-8 character. */ 204 | const char* U8_next(const char* string); 205 | 206 | /*! Inserts a UTF-8 string into 'string' at the given position. Use a position of -1 to append. Returns 0 when unable to insert the string. */ 207 | int U8_strinsert(char* string, int position, const char* source, int max_bytes); 208 | 209 | /*! Erases the UTF-8 character at the given position, moving the subsequent characters down. */ 210 | void U8_strdel(char* string, int position); 211 | 212 | 213 | // Internal settings 214 | 215 | /*! Sets the string from which to load the initial glyphs. Use this if you need upfront loading for any reason (such as lack of render-target support). */ 216 | void FC_SetLoadingString(FC_Font* font, const char* string); 217 | 218 | /*! Returns the size of the internal buffer which is used for unpacking variadic text data. This buffer is shared by all FC_Fonts. */ 219 | unsigned int FC_GetBufferSize(void); 220 | 221 | /*! Changes the size of the internal buffer which is used for unpacking variadic text data. This buffer is shared by all FC_Fonts. */ 222 | void FC_SetBufferSize(unsigned int size); 223 | 224 | /*! Returns the width of a single horizontal tab in multiples of the width of a space (default: 4) */ 225 | unsigned int FC_GetTabWidth(void); 226 | 227 | /*! Changes the width of a horizontal tab in multiples of the width of a space (default: 4) */ 228 | void FC_SetTabWidth(unsigned int width_in_spaces); 229 | 230 | void FC_SetRenderCallback(FC_Rect (*callback)(FC_Image* src, FC_Rect* srcrect, FC_Target* dest, float x, float y, float xscale, float yscale)); 231 | 232 | FC_Rect FC_DefaultRenderCallback(FC_Image* src, FC_Rect* srcrect, FC_Target* dest, float x, float y, float xscale, float yscale); 233 | 234 | 235 | // Custom caching 236 | 237 | /*! Returns the number of cache levels that are active. */ 238 | int FC_GetNumCacheLevels(FC_Font* font); 239 | 240 | /*! Returns the cache source texture at the given cache level. */ 241 | FC_Image* FC_GetGlyphCacheLevel(FC_Font* font, int cache_level); 242 | 243 | // TODO: Specify ownership of the texture (should be shareable) 244 | /*! Sets a cache source texture for rendering. New cache levels must be sequential. */ 245 | Uint8 FC_SetGlyphCacheLevel(FC_Font* font, int cache_level, FC_Image* cache_texture); 246 | 247 | /*! Copies the given surface to the given cache level as a texture. New cache levels must be sequential. */ 248 | Uint8 FC_UploadGlyphCache(FC_Font* font, int cache_level, SDL_Surface* data_surface); 249 | 250 | 251 | /*! Returns the number of codepoints that are stored in the font's glyph data map. */ 252 | unsigned int FC_GetNumCodepoints(FC_Font* font); 253 | 254 | /*! Copies the stored codepoints into the given array. */ 255 | void FC_GetCodepoints(FC_Font* font, Uint32* result); 256 | 257 | /*! Stores the glyph data for the given codepoint in 'result'. Returns 0 if the codepoint was not found in the cache. */ 258 | Uint8 FC_GetGlyphData(FC_Font* font, FC_GlyphData* result, Uint32 codepoint); 259 | 260 | /*! Sets the glyph data for the given codepoint. Duplicates are not checked. Returns a pointer to the stored data. */ 261 | FC_GlyphData* FC_SetGlyphData(FC_Font* font, Uint32 codepoint, FC_GlyphData glyph_data); 262 | 263 | 264 | // Rendering 265 | 266 | FC_Rect FC_Draw(FC_Font* font, FC_Target* dest, float x, float y, const char* formatted_text, ...); 267 | FC_Rect FC_DrawAlign(FC_Font* font, FC_Target* dest, float x, float y, FC_AlignEnum align, const char* formatted_text, ...); 268 | FC_Rect FC_DrawScale(FC_Font* font, FC_Target* dest, float x, float y, FC_Scale scale, const char* formatted_text, ...); 269 | FC_Rect FC_DrawColor(FC_Font* font, FC_Target* dest, float x, float y, SDL_Color color, const char* formatted_text, ...); 270 | FC_Rect FC_DrawEffect(FC_Font* font, FC_Target* dest, float x, float y, FC_Effect effect, const char* formatted_text, ...); 271 | 272 | FC_Rect FC_DrawBox(FC_Font* font, FC_Target* dest, FC_Rect box, const char* formatted_text, ...); 273 | FC_Rect FC_DrawBoxAlign(FC_Font* font, FC_Target* dest, FC_Rect box, FC_AlignEnum align, const char* formatted_text, ...); 274 | FC_Rect FC_DrawBoxScale(FC_Font* font, FC_Target* dest, FC_Rect box, FC_Scale scale, const char* formatted_text, ...); 275 | FC_Rect FC_DrawBoxColor(FC_Font* font, FC_Target* dest, FC_Rect box, SDL_Color color, const char* formatted_text, ...); 276 | FC_Rect FC_DrawBoxEffect(FC_Font* font, FC_Target* dest, FC_Rect box, FC_Effect effect, const char* formatted_text, ...); 277 | 278 | FC_Rect FC_DrawColumn(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, const char* formatted_text, ...); 279 | FC_Rect FC_DrawColumnAlign(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, FC_AlignEnum align, const char* formatted_text, ...); 280 | FC_Rect FC_DrawColumnScale(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, FC_Scale scale, const char* formatted_text, ...); 281 | FC_Rect FC_DrawColumnColor(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, SDL_Color color, const char* formatted_text, ...); 282 | FC_Rect FC_DrawColumnEffect(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, FC_Effect effect, const char* formatted_text, ...); 283 | 284 | 285 | // Getters 286 | 287 | FC_FilterEnum FC_GetFilterMode(FC_Font* font); 288 | Uint16 FC_GetLineHeight(FC_Font* font); 289 | Uint16 FC_GetHeight(FC_Font* font, const char* formatted_text, ...); 290 | Uint16 FC_GetWidth(FC_Font* font, const char* formatted_text, ...); 291 | 292 | // Returns a 1-pixel wide box in front of the character in the given position (index) 293 | FC_Rect FC_GetCharacterOffset(FC_Font* font, Uint16 position_index, int column_width, const char* formatted_text, ...); 294 | Uint16 FC_GetColumnHeight(FC_Font* font, Uint16 width, const char* formatted_text, ...); 295 | 296 | int FC_GetAscent(FC_Font* font, const char* formatted_text, ...); 297 | int FC_GetDescent(FC_Font* font, const char* formatted_text, ...); 298 | int FC_GetBaseline(FC_Font* font); 299 | int FC_GetSpacing(FC_Font* font); 300 | int FC_GetLineSpacing(FC_Font* font); 301 | Uint16 FC_GetMaxWidth(FC_Font* font); 302 | SDL_Color FC_GetDefaultColor(FC_Font* font); 303 | 304 | FC_Rect FC_GetBounds(FC_Font* font, float x, float y, FC_AlignEnum align, FC_Scale scale, const char* formatted_text, ...); 305 | 306 | Uint8 FC_InRect(float x, float y, FC_Rect input_rect); 307 | // Given an offset (x,y) from the text draw position (the upper-left corner), returns the character position (UTF-8 index) 308 | Uint16 FC_GetPositionFromOffset(FC_Font* font, float x, float y, int column_width, FC_AlignEnum align, const char* formatted_text, ...); 309 | 310 | // Returns the number of characters in the new wrapped text written into `result`. 311 | int FC_GetWrappedText(FC_Font* font, char* result, int max_result_size, Uint16 width, const char* formatted_text, ...); 312 | 313 | // Setters 314 | 315 | void FC_SetFilterMode(FC_Font* font, FC_FilterEnum filter); 316 | void FC_SetSpacing(FC_Font* font, int LetterSpacing); 317 | void FC_SetLineSpacing(FC_Font* font, int LineSpacing); 318 | void FC_SetDefaultColor(FC_Font* font, SDL_Color color); 319 | 320 | 321 | #ifdef __cplusplus 322 | } 323 | #endif 324 | 325 | 326 | 327 | #endif 328 | -------------------------------------------------------------------------------- /src/linux/drawing.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by cpasjuste on 03/02/2020. 3 | // 4 | 5 | #include 6 | #include "SDL_FontCache.h" 7 | #include "retrodream.h" 8 | #include "drawing.h" 9 | 10 | static SDL_Window *window; 11 | static SDL_Renderer *renderer; 12 | static FC_Font *font; 13 | static int drawing = 0; 14 | 15 | void draw_init() { 16 | 17 | SDL_Init(SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE); 18 | 19 | window = SDL_CreateWindow( 20 | "LOADER", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 21 | 640, 480, SDL_WINDOW_OPENGL); 22 | 23 | renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); 24 | 25 | font = FC_CreateFont(); 26 | FC_LoadFont(font, renderer, "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 27 | DRAW_FONT_HEIGHT, FC_MakeColor(0, 0, 0, 255), TTF_STYLE_NORMAL); 28 | } 29 | 30 | void draw_exit() { 31 | FC_FreeFont(font); 32 | SDL_DestroyRenderer(renderer); 33 | SDL_DestroyWindow(window); 34 | } 35 | 36 | void draw_start() { 37 | if (drawing == 0) { 38 | SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); 39 | SDL_RenderClear(renderer); 40 | drawing = 1; 41 | } 42 | } 43 | 44 | void draw_end() { 45 | if (drawing == 1) { 46 | SDL_RenderPresent(renderer); 47 | drawing = 0; 48 | } 49 | } 50 | 51 | Vec2 draw_get_screen_size() { 52 | return (Vec2) {640, 480}; 53 | } 54 | 55 | void draw_string(float x, float y, float z, Color color, char *str) { 56 | SDL_Color c = {color.r, color.g, color.b, color.a}; 57 | FC_DrawColor(font, renderer, x, y, c, str); 58 | } 59 | 60 | void draw_box(float x, float y, float w, float h, float z, Color color) { 61 | SDL_Rect r = {(int) x, (int) y, (int) w, (int) h}; 62 | SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a); 63 | SDL_RenderFillRect(renderer, &r); 64 | } 65 | 66 | void draw_box_outline(float x, float y, float w, float h, float z, 67 | Color color, Color outline_color, float outline_size) { 68 | draw_box(x - outline_size, y - outline_size, w + (outline_size * 2), h + (outline_size * 2), z - 1, outline_color); 69 | draw_box(x, y, w, h, z, color); 70 | } 71 | 72 | int draw_printf(int level, const char *fmt, ...) { 73 | 74 | char buff[512]; 75 | va_list args; 76 | Color color = COL_WHITE; 77 | Vec2 screenSize = draw_get_screen_size(); 78 | 79 | memset(buff, 0, 512); 80 | va_start(args, fmt); 81 | int ret = vsnprintf(buff, 512, fmt, args); 82 | va_end(args); 83 | 84 | switch (level) { 85 | case DBG_DEAD: 86 | case DBG_ERROR: 87 | case DBG_CRITICAL: 88 | color = COL_RED; 89 | break; 90 | case DBG_WARNING: 91 | color = COL_YELLOW; 92 | default: 93 | break; 94 | } 95 | 96 | draw_start(); 97 | draw_string(16, screenSize.y - DRAW_FONT_HEIGHT - 16, 200, color, buff); 98 | draw_end(); 99 | 100 | return ret; 101 | } 102 | -------------------------------------------------------------------------------- /src/linux/input.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by cpasjuste on 03/02/2020. 3 | // 4 | 5 | #include 6 | #include "retrodream.h" 7 | #include "input.h" 8 | 9 | uint32 get_input() { 10 | 11 | uint32 input = 0; 12 | SDL_Event ev; 13 | 14 | while (SDL_PollEvent(&ev)) { 15 | if (ev.type == SDL_QUIT) { 16 | return INPUT_QUIT; 17 | } 18 | 19 | if (ev.type == SDL_KEYDOWN) { 20 | switch (ev.key.keysym.scancode) { 21 | case SDL_SCANCODE_LEFT: 22 | input |= INPUT_LEFT; 23 | break; 24 | case SDL_SCANCODE_RIGHT: 25 | input |= INPUT_RIGHT; 26 | break; 27 | case SDL_SCANCODE_UP: 28 | input |= INPUT_UP; 29 | break; 30 | case SDL_SCANCODE_DOWN: 31 | input |= INPUT_DOWN; 32 | break; 33 | case SDL_SCANCODE_A: 34 | input |= INPUT_A; 35 | break; 36 | case SDL_SCANCODE_Z: 37 | input |= INPUT_B; 38 | break; 39 | case SDL_SCANCODE_Q: 40 | input |= INPUT_X; 41 | break; 42 | case SDL_SCANCODE_S: 43 | input |= INPUT_Y; 44 | break; 45 | case SDL_SCANCODE_RETURN: 46 | input |= INPUT_START; 47 | break; 48 | default: 49 | break; 50 | } 51 | } 52 | } 53 | 54 | return input; 55 | } 56 | -------------------------------------------------------------------------------- /src/linux/utility.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by cpasjuste on 03/02/2020. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "retrodream.h" 11 | #include "uthash/utlist.h" 12 | #include "utility.h" 13 | 14 | int file_exists(const char *fn) { 15 | struct stat st; 16 | return (stat(fn, &st) == 0); 17 | } 18 | 19 | int dir_exists(const char *dir) { 20 | return file_exists(dir); 21 | } 22 | 23 | void get_dir(List *list, const char *path) { 24 | 25 | DIR *dir; 26 | struct dirent *ent; 27 | ListItem *entry; 28 | 29 | memset(list, 0, sizeof(List)); 30 | strncpy(list->path, path, MAX_PATH - 1); 31 | 32 | if ((dir = opendir(path)) != NULL) { 33 | while ((ent = readdir(dir)) != NULL) { 34 | 35 | // skip "." 36 | if (ent->d_name[0] == '.') { 37 | continue; 38 | } 39 | 40 | entry = (ListItem *) malloc(sizeof *entry); 41 | memset(entry, 0, sizeof(ListItem)); 42 | 43 | strncpy(entry->name, ent->d_name, MAX_PATH - 1); 44 | if (list->path[strlen(list->path) - 1] != '/') { 45 | snprintf(entry->path, MAX_PATH - 1, "%s/%s", list->path, ent->d_name); 46 | } else { 47 | snprintf(entry->path, MAX_PATH - 1, "%s%s", list->path, ent->d_name); 48 | } 49 | 50 | struct stat st; 51 | if (stat(entry->path, &st) == 0) { 52 | entry->type = S_ISDIR(st.st_mode) ? TYPE_DIR : TYPE_FILE; 53 | } 54 | 55 | DL_APPEND(list->head, entry); 56 | list->size++; 57 | } 58 | 59 | DL_SORT(list->head, list_cmp); 60 | closedir(dir); 61 | } 62 | } 63 | 64 | char *read_file(const char *file) { 65 | 66 | size_t size; 67 | FILE *fp = NULL; 68 | char *buffer = NULL; 69 | 70 | fp = fopen(file, "rb"); 71 | if (fp == NULL) { 72 | printf("read_file: can't open %s\n", file); 73 | return NULL; 74 | } 75 | 76 | fseek(fp, 0L, SEEK_END); 77 | size = ftell(fp); 78 | fseek(fp, 0L, SEEK_SET); 79 | buffer = (char *) malloc(size); 80 | memset(buffer, 0, size); 81 | 82 | if (fread(buffer, 1, size, fp) != size) { 83 | fclose(fp); 84 | free(buffer); 85 | printf("read_file: can't read %s\n", file); 86 | return NULL; 87 | } 88 | 89 | fclose(fp); 90 | 91 | return buffer; 92 | } 93 | 94 | int flash_get_region() { 95 | return 0; 96 | } 97 | 98 | 99 | int is_hacked_bios() { 100 | return 0; 101 | } 102 | 103 | int is_custom_bios() { 104 | return 0; 105 | } 106 | 107 | int is_no_syscalls() { 108 | return 0; 109 | } 110 | 111 | void loader_init() { 112 | printf("loader_init\n"); 113 | } 114 | 115 | void dc_load_serial(void) { 116 | printf("dc_load_serial\n"); 117 | } 118 | 119 | void dc_load_ip(void) { 120 | printf("dc_load_ip\n"); 121 | } 122 | 123 | void exec(const char *path) { 124 | printf("exec(%s)\n", path); 125 | } 126 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by cpasjuste on 28/01/2020. 3 | // 4 | 5 | #include "retrodream.h" 6 | #include "menu.h" 7 | #include "input.h" 8 | #include "utility.h" 9 | #include "drawing.h" 10 | 11 | int main(int argc, char **argv) { 12 | 13 | uint32 keys = get_input(); 14 | if (keys & INPUT_A && keys & INPUT_B) { 15 | dc_load_serial(); 16 | } else if (keys & INPUT_X && keys & INPUT_Y) { 17 | dc_load_ip(); 18 | } 19 | 20 | draw_init(); 21 | loader_init(); 22 | 23 | if (keys & INPUT_START) { 24 | menu_run(); 25 | } else { 26 | #ifndef __DEBUG_EMU__ 27 | try_boot(); 28 | #endif 29 | menu_run(); 30 | } 31 | 32 | draw_exit(); 33 | 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /src/menu.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by cpasjuste on 28/01/2020. 3 | // 4 | 5 | #include 6 | #include 7 | #include "uthash/utlist.h" 8 | #include "retrodream.h" 9 | #include "retrolog.h" 10 | #include "input.h" 11 | #include "drawing.h" 12 | #include "utility.h" 13 | #include "menu.h" 14 | 15 | static char dreamboot_version[MAX_PATH]; 16 | static int menu_id = MENU_MAIN; 17 | static int line_height = 0; 18 | static int line_max = 0; 19 | static int list_index = 0; 20 | static int highlight_index = 0; 21 | static Rect menuRect; 22 | static Rect pathRect; 23 | static Rect filerRect; 24 | static List menuList = {NULL, 0, "BOOT MENU"}; 25 | static List fileList; 26 | extern List logList; 27 | 28 | static void menu_main_add_item(const char *name, int menu_id) { 29 | ListItem *item = (ListItem *) malloc(sizeof *item); 30 | memset(item, 0, sizeof(ListItem)); 31 | item->type = menu_id; 32 | strcpy(item->name, name); 33 | DL_APPEND(menuList.head, item); 34 | menuList.size++; 35 | } 36 | 37 | static void menu_init() { 38 | 39 | Vec2 screenSize = draw_get_screen_size(); 40 | 41 | menuRect = (Rect) {32, 32, screenSize.x - 64, screenSize.y - 64}; 42 | 43 | pathRect = (Rect) {menuRect.left + 8, menuRect.top + 8, 44 | menuRect.width - 16, DRAW_FONT_HEIGHT + 16}; 45 | 46 | filerRect = (Rect) {menuRect.left + 8, pathRect.top + pathRect.height + 10, 47 | menuRect.width - 16, menuRect.height - pathRect.height - 26}; 48 | 49 | line_height = DRAW_FONT_HEIGHT + DRAW_FONT_LINE_SPACING; 50 | line_max = (int) filerRect.height / line_height; 51 | if (line_max * line_height < (int) filerRect.height) { 52 | line_height = (int) filerRect.height / line_max; 53 | } 54 | 55 | // build main menu 56 | menu_main_add_item("FILE BROWSER", MENU_FILER); 57 | menu_main_add_item("DCLOAD SERIAL", MENU_DCLOAD_SERIAL); 58 | menu_main_add_item("DCLOAD IP", MENU_DCLOAD_IP); 59 | menu_main_add_item("VIEW LOGS", MENU_LOGS); 60 | 61 | sprintf(dreamboot_version, "DREAMBOOT v%s @ CPASJUSTE", __DB_VERSION__); 62 | } 63 | 64 | static void menu_get_dir(char *path) { 65 | 66 | list_index = 0; 67 | highlight_index = 0; 68 | 69 | free_dir(&fileList); 70 | get_dir(&fileList, path); 71 | } 72 | 73 | static List *menu_get_list() { 74 | 75 | List *list = &menuList; 76 | if (menu_id == MENU_FILER) { 77 | list = &fileList; 78 | } else if (menu_id == MENU_LOGS) { 79 | list = &logList; 80 | } 81 | return list; 82 | } 83 | 84 | static void menu_draw_main() { 85 | 86 | List *list = &menuList; 87 | 88 | Rect topRect = (Rect) {menuRect.left + 160, menuRect.top + 96, 89 | menuRect.width - 320, DRAW_FONT_HEIGHT + 16}; 90 | 91 | Rect mainRect = (Rect) {topRect.left, topRect.top + topRect.height + 16, 92 | topRect.width, (DRAW_FONT_HEIGHT + DRAW_FONT_LINE_SPACING + 2) * (float) list->size}; 93 | 94 | draw_box_outline(topRect.left, topRect.top, topRect.width, topRect.height, 95 | 100, COL_BLUE, COL_YELLOW, 4); 96 | 97 | draw_string(topRect.left + 70, topRect.top + (topRect.height / 2) - (DRAW_FONT_HEIGHT / 2) + 2, 98 | 103, COL_RED, list->path); 99 | 100 | draw_box_outline(mainRect.left, mainRect.top, mainRect.width, mainRect.height, 101 | 100, COL_BLUE, COL_RED, 4); 102 | 103 | for (int i = 0; i < (unsigned int) line_max; i++) { 104 | 105 | if (list_index + i < list->size) { 106 | 107 | if (i == highlight_index) { 108 | draw_box_outline(mainRect.left, mainRect.top + ((float) (i * line_height)), 109 | mainRect.width, (float) line_height, 110 | 102, COL_RED, COL_WHITE, 2); 111 | } 112 | 113 | ListItem *item = get_item(list, list_index + i); 114 | if (item != NULL) { 115 | draw_string(mainRect.left + 4, 116 | mainRect.top + (DRAW_FONT_LINE_SPACING / 2) + ((float) (i * line_height)) + 2, 117 | 103, COL_WHITE, item->name); 118 | } 119 | } 120 | } 121 | 122 | // version 123 | draw_string(16, draw_get_screen_size().y - DRAW_FONT_HEIGHT - 16, 124 | 103, COL_RED, "DREAMBOOT BOOTLOADER v"__DB_VERSION__ " @ CPASJUSTE"); 125 | } 126 | 127 | static void menu_draw() { 128 | 129 | if (menu_id == MENU_MAIN) { 130 | menu_draw_main(); 131 | return; 132 | } 133 | 134 | List *list = menu_get_list(); 135 | 136 | draw_box_outline(pathRect.left, pathRect.top, pathRect.width, pathRect.height, 137 | 100, COL_BLUE, COL_YELLOW, 4); 138 | draw_string(pathRect.left + 4, pathRect.top + (DRAW_FONT_LINE_SPACING / 2) + 6, 103, COL_RED, list->path); 139 | 140 | draw_box_outline(filerRect.left, filerRect.top, filerRect.width, filerRect.height, 141 | 100, COL_BLUE, COL_RED, 4); 142 | 143 | for (int i = 0; i < (unsigned int) line_max; i++) { 144 | 145 | if (list_index + i < list->size) { 146 | 147 | if (menu_id == MENU_FILER && i == highlight_index) { 148 | draw_box_outline(filerRect.left, filerRect.top + ((float) (i * line_height)), 149 | filerRect.width, (float) line_height, 150 | 102, COL_RED, COL_WHITE, 2); 151 | } 152 | 153 | ListItem *item = get_item(list, list_index + i); 154 | if (item != NULL) { 155 | Color color = COL_WHITE; 156 | if ((menu_id == MENU_FILER && item->type == TYPE_DIR) 157 | || (menu_id == MENU_LOGS && item->type == TYPE_BIN)) { 158 | color = COL_YELLOW; 159 | } else if (menu_id == MENU_LOGS && item->type == TYPE_DIR) { 160 | color = COL_RED; 161 | } 162 | draw_string(filerRect.left + 4, 163 | filerRect.top + (DRAW_FONT_LINE_SPACING / 2) + ((float) (i * line_height)), 164 | 103, color, item->name); 165 | } 166 | } 167 | } 168 | } 169 | 170 | static int menu_input() { 171 | 172 | uint32 input = get_input(); 173 | List *list = menu_get_list(); 174 | 175 | if (input & INPUT_QUIT) { 176 | return INPUT_QUIT; 177 | } 178 | 179 | if (input & INPUT_UP) { 180 | if (highlight_index <= line_max / 2 && list_index > 0) { 181 | list_index--; 182 | } else { 183 | highlight_index--; 184 | if (highlight_index < 0) { 185 | highlight_index = line_max / 2; 186 | if (highlight_index >= list->size) { 187 | highlight_index = list->size - 1; 188 | list_index = 0; 189 | } else { 190 | list_index = (list->size - 1) - highlight_index; 191 | } 192 | } 193 | } 194 | } else if (input & INPUT_DOWN) { 195 | if (highlight_index >= line_max / 2) { 196 | list_index++; 197 | if (list_index + highlight_index >= list->size) { 198 | list_index = 0; 199 | highlight_index = 0; 200 | } 201 | } else { 202 | highlight_index++; 203 | if (highlight_index >= list->size) { 204 | highlight_index = 0; 205 | } 206 | } 207 | } 208 | 209 | if (menu_id == MENU_MAIN) { 210 | if (input & INPUT_A) { 211 | ListItem *item = get_item(list, list_index + highlight_index); 212 | if (item != NULL) { 213 | if (item->type == MENU_FILER) { 214 | menu_id = MENU_FILER; 215 | menu_get_dir("/"); 216 | } else if (item->type == MENU_LOGS) { 217 | list_index = 0; 218 | highlight_index = 0; 219 | menu_id = MENU_LOGS; 220 | } else if (item->type == MENU_DCLOAD_IP) { 221 | dc_load_ip(); 222 | } else if (item->type == MENU_DCLOAD_SERIAL) { 223 | dc_load_serial(); 224 | } 225 | } 226 | } 227 | } else if (menu_id == MENU_LOGS) { 228 | if (input & INPUT_B) { 229 | list_index = 0; 230 | highlight_index = 0; 231 | menu_id = MENU_MAIN; 232 | } 233 | } else if (menu_id == MENU_FILER) { 234 | if (input & INPUT_A) { 235 | ListItem *file = get_item(list, list_index + highlight_index); 236 | if (file != NULL) { 237 | if (file->type == TYPE_DIR) { 238 | menu_get_dir(file->path); 239 | } else if (file->type == TYPE_BIN) { 240 | exec(file->path); 241 | } 242 | } 243 | } else if (input & INPUT_B) { 244 | if (strlen(list->path) > 1) { 245 | char *pos = strrchr(list->path, '/'); 246 | if (pos != NULL) { 247 | if (strlen(pos) == 1) { 248 | menu_get_dir("/"); 249 | } else { 250 | char prev[MAX_PATH]; 251 | memset(prev, 0, MAX_PATH); 252 | strncpy(prev, list->path, strlen(list->path) - strlen(pos) + 1); 253 | menu_get_dir(prev); 254 | } 255 | } 256 | } else { 257 | list_index = 0; 258 | highlight_index = 0; 259 | menu_id = MENU_MAIN; 260 | } 261 | } 262 | } 263 | 264 | return 0; 265 | } 266 | 267 | void menu_run() { 268 | 269 | uint32 input = 0; 270 | 271 | menu_init(); 272 | 273 | while (1) { 274 | 275 | input = menu_input(); 276 | if (input & INPUT_QUIT) { 277 | break; 278 | } 279 | 280 | draw_start(); 281 | 282 | menu_draw(); 283 | 284 | draw_end(); 285 | } 286 | } 287 | -------------------------------------------------------------------------------- /src/menu.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by cpasjuste on 28/01/2020. 3 | // 4 | 5 | #ifndef LOADER_MENU_H 6 | #define LOADER_MENU_H 7 | 8 | enum Menu { 9 | MENU_MAIN, 10 | MENU_FILER, 11 | MENU_DCLOAD_SERIAL, 12 | MENU_DCLOAD_IP, 13 | MENU_LOGS 14 | }; 15 | 16 | void menu_run(); 17 | 18 | #endif //LOADER_MENU_H 19 | -------------------------------------------------------------------------------- /src/retrodream.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by cpasjuste on 03/02/2020. 3 | // 4 | 5 | #ifndef LOADER_CROSS_H 6 | #define LOADER_CROSS_H 7 | 8 | #ifdef __LINUX__ 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | typedef uint8_t uint8; 15 | typedef uint32_t uint32; 16 | 17 | #define DBG_DEAD 0 18 | #define DBG_CRITICAL 1 19 | #define DBG_ERROR 2 20 | #define DBG_WARNING 3 21 | #define DBG_NOTICE 4 22 | #define DBG_INFO 5 23 | #define DBG_DEBUG 6 24 | #define DBG_KDEBUG 7 25 | 26 | #else 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | #endif 33 | 34 | #define ROMDISK_PATH "/rd" 35 | 36 | #endif //LOADER_CROSS_H 37 | -------------------------------------------------------------------------------- /src/retrolog.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by cpasjuste on 05/02/2020. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "retrodream.h" 10 | #include "uthash/utlist.h" 11 | #include "utility.h" 12 | #include "drawing.h" 13 | 14 | List logList = {NULL, 0, "LOGS"}; 15 | 16 | void retro_log(int level, const char *fmt, ...) { 17 | 18 | ListItem *item; 19 | va_list args; 20 | 21 | item = (ListItem *) malloc(sizeof *item); 22 | memset(item, 0, sizeof(ListItem)); 23 | 24 | switch (level) { 25 | case DBG_DEAD: 26 | case DBG_CRITICAL: 27 | case DBG_ERROR: 28 | item->type = TYPE_DIR; 29 | break; 30 | case DBG_WARNING: 31 | item->type = TYPE_BIN; 32 | break; 33 | 34 | default: 35 | item->type = TYPE_FILE; 36 | break; 37 | } 38 | 39 | va_start(args, fmt); 40 | vsnprintf(item->name, MAX_PATH, fmt, args); 41 | va_end(args); 42 | 43 | DL_APPEND(logList.head, item); 44 | logList.size++; 45 | 46 | // debug to screen too 47 | draw_printf(level, item->name); 48 | } 49 | -------------------------------------------------------------------------------- /src/retrolog.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by cpasjuste on 05/02/2020. 3 | // 4 | 5 | #ifndef DREAMBOOT_RETROLOG_H 6 | #define DREAMBOOT_RETROLOG_H 7 | 8 | void retro_log(int level, const char *fmt, ...); 9 | 10 | #ifndef __DEBUG_EMU__ 11 | #define dbglog(lv, fmt, ...) retro_log(lv, fmt, ##__VA_ARGS__) 12 | #endif 13 | 14 | #endif //DREAMBOOT_RETROLOG_H 15 | -------------------------------------------------------------------------------- /src/uthash/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2005-2018, Troy D. Hanson http://troydhanson.github.com/uthash/ 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | 10 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 11 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 12 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 13 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 14 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 15 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 16 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 17 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 18 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 19 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 20 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 21 | 22 | -------------------------------------------------------------------------------- /src/uthash/utarray.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2008-2018, Troy D. Hanson http://troydhanson.github.com/uthash/ 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 12 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 13 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 14 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 15 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 16 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 17 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 18 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 19 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 20 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | 24 | /* a dynamic array implementation using macros 25 | */ 26 | #ifndef UTARRAY_H 27 | #define UTARRAY_H 28 | 29 | #define UTARRAY_VERSION 2.1.0 30 | 31 | #include /* size_t */ 32 | #include /* memset, etc */ 33 | #include /* exit */ 34 | 35 | #ifdef __GNUC__ 36 | #define UTARRAY_UNUSED __attribute__((__unused__)) 37 | #else 38 | #define UTARRAY_UNUSED 39 | #endif 40 | 41 | #ifdef oom 42 | #error "The name of macro 'oom' has been changed to 'utarray_oom'. Please update your code." 43 | #define utarray_oom() oom() 44 | #endif 45 | 46 | #ifndef utarray_oom 47 | #define utarray_oom() exit(-1) 48 | #endif 49 | 50 | typedef void (ctor_f)(void *dst, const void *src); 51 | typedef void (dtor_f)(void *elt); 52 | typedef void (init_f)(void *elt); 53 | typedef struct { 54 | size_t sz; 55 | init_f *init; 56 | ctor_f *copy; 57 | dtor_f *dtor; 58 | } UT_icd; 59 | 60 | typedef struct { 61 | unsigned i,n;/* i: index of next available slot, n: num slots */ 62 | UT_icd icd; /* initializer, copy and destructor functions */ 63 | char *d; /* n slots of size icd->sz*/ 64 | } UT_array; 65 | 66 | #define utarray_init(a,_icd) do { \ 67 | memset(a,0,sizeof(UT_array)); \ 68 | (a)->icd = *(_icd); \ 69 | } while(0) 70 | 71 | #define utarray_done(a) do { \ 72 | if ((a)->n) { \ 73 | if ((a)->icd.dtor) { \ 74 | unsigned _ut_i; \ 75 | for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \ 76 | (a)->icd.dtor(utarray_eltptr(a,_ut_i)); \ 77 | } \ 78 | } \ 79 | free((a)->d); \ 80 | } \ 81 | (a)->n=0; \ 82 | } while(0) 83 | 84 | #define utarray_new(a,_icd) do { \ 85 | (a) = (UT_array*)malloc(sizeof(UT_array)); \ 86 | if ((a) == NULL) { \ 87 | utarray_oom(); \ 88 | } \ 89 | utarray_init(a,_icd); \ 90 | } while(0) 91 | 92 | #define utarray_free(a) do { \ 93 | utarray_done(a); \ 94 | free(a); \ 95 | } while(0) 96 | 97 | #define utarray_reserve(a,by) do { \ 98 | if (((a)->i+(by)) > (a)->n) { \ 99 | char *utarray_tmp; \ 100 | while (((a)->i+(by)) > (a)->n) { (a)->n = ((a)->n ? (2*(a)->n) : 8); } \ 101 | utarray_tmp=(char*)realloc((a)->d, (a)->n*(a)->icd.sz); \ 102 | if (utarray_tmp == NULL) { \ 103 | utarray_oom(); \ 104 | } \ 105 | (a)->d=utarray_tmp; \ 106 | } \ 107 | } while(0) 108 | 109 | #define utarray_push_back(a,p) do { \ 110 | utarray_reserve(a,1); \ 111 | if ((a)->icd.copy) { (a)->icd.copy( _utarray_eltptr(a,(a)->i++), p); } \ 112 | else { memcpy(_utarray_eltptr(a,(a)->i++), p, (a)->icd.sz); }; \ 113 | } while(0) 114 | 115 | #define utarray_pop_back(a) do { \ 116 | if ((a)->icd.dtor) { (a)->icd.dtor( _utarray_eltptr(a,--((a)->i))); } \ 117 | else { (a)->i--; } \ 118 | } while(0) 119 | 120 | #define utarray_extend_back(a) do { \ 121 | utarray_reserve(a,1); \ 122 | if ((a)->icd.init) { (a)->icd.init(_utarray_eltptr(a,(a)->i)); } \ 123 | else { memset(_utarray_eltptr(a,(a)->i),0,(a)->icd.sz); } \ 124 | (a)->i++; \ 125 | } while(0) 126 | 127 | #define utarray_len(a) ((a)->i) 128 | 129 | #define utarray_eltptr(a,j) (((j) < (a)->i) ? _utarray_eltptr(a,j) : NULL) 130 | #define _utarray_eltptr(a,j) ((void*)((a)->d + ((a)->icd.sz * (j)))) 131 | 132 | #define utarray_insert(a,p,j) do { \ 133 | if ((j) > (a)->i) utarray_resize(a,j); \ 134 | utarray_reserve(a,1); \ 135 | if ((j) < (a)->i) { \ 136 | memmove( _utarray_eltptr(a,(j)+1), _utarray_eltptr(a,j), \ 137 | ((a)->i - (j))*((a)->icd.sz)); \ 138 | } \ 139 | if ((a)->icd.copy) { (a)->icd.copy( _utarray_eltptr(a,j), p); } \ 140 | else { memcpy(_utarray_eltptr(a,j), p, (a)->icd.sz); }; \ 141 | (a)->i++; \ 142 | } while(0) 143 | 144 | #define utarray_inserta(a,w,j) do { \ 145 | if (utarray_len(w) == 0) break; \ 146 | if ((j) > (a)->i) utarray_resize(a,j); \ 147 | utarray_reserve(a,utarray_len(w)); \ 148 | if ((j) < (a)->i) { \ 149 | memmove(_utarray_eltptr(a,(j)+utarray_len(w)), \ 150 | _utarray_eltptr(a,j), \ 151 | ((a)->i - (j))*((a)->icd.sz)); \ 152 | } \ 153 | if ((a)->icd.copy) { \ 154 | unsigned _ut_i; \ 155 | for(_ut_i=0;_ut_i<(w)->i;_ut_i++) { \ 156 | (a)->icd.copy(_utarray_eltptr(a, (j) + _ut_i), _utarray_eltptr(w, _ut_i)); \ 157 | } \ 158 | } else { \ 159 | memcpy(_utarray_eltptr(a,j), _utarray_eltptr(w,0), \ 160 | utarray_len(w)*((a)->icd.sz)); \ 161 | } \ 162 | (a)->i += utarray_len(w); \ 163 | } while(0) 164 | 165 | #define utarray_resize(dst,num) do { \ 166 | unsigned _ut_i; \ 167 | if ((dst)->i > (unsigned)(num)) { \ 168 | if ((dst)->icd.dtor) { \ 169 | for (_ut_i = (num); _ut_i < (dst)->i; ++_ut_i) { \ 170 | (dst)->icd.dtor(_utarray_eltptr(dst, _ut_i)); \ 171 | } \ 172 | } \ 173 | } else if ((dst)->i < (unsigned)(num)) { \ 174 | utarray_reserve(dst, (num) - (dst)->i); \ 175 | if ((dst)->icd.init) { \ 176 | for (_ut_i = (dst)->i; _ut_i < (unsigned)(num); ++_ut_i) { \ 177 | (dst)->icd.init(_utarray_eltptr(dst, _ut_i)); \ 178 | } \ 179 | } else { \ 180 | memset(_utarray_eltptr(dst, (dst)->i), 0, (dst)->icd.sz*((num) - (dst)->i)); \ 181 | } \ 182 | } \ 183 | (dst)->i = (num); \ 184 | } while(0) 185 | 186 | #define utarray_concat(dst,src) do { \ 187 | utarray_inserta(dst, src, utarray_len(dst)); \ 188 | } while(0) 189 | 190 | #define utarray_erase(a,pos,len) do { \ 191 | if ((a)->icd.dtor) { \ 192 | unsigned _ut_i; \ 193 | for (_ut_i = 0; _ut_i < (len); _ut_i++) { \ 194 | (a)->icd.dtor(utarray_eltptr(a, (pos) + _ut_i)); \ 195 | } \ 196 | } \ 197 | if ((a)->i > ((pos) + (len))) { \ 198 | memmove(_utarray_eltptr(a, pos), _utarray_eltptr(a, (pos) + (len)), \ 199 | ((a)->i - ((pos) + (len))) * (a)->icd.sz); \ 200 | } \ 201 | (a)->i -= (len); \ 202 | } while(0) 203 | 204 | #define utarray_renew(a,u) do { \ 205 | if (a) utarray_clear(a); \ 206 | else utarray_new(a, u); \ 207 | } while(0) 208 | 209 | #define utarray_clear(a) do { \ 210 | if ((a)->i > 0) { \ 211 | if ((a)->icd.dtor) { \ 212 | unsigned _ut_i; \ 213 | for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \ 214 | (a)->icd.dtor(_utarray_eltptr(a, _ut_i)); \ 215 | } \ 216 | } \ 217 | (a)->i = 0; \ 218 | } \ 219 | } while(0) 220 | 221 | #define utarray_sort(a,cmp) do { \ 222 | qsort((a)->d, (a)->i, (a)->icd.sz, cmp); \ 223 | } while(0) 224 | 225 | #define utarray_find(a,v,cmp) bsearch((v),(a)->d,(a)->i,(a)->icd.sz,cmp) 226 | 227 | #define utarray_front(a) (((a)->i) ? (_utarray_eltptr(a,0)) : NULL) 228 | #define utarray_next(a,e) (((e)==NULL) ? utarray_front(a) : (((a)->i != utarray_eltidx(a,e)+1) ? _utarray_eltptr(a,utarray_eltidx(a,e)+1) : NULL)) 229 | #define utarray_prev(a,e) (((e)==NULL) ? utarray_back(a) : ((utarray_eltidx(a,e) != 0) ? _utarray_eltptr(a,utarray_eltidx(a,e)-1) : NULL)) 230 | #define utarray_back(a) (((a)->i) ? (_utarray_eltptr(a,(a)->i-1)) : NULL) 231 | #define utarray_eltidx(a,e) (((char*)(e) - (a)->d) / (a)->icd.sz) 232 | 233 | /* last we pre-define a few icd for common utarrays of ints and strings */ 234 | static void utarray_str_cpy(void *dst, const void *src) { 235 | char **_src = (char**)src, **_dst = (char**)dst; 236 | *_dst = (*_src == NULL) ? NULL : strdup(*_src); 237 | } 238 | static void utarray_str_dtor(void *elt) { 239 | char **eltc = (char**)elt; 240 | if (*eltc != NULL) free(*eltc); 241 | } 242 | static const UT_icd ut_str_icd UTARRAY_UNUSED = {sizeof(char*),NULL,utarray_str_cpy,utarray_str_dtor}; 243 | static const UT_icd ut_int_icd UTARRAY_UNUSED = {sizeof(int),NULL,NULL,NULL}; 244 | static const UT_icd ut_ptr_icd UTARRAY_UNUSED = {sizeof(void*),NULL,NULL,NULL}; 245 | 246 | 247 | #endif /* UTARRAY_H */ 248 | -------------------------------------------------------------------------------- /src/uthash/utringbuffer.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015-2018, Troy D. Hanson http://troydhanson.github.com/uthash/ 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 12 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 13 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 14 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 15 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 16 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 17 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 18 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 19 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 20 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | 24 | /* a ring-buffer implementation using macros 25 | */ 26 | #ifndef UTRINGBUFFER_H 27 | #define UTRINGBUFFER_H 28 | 29 | #define UTRINGBUFFER_VERSION 2.1.0 30 | 31 | #include 32 | #include 33 | #include "utarray.h" // for "UT_icd" 34 | 35 | typedef struct { 36 | unsigned i; /* index of next available slot; wraps at n */ 37 | unsigned n; /* capacity */ 38 | unsigned char f; /* full */ 39 | UT_icd icd; /* initializer, copy and destructor functions */ 40 | char *d; /* n slots of size icd->sz */ 41 | } UT_ringbuffer; 42 | 43 | #define utringbuffer_init(a, _n, _icd) do { \ 44 | memset(a, 0, sizeof(UT_ringbuffer)); \ 45 | (a)->icd = *(_icd); \ 46 | (a)->n = (_n); \ 47 | if ((a)->n) { (a)->d = (char*)malloc((a)->n * (_icd)->sz); } \ 48 | } while(0) 49 | 50 | #define utringbuffer_clear(a) do { \ 51 | if ((a)->icd.dtor) { \ 52 | if ((a)->f) { \ 53 | unsigned _ut_i; \ 54 | for (_ut_i = 0; _ut_i < (a)->n; ++_ut_i) { \ 55 | (a)->icd.dtor(utringbuffer_eltptr(a, _ut_i)); \ 56 | } \ 57 | } else { \ 58 | unsigned _ut_i; \ 59 | for (_ut_i = 0; _ut_i < (a)->i; ++_ut_i) { \ 60 | (a)->icd.dtor(utringbuffer_eltptr(a, _ut_i)); \ 61 | } \ 62 | } \ 63 | } \ 64 | (a)->i = 0; \ 65 | (a)->f = 0; \ 66 | } while(0) 67 | 68 | #define utringbuffer_done(a) do { \ 69 | utringbuffer_clear(a); \ 70 | free((a)->d); (a)->d = NULL; \ 71 | (a)->n = 0; \ 72 | } while(0) 73 | 74 | #define utringbuffer_new(a,n,_icd) do { \ 75 | a = (UT_ringbuffer*)malloc(sizeof(UT_ringbuffer)); \ 76 | utringbuffer_init(a, n, _icd); \ 77 | } while(0) 78 | 79 | #define utringbuffer_free(a) do { \ 80 | utringbuffer_done(a); \ 81 | free(a); \ 82 | } while(0) 83 | 84 | #define utringbuffer_push_back(a,p) do { \ 85 | if ((a)->icd.dtor && (a)->f) { (a)->icd.dtor(_utringbuffer_internalptr(a,(a)->i)); } \ 86 | if ((a)->icd.copy) { (a)->icd.copy( _utringbuffer_internalptr(a,(a)->i), p); } \ 87 | else { memcpy(_utringbuffer_internalptr(a,(a)->i), p, (a)->icd.sz); }; \ 88 | if (++(a)->i == (a)->n) { (a)->i = 0; (a)->f = 1; } \ 89 | } while(0) 90 | 91 | #define utringbuffer_len(a) ((a)->f ? (a)->n : (a)->i) 92 | #define utringbuffer_empty(a) ((a)->i == 0 && !(a)->f) 93 | #define utringbuffer_full(a) ((a)->f != 0) 94 | 95 | #define _utringbuffer_real_idx(a,j) ((a)->f ? ((j) + (a)->i) % (a)->n : (j)) 96 | #define _utringbuffer_internalptr(a,j) ((void*)((a)->d + ((a)->icd.sz * (j)))) 97 | #define utringbuffer_eltptr(a,j) ((0 <= (j) && (j) < utringbuffer_len(a)) ? _utringbuffer_internalptr(a,_utringbuffer_real_idx(a,j)) : NULL) 98 | 99 | #define _utringbuffer_fake_idx(a,j) ((a)->f ? ((j) + (a)->n - (a)->i) % (a)->n : (j)) 100 | #define _utringbuffer_internalidx(a,e) (((char*)(e) >= (a)->d) ? (((char*)(e) - (a)->d)/(a)->icd.sz) : -1) 101 | #define utringbuffer_eltidx(a,e) _utringbuffer_fake_idx(a, _utringbuffer_internalidx(a,e)) 102 | 103 | #define utringbuffer_front(a) utringbuffer_eltptr(a,0) 104 | #define utringbuffer_next(a,e) ((e)==NULL ? utringbuffer_front(a) : utringbuffer_eltptr(a, utringbuffer_eltidx(a,e)+1)) 105 | #define utringbuffer_prev(a,e) ((e)==NULL ? utringbuffer_back(a) : utringbuffer_eltptr(a, utringbuffer_eltidx(a,e)-1)) 106 | #define utringbuffer_back(a) (utringbuffer_empty(a) ? NULL : utringbuffer_eltptr(a, utringbuffer_len(a) - 1)) 107 | 108 | #endif /* UTRINGBUFFER_H */ 109 | -------------------------------------------------------------------------------- /src/uthash/utstack.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2018-2018, Troy D. Hanson http://troydhanson.github.com/uthash/ 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 12 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 13 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 14 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 15 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 16 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 17 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 18 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 19 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 20 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | 24 | #ifndef UTSTACK_H 25 | #define UTSTACK_H 26 | 27 | #define UTSTACK_VERSION 2.1.0 28 | 29 | /* 30 | * This file contains macros to manipulate a singly-linked list as a stack. 31 | * 32 | * To use utstack, your structure must have a "next" pointer. 33 | * 34 | * ----------------.EXAMPLE ------------------------- 35 | * struct item { 36 | * int id; 37 | * struct item *next; 38 | * } 39 | * 40 | * struct item *stack = NULL: 41 | * 42 | * int main() { 43 | * int count; 44 | * struct item *tmp; 45 | * struct item *item = malloc(sizeof *item); 46 | * item->id = 42; 47 | * STACK_COUNT(stack, tmp, count); assert(count == 0); 48 | * STACK_PUSH(stack, item); 49 | * STACK_COUNT(stack, tmp, count); assert(count == 1); 50 | * STACK_POP(stack, item); 51 | * free(item); 52 | * STACK_COUNT(stack, tmp, count); assert(count == 0); 53 | * } 54 | * -------------------------------------------------- 55 | */ 56 | 57 | #define STACK_TOP(head) (head) 58 | 59 | #define STACK_EMPTY(head) (!(head)) 60 | 61 | #define STACK_PUSH(head,add) \ 62 | STACK_PUSH2(head,add,next) 63 | 64 | #define STACK_PUSH2(head,add,next) \ 65 | do { \ 66 | (add)->next = (head); \ 67 | (head) = (add); \ 68 | } while (0) 69 | 70 | #define STACK_POP(head,result) \ 71 | STACK_POP2(head,result,next) 72 | 73 | #define STACK_POP2(head,result,next) \ 74 | do { \ 75 | (result) = (head); \ 76 | (head) = (head)->next; \ 77 | } while (0) 78 | 79 | #define STACK_COUNT(head,el,counter) \ 80 | STACK_COUNT2(head,el,counter,next) \ 81 | 82 | #define STACK_COUNT2(head,el,counter,next) \ 83 | do { \ 84 | (counter) = 0; \ 85 | for ((el) = (head); el; (el) = (el)->next) { ++(counter); } \ 86 | } while (0) 87 | 88 | #endif /* UTSTACK_H */ 89 | -------------------------------------------------------------------------------- /src/uthash/utstring.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2008-2018, Troy D. Hanson http://troydhanson.github.com/uthash/ 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 12 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 13 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 14 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 15 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 16 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 17 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 18 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 19 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 20 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | 24 | /* a dynamic string implementation using macros 25 | */ 26 | #ifndef UTSTRING_H 27 | #define UTSTRING_H 28 | 29 | #define UTSTRING_VERSION 2.1.0 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #ifdef __GNUC__ 37 | #define UTSTRING_UNUSED __attribute__((__unused__)) 38 | #else 39 | #define UTSTRING_UNUSED 40 | #endif 41 | 42 | #ifdef oom 43 | #error "The name of macro 'oom' has been changed to 'utstring_oom'. Please update your code." 44 | #define utstring_oom() oom() 45 | #endif 46 | 47 | #ifndef utstring_oom 48 | #define utstring_oom() exit(-1) 49 | #endif 50 | 51 | typedef struct { 52 | char *d; /* pointer to allocated buffer */ 53 | size_t n; /* allocated capacity */ 54 | size_t i; /* index of first unused byte */ 55 | } UT_string; 56 | 57 | #define utstring_reserve(s,amt) \ 58 | do { \ 59 | if (((s)->n - (s)->i) < (size_t)(amt)) { \ 60 | char *utstring_tmp = (char*)realloc( \ 61 | (s)->d, (s)->n + (amt)); \ 62 | if (!utstring_tmp) { \ 63 | utstring_oom(); \ 64 | } \ 65 | (s)->d = utstring_tmp; \ 66 | (s)->n += (amt); \ 67 | } \ 68 | } while(0) 69 | 70 | #define utstring_init(s) \ 71 | do { \ 72 | (s)->n = 0; (s)->i = 0; (s)->d = NULL; \ 73 | utstring_reserve(s,100); \ 74 | (s)->d[0] = '\0'; \ 75 | } while(0) 76 | 77 | #define utstring_done(s) \ 78 | do { \ 79 | if ((s)->d != NULL) free((s)->d); \ 80 | (s)->n = 0; \ 81 | } while(0) 82 | 83 | #define utstring_free(s) \ 84 | do { \ 85 | utstring_done(s); \ 86 | free(s); \ 87 | } while(0) 88 | 89 | #define utstring_new(s) \ 90 | do { \ 91 | (s) = (UT_string*)malloc(sizeof(UT_string)); \ 92 | if (!(s)) { \ 93 | utstring_oom(); \ 94 | } \ 95 | utstring_init(s); \ 96 | } while(0) 97 | 98 | #define utstring_renew(s) \ 99 | do { \ 100 | if (s) { \ 101 | utstring_clear(s); \ 102 | } else { \ 103 | utstring_new(s); \ 104 | } \ 105 | } while(0) 106 | 107 | #define utstring_clear(s) \ 108 | do { \ 109 | (s)->i = 0; \ 110 | (s)->d[0] = '\0'; \ 111 | } while(0) 112 | 113 | #define utstring_bincpy(s,b,l) \ 114 | do { \ 115 | utstring_reserve((s),(l)+1); \ 116 | if (l) memcpy(&(s)->d[(s)->i], b, l); \ 117 | (s)->i += (l); \ 118 | (s)->d[(s)->i]='\0'; \ 119 | } while(0) 120 | 121 | #define utstring_concat(dst,src) \ 122 | do { \ 123 | utstring_reserve((dst),((src)->i)+1); \ 124 | if ((src)->i) memcpy(&(dst)->d[(dst)->i], (src)->d, (src)->i); \ 125 | (dst)->i += (src)->i; \ 126 | (dst)->d[(dst)->i]='\0'; \ 127 | } while(0) 128 | 129 | #define utstring_len(s) ((s)->i) 130 | 131 | #define utstring_body(s) ((s)->d) 132 | 133 | UTSTRING_UNUSED static void utstring_printf_va(UT_string *s, const char *fmt, va_list ap) { 134 | int n; 135 | va_list cp; 136 | for (;;) { 137 | #ifdef _WIN32 138 | cp = ap; 139 | #else 140 | va_copy(cp, ap); 141 | #endif 142 | n = vsnprintf (&s->d[s->i], s->n-s->i, fmt, cp); 143 | va_end(cp); 144 | 145 | if ((n > -1) && ((size_t) n < (s->n-s->i))) { 146 | s->i += n; 147 | return; 148 | } 149 | 150 | /* Else try again with more space. */ 151 | if (n > -1) utstring_reserve(s,n+1); /* exact */ 152 | else utstring_reserve(s,(s->n)*2); /* 2x */ 153 | } 154 | } 155 | #ifdef __GNUC__ 156 | /* support printf format checking (2=the format string, 3=start of varargs) */ 157 | static void utstring_printf(UT_string *s, const char *fmt, ...) 158 | __attribute__ (( format( printf, 2, 3) )); 159 | #endif 160 | UTSTRING_UNUSED static void utstring_printf(UT_string *s, const char *fmt, ...) { 161 | va_list ap; 162 | va_start(ap,fmt); 163 | utstring_printf_va(s,fmt,ap); 164 | va_end(ap); 165 | } 166 | 167 | /******************************************************************************* 168 | * begin substring search functions * 169 | ******************************************************************************/ 170 | /* Build KMP table from left to right. */ 171 | UTSTRING_UNUSED static void _utstring_BuildTable( 172 | const char *P_Needle, 173 | size_t P_NeedleLen, 174 | long *P_KMP_Table) 175 | { 176 | long i, j; 177 | 178 | i = 0; 179 | j = i - 1; 180 | P_KMP_Table[i] = j; 181 | while (i < (long) P_NeedleLen) 182 | { 183 | while ( (j > -1) && (P_Needle[i] != P_Needle[j]) ) 184 | { 185 | j = P_KMP_Table[j]; 186 | } 187 | i++; 188 | j++; 189 | if (i < (long) P_NeedleLen) 190 | { 191 | if (P_Needle[i] == P_Needle[j]) 192 | { 193 | P_KMP_Table[i] = P_KMP_Table[j]; 194 | } 195 | else 196 | { 197 | P_KMP_Table[i] = j; 198 | } 199 | } 200 | else 201 | { 202 | P_KMP_Table[i] = j; 203 | } 204 | } 205 | 206 | return; 207 | } 208 | 209 | 210 | /* Build KMP table from right to left. */ 211 | UTSTRING_UNUSED static void _utstring_BuildTableR( 212 | const char *P_Needle, 213 | size_t P_NeedleLen, 214 | long *P_KMP_Table) 215 | { 216 | long i, j; 217 | 218 | i = P_NeedleLen - 1; 219 | j = i + 1; 220 | P_KMP_Table[i + 1] = j; 221 | while (i >= 0) 222 | { 223 | while ( (j < (long) P_NeedleLen) && (P_Needle[i] != P_Needle[j]) ) 224 | { 225 | j = P_KMP_Table[j + 1]; 226 | } 227 | i--; 228 | j--; 229 | if (i >= 0) 230 | { 231 | if (P_Needle[i] == P_Needle[j]) 232 | { 233 | P_KMP_Table[i + 1] = P_KMP_Table[j + 1]; 234 | } 235 | else 236 | { 237 | P_KMP_Table[i + 1] = j; 238 | } 239 | } 240 | else 241 | { 242 | P_KMP_Table[i + 1] = j; 243 | } 244 | } 245 | 246 | return; 247 | } 248 | 249 | 250 | /* Search data from left to right. ( Multiple search mode. ) */ 251 | UTSTRING_UNUSED static long _utstring_find( 252 | const char *P_Haystack, 253 | size_t P_HaystackLen, 254 | const char *P_Needle, 255 | size_t P_NeedleLen, 256 | long *P_KMP_Table) 257 | { 258 | long i, j; 259 | long V_FindPosition = -1; 260 | 261 | /* Search from left to right. */ 262 | i = j = 0; 263 | while ( (j < (int)P_HaystackLen) && (((P_HaystackLen - j) + i) >= P_NeedleLen) ) 264 | { 265 | while ( (i > -1) && (P_Needle[i] != P_Haystack[j]) ) 266 | { 267 | i = P_KMP_Table[i]; 268 | } 269 | i++; 270 | j++; 271 | if (i >= (int)P_NeedleLen) 272 | { 273 | /* Found. */ 274 | V_FindPosition = j - i; 275 | break; 276 | } 277 | } 278 | 279 | return V_FindPosition; 280 | } 281 | 282 | 283 | /* Search data from right to left. ( Multiple search mode. ) */ 284 | UTSTRING_UNUSED static long _utstring_findR( 285 | const char *P_Haystack, 286 | size_t P_HaystackLen, 287 | const char *P_Needle, 288 | size_t P_NeedleLen, 289 | long *P_KMP_Table) 290 | { 291 | long i, j; 292 | long V_FindPosition = -1; 293 | 294 | /* Search from right to left. */ 295 | j = (P_HaystackLen - 1); 296 | i = (P_NeedleLen - 1); 297 | while ( (j >= 0) && (j >= i) ) 298 | { 299 | while ( (i < (int)P_NeedleLen) && (P_Needle[i] != P_Haystack[j]) ) 300 | { 301 | i = P_KMP_Table[i + 1]; 302 | } 303 | i--; 304 | j--; 305 | if (i < 0) 306 | { 307 | /* Found. */ 308 | V_FindPosition = j + 1; 309 | break; 310 | } 311 | } 312 | 313 | return V_FindPosition; 314 | } 315 | 316 | 317 | /* Search data from left to right. ( One time search mode. ) */ 318 | UTSTRING_UNUSED static long utstring_find( 319 | UT_string *s, 320 | long P_StartPosition, /* Start from 0. -1 means last position. */ 321 | const char *P_Needle, 322 | size_t P_NeedleLen) 323 | { 324 | long V_StartPosition; 325 | long V_HaystackLen; 326 | long *V_KMP_Table; 327 | long V_FindPosition = -1; 328 | 329 | if (P_StartPosition < 0) 330 | { 331 | V_StartPosition = s->i + P_StartPosition; 332 | } 333 | else 334 | { 335 | V_StartPosition = P_StartPosition; 336 | } 337 | V_HaystackLen = s->i - V_StartPosition; 338 | if ( (V_HaystackLen >= (long) P_NeedleLen) && (P_NeedleLen > 0) ) 339 | { 340 | V_KMP_Table = (long *)malloc(sizeof(long) * (P_NeedleLen + 1)); 341 | if (V_KMP_Table != NULL) 342 | { 343 | _utstring_BuildTable(P_Needle, P_NeedleLen, V_KMP_Table); 344 | 345 | V_FindPosition = _utstring_find(s->d + V_StartPosition, 346 | V_HaystackLen, 347 | P_Needle, 348 | P_NeedleLen, 349 | V_KMP_Table); 350 | if (V_FindPosition >= 0) 351 | { 352 | V_FindPosition += V_StartPosition; 353 | } 354 | 355 | free(V_KMP_Table); 356 | } 357 | } 358 | 359 | return V_FindPosition; 360 | } 361 | 362 | 363 | /* Search data from right to left. ( One time search mode. ) */ 364 | UTSTRING_UNUSED static long utstring_findR( 365 | UT_string *s, 366 | long P_StartPosition, /* Start from 0. -1 means last position. */ 367 | const char *P_Needle, 368 | size_t P_NeedleLen) 369 | { 370 | long V_StartPosition; 371 | long V_HaystackLen; 372 | long *V_KMP_Table; 373 | long V_FindPosition = -1; 374 | 375 | if (P_StartPosition < 0) 376 | { 377 | V_StartPosition = s->i + P_StartPosition; 378 | } 379 | else 380 | { 381 | V_StartPosition = P_StartPosition; 382 | } 383 | V_HaystackLen = V_StartPosition + 1; 384 | if ( (V_HaystackLen >= (long) P_NeedleLen) && (P_NeedleLen > 0) ) 385 | { 386 | V_KMP_Table = (long *)malloc(sizeof(long) * (P_NeedleLen + 1)); 387 | if (V_KMP_Table != NULL) 388 | { 389 | _utstring_BuildTableR(P_Needle, P_NeedleLen, V_KMP_Table); 390 | 391 | V_FindPosition = _utstring_findR(s->d, 392 | V_HaystackLen, 393 | P_Needle, 394 | P_NeedleLen, 395 | V_KMP_Table); 396 | 397 | free(V_KMP_Table); 398 | } 399 | } 400 | 401 | return V_FindPosition; 402 | } 403 | /******************************************************************************* 404 | * end substring search functions * 405 | ******************************************************************************/ 406 | 407 | #endif /* UTSTRING_H */ 408 | -------------------------------------------------------------------------------- /src/utility.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by cpasjuste on 03/02/2020. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include "retrodream.h" 9 | #include "utility.h" 10 | 11 | int list_cmp(ListItem *a, ListItem *b) { 12 | 13 | if (a->type == TYPE_DIR && b->type != TYPE_DIR) { 14 | return -1; 15 | } else if (a->type != TYPE_DIR && b->type == TYPE_DIR) { 16 | return 1; 17 | } 18 | 19 | return strcasecmp(a->name, b->name); 20 | } 21 | 22 | void free_dir(List *list) { 23 | 24 | ListItem *elt, *tmp; 25 | DL_FOREACH_SAFE(list->head, elt, tmp) { 26 | DL_DELETE(list->head, elt); 27 | free(elt); 28 | } 29 | } 30 | 31 | ListItem *get_item(List *list, int index) { 32 | 33 | ListItem *file = list->head; 34 | if (index == 0) { 35 | return file; 36 | } 37 | 38 | for (int i = 1; i < list->size; i++) { 39 | file = (ListItem *) file->next; 40 | if (index == i) { 41 | return file; 42 | } 43 | } 44 | 45 | return NULL; 46 | } 47 | 48 | void try_boot() { 49 | 50 | // first check for boot config 51 | if (file_exists("/sd/boot.cfg")) { 52 | char *path = read_file("/sd/boot.cfg", NULL); 53 | if (path != NULL) { 54 | trim(path); 55 | if (file_exists(path)) { 56 | exec(path); 57 | } 58 | } 59 | } else if (file_exists("/ide/boot.cfg")) { 60 | char *path = read_file("/ide/boot.cfg", NULL); 61 | if (path != NULL) { 62 | trim(path); 63 | if (file_exists(path)) { 64 | exec(path); 65 | } 66 | } 67 | } 68 | 69 | // then retrodream.bin 70 | if (file_exists("/sd/RD/retrodream.bin")) { 71 | exec("/sd/RD/retrodream.bin"); 72 | } else if (file_exists("/ide/RD/retrodream.bin")) { 73 | exec("/ide/RD/retrodream.bin"); 74 | } 75 | 76 | // finally check for DS_CORE.BIN 77 | if (file_exists("/sd/DS/DS_CORE.BIN")) { 78 | exec("/sd/DS/DS_CORE.BIN"); 79 | } else if (file_exists("/ide/DS/DS_CORE.BIN")) { 80 | exec("/ide/DS/DS_CORE.BIN"); 81 | } 82 | } 83 | 84 | void trim(char *str) { 85 | 86 | char *pos = NULL; 87 | 88 | while ((pos = strrchr(str, '\n')) != NULL) { 89 | *pos = '\0'; 90 | } 91 | 92 | size_t len = strlen(str) - 1; 93 | for (int i = len; i; i--) { 94 | if (str[i] > ' ') { 95 | break; 96 | } 97 | str[i] = '\0'; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/utility.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by cpasjuste on 28/01/2020. 3 | // 4 | 5 | #ifndef LOADER_UTILITY_H 6 | #define LOADER_UTILITY_H 7 | 8 | #define MAX_PATH 512 9 | 10 | enum FileType { 11 | TYPE_DIR, 12 | TYPE_FILE, 13 | TYPE_BIN 14 | }; 15 | 16 | typedef struct ListItem { 17 | struct ListItem *next, *prev; 18 | char name[MAX_PATH]; 19 | char path[MAX_PATH]; 20 | int type; 21 | } ListItem; 22 | 23 | typedef struct List { 24 | ListItem *head; 25 | int size; 26 | char path[MAX_PATH]; 27 | } List; 28 | 29 | int list_cmp(ListItem *a, ListItem *b); 30 | 31 | void get_dir(List *list, const char *path); 32 | 33 | void free_dir(List *list); 34 | 35 | ListItem *get_item(List *list, int index); 36 | 37 | int file_exists(const char *file); 38 | 39 | int dir_exists(const char *dir); 40 | 41 | void try_boot(); 42 | 43 | char *read_file(const char *file, int *size); 44 | 45 | void exec(const char *path); 46 | 47 | int is_hacked_bios(); 48 | 49 | int is_custom_bios(); 50 | 51 | int is_no_syscalls(); 52 | 53 | int flash_get_region(); 54 | 55 | void descramble(uint8 *source, uint8 *dest, uint32 size); 56 | 57 | int setup_syscalls(); 58 | 59 | void dc_load_serial(); 60 | 61 | void dc_load_ip(); 62 | 63 | void loader_init(); 64 | 65 | void trim(char *str); 66 | 67 | #endif //LOADER_UTILITY_H 68 | -------------------------------------------------------------------------------- /targets.cmake: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1) 2 | #set(CMAKE_VERBOSE_MAKEFILE ON) 3 | 4 | if (NOT PLATFORM_LINUX) 5 | # romdisk handling (tricky..) 6 | add_custom_target( 7 | ${PROJECT_NAME}.romdisk ALL 8 | DEPENDS dummy_romdisk 9 | ) 10 | add_custom_command(OUTPUT 11 | dummy_romdisk ${CMAKE_BINARY_DIR}/romdisk.o 12 | COMMAND ${KOS_BASE}/utils/genromfs/genromfs -f ${CMAKE_BINARY_DIR}/romdisk.img -d ${CMAKE_CURRENT_SOURCE_DIR}/romdisk -v 13 | COMMAND KOS_ARCH=${KOS_ARCH} KOS_AS=${KOS_AS} KOS_AFLAGS=${KOS_AFLAGS} KOS_LD=${KOS_LD} KOS_OBJCOPY=${KOS_OBJCOPY} 14 | /bin/bash ${KOS_BASE}/utils/bin2o/bin2o ${CMAKE_BINARY_DIR}/romdisk.img romdisk ${CMAKE_BINARY_DIR}/romdisk.o 15 | ) 16 | target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_BINARY_DIR}/romdisk.o) 17 | add_custom_target(${PROJECT_NAME}.bin 18 | DEPENDS ${PROJECT_NAME} 19 | COMMAND ${CMAKE_OBJCOPY} -R .stack -O binary ${PROJECT_NAME}${CMAKE_EXECUTABLE_SUFFIX} ${PROJECT_NAME}.bin 20 | ) 21 | add_custom_target(${PROJECT_NAME}.bios 22 | DEPENDS ${PROJECT_NAME}.bin 23 | COMMAND cp -f ${CMAKE_SOURCE_DIR}/res/boot_loader_retail.bios ${PROJECT_NAME}.bios 24 | COMMAND dd if=${PROJECT_NAME}.bin of=${PROJECT_NAME}.bios bs=1 seek=65536 conv=notrunc 25 | ) 26 | add_custom_target(${PROJECT_NAME}-nogdrom.bios 27 | DEPENDS ${PROJECT_NAME}.bin 28 | COMMAND cp -f ${CMAKE_SOURCE_DIR}/res/boot_loader_retail_nogdrom.bios ${PROJECT_NAME}-nogdrom.bios 29 | COMMAND dd if=${PROJECT_NAME}.bin of=${PROJECT_NAME}-nogdrom.bios bs=1 seek=65536 conv=notrunc 30 | ) 31 | add_custom_target(${PROJECT_NAME}-devkit.bios 32 | DEPENDS ${PROJECT_NAME}.bin 33 | COMMAND cp -f ${CMAKE_SOURCE_DIR}/res/boot_loader_devkit.bios ${PROJECT_NAME}-devkit.bios 34 | COMMAND dd if=${PROJECT_NAME}.bin of=${PROJECT_NAME}-devkit.bios bs=1 seek=65536 conv=notrunc 35 | ) 36 | add_custom_target(${PROJECT_NAME}-devkit-nogdrom.bios 37 | DEPENDS ${PROJECT_NAME}.bin 38 | COMMAND cp -f ${CMAKE_SOURCE_DIR}/res/boot_loader_devkit_nogdrom.bios ${PROJECT_NAME}-devkit-nogdrom.bios 39 | COMMAND dd if=${PROJECT_NAME}.bin of=${PROJECT_NAME}-devkit-nogdrom.bios bs=1 seek=65536 conv=notrunc 40 | ) 41 | add_custom_target(${PROJECT_NAME}-32mb.bios 42 | DEPENDS ${PROJECT_NAME}.bin 43 | COMMAND cp -f ${CMAKE_SOURCE_DIR}/res/boot_loader_retail_32mb.bios ${PROJECT_NAME}-32mb.bios 44 | COMMAND dd if=${PROJECT_NAME}.bin of=${PROJECT_NAME}-32mb.bios bs=1 seek=65536 conv=notrunc 45 | ) 46 | add_custom_target(${PROJECT_NAME}-nogdrom-32mb.bios 47 | DEPENDS ${PROJECT_NAME}.bin 48 | COMMAND cp -f ${CMAKE_SOURCE_DIR}/res/boot_loader_retail_nogdrom_32mb.bios ${PROJECT_NAME}-nogdrom-32mb.bios 49 | COMMAND dd if=${PROJECT_NAME}.bin of=${PROJECT_NAME}-nogdrom-32mb.bios bs=1 seek=65536 conv=notrunc 50 | ) 51 | add_custom_target(${PROJECT_NAME}-devkit-32mb.bios 52 | DEPENDS ${PROJECT_NAME}.bin 53 | COMMAND cp -f ${CMAKE_SOURCE_DIR}/res/boot_loader_devkit_32mb.bios ${PROJECT_NAME}-devkit-32mb.bios 54 | COMMAND dd if=${PROJECT_NAME}.bin of=${PROJECT_NAME}-devkit-32mb.bios bs=1 seek=65536 conv=notrunc 55 | ) 56 | add_custom_target(${PROJECT_NAME}-devkit-nogdrom-32mb.bios 57 | DEPENDS ${PROJECT_NAME}.bin 58 | COMMAND cp -f ${CMAKE_SOURCE_DIR}/res/boot_loader_devkit_nogdrom_32mb.bios ${PROJECT_NAME}-devkit-nogdrom-32mb.bios 59 | COMMAND dd if=${PROJECT_NAME}.bin of=${PROJECT_NAME}-devkit-nogdrom-32mb.bios bs=1 seek=65536 conv=notrunc 60 | ) 61 | add_custom_target(${PROJECT_NAME}-nogdrom.bios-lx 62 | DEPENDS ${PROJECT_NAME}-nogdrom.bios 63 | COMMAND cp ${PROJECT_NAME}-nogdrom.bios ~/.lxdream/dcboot.rom 64 | ) 65 | add_custom_target(${PROJECT_NAME}-nogdrom.bios-reicast 66 | DEPENDS ${PROJECT_NAME}-nogdrom.bios 67 | COMMAND cp ${PROJECT_NAME}-nogdrom.bios ~/.local/share/reicast/data/dc_boot.bin 68 | ) 69 | endif () 70 | -------------------------------------------------------------------------------- /toolchain.cmake: -------------------------------------------------------------------------------- 1 | # setup toolchains 2 | 3 | if (PLATFORM_LINUX) 4 | set(CMAKE_SYSTEM_NAME "Linux") 5 | set(TARGET_PLATFORM linux CACHE STRING "") 6 | else () 7 | 8 | set(TARGET_PLATFORM dreamcast CACHE STRING "" FORCE) 9 | 10 | set(CMAKE_SYSTEM_NAME "Generic") 11 | set(CMAKE_SYSTEM_PROCESSOR "sh") 12 | 13 | set(SH_ELF_PREFIX /opt/toolchains/dc/sh-elf) 14 | set(KOS_BASE $ENV{KOS_BASE} CACHE STRING "" FORCE) 15 | set(KOS_ARCH "dreamcast" CACHE STRING "" FORCE) 16 | set(KOS_SUBARCH "pristine" CACHE STRING "" FORCE) 17 | set(KOS_AS "${SH_ELF_PREFIX}/bin/sh-elf-as" CACHE STRING "" FORCE) 18 | set(KOS_AFLAGS "-little" CACHE STRING "" FORCE) 19 | set(KOS_LD "${SH_ELF_PREFIX}/bin/sh-elf-ld" CACHE STRING "" FORCE) 20 | set(KOS_OBJCOPY "${SH_ELF_PREFIX}/bin/sh-elf-objcopy" CACHE STRING "" FORCE) 21 | 22 | set(CMAKE_OBJCOPY ${SH_ELF_PREFIX}/bin/sh-elf-objcopy CACHE FILEPATH "") 23 | set(CMAKE_C_COMPILER ${SH_ELF_PREFIX}/bin/sh-elf-gcc CACHE FILEPATH "") 24 | set(CMAKE_CXX_COMPILER ${SH_ELF_PREFIX}/bin/sh-elf-g++ CACHE FILEPATH "") 25 | set(CMAKE_AR ${SH_ELF_PREFIX}/bin/sh-elf-ar CACHE FILEPATH "") 26 | set(CMAKE_ASM_COMPILER ${SH_ELF_PREFIX}/bin/sh-elf-gcc CACHE FILEPATH "") 27 | set(CMAKE_LINKER ${SH_ELF_PREFIX}/bin/sh-elf-ld CACHE FILEPATH "") 28 | 29 | set(KOS_INC_PATHS "-I${KOS_BASE}/include -I${KOS_BASE}/kernel/arch/dreamcast/include -I${KOS_BASE}/addons/include -I${KOS_BASE}/../kos-ports/include") 30 | set(KOS_LIB_PATHS "-L${KOS_BASE}/lib/${KOS_ARCH} -L${KOS_BASE}/addons/lib/${KOS_ARCH} -L${KOS_BASE}/../kos-ports/lib") 31 | set(KOS_LIBS "-Wl,--start-group -lkallisti -lc -lgcc -Wl,--end-group" CACHE STRING "KOS_LIBS" FORCE) 32 | set(KOS_CFLAGS "-D__DREAMCAST__ -O2 -fomit-frame-pointer -ml -m4-single-only -ffunction-sections -fdata-sections -D_arch_dreamcast -D_arch_sub_pristine -Wall -g -fno-builtin") 33 | 34 | set(CMAKE_C_FLAGS "${KOS_CFLAGS} ${KOS_INC_PATHS}" CACHE STRING "C flags" FORCE) 35 | set(CMAKE_C_FLAGS_RELEASE "-O2" CACHE STRING "CMAKE_C_FLAGS_RELEASE" FORCE) 36 | set(CMAKE_CXX_FLAGS "${KOS_CFLAGS} ${KOS_INC_PATHS} -std=gnu++11 -fno-operator-names -fno-rtti -fno-exceptions" CACHE STRING "C++ flags" FORCE) 37 | 38 | set(CMAKE_C_LINK_FLAGS "${KOS_LIB_PATHS} ${KOS_CFLAGS} -Wl,-Ttext=0x8c010000 -Wl,--gc-sections -nodefaultlibs -T${KOS_BASE}/utils/ldscripts/shlelf.xc" CACHE STRING "" FORCE) 39 | set(CMAKE_CXX_LINK_FLAGS "${KOS_LIB_PATHS} ${KOS_LIBS} -T${KOS_BASE}/utils/ldscripts/shlelf.xc ${KOS_LIBS}" CACHE STRING "" FORCE) 40 | 41 | set(CMAKE_C_LINK_EXECUTABLE "${CMAKE_C_COMPILER} ${CMAKE_C_FLAGS} -o ") 42 | #set(CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_COMPILER} ${CMAKE_CXX_FLAGS} ${CMAKE_CXX_LINK_FLAGS} -o ") 43 | 44 | set_property(DIRECTORY PROPERTY TARGET_SUPPORTS_SHARED_LIBS FALSE) 45 | set(CMAKE_FIND_ROOT_PATH ${SH_ELF_PREFIX} $ENV{KOS_BASE}/ $ENV{KOS_BASE}/addons $ENV{KOS_BASE}/../kos-ports) 46 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 47 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) 48 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) 49 | set(CMAKE_EXECUTABLE_SUFFIX_C ".elf" CACHE STRING "" FORCE) 50 | set(CMAKE_EXECUTABLE_SUFFIX_CXX ".elf" CACHE STRING "" FORCE) 51 | 52 | endif () --------------------------------------------------------------------------------