diff options
| author | Xavi Del Campo <xavi.dcr@tutanota.com> | 2020-03-03 18:39:09 +0100 |
|---|---|---|
| committer | Xavi Del Campo <xavi.dcr@tutanota.com> | 2020-03-03 19:40:00 +0100 |
| commit | 792e22676786a577b2edc0ed0ed78e51c5b38245 (patch) | |
| tree | 3a5b1092af322003be3189bf6d58f362dcfe1dca | |
| parent | 62adc2edd17cbd39272715d29d1b4c8650ef7dde (diff) | |
| download | opensend-792e22676786a577b2edc0ed0ed78e51c5b38245.tar.gz | |
Refactoring
| -rw-r--r-- | LICENSE | 8 | ||||
| -rw-r--r-- | Makefile | 172 | ||||
| -rw-r--r-- | bin/OPENSEND.bin | bin | 627984 -> 0 bytes | |||
| -rw-r--r-- | bin/OPENSEND.cue | 3 | ||||
| -rw-r--r-- | include/EndAnimation.h | 25 | ||||
| -rw-r--r-- | include/Font.h | 78 | ||||
| -rw-r--r-- | include/GameStructures.h | 57 | ||||
| -rw-r--r-- | include/Gfx.h | 133 | ||||
| -rw-r--r-- | include/Global_Inc.h | 41 | ||||
| -rw-r--r-- | include/IO.h | 50 | ||||
| -rw-r--r-- | include/Interrupts.h | 68 | ||||
| -rw-r--r-- | include/LoadMenu.h | 19 | ||||
| -rw-r--r-- | include/Serial.h | 58 | ||||
| -rw-r--r-- | include/System.h | 118 | ||||
| -rw-r--r-- | src/EndAnimation.c | 233 | ||||
| -rw-r--r-- | src/Font.c | 198 | ||||
| -rw-r--r-- | src/Gfx.c | 895 | ||||
| -rw-r--r-- | src/IO.c | 266 | ||||
| -rw-r--r-- | src/Interrupts.c | 126 | ||||
| -rw-r--r-- | src/LoadMenu.c | 106 | ||||
| -rw-r--r-- | src/Serial.c | 283 | ||||
| -rw-r--r-- | src/System.c | 492 | ||||
| -rw-r--r-- | src/main.c | 85 |
23 files changed, 1407 insertions, 2107 deletions
@@ -1,7 +1,7 @@ GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 - Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Copyright (C) 2007 Free Software Foundation, Inc. <http:/* fsf.org/> */ Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. @@ -645,7 +645,7 @@ the "copyright" line and a pointer to where the full notice is found. GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. + along with this program. If not, see <http:/* www.gnu.org/licenses/>. */ Also add information on how to contact you by electronic and paper mail. @@ -664,11 +664,11 @@ might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see -<http://www.gnu.org/licenses/>. +<http:/* www.gnu.org/licenses/>. */ The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read -<http://www.gnu.org/philosophy/why-not-lgpl.html>. +<http:/* www.gnu.org/philosophy/why-not-lgpl.html>. */ @@ -1,74 +1,128 @@ -CC = psxsdkserial-gcc -DEFINE= -D_PAL_MODE_ -DEFINE += -DPSXSDK_DEBUG -LIBS=-lfixmath -CC_FLAGS = -Wall -Werror -c -Os -Wfatal-errors -g -LINKER = psxsdkserial-gcc +PSXSDK_DIR = /usr/local/psxsdk -PROJECT = OPENSEND -PROJECT_DIR = ~/OpenSend +CC = mipsel-unknown-elf-gcc +DEFINE = -DPSXSDK_DEBUG +LIBS = -lfixmath +INCLUDE = include $(PSXSDK_DIR)/include +CC_FLAGS = -Wall -Werror -ffunction-sections -fdata-sections -c -Os -Wfatal-errors -g $(addprefix -I, $(INCLUDE)) +LD = mipsel-unknown-elf-gcc +LD_FLAGS = $(LIBS) -Wl,--gc-sections -INIT_ADDR=0x801A0000 +PROJECT = opensend + +INIT_ADDR = 0x801A0000 ELF2EXE = elf2exe ELF2EXE_FLAGS = -mark="Open-source PSX-EXE loader created with PSXSDK" -init_addr=$(INIT_ADDR) LICENSE_FILE = /usr/local/psxsdk/share/licenses/infoeur.dat -PSXSDK_DIR = /usr/local/psxsdk/bin +PATH := $(PATH):$(PSXSDK_DIR)/bin -EMULATOR_DIR = ~/pcsxr -EMULATOR = pcsxr.exe +EMULATOR = pcsxr SOUND_INTERFACE = EMULATOR_FLAGS = -nogui -psxout -OBJ_DIR = Obj -SRC_DIR = . -MUSIC_TRACKS = -#FFMPEG = ffmpeg -#FFMPEG_DIR = ../Music/ffmpeg/bin -#FFMPEG_FLAGS = -f s16le -acodec pcm_s16le +OBJ_DIR = obj +SRC_DIR = src +EXE_PATH = obj + +BIN_TARGET_PATH = bin GNU_SIZE = mipsel-unknown-elf-size -all: build image clean -#emulator clean - -rebuild: remove build - -build: clean objects $(PROJECT).elf $(PROJECT).exe - -objects: $(addprefix $(OBJ_DIR)/,main.o System.o Gfx.o \ - LoadMenu.o EndAnimation.o \ - Font.o Serial.o) - -remove: - rm -f Obj/*.o - -$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c - $(CC) $< -o $@ $(DEFINE) $(CC_FLAGS) - -$(PROJECT).elf: - $(LINKER) Obj/*.o -o Exe/$(PROJECT).elf $(LIBS) -Wl,--gc-sections - -$(PROJECT).exe: - $(ELF2EXE) Exe/$(PROJECT).elf Exe/$(PROJECT).exe $(ELF2EXE_FLAGS) - cp Exe/$(PROJECT).exe ../cdimg - -image: - rm -f $(PROJECT).iso $(PROJECT).bin - rm -f $(PROJECT).cue - mkisofs -o $(PROJECT).iso -V $(PROJECT) -sysid PLAYSTATION ../cdimg - mkpsxiso $(PROJECT).iso $(PROJECT).bin $(LICENSE_FILE) - mv $(PROJECT).bin ../Bin - mv $(PROJECT).cue ../Bin - rm -f $(PROJECT).cue - rm -f $(PROJECT).iso - $(GNU_SIZE) Exe/$(PROJECT).elf - -emulator: - export PATH=$$PATH:$(EMULATOR_DIR) - $(EMULATOR) -cdfile $(PROJECT_DIR)/Bin/$(PROJECT).bin $(EMULATOR_FLAGS) - +OBJECTS = $(addprefix $(OBJ_DIR)/, \ + EndAnimation.o Font.o Gfx.o LoadMenu.o main.o Serial.o System.o \ + Interrupts.o IO.o \ + ) + +$(BIN_TARGET_PATH)/$(PROJECT).bin: $(EXE_PATH)/$(PROJECT).iso + mkdir -p $(BIN_TARGET_PATH) +#~ mkpsxiso $< $@ $(LICENSE_FILE) $(MUSIC_TRACKS) + mkpsxiso $< $@ $(LICENSE_FILE) -s +# $(PROJECT).cue is automatically generated by mkpsxiso + $(GNU_SIZE) $(EXE_PATH)/$(PROJECT).elf + +rebuild: + make clean + make $(BIN_TARGET_PATH)/$(PROJECT).bin + +-include $(DEPS) + +#music_objects: $(addprefix ../Music/, TRACK01.bin TRACK02.bin TRACK03.bin) + clean: - rm -f $(PROJECT).elf cdimg/$(PROJECT).exe $(PROJECT).bin $(PROJECT).cue cdimg/README.txt - rm -f $(PROJECT).iso $(PROJECT).exe $(PROJECT).elf + rm -f $(EXE_DIR)/*.EXE + rm -f $(EXE_DIR)/*.iso + rm -f $(EXE_DIR)/*.elf + rm -f $(OBJ_DIR)/*.o + rm -f $(OBJ_DIR)/*.d + rm -f $(OBJ_SOUNDS_DIR)/*.VAG + rm -f $(OBJ_LEVELS_DIR)/*.LVL + rm -f $(OBJ_LEVELS_DIR)/*.PLT + rm -f $(OBJ_SPRITES_PATH)/*.TIM + rm -f $(OBJ_FONTS_PATH)/*.TIM + +$(OBJ_DIR)/%.d: $(SRC_DIR)/%.cpp + @mkdir -p $(OBJ_DIR) + $(CXX) $< $(DEFINE) $(CXX_FLAGS) -MM > $@ + +$(OBJ_DIR)/%.d: $(SRC_DIR)/%.c + @mkdir -p $(OBJ_DIR) + echo $$PATH + $(CC) $< $(DEFINE) $(CC_FLAGS) -MM > $@ + +$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp $(OBJ_DIR)/%.d + @mkdir -p $(OBJ_DIR) + $(CXX) $< -o $@ $(DEFINE) $(CXX_FLAGS) -MMD + +$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c $(OBJ_DIR)/%.d + @mkdir -p $(OBJ_DIR) + $(CC) $< -o $@ $(DEFINE) $(CC_FLAGS) -MMD + +$(OBJ_DIR)/%.o: $(SRC_DIR)/%.s + @mkdir -p $(OBJ_DIR) + $(AS) $< -o $@ $(AS_FLAGS) + +$(EXE_PATH)/$(PROJECT).elf: $(OBJECTS) + @mkdir -p $(EXE_PATH) + $(LD) $^ -o $@ $(LIBS) -Wl,--gc-sections + +$(EXE_PATH)/$(PROJECT).iso: $(EXE_PATH)/$(PROJECT).EXE $(SOUND_OBJECTS) $(LEVEL_OBJECTS) $(SPRITE_OBJECTS) $(APPS_OBJECTS) + @mkdir -p $(EXE_PATH) + mkisofs -o $@ -V $(PROJECT) -sysid PLAYSTATION $(CDROM_ROOT) + +$(EXE_PATH)/$(PROJECT).EXE: $(EXE_PATH)/$(PROJECT).elf + @mkdir -p $(EXE_PATH) + $(ELF2EXE) $< $@ $(ELF2EXE_FLAGS) + @mkdir -p $(CDROM_ROOT) + cp $@ $(CDROM_ROOT) + +run: $(BIN_TARGET_PATH)/$(PROJECT).bin + export PATH=$$PATH:$(EMULATOR_DIR) + @mkdir -p $(BIN_TARGET_PATH) + $(EMULATOR) -cdfile $(BIN_TARGET_PATH)/$(PROJECT).bin $(EMULATOR_FLAGS) + +$(OBJ_SPRITES_PATH)/%.TIM: $(SRC_SPRITES_PATH)/%.bmp $(SRC_SPRITES_PATH)/%.flags + @mkdir -p $(OBJ_SPRITES_PATH) + $(BMP2TIM) $< $@ `cat $(word 2,$^)` + +$(OBJ_APPS_PATH)/%.EOL: $(SRC_APPS_PATH)/%.EOL + @mkdir -p $(OBJ_APPS_PATH) + cp $^ $@ + +$(OBJ_FONTS_PATH)/%.TIM: $(SRC_SPRITES_PATH)/%.bmp $(SRC_SPRITES_PATH)/%.flags + @mkdir -p $(OBJ_FONTS_PATH) + $(BMP2TIM) $< $@ `cat $(word 2,$^)` + +$(OBJ_SOUNDS_DIR)/%.VAG: $(SOURCE_SOUNDS_FOLDER)/%.wav $(SOURCE_SOUNDS_FOLDER)/%.flags + @mkdir -p $(OBJ_SOUNDS_DIR) + wav2vag $< $@ `cat $(word 2,$^)` + +%.bin: %.mp3 + rm -f ../Bin/$@1 + $(FFMPEG) -i $< $(FFMPEG_FLAGS) $@ + cp ../Music/$@ ../Bin/ +# ---------------------------------------- +# Phony targets +# ---------------------------------------- +.PHONY: clean run rebuild diff --git a/bin/OPENSEND.bin b/bin/OPENSEND.bin Binary files differdeleted file mode 100644 index 39a962a..0000000 --- a/bin/OPENSEND.bin +++ /dev/null diff --git a/bin/OPENSEND.cue b/bin/OPENSEND.cue deleted file mode 100644 index 4b18ec2..0000000 --- a/bin/OPENSEND.cue +++ /dev/null @@ -1,3 +0,0 @@ -FILE "OPENSEND.bin" BINARY -TRACK 01 MODE2/2352 - INDEX 01 00:00:00 diff --git a/include/EndAnimation.h b/include/EndAnimation.h deleted file mode 100644 index edb7b07..0000000 --- a/include/EndAnimation.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef __END_SCREEN_HEADER__ -#define __END_SCREEN_HEADER__ - -/* ************************************** - * Includes * - * **************************************/ - -#include "Global_Inc.h" -#include "Gfx.h" - -/* ************************************** - * Defines * - * **************************************/ - -/* ************************************** - * Global Prototypes * - * **************************************/ - -void EndAnimation(void); - -/* ************************************** - * Global Variables * - * **************************************/ - -#endif // __END_SCREEN_HEADER__ diff --git a/include/Font.h b/include/Font.h index 5a7d6b5..97a52ac 100644 --- a/include/Font.h +++ b/include/Font.h @@ -1,44 +1,60 @@ -#ifndef __FONT_HEADER__ -#define __FONT_HEADER__ +#ifndef FONT_H +#define FONT_H /* ************************************* * Includes * *************************************/ -#include "Global_Inc.h" -#include "System.h" -#include "Gfx.h" -#include "GameStructures.h" #include <stdarg.h> - -/* ************************************* - * Defines - * *************************************/ - -#define FONT_DEFAULT_CHAR_SIZE 16 -#define FONT_DEFAULT_INIT_CHAR '!' - -/* ************************************** - * Structs and enums * - * *************************************/ - -/* ************************************* - * Global prototypes - * *************************************/ - -bool FontLoadImage(char* strPath, TYPE_FONT * ptrFont); -void FontSetSize(TYPE_FONT * ptrFont, short size, short bitshift); -void FontPrintText(TYPE_FONT *ptrFont, short x, short y, char* str, ...); -void FontSetInitChar(TYPE_FONT * ptrFont, char c); -void FontSetFlags(TYPE_FONT * ptrFont, FONT_FLAGS flags); +#include <stdbool.h> + +enum +{ + FONT_DEFAULT_CHAR_SIZE = 16, + FONT_DEFAULT_INIT_CHAR = '!' +}; + +enum t_fontflags +{ + FONT_NOFLAGS, + FONT_CENTERED = 0x01, + FONT_WRAP_LINE = 0x02, + FONT_BLEND_EFFECT = 0x04, + FONT_1HZ_FLASH = 0x08, + FONT_2HZ_FLASH = 0x10, + FONT_H_CENTERED = 0x20 +}; + +struct font +{ + GsSprite spr; + short char_spacing; + short char_w; + short char_w_bitshift; + short char_h; + char init_ch; + uint8_t char_per_row; + uint8_t max_ch_wrap; + enum font_flags flags; + short spr_w; + short spr_h; + short spr_u; + short spr_v; +}; + +bool FontLoadImage(const char *path, struct font *font); +void FontSetSize(struct font *font, short size, short bitshift); +void FontPrintText(struct font *font, short x, short y, char* str, ...); +void FontSetInitChar(struct font *font, char c); +void FontSetFlags(struct font *font, enum font_flags flags); void FontCyclic(void); -void FontSetSpacing(TYPE_FONT* ptrFont, short spacing); +void FontSetSpacing(struct font *font, short spacing); /* ************************************* * Global variables * *************************************/ -TYPE_FONT RadioFont; -TYPE_FONT SmallFont; +extern struct font RadioFont; +extern struct font SmallFont; -#endif //__FONT_HEADER__ +#endif /* FONT_H */ diff --git a/include/GameStructures.h b/include/GameStructures.h deleted file mode 100644 index e092e1d..0000000 --- a/include/GameStructures.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef __GAME_STRUCTURES__HEADER__ -#define __GAME_STRUCTURES__HEADER__ - -/* ************************************* - * Defines - * *************************************/ - -#define CHEAT_ARRAY_SIZE 16 - -/* ************************************* - * Structs and enums - * *************************************/ - -typedef enum t_fontflags -{ - FONT_NOFLAGS = 0, - FONT_CENTERED = 0x01, - FONT_WRAP_LINE = 0x02, - FONT_BLEND_EFFECT = 0x04, - FONT_1HZ_FLASH = 0x08, - FONT_2HZ_FLASH = 0x10, - FONT_H_CENTERED = 0x20 -}FONT_FLAGS; - -typedef struct t_Font -{ - GsSprite spr; - short char_spacing; - short char_w; - short char_w_bitshift; - short char_h; - char init_ch; - uint8_t char_per_row; - uint8_t max_ch_wrap; - FONT_FLAGS flags; - short spr_w; - short spr_h; - short spr_u; - short spr_v; -}TYPE_FONT; - -typedef struct t_Timer -{ - uint32_t time; - uint32_t orig_time; - bool repeat_flag; - bool busy; - void (*Timeout_Callback)(void); -}TYPE_TIMER; - -typedef struct t_Cheat -{ - unsigned short Combination[CHEAT_ARRAY_SIZE]; - void (*Callback)(void); -}TYPE_CHEAT; - -#endif // __GAME_STRUCTURES__HEADER__ diff --git a/include/Gfx.h b/include/Gfx.h index b2b8295..9f1ec03 100644 --- a/include/Gfx.h +++ b/include/Gfx.h @@ -1,109 +1,58 @@ -#ifndef __GFX_HEADER__ -#define __GFX_HEADER__ +#ifndef GFX_H +#define GFX_H -/* ************************************* - * Includes - * *************************************/ +#include <psxgpu.h> +#include <stdbool.h> -#include "Global_Inc.h" -#include "System.h" +#ifdef __cplusplus +extern "C" +{ +#endif +#define SPRITE_INDEX_INVALID (size_t)(0xFFFFFFFF) +#define MAX_SIZE_FOR_GSSPRITE ((short)256) +enum +{ + GFX_TPAGE_WIDTH = 64, + GFX_TPAGE_WIDTH_BITSHIFT = __builtin_ctz(GFX_TPAGE_WIDTH) +}; /* ************************************* - * Defines + * Public types definition * *************************************/ -#define X_SCREEN_RESOLUTION 384 -#define Y_SCREEN_RESOLUTION 240 -#define VRAM_W 1024 -#define VRAM_H 512 -#define MAX_SIZE_FOR_GSSPRITE 256 -#define GFX_TPAGE_WIDTH 64 -#define GFX_TPAGE_HEIGHT 256 -#define GFX_1HZ_FLASH (1<<7) -#define GFX_2HZ_FLASH (1<<8) -#define FULL_LUMINANCE 0xFF +enum +{ + X_SCREEN_RESOLUTION = 368, + Y_SCREEN_RESOLUTION = 240 +}; /* ************************************* - * Global prototypes + * Public variables declaration * *************************************/ -void GfxInitDrawEnv(void); -void GfxInitDispEnv(void); -void GfxSetPrimitiveList(void); - -// Renders new scene. Use this function unless you know what you are doing! -void GfxDrawScene(void); - -// Blocking version. Calls GfxDrawScene() and then adds a while(GfxIsBusy() ) -// after it. -void GfxDrawScene_Slow(void); - -void GfxDrawScene_NoSwap(void); - -void GfxSwapBuffers(void); - -// Only renders screen and does not update any pad data or timer data. -// To be used in ISR! -void GfxDrawScene_Fast(void); - -// Repotedly, tells is GPU is ready for a DMA transfer. -bool GfxReadyForDMATransfer(void); - -// Fills a GsSprite structure with information from a TIM file. -bool GfxSpriteFromFile(char* fname, GsSprite * spr); - -// Reportedly, loads CLUT data from a TIM image (image data is discarded) -bool GfxCLUTFromFile(char* fname); +/* ************************************* + * Public functions declaration + * *************************************/ -// Returns true if current object is within screen limits, false otherwise. +void GfxInit(void); +bool GfxSpriteFromFile(const char* path, GsSprite *spr); +void GfxSortSprite(GsSprite *spr); bool GfxIsInsideScreenArea(short x, short y, short w, short h); +bool GfxIsSpriteInsideScreenArea(const GsSprite *spr); +void GfxDrawScene(void); +void GfxClear(void); +int GfxToDegrees(int rotate); +int GfxFromDegrees(int degrees); +bool GfxIsBusy(void); +void GfxDrawRectangle(GsRectangle *rect); +void GfxSaveDisplayData(GsSprite *const spr); -// Function overload for GsSprite structures. -bool GfxIsSpriteInsideScreenArea(GsSprite * spr); - -// Used to know whether GPU operation can be done. -bool GfxIsGPUBusy(void); - -// Draws a sprite on screen. First, it checks whether sprite is inside -// screen limits. -void GfxSortSprite(GsSprite * spr); - -uint8_t GfxGetGlobalLuminance(void); - -void GfxSetGlobalLuminance(uint8_t value); - -void GfxIncreaseGlobalLuminance(int8_t step); - -void GfxButtonSetFlags(uint8_t flags); - -void GfxButtonRemoveFlags(uint8_t flags); - -int GfxRotateFromDegrees(int deg); - -void GfxDrawButton(short x, short y, unsigned short btn); - -// Sends current display data on a specific VRAM section and fills -// sprite structure pointed to by "spr". -void GfxSaveDisplayData(GsSprite *spr); - -// Fills GsSprite structure pointed to by "spr" with texture page and U/V -// offset data given a position in VRAM. -bool GfxTPageOffsetFromVRAMPosition(GsSprite * spr, short x, short y); - -void GfxSetSplitScreen(uint8_t playerIndex); - -void GfxDisableSplitScreen(void); - -void GfxDrawScene_NoSwap(void); - -void GfxDevMenuEnable(void); - -/* ************************************* - * Global variables - * *************************************/ +/** \} */ -extern GsSprite PSXButtons; +#ifdef __cplusplus +} +#endif -#endif //__GFX_HEADER__ +#endif /* GFX_H */ diff --git a/include/Global_Inc.h b/include/Global_Inc.h deleted file mode 100644 index 0c8f446..0000000 --- a/include/Global_Inc.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef __GLOBAL_INC__H__ -#define __GLOBAL_INC__H__ - -/* ************************************* - * Includes - * *************************************/ - -#include <psx.h> -#include <stdio.h> -#include <psxsio.h> -#include <stdlib.h> -#include <string.h> -#include <types.h> -#include <fixmath.h> -#include <runexe.h> - -/* ************************************* - * Defines - * *************************************/ - -#define REFRESH_FREQUENCY 50 //50 Hz PAL / 60 Hz NTSC -#define DEBUG_PRINT_VAR(var) dprintf(#var " = %d\n", var); - -#ifndef bool - typedef enum - { - false = 0, - true = 1 - }bool; -#endif - -#if (PSXSDK_VERSION != 0x0599) -#error "Wrong PSXSDK version! Please use version 0.5.99." -#endif - -/* Test for GCC > 5.2.0 */ -#if ( (__GNUC__ != 5) || (__GNUC_MINOR__ != 2) || (__GNUC_PATCHLEVEL__ != 0) ) -#error "Wrong GCC version! Please use version 5.2.0." -#endif - -#endif // __GLOBAL_INC__H__ diff --git a/include/IO.h b/include/IO.h new file mode 100644 index 0000000..4a6343d --- /dev/null +++ b/include/IO.h @@ -0,0 +1,50 @@ +#ifndef IO_H +#define IO_H + +/*******************************************************************//** +* +* \file IO.h +* +* \author Xavier Del Campo +* +* \brief Include file for IO module. +* +************************************************************************/ + +/* ************************************* + * Includes + * *************************************/ + +#include <stdint.h> +#include <stddef.h> + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* ************************************* + * Defines + * *************************************/ + +#define IO_INVALID_FILE_SIZE (size_t)(-1) + +/* ************************************* + * Public types definition + * *************************************/ + +/* ************************************* + * Public variables declaration + * *************************************/ + +/* ************************************* + * Public functions declaration + * *************************************/ + +const uint8_t *IOLoadFile(const char* const strFilePath, size_t* const fileSize); + +#ifdef __cplusplus +} +#endif + +#endif /* IO_H */ diff --git a/include/Interrupts.h b/include/Interrupts.h new file mode 100644 index 0000000..e06e1e3 --- /dev/null +++ b/include/Interrupts.h @@ -0,0 +1,68 @@ +#ifndef INTERRUPTS_H +#define INTERRUPTS_H + +/*******************************************************************//** +* +* @file Interrupts.h +* +* @author Xavier Del Campo +* +* @brief Include file for Interrupts module. +* +************************************************************************/ + +/* ************************************* + * Includes + * *************************************/ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* ************************************* + * Defines + * *************************************/ + +/* ************************************* + * Public types definition + * *************************************/ + +/*******************************************************************//** +* +* \brief List of HW interrupt sources. +* +************************************************************************/ +enum InterruptSource +{ + INT_SOURCE_VBLANK, + INT_SOURCE_GPU, + INT_SOURCE_CDROM, + INT_SOURCE_DMA, + INT_SOURCE_RCNT0, + INT_SOURCE_RCNT1, + INT_SOURCE_RCNT2, + INT_CONTROLLER_MEMCARD_BYTE_RECEIVED, + INT_SIO, + INT_SPU, + INT_CONTROLLER_LIGHTPEN_PIO, + + MAX_INTERRUPT_SOURCES +}; + +/* ************************************* + * Public variables declaration + * *************************************/ + +/* ************************************* + * Public functions declaration + * *************************************/ + +void InterruptsEnableInt(const enum InterruptSource intSource); +void InterruptsDisableInt(const enum InterruptSource intSource); + +#ifdef __cplusplus +} +#endif + +#endif /* INTERRUPTS_H */ diff --git a/include/LoadMenu.h b/include/LoadMenu.h index 8afc373..881eb01 100644 --- a/include/LoadMenu.h +++ b/include/LoadMenu.h @@ -1,14 +1,11 @@ -#ifndef __LOAD_MENU_HEADER__ -#define __LOAD_MENU_HEADER__ +#ifndef LOAD_MENU_H +#define LOAD_MENU_H /* ************************************* * Includes * *************************************/ -#include "Global_Inc.h" -#include "Gfx.h" -#include "System.h" -#include "Font.h" +#include <stdint.h> /* ************************************* * Defines @@ -20,10 +17,10 @@ void LoadMenuInit(void); -void LoadMenu( char* fileList[], - void * dest[], - uint8_t szFileList , uint8_t szDestList); - +void LoadMenu( const char *const *fileList, + void *const *dest, + uint8_t szFileList, uint8_t szDestList); + void LoadMenuEnd(void); -#endif //__LOAD_MENU_HEADER__ +#endif /* LOAD_MENU_H */ diff --git a/include/Serial.h b/include/Serial.h index da2c4ce..88e50db 100644 --- a/include/Serial.h +++ b/include/Serial.h @@ -1,49 +1,31 @@ -#ifndef __SERIAL_HEADER__ -#define __SERIAL_HEADER__ +#ifndef SERIAL_H +#define SERIAL_H /* ************************************* - * Includes + * Includes * *************************************/ -#include "Global_Inc.h" -#include "System.h" -#include "Gfx.h" -#include "Font.h" +#include <stdint.h> +#include <stddef.h> -/* ************************************* - * Defines - * *************************************/ +#ifdef __cplusplus +extern "C" +{ +#endif +#define SERIAL_DATA_PACKET_SIZE 8 #define ACK_BYTE_STRING "b" -/* ************************************** - * Structs and enums * - * *************************************/ +void SerialInit(void); +void SerialRead(uint8_t *ptrArray, size_t nBytes); +void SerialWrite(const void* ptrArray, size_t nBytes); -typedef enum -{ - SERIAL_STATE_INIT = 0, - SERIAL_STATE_STANDBY, - SERIAL_STATE_WRITING_ACK, - SERIAL_STATE_READING_HEADER, - SERIAL_STATE_READING_EXE_SIZE, - SERIAL_STATE_READING_EXE_DATA, - SERIAL_STATE_WAITING_USER_INPUT, - SERIAL_STATE_CLEANING_MEMORY, -}SERIAL_STATE; +#ifdef SERIAL_INTERFACE +void Serial_printf(const char* str, ...); +#endif // SERIAL_INTERFACE -/* ************************************* - * Global prototypes - * *************************************/ +#ifdef __cplusplus +} +#endif -void SerialInit(void); -bool SerialRead(uint8_t* ptrArray, size_t nBytes); -bool SerialWrite(void* ptrArray, size_t nBytes); -void ISR_Serial(void); -void SerialSetState(SERIAL_STATE state); -void SerialSetPCAddress(uint32_t addr); -void SerialSetRAMDestAddress(uint32_t addr); -void SerialSetExeSize(size_t size); -void SerialSetExeBytesReceived(uint32_t bytes_read); - -#endif // __SERIAL_HEADER__ +#endif /* SERIAL_H */ diff --git a/include/System.h b/include/System.h index 2994366..028a840 100644 --- a/include/System.h +++ b/include/System.h @@ -1,118 +1,6 @@ -#ifndef __SYSTEM_HEADER__ -#define __SYSTEM_HEADER__ +#ifndef SYSTEM_H +#define SYSTEM_H -/* ************************************** - * Includes * - * **************************************/ - -#include "Global_Inc.h" -#include "Gfx.h" -#include "Serial.h" - -/* ************************************** - * Defines * - * **************************************/ - -#define TIMER_PRESCALER_1_SECOND 10 -#define TIMER_PRESCALER_1_MINUTE (TIMER_PRESCALER_1_SECOND * 60) - -/* ************************************** - * Global Prototypes * - * **************************************/ - -// Calls PSXSDK init routines void SystemInit(void); -// Sets default VSync (only sets flag to true and increases global_timer) -void ISR_SystemDefaultVBlank(void); - -void SystemSetBusyFlag(bool value); - -// Calls srand() using current global_timer value as seed -void SystemSetRandSeed(void); - -// Returns VSync flag value -bool SystemRefreshNeeded(void); - -// Loads a file into system's internal buffer -bool SystemLoadFile(char*fname); - -// Loads a file into desired buffer -bool SystemLoadFileToBuffer(char* fname, uint32_t init_pos, uint8_t* buffer, uint32_t szBuffer); - -// Clears VSync flag after each frame -void SystemDisableScreenRefresh(void); - -// Returns file buffer address -uint8_t* SystemGetBufferAddress(void); - -// Tells whether srand() has been called using a pseudo-random value -bool SystemIsRandSeedSet(void); - -// Stops program flow during X cycles -void SystemWaitCycles(uint32_t cycles); - -// 1 cycle-length flag with a frequency of 1 Hz -bool System1SecondTick(void); - -// 1 cycle-length flag with a frequency of 2 Hz -bool System500msTick(void); - -// 1 cycle-length flag with a frequency of 10 Hz -bool System100msTick(void); - -// Returns random value between given minimum and maximum values -uint32_t SystemRand(uint32_t min, uint32_t max); - -// Increases global timer by 1 step -void SystemIncreaseGlobalTimer(void); - -// Sets value to emergency mode flag -void SystemSetEmergencyMode(bool value); - -// Returns emergency mode flag state -bool SystemGetEmergencyMode(void); - -// (Experimental) -uint64_t SystemGetGlobalTimer(void); - -// Returns whether critical section of code is being entered -volatile bool SystemIsBusy(void); - -// Returns whether indicated value is contained inside buffer -bool SystemContains_u8(uint8_t value, uint8_t* buffer, size_t sz); - -// Overload for uint16_t -bool SystemContains_u16(uint16_t value, uint16_t* buffer, size_t sz); - -// Reportedly, sets all timer data to zero. -void SystemResetTimers(void); - -// To be called every cycle (i.e.: inside GfxDrawScene() ). -void SystemUserTimersHandler(void); - -// Looks for string "str" inside a string array pointed to by "array". -// Returns index inside string array on success, -1 if not found. -int32_t SystemIndexOfStringArray(char* str, char** array); - -// Function overload for uint16_t data type. -int32_t SystemIndexOf_U16(uint16_t value, uint16_t* array, uint32_t sz); - -// Function overload for uint8_t data type. -int32_t SystemIndexOf_U8(uint8_t value, uint8_t* array, uint32_t from, uint32_t sz); - -void SystemCyclicHandler(void); - -size_t SystemGetBufferSize(void); - -void SystemClearBuffer(void); - -void SystemDisableVBlankInterrupt(void); - -void SystemEnableVBlankInterrupt(void); - -/* ************************************** - * Global Variables * - * **************************************/ - -#endif //__SYSTEM_HEADER__ +#endif /* SYSTEM_H */ diff --git a/src/EndAnimation.c b/src/EndAnimation.c deleted file mode 100644 index 027ca1a..0000000 --- a/src/EndAnimation.c +++ /dev/null @@ -1,233 +0,0 @@ -/* ************************************* - * Includes - * *************************************/ - -#include "EndAnimation.h" - -/* ************************************* - * Defines - * *************************************/ - -/* ************************************* - * Structs and enums - * *************************************/ - -enum -{ - END_ANIMATION_FADEOUT_STEP = 8, - - END_ANIMATION_LINE_STEP = 2, - - END_ANIMATION_SQUARES_SIZE_BITSHIFT = 5, - END_ANIMATION_SQUARES_SIZE = 32, - END_ANIMATION_SQUARES_PER_COLUMN = 8, - END_ANIMATION_SQUARES_PER_ROW = 12, - END_ANIMATION_SQUARES_TOTAL = END_ANIMATION_SQUARES_PER_COLUMN * - END_ANIMATION_SQUARES_PER_ROW, - - END_ANIMATION_SQUARES_TOTAL_MAX_INDEX = END_ANIMATION_SQUARES_TOTAL - 1, - - END_ANIMATION_SQUARES = 0, - END_ANIMATION_FADEOUT, - END_ANIMATION_LINE, - END_ANIMATION_MAX_RAND_VALUE = END_ANIMATION_LINE -}; - -/* ************************************* - * Local Prototypes - * *************************************/ - -static void EndAnimationSquares(void); -static void EndAnimationFadeOut(void); -static void EndAnimationLine(void); - -/* ************************************* - * Local Variables - * *************************************/ - -static GsRectangle EndAnimationRect; -static GsSprite EndAnimationDisplay; - -void EndAnimation(void) -{ - uint8_t randIndex = 0; - - GfxSaveDisplayData(&EndAnimationDisplay); - - GfxSetGlobalLuminance(NORMAL_LUMINANCE); - - if(SystemIsRandSeedSet() == false) - { - // Set default end animation - EndAnimationFadeOut(); - } - else - { - randIndex = rand() % (END_ANIMATION_MAX_RAND_VALUE + 1); - - switch(randIndex) - { - case END_ANIMATION_SQUARES: - EndAnimationSquares(); - break; - - case END_ANIMATION_FADEOUT: - EndAnimationFadeOut(); - break; - - case END_ANIMATION_LINE: - EndAnimationLine(); - break; - - default: - break; - } - } -} - -void EndAnimationFadeOut(void) -{ - uint8_t i; - - while(1) - { - if( GfxGetGlobalLuminance() > 0) - { - GfxSetGlobalLuminance(GfxGetGlobalLuminance() - END_ANIMATION_FADEOUT_STEP); - - GfxSortSprite(&EndAnimationDisplay);; - GfxDrawScene_Slow(); - } - else - { - GsSortCls(0,0,0); - - for(i = 0 ; i < 2 ; i++) - { - // Draw two frames to ensure black display - GfxDrawScene_Slow(); - } - - break; - } - } -} - -void EndAnimationLine(void) -{ - short rectIndex = 0; - - do - { - GfxSortSprite(&EndAnimationDisplay); - - // Draw upper half rectangle - - EndAnimationRect.x = 0; - EndAnimationRect.y = 0; - - EndAnimationRect.w = X_SCREEN_RESOLUTION; - EndAnimationRect.h = rectIndex; - - GsSortRectangle(&EndAnimationRect); - - EndAnimationRect.x = 0; - EndAnimationRect.y = Y_SCREEN_RESOLUTION - rectIndex; - - EndAnimationRect.w = X_SCREEN_RESOLUTION; - EndAnimationRect.h = rectIndex; - - GsSortRectangle(&EndAnimationRect); - - GfxDrawScene_Slow(); - - rectIndex += END_ANIMATION_LINE_STEP; - - }while(rectIndex <= (X_SCREEN_RESOLUTION >> 1) ); - -} - -void EndAnimationSquares(void) -{ - uint16_t i, j, k; - uint16_t randInd = 0; - bool sqPos[END_ANIMATION_SQUARES_TOTAL]; - uint16_t sqCounter = END_ANIMATION_SQUARES_TOTAL; - uint16_t maxIndex = END_ANIMATION_SQUARES_TOTAL_MAX_INDEX; - - EndAnimationRect.w = END_ANIMATION_SQUARES_SIZE; - EndAnimationRect.h = END_ANIMATION_SQUARES_SIZE; - - EndAnimationRect.r = 0; - EndAnimationRect.g = 0; - EndAnimationRect.b = 0; - - memset(sqPos, false , END_ANIMATION_SQUARES_TOTAL); - - for(i = 0; i < END_ANIMATION_SQUARES_TOTAL ; i++) - { - - do - { - randInd = SystemRand(0,maxIndex); - - /*dprintf("randInd = %d\t",randInd); - dprintf("sqPos[randInd] = %d\n", sqPos[randInd]);*/ - - if(sqPos[randInd] == false) - { - sqPos[randInd] = true; - sqCounter--; - - while(sqPos[maxIndex] == true) - { - // Lower maximum value for rand() so that it's - // easier to spot new empty index on next iteration. - maxIndex--; - } - - break; - } - else - { - if(sqCounter == 0) - { - break; - } - } - - }while(1); - - GfxSortSprite(&EndAnimationDisplay); - - if(sqCounter != 0) - { - for(j = 0; j < END_ANIMATION_SQUARES_TOTAL ; j++) - { - if(sqPos[j] == true) - { - EndAnimationRect.x = ((j) << END_ANIMATION_SQUARES_SIZE_BITSHIFT) - - (short)( (j / END_ANIMATION_SQUARES_PER_ROW) * - X_SCREEN_RESOLUTION); - - EndAnimationRect.y = (short) (j/ END_ANIMATION_SQUARES_PER_ROW) << - END_ANIMATION_SQUARES_SIZE_BITSHIFT; - - GsSortRectangle(&EndAnimationRect); - } - } - } - else - { - // Quick fix: draw a full black rectangle instead of multiple squares - for(k = 0 ; k < 2 ; k++) - { - // Draw two frames to ensure black display - GsSortCls(0,0,0); - GfxDrawScene_Slow(); - } - } - - GfxDrawScene_Slow(); - } -} @@ -21,73 +21,73 @@ static char _internal_text[FONT_INTERNAL_TEXT_BUFFER_MAX_SIZE]; static unsigned char _blend_effect_lum; -bool FontLoadImage(char* strPath, TYPE_FONT * ptrFont) +bool FontLoadImage(char *path, struct font *font) { - if(GfxSpriteFromFile(strPath, &ptrFont->spr) == false) + if (GfxSpriteFromFile(path, &font->spr) == false) { return false; } - - ptrFont->spr_w = ptrFont->spr.w; - ptrFont->spr_h = ptrFont->spr.h; - ptrFont->spr_u = ptrFont->spr.u; - ptrFont->spr_v = ptrFont->spr.v; - - //Now set default values to font - - ptrFont->char_w = FONT_DEFAULT_CHAR_SIZE; - ptrFont->char_h = FONT_DEFAULT_CHAR_SIZE; - - ptrFont->spr.attribute |= COLORMODE(COLORMODE_4BPP); - ptrFont->spr.attribute &= COLORMODE(~(COLORMODE_8BPP | COLORMODE_16BPP | COLORMODE_24BPP)); - ptrFont->spr.r = NORMAL_LUMINANCE; - ptrFont->spr.g = NORMAL_LUMINANCE; - ptrFont->spr.b = NORMAL_LUMINANCE; - - //At this point, spr.w and spr.h = real w/h - ptrFont->char_per_row = (uint8_t)(ptrFont->spr_w / ptrFont->char_w); - ptrFont->max_ch_wrap = 0; - - ptrFont->spr.w = ptrFont->char_w; - ptrFont->spr.h = ptrFont->char_h; - - ptrFont->flags = FONT_NOFLAGS; - - ptrFont->init_ch = FONT_DEFAULT_INIT_CHAR; - - dprintf("Sprite CX = %d, sprite CY = %d\n",ptrFont->spr.cx, ptrFont->spr.cy); - + + font->spr_w = font->spr.w; + font->spr_h = font->spr.h; + font->spr_u = font->spr.u; + font->spr_v = font->spr.v; + + /* Now set default values to font */ + + font->char_w = FONT_DEFAULT_CHAR_SIZE; + font->char_h = FONT_DEFAULT_CHAR_SIZE; + + font->spr.attribute |= COLORMODE(COLORMODE_4BPP); + font->spr.attribute &= COLORMODE(~(COLORMODE_8BPP | COLORMODE_16BPP | COLORMODE_24BPP)); + font->spr.r = NORMAL_LUMINANCE; + font->spr.g = NORMAL_LUMINANCE; + font->spr.b = NORMAL_LUMINANCE; + + /* At this point, spr.w and spr.h = real w/h */ + font->char_per_row = (uint8_t)(font->spr_w / font->char_w); + font->max_ch_wrap = 0; + + font->spr.w = font->char_w; + font->spr.h = font->char_h; + + font->flags = FONT_NOFLAGS; + + font->init_ch = FONT_DEFAULT_INIT_CHAR; + + dprintf("Sprite CX = %d, sprite CY = %d\n",font->spr.cx, font->spr.cy); + return true; } -void FontSetInitChar(TYPE_FONT * ptrFont, char c) +void FontSetInitChar(struct font *font, char c) { - ptrFont->init_ch = c; + font->init_ch = c; } -void FontSetFlags(TYPE_FONT * ptrFont, FONT_FLAGS flags) +void FontSetFlags(struct font *font, enum font_flags flags) { - ptrFont->flags = flags; + font->flags = flags; } -void FontSetSize(TYPE_FONT * ptrFont, short size, short bitshift) +void FontSetSize(struct font *font, short size, short bitshift) { - ptrFont->char_w = size; - ptrFont->char_h = size; - - ptrFont->char_w_bitshift = bitshift; - - //At this point, spr.w and spr.h = real w/h - ptrFont->char_per_row = (uint8_t)(ptrFont->spr_w / ptrFont->char_w); - ptrFont->max_ch_wrap = 0; - - ptrFont->spr.w = ptrFont->char_w; - ptrFont->spr.h = ptrFont->char_h; + font->char_w = size; + font->char_h = size; + + font->char_w_bitshift = bitshift; + + /* At this point, spr.w and spr.h = real w/h */ + font->char_per_row = (uint8_t)(font->spr_w / font->char_w); + font->max_ch_wrap = 0; + + font->spr.w = font->char_w; + font->spr.h = font->char_h; } -void FontSetSpacing(TYPE_FONT* ptrFont, short spacing) +void FontSetSpacing(struct font *font, short spacing) { - ptrFont->char_spacing = spacing; + font->char_spacing = spacing; } void FontCyclic(void) @@ -95,99 +95,99 @@ void FontCyclic(void) _blend_effect_lum -= 8; } -void FontPrintText(TYPE_FONT * ptrFont, short x, short y, char* str, ...) +void FontPrintText(struct font *font, short x, short y, char* str, ...) { uint16_t i; uint16_t line_count = 0; int result; short orig_x = x; - + va_list ap; - + va_start(ap, str); - + result = vsnprintf( _internal_text, FONT_INTERNAL_TEXT_BUFFER_MAX_SIZE, str, ap ); - if(ptrFont->flags & FONT_H_CENTERED) + if (font->flags & FONT_H_CENTERED) { - x = (X_SCREEN_RESOLUTION >> 1) - ((result >> 1) << ptrFont->char_w_bitshift); + x = (X_SCREEN_RESOLUTION >> 1) - ((result >> 1) << font->char_w_bitshift); orig_x = x; } - - for(i = 0; i < result ; i++) + + for (i = 0; i < result ; i++) { char _ch = _internal_text[i]; - - if(_ch == '\0') + + if (_ch == '\0') { - // End of string + /* End of string */ break; } - + switch(_ch) { case ' ': - x += ptrFont->char_w; + x += font->char_w; continue; case '\n': x = orig_x; - y += ptrFont->char_h; + y += font->char_h; break; default: - if( (ptrFont->flags & FONT_WRAP_LINE) && (ptrFont->max_ch_wrap != 0) ) + if ( (font->flags & FONT_WRAP_LINE) && (font->max_ch_wrap != 0) ) { - if(++line_count >= ptrFont->max_ch_wrap) + if (++line_count >= font->max_ch_wrap) { line_count = 0; x = orig_x; - y += ptrFont->char_h; + y += font->char_h; } } - - ptrFont->spr.x = x; - ptrFont->spr.y = y; - ptrFont->spr.w = ptrFont->char_w; - ptrFont->spr.h = ptrFont->char_h; - ptrFont->spr.u = (short)( (_ch - ptrFont->init_ch) % ptrFont->char_per_row) * ptrFont->char_w; - ptrFont->spr.u += ptrFont->spr_u; // Add original offset for image - ptrFont->spr.v = (short)( (_ch - ptrFont->init_ch) / ptrFont->char_per_row) * ptrFont->char_h; - ptrFont->spr.v += ptrFont->spr_v; // Add original offset for image - - if(ptrFont->flags & FONT_BLEND_EFFECT) + + font->spr.x = x; + font->spr.y = y; + font->spr.w = font->char_w; + font->spr.h = font->char_h; + font->spr.u = (short)( (_ch - font->init_ch) % font->char_per_row) *font->char_w; + font->spr.u += font->spr_u; /* Add original offset for image */ + font->spr.v = (short)( (_ch - font->init_ch) / font->char_per_row) *font->char_h; + font->spr.v += font->spr_v; /* Add original offset for image */ + + if (font->flags & FONT_BLEND_EFFECT) { - ptrFont->spr.r += 8; - ptrFont->spr.g += 8; - ptrFont->spr.b += 8; + font->spr.r += 8; + font->spr.g += 8; + font->spr.b += 8; } else { - ptrFont->spr.r = NORMAL_LUMINANCE; - ptrFont->spr.g = NORMAL_LUMINANCE; - ptrFont->spr.b = NORMAL_LUMINANCE; + font->spr.r = NORMAL_LUMINANCE; + font->spr.g = NORMAL_LUMINANCE; + font->spr.b = NORMAL_LUMINANCE; } /*dprintf("char_w = %d, char_h = %d, char_per_row = %d, init_ch: %c\n", - ptrFont->char_w, - ptrFont->char_h, - ptrFont->char_per_row, - ptrFont->init_ch); - dprintf("Char: %c, spr.u = %d, spr.v = %d\n",str[i],ptrFont->spr.u, ptrFont->spr.v); - dprintf("Sprite CX = %d, sprite CY = %d\n",ptrFont->spr.cx, ptrFont->spr.cy);*/ - //dprintf("Sprite rgb={%d,%d,%d}\n",ptrFont->spr.r, ptrFont->spr.g, ptrFont->spr.b); - - GfxSortSprite(&ptrFont->spr); - x += ptrFont->char_spacing; + font->char_w, + font->char_h, + font->char_per_row, + font->init_ch); + dprintf("Char: %c, spr.u = %d, spr.v = %d\n",str[i],font->spr.u, font->spr.v); + dprintf("Sprite CX = %d, sprite CY = %d\n",font->spr.cx, font->spr.cy);*/ + /* dprintf("Sprite rgb={%d,%d,%d}\n",font->spr.r, font->spr.g, font->spr.b); */ + + GfxSortSprite(&font->spr); + x += font->char_spacing; break; } } - - if(ptrFont->flags & FONT_BLEND_EFFECT) + + if (font->flags & FONT_BLEND_EFFECT) { - ptrFont->spr.r = _blend_effect_lum; - ptrFont->spr.g = _blend_effect_lum; - ptrFont->spr.b = _blend_effect_lum; + font->spr.r = _blend_effect_lum; + font->spr.g = _blend_effect_lum; + font->spr.b = _blend_effect_lum; } va_end(ap); @@ -1,552 +1,523 @@ +/*******************************************************************//** +* +* \file Gfx.c +* +* \author Xavier Del Campo +* +* \brief Implementation of Gfx module. +* +************************************************************************/ + /* ************************************* - * Includes + * Includes * *************************************/ #include "Gfx.h" +#include "IO.h" +#include <psx.h> +#include <psxgpu.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <stdint.h> /* ************************************* - * Defines + * Defines * *************************************/ -#define PRIMITIVE_LIST_SIZE 0x1000 -#define DOUBLE_BUFFERING_SWAP_Y 256 -#define UPLOAD_IMAGE_FLAG 1 -#define MAX_LUMINANCE 0xFF -#define ROTATE_BIT_SHIFT 12 -#define GPUSTAT (*(unsigned int*)0x1F801814) -#define D2_CHCR (*(unsigned int*)0x1F8010A8) +/* ***************************************************************************** + * Types definition + * ****************************************************************************/ + +/* ***************************************************************************** + * Global variables definition + * ****************************************************************************/ + +/* ***************************************************************************** + * Local variables definition + * ****************************************************************************/ + +/* The drawing environment points to VRAM + * coordinates where primitive data is + * being drawn onto. */ +static GsDrawEnv sDrawEnv; + +/* The display environment points to VRAM + * coordinates where primitive data is + * being shown on screen. */ +static GsDispEnv sDispEnv; + +/* This variable is set to true on VSYNC event. */ +static volatile bool bSyncFlag; + +/* ***************************************************************************** + * Local prototypes declaration + * ****************************************************************************/ + +static void GfxInitDrawEnv(void); +static void GfxInitDispEnv(void); +static void GfxSwapBuffers(void); +static void GfxSortBigSprite(GsSprite *const psSpr); +static void GfxSetPrimList(void); +static void ISR_VBlank(void); + +/* ***************************************************************************** + * Functions definition + * ****************************************************************************/ + +/***************************************************************************//** +* +* \brief Initialization of Gfx module. +* +* \remarks This is where PSX GPU and its interface get initialized. +* +*******************************************************************************/ +void GfxInit(void) +{ + /* Graphics synthetiser (GPU) initialization. */ + GsInit(); -/* ************************************* - * Structs and enums - * *************************************/ + /* Clear VRAM. */ + GsClearMem(); -enum -{ - BUTTON_SIZE = 16, - - BUTTON_CROSS_U = 48, - BUTTON_CROSS_V = 0, - - BUTTON_SQUARE_U = 0, - BUTTON_SQUARE_V = 0, - - BUTTON_TRIANGLE_U = 32, - BUTTON_TRIANGLE_V = 0, - - BUTTON_CIRCLE_U = 16, - BUTTON_CIRCLE_V = 0, - - BUTTON_DIRECTION_U = 64, - BUTTON_DIRECTION_V = 0, - - BUTTON_LR_U = 80, - BUTTON_LR_V = 0, - BUTTON_LR_SIZE = 24, - - LETTER_SIZE = 8, - - LETTER_L1_U = 104, - LETTER_L1_V = 0, - - LETTER_L2_U = 112, - LETTER_L2_V = 0, - - LETTER_R1_U = 104, - LETTER_R1_V = 8, - - LETTER_R2_U = 112, - LETTER_R2_V = 8, - - LETTER_OFFSET_INSIDE_BUTTON_LR_X = 8, - LETTER_OFFSET_INSIDE_BUTTON_LR_Y = 6 - -}; - -enum -{ - GFX_SECOND_DISPLAY_X = 384, - GFX_SECOND_DISPLAY_Y = 256, - GFX_SECOND_DISPLAY_TPAGE = 22 -}; +#if (VIDEO_MODE == VMODE_PAL) || (VIDEO_MODE == VMODE_NSTC) -/* ************************************* - * Global Variables - * *************************************/ + /* Set Video Resolution. VIDEO_MODE can be either VMODE_PAL or VMODE_NTSC */ + GsSetVideoMode(X_SCREEN_RESOLUTION, Y_SCREEN_RESOLUTION, VIDEO_MODE); -GsSprite PSXButtons; +#else /* (VIDEO_MODE == VMODE_PAL) || (VIDEO_MODE == VMODE_NSTC) */ -/* ************************************* - * Local Prototypes - * *************************************/ +#error "Undefined VIDEO_MODE" +#endif /* (VIDEO_MODE == VMODE_PAL) || (VIDEO_MODE == VMODE_NSTC) */ + /* Set Drawing Environment. */ + GfxInitDrawEnv(); -/* ************************************* - * Local Variables - * *************************************/ + /* Set Display Environment. */ + GfxInitDispEnv(); -// Drawing environment -static GsDrawEnv DrawEnv; -// Display environment -static GsDispEnv DispEnv; -// Primitive list (it contains all the graphical data for the GPU) -static unsigned int prim_list[PRIMITIVE_LIST_SIZE]; -// Tells other modules whether data is being loaded to GPU -static volatile bool gfx_busy; -// Dictates (R,G,B) brigthness to all sprites silently -static uint8_t global_lum; -// When true, it draws a rectangle on top of all primitives with -// information for development purposes. -static bool GfxDevMenuEnableFlag; - -void GfxSwapBuffers(void) -{ - // Consistency check -#if PSXSDK_DEBUG - - if(GsListPos() >= PRIMITIVE_LIST_SIZE) - { - dprintf("Linked list iterator overflow!\n"); - while(1); - } - - if( (DrawEnv.h != Y_SCREEN_RESOLUTION) - || - ( (DrawEnv.w != X_SCREEN_RESOLUTION) - && - (DrawEnv.w != X_SCREEN_RESOLUTION >> 1) ) - || - ( (DispEnv.y != DOUBLE_BUFFERING_SWAP_Y) - && - (DispEnv.y != 0) ) ) - { - dprintf("What the hell is happening?\n"); - DEBUG_PRINT_VAR(DispEnv.x); - DEBUG_PRINT_VAR(DispEnv.y); - DEBUG_PRINT_VAR(DrawEnv.x); - DEBUG_PRINT_VAR(DrawEnv.y); - - while(1); - } -#endif // PSXSDK_DEBUG - - if(DrawEnv.h == Y_SCREEN_RESOLUTION) - { - if(DispEnv.y == 0) - { - DispEnv.y = DOUBLE_BUFFERING_SWAP_Y; - DrawEnv.y = 0; - } - else if(DispEnv.y == DOUBLE_BUFFERING_SWAP_Y) - { - DispEnv.y = 0; - DrawEnv.y = DOUBLE_BUFFERING_SWAP_Y; - } - - GsSetDispEnv(&DispEnv); - GsSetDrawEnv(&DrawEnv); - } -} + /* Set primitive list. */ + GfxSetPrimList(); -void GfxDevMenuEnable(void) -{ - GfxDevMenuEnableFlag = true; + /* Set Vsync interrupt handler for screen refresh. */ + SetVBlankHandler(&ISR_VBlank); } -void GfxInitDrawEnv(void) +/***************************************************************************//** +* +* \brief Loads data from file indicated by strFilePath, uploads +* it into VRAM and sets up a new GsSprite instance. +* +* \param strFilePath +* Absolute file path e.g.: +* "cdrom:\\DATA\\SPRITES\\TILESET1.TIM;1". +* +* \param pSpr +* Pointer to sprite to be filled with image data. +* +* \return Returns true when tasks could be made successfully, +* false otherwise. +* +* \see IOLoadFile() for file I/O handling implementation. +* +*******************************************************************************/ +bool GfxSpriteFromFile(const char* const strFilePath, GsSprite *const pSpr) { - DrawEnv.x = 0; - DrawEnv.y = 0; - DrawEnv.draw_on_display = false; - DrawEnv.w = X_SCREEN_RESOLUTION; - DrawEnv.h = Y_SCREEN_RESOLUTION; - - GsSetDrawEnv(&DrawEnv); + /* File size in bytes. Modified by IOLoadFile(). */ + size_t eSize; + + /* Get buffer address where file data is contained. */ + const uint8_t *const buffer = IOLoadFile(strFilePath, &eSize); + + if (buffer && (eSize != IO_INVALID_FILE_SIZE)) + { + /* File was loaded successfully into buffer. + * Now read buffer data and upload it to VRAM. */ + + /* Declare a GsImage instance, needed by GsImageFromTim(). */ + GsImage sGsi; + + while (GsIsDrawing()); + + if (GsImageFromTim(&sGsi, buffer) == 1 /* Success code. */) + { + enum + { + UPLOAD_IMAGE_FLAG = 1 + }; + + /* sGsi is now filled with data. Create + * a GsSprite instance from it. */ + + /* Call PSXSDK libs to upload image data to VRAM. "const" flag must be removed. */ + if (GsSpriteFromImage(pSpr, &sGsi, UPLOAD_IMAGE_FLAG) == 1 /* Success code. */) + { + /* Return success code. */ + return true; + } + else + { + /* Something went wrong when obtaining data + * from GsImage instance. Fall through. */ + } + } + else + { + /* Something went wrong when obtaining *.TIM data. + * Fall through. */ + } + } + else + { + /* Something went wrong when loading the file. Fall through. */ + } + + /* Return failure code if reached here. */ + return false; } -void GfxInitDispEnv(void) +void GfxClear(void) { - DispEnv.x = 0; - DispEnv.y = 0; - - GsSetDispEnv(&DispEnv); + GsSortCls(0, 0, 0); } -void GfxSetPrimitiveList(void) +/***************************************************************************//** +* +* \brief Draws current primitive list into screen and performs double +* buffering. +* +* \remarks Blocking function. This function waits for GPU to be free and GPU +* VSYNC IRQ flag to be set. +* +*******************************************************************************/ +void GfxDrawScene(void) { - GsSetList(prim_list); -} + /* Hold program execution until VSYNC flag is set + * and GPU is ready to work. */ + while (!bSyncFlag || GsIsDrawing()); -void GfxDrawScene_Fast(void) -{ - GfxSwapBuffers(); - FontCyclic(); - GsDrawList(); -} + /* Reset VSYNC event flag. */ + bSyncFlag = false; -bool GfxReadyForDMATransfer(void) -{ - return ( (GPUSTAT & 1<<28) && !(D2_CHCR & 1<<24) ); -} + /* Swap drawing and display enviroments Y position. */ + GfxSwapBuffers(); -void GfxDrawScene(void) -{ - while( (SystemRefreshNeeded() == false) - || - (GfxIsGPUBusy() == true) ); - - GfxDrawScene_Fast(); - - SystemCyclicHandler(); + /* Draw all primitives into screen. */ + GsDrawList(); } -void GfxDrawScene_Slow(void) +bool GfxIsBusy(void) { - GfxDrawScene(); - while(GfxIsGPUBusy() == true); + return GsIsDrawing(); } -void GfxSortSprite(GsSprite * spr) +/***************************************************************************//** +* +* \brief Indicates whether a rectangle defined by x, y, w and h whether +* inside current drawing area. +* +* \param x +* Rectangle initial X offset. +* +* \param y +* Rectangle initial X offset. +* +* \param w +* Rectangle width. +* +* \param h +* Rectangle height. +* +* \return Returns true if rectangle defined by input parameters +* is inside screen area, false otherwise. +* +*******************************************************************************/ +bool GfxIsInsideScreenArea(const short x, const short y, const short w, const short h) { - uint8_t aux_r = spr->r; - uint8_t aux_g = spr->g; - uint8_t aux_b = spr->b; - unsigned char aux_tpage = spr->tpage; - short aux_w = spr->w; - short aux_x = spr->x; - - if( (spr->w <= 0) || (spr->h <= 0) ) - { - // Invalid width or heigth - return; - } - - if(GfxIsSpriteInsideScreenArea(spr) == false) - { - return; - } - - if(global_lum != NORMAL_LUMINANCE) - { - if(spr->r < NORMAL_LUMINANCE - global_lum) - { - spr->r = 0; - } - else - { - spr->r -= NORMAL_LUMINANCE - global_lum; - } - - if(spr->g < NORMAL_LUMINANCE - global_lum) - { - spr->g = 0; - } - else - { - spr->g -= NORMAL_LUMINANCE - global_lum; - } - - if(spr->b < NORMAL_LUMINANCE - global_lum) - { - spr->b = 0; - } - else - { - spr->b -= NORMAL_LUMINANCE - global_lum; - } - } - - if(spr->w > MAX_SIZE_FOR_GSSPRITE) - { - // GsSprites can't be bigger than 256x256, so since display - // resolution is 384x240, it must be split into two primitives. - - spr->w = MAX_SIZE_FOR_GSSPRITE; - GsSortSprite(spr); - - spr->x += MAX_SIZE_FOR_GSSPRITE; - spr->w = X_SCREEN_RESOLUTION - MAX_SIZE_FOR_GSSPRITE; - spr->tpage += MAX_SIZE_FOR_GSSPRITE / GFX_TPAGE_WIDTH; - GsSortSprite(spr); - - // Restore original values after sorting - spr->w = aux_w; - spr->tpage = aux_tpage; - spr->x = aux_x; - } - else - { - GsSortSprite(spr); - } - - spr->r = aux_r; - spr->g = aux_g; - spr->b = aux_b; + if (((x + w) >= 0) + && + (x < sDrawEnv.w) + && + ((y + h) >= 0) + && + (y < sDrawEnv.h)) + { + /* Rectangle is inside drawing environment area. */ + return true; + } + else + { + /* Rectangle is outside drawing environment area. + * Fall through. */ + } + + /* Return failure code if reached here. */ + return false; } -uint8_t GfxGetGlobalLuminance(void) +/***************************************************************************//** +* +* \brief Indicates whether a tSprite instance is inside active +* drawing environment area. +* +* \param psSpr +* Pointer to tSprite structure. +* +*******************************************************************************/ +bool GfxIsSpriteInsideScreenArea(const GsSprite *const psSpr) { - return global_lum; + /* Define X/Y and width/height parameters. */ + const short x = psSpr->x; + const short y = psSpr->y; + const short w = psSpr->w; + const short h = psSpr->h; + + /* Return results. */ + return GfxIsInsideScreenArea(x, y, w, h); } -void GfxSetGlobalLuminance(uint8_t value) +/***************************************************************************//** +* +* \brief Extracting information from tSprite instance, this function adds a +* low-level GsSprite structure into internal primitive list if inside +* drawing environment area. +* +* \param psSpr +* Index of low-level sprite structure inside the internal array. +* +* \remarks Sprites bigger than 256x256 px are also supported. Internally, +* GfxSortBigSprite() draws two primitive, so up to 512x256 px +* primitives are supported. +* +* \see GfxSortBigSprite() to see how big sprites are handled. +* +*******************************************************************************/ +void GfxSortSprite(GsSprite *const psSpr) { - global_lum = value; + if (GfxIsSpriteInsideScreenArea(psSpr)) + { + /* Small sprites can be directly drawn using PSXSDK function. + * On the other hand, big sprites need some more processing. */ + psSpr->w > MAX_SIZE_FOR_GSSPRITE ? GfxSortBigSprite(psSpr) : GsSortSprite(psSpr); + } + else + { + /* Sprite is outside drawing environment area. Exit. */ + } } -void GfxIncreaseGlobalLuminance(int8_t step) -{ - if( ( (global_lum + step) < MAX_LUMINANCE ) - && - ( (global_lum + step) > 0 ) ) - { - global_lum += step; - } - else - { - global_lum = MAX_LUMINANCE; - } -} - -int GfxRotateFromDegrees(int deg) +int GfxToDegrees(const int rotate) { - return deg << ROTATE_BIT_SHIFT; + return rotate >> 12; } -bool GfxIsGPUBusy(void) +int GfxFromDegrees(const int degrees) { - return (GsIsDrawing() || gfx_busy || (GfxReadyForDMATransfer() == false) ); + return degrees << 12; } -bool GfxSpriteFromFile(char* fname, GsSprite * spr) +void GfxDrawRectangle(GsRectangle* const rect) { - GsImage gsi; - - if(SystemLoadFile(fname) == false) - { - return false; - } - - while(GfxIsGPUBusy() == true); - - gfx_busy = true; - - GsImageFromTim(&gsi,SystemGetBufferAddress() ); - - GsSpriteFromImage(spr,&gsi,UPLOAD_IMAGE_FLAG); - gfx_busy = false; - - DEBUG_PRINT_VAR(spr->tpage); - DEBUG_PRINT_VAR(spr->u); - DEBUG_PRINT_VAR(spr->v); - DEBUG_PRINT_VAR(spr->w); - DEBUG_PRINT_VAR(spr->h); - - return true; + GsSortRectangle(rect); } -bool GfxCLUTFromFile(char* fname) +/***************************************************************************//** +* +* \brief Processes big sprites (e.g.: more than 256 px wide) by drawing two +* separate primitives. +* +* \param psSpr +* Pointer to low-level GsSprite structure (given by +* GfxSortSprite()). +* +*******************************************************************************/ +static void GfxSortBigSprite(GsSprite *const psSpr) { - GsImage gsi; - - if(SystemLoadFile(fname) == false) - { - return false; - } - - while(GfxIsGPUBusy() == true); - - gfx_busy = true; - - GsImageFromTim(&gsi,SystemGetBufferAddress() ); - - GsUploadCLUT(&gsi); - - gfx_busy = false; - - return true; + /* On the other hand, GsSprite instances bigger than + * 256x256 px must be split into two primitives, so + * GsSortSprite shall be called twice. */ + + /* Store original TPage, width and X data. */ + const unsigned char aux_tpage = psSpr->tpage; + const short aux_w = psSpr->w; + const short aux_x = psSpr->x; + + /* First primitive will be 256x256 px. */ + psSpr->w = MAX_SIZE_FOR_GSSPRITE; + + /* Render first primitive (256x256 px). */ + GsSortSprite(psSpr); + + /* Second primitive will be: + * Width = Original Width - 256 px. + * Height = Original Height - 256 px. */ + psSpr->x += MAX_SIZE_FOR_GSSPRITE; + psSpr->w = X_SCREEN_RESOLUTION - MAX_SIZE_FOR_GSSPRITE; + + /* TPage must be increased as we are looking 256 px to + * the right inside VRAM. Remember that TPages are 64x64 px. */ + psSpr->tpage += MAX_SIZE_FOR_GSSPRITE >> GFX_TPAGE_WIDTH_BITSHIFT; + + /* Render second primitive. */ + GsSortSprite(psSpr); + + /* Restore original TPage, width and X values. */ + psSpr->tpage = aux_tpage; + psSpr->w = aux_w; + psSpr->x = aux_x; } -bool GfxIsInsideScreenArea(short x, short y, short w, short h) +/*******************************************************************//** +* +* \brief Initialization of PSX low-level drawing environment. +* +* The drawing environment is a rectangle where primitives +* are drawn on. +* +* \remarks Not to be confused with display environment, which is a +* rectangle showing VRAM active display area. +* +************************************************************************/ +static void GfxInitDrawEnv(void) { - if( ( (x + w) >= 0) - && - (x < DrawEnv.w) - && - ( (y + h) >= 0) - && - (y < DrawEnv.h) ) - { - return true; - } - - return false; + /* Initialize drawing environment default values. */ + sDrawEnv.w = X_SCREEN_RESOLUTION; + sDrawEnv.h = Y_SCREEN_RESOLUTION; + + /* Initialize drawing environment. */ + GsSetDrawEnv(&sDrawEnv); } -bool GfxIsSpriteInsideScreenArea(GsSprite * spr) +/*******************************************************************//** +* +* \brief Initialization of PSX low-level display environment. +* +* The display environment is a rectangle describing VRAM +* (video RAM) active display area. +* +* \remarks Not to be confused with drawing environment, which is a +* rectangle where primitives are drawn on. +* +************************************************************************/ +static void GfxInitDispEnv(void) { - return GfxIsInsideScreenArea(spr->x, spr->y, spr->w, spr->h); + /* Initialize display environment. */ + GsSetDispEnv(&sDispEnv); } -void GfxButtonSetFlags(uint8_t flags) +/*******************************************************************//** +* +* \brief This function sets a pointer to a buffer which holds +* low-level primitive data, and performs double buffering +* so a secondary buffer can be used to calculate the new scene. +* +************************************************************************/ +static void GfxSetPrimList(void) { - PSXButtons.attribute |= flags; + enum + { + /* Maximum amount of each low-level primitive data buffer. */ + PRIMITIVE_LIST_SIZE = 0x400 + }; + + /* Buffers that will hold all primitive low-level data. */ + static uint32_t primList[PRIMITIVE_LIST_SIZE]; + + /* Set primitive list. */ + GsSetList(primList); } -void GfxButtonRemoveFlags(uint8_t flags) +/*******************************************************************//** +* +* \brief Performs double buffering. +* +* Double buffering consists of swapping drawing and display +* environments Y position, so that the display environment is +* showing current frame, whereas the drawing environment +* is calculating the next frame. +* +************************************************************************/ +static void GfxSwapBuffers(void) { - PSXButtons.attribute &= ~flags; + enum + { + DOUBLE_BUFFERING_SWAP_Y = 256 + }; + + if (sDispEnv.y == 0) + { + sDispEnv.y = DOUBLE_BUFFERING_SWAP_Y; + sDrawEnv.y = 0; + } + else if (sDispEnv.y == DOUBLE_BUFFERING_SWAP_Y) + { + sDispEnv.y = 0; + sDrawEnv.y = DOUBLE_BUFFERING_SWAP_Y; + } + + /* Update drawing and display environments + * with new calculated Y position. */ + GsSetDispEnv(&sDispEnv); + GsSetDrawEnv(&sDrawEnv); } -void GfxDrawButton(short x, short y, unsigned short btn) +/*******************************************************************//** +* +* \brief This function is executed on VSYNC event. +* +* Game runs at a fixed rate of 50 Hz (if PAL) or 60 Hz (NTSC), +* so if CPU has finished calculating the new scene, it must +* wait for this interrupt to be triggered so the game runs +* at desired frame rate. +* +************************************************************************/ +static void ISR_VBlank(void) { - static bool first_entered = true; - static short orig_u; - static short orig_v; - - if(first_entered == true) - { - first_entered = false; - orig_u = PSXButtons.u; - orig_v = PSXButtons.v; - } - - PSXButtons.w = BUTTON_SIZE; - PSXButtons.h = BUTTON_SIZE; - - PSXButtons.r = NORMAL_LUMINANCE; - PSXButtons.g = NORMAL_LUMINANCE; - PSXButtons.b = NORMAL_LUMINANCE; - - PSXButtons.x = x; - PSXButtons.y = y; - PSXButtons.mx = PSXButtons.w >> 1; - PSXButtons.my = PSXButtons.h >> 1; - - switch(btn) - { - case PAD_CROSS: - PSXButtons.u = BUTTON_CROSS_U; - PSXButtons.v = BUTTON_CROSS_V; - break; - - case PAD_SQUARE: - PSXButtons.u = BUTTON_SQUARE_U; - PSXButtons.v = BUTTON_SQUARE_V; - break; - - case PAD_TRIANGLE: - PSXButtons.u = BUTTON_TRIANGLE_U; - PSXButtons.v = BUTTON_TRIANGLE_V; - break; - - case PAD_CIRCLE: - PSXButtons.u = BUTTON_CIRCLE_U; - PSXButtons.v = BUTTON_CIRCLE_V; - break; - - case PAD_RIGHT: - PSXButtons.u = BUTTON_DIRECTION_U; - PSXButtons.v = BUTTON_DIRECTION_V; - break; - - case PAD_UP: - PSXButtons.u = BUTTON_DIRECTION_U; - PSXButtons.v = BUTTON_DIRECTION_V; - PSXButtons.rotate = 90 << ROTATE_BIT_SHIFT; - break; - - case PAD_DOWN: - PSXButtons.u = BUTTON_DIRECTION_U; - PSXButtons.v = BUTTON_DIRECTION_V; - PSXButtons.rotate = 270 << ROTATE_BIT_SHIFT; - break; - - case PAD_LEFT: - PSXButtons.u = BUTTON_DIRECTION_U; - PSXButtons.v = BUTTON_DIRECTION_V; - PSXButtons.attribute |= H_FLIP; - break; - - case PAD_L1: - // Fall through - case PAD_L2: - // Fall through - case PAD_R1: - // Fall through - case PAD_R2: - PSXButtons.u = BUTTON_LR_U; - PSXButtons.v = BUTTON_LR_V; - PSXButtons.w = BUTTON_LR_SIZE; - break; - - case PAD_SELECT: - // Fall through - case PAD_START: - // Fall through - default: - // Set null width and height so that sprite doesn't get sorted - PSXButtons.w = 0; - PSXButtons.h = 0; - break; - } - - PSXButtons.u += orig_u; - PSXButtons.v += orig_v; - - GfxSortSprite(&PSXButtons); - - PSXButtons.attribute &= ~H_FLIP; - PSXButtons.rotate = 0; + /* Set VSYNC flag. */ + bSyncFlag = true; } -void GfxSaveDisplayData(GsSprite *spr) +/*******************************************************************//** +* +* \brief Duplicates current displayed screen as into a separate part +* of VRAM so it can be used as a sprite. +* +************************************************************************/ +void GfxSaveDisplayData(GsSprite *const spr) { - while(GfxIsGPUBusy() == true); - + enum + { + VRAM_W = 1024, + VRAM_H = 512, + GFX_SECOND_DISPLAY_X = 368, + GFX_SECOND_DISPLAY_Y = 256, + + GFX_SECOND_DISPLAY_TPAGE = (GFX_SECOND_DISPLAY_X / GFX_TPAGE_WIDTH) + ((GFX_SECOND_DISPLAY_Y / (VRAM_H / 2)) * VRAM_W / GFX_TPAGE_WIDTH), + GFX_SECOND_DISPLAY_U = GFX_SECOND_DISPLAY_X % GFX_TPAGE_WIDTH + }; + + while (GfxIsGPUBusy()); + MoveImage( DispEnv.x, DispEnv.y, GFX_SECOND_DISPLAY_X, GFX_SECOND_DISPLAY_Y, X_SCREEN_RESOLUTION, Y_SCREEN_RESOLUTION); - + spr->x = 0; spr->y = 0; spr->tpage = GFX_SECOND_DISPLAY_TPAGE; spr->attribute |= COLORMODE(COLORMODE_16BPP); spr->w = X_SCREEN_RESOLUTION; spr->h = Y_SCREEN_RESOLUTION; - spr->u = 0; + spr->u = GFX_SECOND_DISPLAY_U; spr->v = 0; spr->r = NORMAL_LUMINANCE; spr->g = NORMAL_LUMINANCE; spr->b = NORMAL_LUMINANCE; - while(GfxIsGPUBusy() == true); -} - -bool GfxTPageOffsetFromVRAMPosition(GsSprite * spr, short x, short y) -{ - if( (x >= VRAM_W) || (x < 0) || (y >= VRAM_H) || (y < 0) ) - { - return false; - } - - spr->tpage = x / GFX_TPAGE_WIDTH; - spr->tpage += (short)(VRAM_W / GFX_TPAGE_WIDTH) * (short)(y / GFX_TPAGE_HEIGHT); - - spr->u = (x % GFX_TPAGE_WIDTH); - - if(spr->attribute & COLORMODE(COLORMODE_8BPP)) - { - // On 8bpp images, it looks like U offset needs to be multiplied by 2. - spr->u <<= 1; - } - - spr->v = (y % GFX_TPAGE_HEIGHT); - - //dprintf("Sprite:\n\tTPAGE: %d\n\tU=%d\n\tV=%d\n",spr->tpage,spr->u, spr->v); - - return false; + while (GfxIsGPUBusy()); } diff --git a/src/IO.c b/src/IO.c new file mode 100644 index 0000000..401971b --- /dev/null +++ b/src/IO.c @@ -0,0 +1,266 @@ +/*******************************************************************//** +* +* \file IO.c +* +* \author Xavier Del Campo +* +* \brief Implementation of IO module. +* +************************************************************************/ + +/* ************************************* + * Includes + * *************************************/ + +#include "IO.h" +#include "Interrupts.h" +#include "Gfx.h" +#include "Serial.h" +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <stddef.h> +#include <string.h> + +/* ************************************* + * Defines + * *************************************/ + +enum +{ + FILE_BUFFER_SIZE = 182 << 10 +}; + +/* ************************************* + * Types definition + * *************************************/ + +/* ************************************* + * Global variables definition + * *************************************/ + +/* ************************************* + * Local variables definition + * *************************************/ + +/* ************************************* + * Local prototypes declaration + * *************************************/ + +/* ************************************* + * Functions definition + * *************************************/ + +#ifndef SERIAL_INTERFACE + +static const uint8_t *IOLoadFileFromCd(char* const buffer, size_t* const fileSize, uint8_t *const fileBuffer) +{ + InterruptsDisableInt(INT_SOURCE_VBLANK); + + /* Get file data from input file path. */ + FILE* pFile = fopen((char*)buffer, "rb"); + + InterruptsEnableInt(INT_SOURCE_VBLANK); + + if (pFile != NULL) + { + /* Move file pointer to end of file. */ + if (fseek(pFile, 0, SEEK_END) == 0 /* Success code. */) + { + if (fileSize != NULL) + { + /* File pointer could be successfully + * moved to the new position. */ + + /* Return file size in bytes to upper layers. */ + *fileSize = ftell(pFile); + + if (*fileSize <= FILE_BUFFER_SIZE) + { + /* Buffer was successfully allocated according + * to file size. Now read file data into buffer. */ + + /* Reset file pointer iterator position first. */ + if (fseek(pFile, 0, SEEK_SET) == 0 /* Sucess code. */) + { + /* Read file data into newly allocated buffer. */ + const size_t eReadBytes = fread(fileBuffer, sizeof (uint8_t), *fileSize, pFile); + + /* Close input opened file first. */ + fclose(pFile); + + if (eReadBytes == *fileSize) + { + /* All bytes could be read from input file successfully. */ + + /* Finally, return address to buffer so it can be + * used by external modules. */ + + printf("%s has been successfully uploaded\n", buffer); + return fileBuffer; + } + else + { + /* Not all bytes from file were read. + * Fall through. */ + } + } + else + { + /* Something went wrong with fseek(). + * Fall through. */ + } + } + else + { + /* Buffer cannot hold such amount of data. + * Fall through. */ + printf("%s does not fit into internal buffer (%ld / %ld bytes)\n", + buffer, *fileSize, FILE_BUFFER_SIZE); + } + + /* Set file size to an invalid value. */ + *fileSize = IO_INVALID_FILE_SIZE; + } + else + { + /* Invalid pointer to file size. */ + } + } + else + { + /* Something went wrong with fseek(). + * Fall through. */ + } + } + else + { + /* File does not exist. Fall through. */ + printf("File %s does not exist\n", buffer); + } + + return NULL; +} + +#else /* SERIAL_INTERFACE */ + +static const uint8_t *IOLoadFileFromSerial(char* const buffer, size_t* const fileSize, uint8_t *const fileBuffer) +{ + uint8_t receivedSizeb[sizeof (uint32_t)] = {0}; + size_t receivedSize = 0; + size_t i; + + Serial_printf("#%s@", buffer); + + SerialRead(receivedSizeb, sizeof (uint32_t)); + + for (i = 0; i < sizeof (uint32_t); i++) + { + receivedSize |= receivedSizeb[i] << (i << 3); // (i << 3) == (i * 8) + } + + SerialWrite(ACK_BYTE_STRING, sizeof (uint8_t)); + + if (receivedSize <= FILE_BUFFER_SIZE) + { + for (i = 0; i < receivedSize; i += SERIAL_DATA_PACKET_SIZE) + { + size_t bytes_to_read; + + // Read actual EXE data into proper RAM address. + + if ( (i + SERIAL_DATA_PACKET_SIZE) >= receivedSize) + { + bytes_to_read = receivedSize - i; + } + else + { + bytes_to_read = SERIAL_DATA_PACKET_SIZE; + } + + SerialRead(&fileBuffer[i], bytes_to_read); + + SerialWrite(ACK_BYTE_STRING, sizeof (uint8_t)); // Write ACK + } + + *fileSize = receivedSize; + + return fileBuffer; + } + else + { + printf("Input file %s cannot be stored into internal buffer\n", buffer); + } + + *fileSize = 0; + + return NULL; +} + +#endif /* SERIAL_INTERFACE */ + +/*******************************************************************//** +* +* \brief Loads a file with absolute file path indicated by +* strFileName. +* +* File data is stored into a statically-allocated buffer +* which can then be handled by external modules. +* +* \param strFilePath +* Relative file path e.g.: +* "DATA\\SPRITES\\TILESET1.TIM". +* +* \param fileSize +* Pointer to size_t variable where file size will +* be stored. +* +* \return Address to a read-only buffer with file data if successful, +* NULL pointer otherwise. +* +* \return fileSize is assigned to actual file size in bytes if +* successful, \ref IO_INVALID_FILE_SIZE otherwise. +* +************************************************************************/ +const uint8_t *IOLoadFile(const char* const strFilePath, size_t* const fileSize) +{ + if (strFilePath) + { + enum + { + MAX_FILE_PATH_LENGTH = 128 + }; + + /* This buffer shall be used to concatenate "cdrom:\\" + * and ";1" substrings along with indicated file path. */ + static char buffer[MAX_FILE_PATH_LENGTH]; + + /* Create absolute file path from indicated path. */ + snprintf(buffer, sizeof (buffer), "cdrom:\\%s;1", strFilePath); + + if (buffer != NULL) + { + /* This buffer holds file data read from CD-ROM or serial port. + * It is cleared out on each call to IOLoadFile(), + * so copy its contents into an auxilar buffer if needed. */ + static uint8_t fileBuffer[FILE_BUFFER_SIZE]; + +#ifdef SERIAL_INTERFACE + return IOLoadFileFromSerial(buffer, fileSize, fileBuffer); +#else /* SERIAL_INTERFACE */ + return IOLoadFileFromCd(buffer, fileSize, fileBuffer); +#endif /* SERIAL_INTERFACE */ + } + else + { + /* File path could not be stored. */ + } + } + else + { + /* Invalid pointer to file path. */ + } + + /* Return failure code if this was reached. */ + return NULL; +} diff --git a/src/Interrupts.c b/src/Interrupts.c new file mode 100644 index 0000000..ce407cf --- /dev/null +++ b/src/Interrupts.c @@ -0,0 +1,126 @@ +/*******************************************************************//** +* +* \file Interrupts.c +* +* \author Xavier Del Campo +* +* \brief Implementation of Interrupts module. +* +************************************************************************/ + +/* ************************************* + * Includes + * *************************************/ + +#include "Interrupts.h" +#include <psx.h> +#include <stdint.h> +#include <stddef.h> + +/* ************************************* + * Defines + * *************************************/ + +#ifndef I_MASK +/*******************************************************************//** +* +* \brief Interrupt mask register. +* +* According to NoCash specifications, I_MASK bits are +* structured as follows: +* +* \arg Bit 0 IRQ0 VBLANK (PAL=50Hz, NTSC=60Hz) +* \arg Bit 1 IRQ1 GPU +* \arg Bit 2 IRQ2 CDROM +* \arg Bit 3 IRQ3 DMA +* \arg Bit 4 IRQ4 TMR0 Timer 0 aka Root Counter 0 +* \arg Bit 5 IRQ5 TMR1 Timer 1 aka Root Counter 1 +* \arg Bit 6 IRQ6 TMR2 Timer 2 aka Root Counter 2 +* \arg Bit 7 IRQ7 Controller and Memory Card +* \arg Bit 8 IRQ8 SIO +* \arg Bit 9 IRQ9 SPU +* \arg Bit 10 IRQ10 Controller - Lightpen Interrupt +* \arg Bits 11-15 Not used (always zero) +* \arg Bits 16-31 Garbage +* +************************************************************************/ +#define I_MASK (*(volatile unsigned int*)0x1F801074) +#endif /* I_MASK */ + +/* ************************************* + * Types definition + * *************************************/ + +/* ************************************* + * Global variables definition + * *************************************/ + +/* ************************************* + * Local variables definition + * *************************************/ + +/* ************************************* + * Local prototypes declaration + * *************************************/ + +/* ************************************* + * Functions definition + * *************************************/ + +/*******************************************************************//** +* +* \brief Enables an interrupt source given by intSource. +* +* \param intSource +* HW interrupt source. +* +* \see \ref InterruptSource for a list of possible HW interrupt causes. +* +************************************************************************/ +void InterruptsEnableInt(const enum InterruptSource intSource) +{ + if (intSource < MAX_INTERRUPT_SOURCES) + { + /* Disable interrupts while I_MASK is modified. */ + EnterCriticalSection(); + + /* Set bit for selected interrupt source. */ + I_MASK |= 1 << intSource; + + /* Re-enable interrupts. */ + ExitCriticalSection(); + } + else + { + /* Invalid selected InterruptSource instance. Exit. */ + } +} + +/*******************************************************************//** +* +* \brief Disables an interrupt source given by intSource. +* +* \param intSource +* HW interrupt source. +* +* \see \ref InterruptSource for a list of possible HW interrupt causes. +* +************************************************************************/ +void InterruptsDisableInt(const enum InterruptSource intSource) +{ + if (intSource < MAX_INTERRUPT_SOURCES) + { + /* Disable interrupts while I_MASK is modified. */ + EnterCriticalSection(); + + /* Remove bit for selected interrupt source. */ + I_MASK &= ~(1 << intSource); + + /* Re-enable interrupts while I_MASK is modified. */ + ExitCriticalSection(); + } + else + { + /* Invalid selected InterruptSource instance. Exit. */ + } +} diff --git a/src/LoadMenu.c b/src/LoadMenu.c index ba8efaf..ffc3f3a 100644 --- a/src/LoadMenu.c +++ b/src/LoadMenu.c @@ -1,11 +1,11 @@ /* ************************************** - * Includes * + * Includes * * *************************************/ #include "LoadMenu.h" /* ************************************** - * Defines * + * Defines * * *************************************/ /* ************************************** @@ -31,10 +31,10 @@ enum LOADING_BAR_X = 64, LOADING_BAR_Y = 200, LOADING_BAR_N_LINES = 4, - + LOADING_BAR_WIDTH = 256, LOADING_BAR_HEIGHT = 16, - + LOADING_BAR_LUMINANCE_TARGET = NORMAL_LUMINANCE, LOADING_BAR_LUMINANCE_STEP = 10 }; @@ -45,23 +45,23 @@ enum LOADING_TITLE_CLUT_Y = 496, LOADING_TITLE_X = 128, LOADING_TITLE_Y = 32, - + LOADING_TITLE_U = 0, LOADING_TITLE_V = 0, - + LOADING_TITLE_LUMINANCE_STEP = 10, LOADING_TITLE_LUMINANCE_TARGET = NORMAL_LUMINANCE }; enum -{ +{ PLANE_START_X = 56, PLANE_START_Y = 200, - + PLANE_U = 0, PLANE_V = 32, PLANE_SIZE = 16, - + PLANE_LUMINANCE_STEP = 0x10, PLANE_LUMINANCE_TARGET_VALUE = NORMAL_LUMINANCE }; @@ -69,8 +69,8 @@ enum /* ************************************* * Local Prototypes * *************************************/ - -static void LoadMenuLoadFileList( char* fileList[], void * dest[], + +static void LoadMenuLoadFileList( char* fileList[], void * dest[], uint8_t szFileList, uint8_t szDestList); /* ************************************* @@ -79,30 +79,30 @@ static void LoadMenuLoadFileList( char* fileList[], void * dest[], static char* LoadMenuFiles[] = { "cdrom:\\DATA\\FONTS\\FONT_2.FNT;1" }; -static void * LoadMenuDest[] = { (TYPE_FONT*)&SmallFont }; +static void * LoadMenuDest[] = { (struct font*)&SmallFont }; static char* strCurrentFile; -// Flags to communicate with ISR state -// * startup_flag: background fades in from black to blue. -// * end_flag: tells the background to fade out to black. -// * isr_ended: background has totally faded out to black. -// * isr_started: tells the ISR has finished starting up. +/* Flags to communicate with ISR state */ +/* * startup_flag: background fades in from black to blue. */ +/* * end_flag: tells the background to fade out to black. */ +/* * isr_ended: background has totally faded out to black. */ +/* * isr_started: tells the ISR has finished starting up. */ static volatile bool startup_flag; static volatile bool isr_started; static volatile bool end_flag; static volatile bool isr_ended; -// Set to true when LoadMenuInit() has been called, and set to false -// once LoadMenuEnd() is called. -// It's used when multiple modules call LoadMenu() at the same time, -// so load menu does not have to be initialised each time; +/* Set to true when LoadMenuInit() has been called, and set to false */ +/* once LoadMenuEnd() is called. */ +/* It's used when multiple modules call LoadMenu() at the same time, */ +/* so load menu does not have to be initialised each time; */ static bool load_menu_running; void LoadMenuInit(void) { static bool first_load = false; - - if(first_load == false) + + if (first_load == false) { first_load = true; LoadMenuLoadFileList( LoadMenuFiles, @@ -110,88 +110,88 @@ void LoadMenuInit(void) sizeof(LoadMenuFiles) / sizeof(char*), sizeof(LoadMenuDest) / sizeof(void*)); } - + FontSetSize(&SmallFont, SMALL_FONT_SIZE, SMALL_FONT_SIZE_BITSHIFT); FontSetSpacing(&SmallFont, SMALL_FONT_SPACING); SmallFont.spr.r = 0; SmallFont.spr.g = 0; SmallFont.spr.b = 0; - + GfxSetGlobalLuminance(NORMAL_LUMINANCE); } -void LoadMenu( char* fileList[], +void LoadMenu( char* fileList[], void * dest[], uint8_t szFileList , uint8_t szDestList) { - - if(load_menu_running == false) + + if (load_menu_running == false) { LoadMenuInit(); } - + LoadMenuLoadFileList(fileList,dest,szFileList,szDestList); } -void LoadMenuLoadFileList( char* fileList[], void * dest[], +void LoadMenuLoadFileList( char* fileList[], void * dest[], uint8_t szFileList, uint8_t szDestList) { char aux_file_name[100]; char* extension; uint8_t fileLoadedCount; - - if(szFileList != szDestList) + + if (szFileList != szDestList) { dprintf("File list size different from dest list size! %d vs %d\n", szFileList, szDestList); return; } - - for(fileLoadedCount = 0; fileLoadedCount < szFileList ; fileLoadedCount++) + + for (fileLoadedCount = 0; fileLoadedCount < szFileList ; fileLoadedCount++) { - if(fileList[fileLoadedCount] == NULL) + if (fileList[fileLoadedCount] == NULL) { continue; } - + strCurrentFile = fileList[fileLoadedCount]; - - //dprintf("Files %d / %d loaded. New plane X = %d.\n",fileLoadedCount,szFileList,LoadMenuPlaneSpr.x); - - // Backup original file path + + /* dprintf("Files %d / %d loaded. New plane X = %d.\n",fileLoadedCount,szFileList,LoadMenuPlaneSpr.x); */ + + /* Backup original file path */ strncpy(aux_file_name,fileList[fileLoadedCount],100); - - //We want to get file extension, so split into tokens + + /* We want to get file extension, so split into tokens */ strtok(fileList[fileLoadedCount],".;"); extension = strtok(NULL,".;"); - + dprintf("File extension: .%s\n",extension); - //Restore original file path in order to load file + /* Restore original file path in order to load file */ strncpy(fileList[fileLoadedCount],aux_file_name,100); - - if(strncmp(extension,"TIM",3) == 0) + + if (strncmp(extension,"TIM",3) == 0) { - if(GfxSpriteFromFile(fileList[fileLoadedCount], dest[fileLoadedCount]) == false) + if (GfxSpriteFromFile(fileList[fileLoadedCount], dest[fileLoadedCount]) == false) { dprintf("Could not load image file \"%s\"!\n",fileList[fileLoadedCount]); } } - else if(strncmp(extension,"CLT",3) == 0) + else if (strncmp(extension,"CLT",3) == 0) { - if(dest[fileLoadedCount] != NULL) + if (dest[fileLoadedCount] != NULL) { dprintf("WARNING: File %s linked to non-NULL destination pointer!\n", dest[fileLoadedCount]); } - - if(GfxCLUTFromFile(fileList[fileLoadedCount]) == false) + + if (GfxCLUTFromFile(fileList[fileLoadedCount]) == false) { dprintf("Could not load CLUT file \"%s\"!\n",fileList[fileLoadedCount]); } } - else if(strncmp(extension,"FNT",3) == 0) + else if (strncmp(extension,"FNT",3) == 0) { - if(FontLoadImage(fileList[fileLoadedCount], dest[fileLoadedCount]) == false) + if (FontLoadImage(fileList[fileLoadedCount], dest[fileLoadedCount]) == false) { dprintf("Could not load font file \"%s\"!\n",fileList[fileLoadedCount]); } diff --git a/src/Serial.c b/src/Serial.c index 2e2a1a4..4bfb45c 100644 --- a/src/Serial.c +++ b/src/Serial.c @@ -1,278 +1,91 @@ /* ************************************* - * Includes + * Includes * *************************************/ #include "Serial.h" +#include "Interrupts.h" +#include <psxsio.h> +#include <stdarg.h> +#include <stdio.h> /* ************************************* - * Defines + * Defines * *************************************/ #define SERIAL_BAUDRATE 115200 #define SERIAL_TX_RX_TIMEOUT 20000 #define SERIAL_RX_FIFO_EMPTY 0 #define SERIAL_TX_NOT_READY 0 +#define SERIAL_PRINTF_INTERNAL_BUFFER_SIZE 256 -/* ************************************* - * Local Variables +/* ************************************** + * Structs and enums * * *************************************/ -static volatile SERIAL_STATE SerialState; -static volatile size_t bytesRead; -static volatile uint32_t initPC_Address; -static volatile uint32_t RAMDest_Address; -static volatile size_t ExeSize; -static volatile size_t totalBytes; -static volatile size_t exeBytesRead; -static volatile bool serial_busy; +/* ************************************* + * Local Variables + * *************************************/ /* ************************************* - * Local Prototypes + * Local Prototypes * *************************************/ -void ISR_Serial(void) +void SerialInit(void) { - enum - { - SERIAL_BG_X0 = 0, - SERIAL_BG_X1 = X_SCREEN_RESOLUTION - SERIAL_BG_X0, - SERIAL_BG_X2 = SERIAL_BG_X0, - SERIAL_BG_X3 = SERIAL_BG_X1, - - SERIAL_BG_Y0 = 0, - SERIAL_BG_Y1 = SERIAL_BG_Y0, - SERIAL_BG_Y2 = Y_SCREEN_RESOLUTION - SERIAL_BG_Y0, - SERIAL_BG_Y3 = SERIAL_BG_Y2, - - SERIAL_BG_R = 0, - SERIAL_BG_G = NORMAL_LUMINANCE, - SERIAL_BG_B = NORMAL_LUMINANCE, - }; - - static GsGPoly4 SerialBg = { .x[0] = SERIAL_BG_X0, - .x[1] = SERIAL_BG_X1, - .x[2] = SERIAL_BG_X2, - .x[3] = SERIAL_BG_X3, - - .y[0] = SERIAL_BG_Y0, - .y[1] = SERIAL_BG_Y1, - .y[2] = SERIAL_BG_Y2, - .y[3] = SERIAL_BG_Y3, - - .r[0] = 0, - .r[1] = 0, - .r[2] = SERIAL_BG_R, - .r[3] = SERIAL_BG_R, - - .g[0] = 0, - .g[1] = 0, - .g[2] = SERIAL_BG_G, - .g[3] = SERIAL_BG_G, - - .b[0] = 0, - .b[1] = 0, - .b[2] = SERIAL_BG_B, - .b[3] = SERIAL_BG_B, }; + SIOStart(115200); +} - enum +void SerialRead(uint8_t *ptrArray, size_t nBytes) +{ + if (nBytes) { - SERIAL_STATE_TEXT_X = 148, - SERIAL_STATE_TEXT_Y = Y_SCREEN_RESOLUTION >> 1, - }; + InterruptsDisableInt(INT_SOURCE_VBLANK); - SystemIncreaseGlobalTimer(); - - if( (GfxIsGPUBusy() == true) || (SystemIsBusy() == true) ) - { - return; - } - - FontSetFlags(&SmallFont, FONT_BLEND_EFFECT | FONT_H_CENTERED); - - if(SerialState == SERIAL_STATE_READING_EXE_DATA) - { - if(System1SecondTick() == false) + do { - return; - } - else - { - FontSetFlags(&SmallFont, FONT_H_CENTERED); - } - } + while ( (SIOCheckInBuffer() == SERIAL_RX_FIFO_EMPTY)); // Wait for RX FIFO not empty - GsSortGPoly4(&SerialBg); + *(ptrArray++) = SIOReadByte(); + } while (--nBytes); - switch(SerialState) - { - case SERIAL_STATE_INIT: - FontPrintText(&SmallFont, SERIAL_STATE_TEXT_X, SERIAL_STATE_TEXT_Y, "Serial initialization"); - break; - - case SERIAL_STATE_STANDBY: - FontPrintText(&SmallFont, SERIAL_STATE_TEXT_X, SERIAL_STATE_TEXT_Y, "Waiting for PC..."); - break; - - case SERIAL_STATE_WRITING_ACK: - FontPrintText(&SmallFont, SERIAL_STATE_TEXT_X, SERIAL_STATE_TEXT_Y, "Writing ACK"); - break; - - case SERIAL_STATE_READING_HEADER: - FontPrintText(&SmallFont, SERIAL_STATE_TEXT_X, SERIAL_STATE_TEXT_Y, "Reading data from header (%d/%d bytes)...", bytesRead, totalBytes); - break; - - case SERIAL_STATE_READING_EXE_SIZE: - FontPrintText(&SmallFont, SERIAL_STATE_TEXT_X, SERIAL_STATE_TEXT_Y, "Getting PSX-EXE size from PC..."); - break; - - case SERIAL_STATE_READING_EXE_DATA: - FontPrintText(&SmallFont, SERIAL_STATE_TEXT_X, SERIAL_STATE_TEXT_Y, "Reading PSX-EXE data (%d/%d bytes)...", exeBytesRead, ExeSize); - break; - - case SERIAL_STATE_WAITING_USER_INPUT: - FontPrintText(&SmallFont, SERIAL_STATE_TEXT_X, SERIAL_STATE_TEXT_Y, "Press any key to continue"); - break; - - case SERIAL_STATE_CLEANING_MEMORY: - FontPrintText(&SmallFont, SERIAL_STATE_TEXT_X, SERIAL_STATE_TEXT_Y, "Cleaning RAM before EXE data transfer..."); - break; - - default: - FontPrintText(&SmallFont, SERIAL_STATE_TEXT_X, SERIAL_STATE_TEXT_Y, "Unknown state"); - break; + InterruptsEnableInt(INT_SOURCE_VBLANK); } - - FontSetFlags(&SmallFont, FONT_H_CENTERED); - - if(RAMDest_Address != 0) - { - FontPrintText(&SmallFont, SERIAL_STATE_TEXT_X, SERIAL_STATE_TEXT_Y + 16, "RAM Dest address: 0x%08X", RAMDest_Address); - } - - if(initPC_Address != 0) - { - FontPrintText(&SmallFont, SERIAL_STATE_TEXT_X, SERIAL_STATE_TEXT_Y + 32, "Init PC address: 0x%08X", initPC_Address); - } - - if(ExeSize != 0) - { - FontPrintText(&SmallFont, SERIAL_STATE_TEXT_X, SERIAL_STATE_TEXT_Y + 48, "PSX-EXE size: 0x%08X", ExeSize); - } - - GfxDrawScene_Fast(); -} - -void SerialSetState(SERIAL_STATE state) -{ - SerialState = state; } -void SerialSetPCAddress(uint32_t addr) +void SerialWrite(const void* ptrArray, size_t nBytes) { - initPC_Address = addr; -} - -void SerialSetRAMDestAddress(uint32_t addr) -{ - RAMDest_Address = addr; -} - -void SerialSetExeSize(size_t size) -{ - ExeSize = size; -} - -void SerialInit(void) -{ - uint8_t receivedBytes; - - SetVBlankHandler(&ISR_Serial); - - SerialState = SERIAL_STATE_INIT; - - SIOStart(SERIAL_BAUDRATE); - - SerialState = SERIAL_STATE_STANDBY; - - // ------------------------------------ - // Protocol description - // ------------------------------------ - - // 1. Wait to receive magic byte "99" from PC. - - SerialRead(&receivedBytes, sizeof(uint8_t) ); - - if(receivedBytes != 99) + if (nBytes) { - dprintf("Did not receive input magic number!\n"); - return; - } - - // 2. Send ACK (magic byte is ASCII code for 'b'). - - SerialState = SERIAL_STATE_WRITING_ACK; - - SerialWrite(ACK_BYTE_STRING, sizeof(uint8_t) ); -} - -void SerialSetExeBytesReceived(uint32_t bytes_read) -{ - exeBytesRead += bytes_read; -} + InterruptsDisableInt(INT_SOURCE_VBLANK); + do + { + while ( (SIOCheckOutBuffer() == SERIAL_TX_NOT_READY)); // Wait for TX FIFO empty. -bool SerialRead(uint8_t* ptrArray, size_t nBytes) -{ - bytesRead = 0; - totalBytes = nBytes; + SIOSendByte(*(uint8_t*)ptrArray++); - serial_busy = true; + } while (--nBytes); - if(nBytes == 0) - { - SerialWrite("SerialRead: invalid size %d\n", strnlen("SerialRead: invalid size %d\n", 30)); - return false; + InterruptsEnableInt(INT_SOURCE_VBLANK); } - - do + else { - //uint16_t timeout = SERIAL_TX_RX_TIMEOUT; - - while( (SIOCheckInBuffer() == SERIAL_RX_FIFO_EMPTY)); // Wait for RX FIFO not empty - - *(ptrArray++) = SIOReadByte(); - bytesRead++; - }while(--nBytes); - - serial_busy = false; - - return true; + } } -bool SerialWrite(void* ptrArray, size_t nBytes) +#ifdef SERIAL_INTERFACE +void Serial_printf(const char* const str, ...) { - serial_busy = true; - - SystemDisableVBlankInterrupt(); - - if(nBytes == 0) - { - SerialWrite("SerialRead: invalid size %d\n", strnlen("SerialRead: invalid size %d\n", 30)); - return false; - } - - do - { - //uint16_t timeout = SERIAL_TX_RX_TIMEOUT; - - while( (SIOCheckOutBuffer() == SERIAL_TX_NOT_READY)); // Wait for TX FIFO empty. - - SIOSendByte(*(uint8_t*)ptrArray++); - - }while(--nBytes); + va_list ap; + int result; + static char internal_buffer[SERIAL_PRINTF_INTERNAL_BUFFER_SIZE]; - SystemEnableVBlankInterrupt(); + va_start(ap, str); - serial_busy = false; + result = vsnprintf( internal_buffer, + SERIAL_PRINTF_INTERNAL_BUFFER_SIZE, + str, + ap ); - return true; + SerialWrite(internal_buffer, result); } +#endif // SERIAL_INTERFACE diff --git a/src/System.c b/src/System.c index 852fea1..d7a1574 100644 --- a/src/System.c +++ b/src/System.c @@ -1,493 +1,11 @@ -/* ************************************* - * Includes - * *************************************/ - #include "System.h" - -/* ************************************* - * Defines - * *************************************/ - -#define SYSTEM_MAX_TIMERS 16 -#define FILE_BUFFER_SIZE 0xC40 -#define END_STACK_PATTERN (uint32_t) 0x18022015 -#define BEGIN_STACK_ADDRESS (uint32_t*) 0x801FFF00 -#define STACK_SIZE 0x1000 -#define I_MASK (*(volatile unsigned int*)0x1F801074) - -/* ************************************* - * Local Prototypes - * *************************************/ - -static void SystemSetStackPattern(void); - -/* ************************************* - * Local Variables - * *************************************/ - -//Buffer to store any kind of files. It supports files up to 128 kB -static uint8_t file_buffer[FILE_BUFFER_SIZE]; -//Global timer (called by interrupt) -static volatile uint64_t global_timer; -//Tells whether rand seed has been set -static bool rand_seed; -//Screen refresh flag (called by interrupt) -static volatile bool refresh_needed; -//Timers -static bool one_second_timer; -//Critical section is entered (i.e.: when accessing fopen() or other BIOS functions -static volatile bool system_busy; - -/* ******************************************************************* - * - * @name: void SystemInit(void) - * - * @author: Xavier Del Campo - * - * @brief: Calls main intialization routines. - * - * @remarks: To be called before main loop. - * - * *******************************************************************/ +#include "Serial.h" +#include "Gfx.h" +#include <psx.h> void SystemInit(void) { - //Reset global timer - global_timer = 0; - //Reset 1 second timer - one_second_timer = 0; - //PSXSDK init PSX_InitEx(PSX_INIT_SAVESTATE | PSX_INIT_CD); - //Graphics init - GsInit(); - //Clear VRAM - GsClearMem(); - //Set Video Resolution -#ifdef _PAL_MODE_ - GsSetVideoMode(X_SCREEN_RESOLUTION, Y_SCREEN_RESOLUTION, VMODE_PAL); -#else - GsSetVideoMode(X_SCREEN_RESOLUTION, Y_SCREEN_RESOLUTION, VMODE_NTSC); -#endif //_PAL_MODE_ - //SPU init - SsInit(); - //Set Drawing Environment - GfxInitDrawEnv(); - //Set Display Environment - GfxInitDispEnv(); - //Set Primitive List - GfxSetPrimitiveList(); - //Initial value for system_busy - system_busy = false; - - GfxSetGlobalLuminance(NORMAL_LUMINANCE); - - SystemSetStackPattern(); -} - -size_t SystemGetBufferSize(void) -{ - return sizeof(file_buffer); -} - -/* ******************************************************************* - * - * @name: void SystemInit(void) - * - * @author: Xavier Del Campo - * - * @brief: - * Calls srand() while avoiding multiple calls by setting internal - * variable rand_seed to true. Internal variable "global_timer" is - * used to generate the new seed. - * - * @remarks: - * It is recommended to call it once user has pressed any key. - * - * *******************************************************************/ - -void SystemSetRandSeed(void) -{ - if(rand_seed == false) - { - rand_seed = true; - //Set random seed using global timer as reference - srand((unsigned int)global_timer); - - dprintf("Seed used: %d\n",(unsigned int)global_timer); - } -} - -/* ******************************************************************* - * - * @name: bool SystemIsRandSeedSet(void) - * - * @author: Xavier Del Campo - * - * @brief: - * Reportedly, returns whether rand seed has already been set. - * - * @remarks: - * - * @return: - * Reportedly, returns whether rand seed has already been set. - * - * *******************************************************************/ - -bool SystemIsRandSeedSet(void) -{ - return rand_seed; -} - -/* ******************************************************************* - * - * @name: bool SystemRefreshNeeded(void) - * - * @author: Xavier Del Campo - * - * @brief: - * - * @remarks: - * - * @return: - * Returns whether VSync flag has been enabled. - * - * *******************************************************************/ - -bool SystemRefreshNeeded(void) -{ - return refresh_needed; -} - -/* ******************************************************************* - * - * @name: void ISR_SystemDefaultVBlank(void) - * - * @author: Xavier Del Campo - * - * @brief: - * - * @remarks: - * Called from VSync interrupt. Called 50 times a second in PAL mode, - * 60 times a second in NTSC mode. - * - * *******************************************************************/ - -void ISR_SystemDefaultVBlank(void) -{ - refresh_needed = true; - SystemIncreaseGlobalTimer(); -} - -/* ******************************************************************* - * - * @name: void SystemIncreaseGlobalTimer(void) - * - * @author: Xavier Del Campo - * - * @brief: - * Increases internal variable responsible for time handling. - * - * @remarks: - * Usually called from ISR_SystemDefaultVBlank(). - * - * *******************************************************************/ - -void SystemIncreaseGlobalTimer(void) -{ - global_timer++; -} - -/* ******************************************************************* - * - * @name: uint64_t SystemGetGlobalTimer(void) - * - * @author: Xavier Del Campo - * - * @brief: Returns internal global timer value. - * - * *******************************************************************/ - -uint64_t SystemGetGlobalTimer(void) -{ - return global_timer; -} - -/* ******************************************************************* - * - * @name: void SystemDisableScreenRefresh(void) - * - * @author: Xavier Del Campo - * - * @brief: Resets VBlank IRQ flag. - * - * *******************************************************************/ - -void SystemDisableScreenRefresh(void) -{ - refresh_needed = false; -} - -/* ******************************************************************* - * - * @name: bool System1SecondTick(void) - * - * @author: Xavier Del Campo - * - * @return: bool variable with a 1-cycle-length pulse that gets - * set each second. - * - * *******************************************************************/ - -bool System1SecondTick(void) -{ - return !(global_timer % REFRESH_FREQUENCY); -} - -/* **************************************************************************************** - * - * @name bool SystemLoadFileToBuffer(char* fname, uint8_t* buffer, uint32_t szBuffer) - * - * @author: Xavier Del Campo - * - * @brief: Given an input path, it fills a buffer pointed to by "buffer" with - * maximum size "szBuffer" with data from CD-ROM. - * - * @return: true if file has been loaded successfully, false otherwise. - * - * ****************************************************************************************/ - -bool SystemLoadFileToBuffer(char* fname, uint32_t init_pos, uint8_t* buffer, uint32_t szBuffer) -{ - FILE *f; - int32_t size; - - // Wait for possible previous operation from the GPU before entering this section. - while( (SystemIsBusy() == true) || (GfxIsGPUBusy() == true) ); - - if(fname == NULL) - { - dprintf("SystemLoadFile: NULL fname!\n"); - return false; - } - - memset(buffer,0,szBuffer); - - system_busy = true; - - SystemDisableVBlankInterrupt(); - - f = fopen(fname, "r"); - - if(f == NULL) - { - dprintf("SystemLoadFile: file could not be found!\n"); - //File couldn't be found - return false; - } - - fseek(f, init_pos, SEEK_END); - - size = ftell(f); - - if(size > szBuffer) - { - dprintf("SystemLoadFile: Exceeds file buffer size (%d bytes)\n",size); - //Bigger than 128 kB (buffer's max size) - return false; - } - - fseek(f, init_pos, SEEK_SET); //f->pos = 0; - - fread(buffer, sizeof(char), size, f); - - fclose(f); - - SystemEnableVBlankInterrupt(); - - system_busy = false; - - dprintf("File \"%s\" loaded successfully!\n",fname); - - return true; -} - -void SystemSetBusyFlag(bool value) -{ - system_busy = value; -} - -/* **************************************************************************************** - * - * @name bool SystemLoadFile(char*fname) - * - * @author: Xavier Del Campo - * - * @brief: Given an input file name, it loads its conents into internal buffer. - * - * @return: true if file has been loaded successfully, false otherwise. - * - * ****************************************************************************************/ - -bool SystemLoadFile(char*fname) -{ - return SystemLoadFileToBuffer(fname,0,file_buffer,sizeof(file_buffer)); -} - -/* ****************************************************************** - * - * @name uint8_t* SystemGetBufferAddress(void) - * - * @author: Xavier Del Campo - * - * @return: Reportedly, returns internal buffer initial address. - * - * *****************************************************************/ - -uint8_t* SystemGetBufferAddress(void) -{ - return file_buffer; -} - -/* ****************************************************************** - * - * @name void SystemClearBuffer(void) - * - * @author: Xavier Del Campo - * - * @return: Fills internal buffer with zeros - * - * *****************************************************************/ - -void SystemClearBuffer(void) -{ - memset(file_buffer, 0, sizeof(file_buffer)); -} - -/* ****************************************************************** - * - * @name uint32_t SystemRand(uint32_t min, uint32_t max) - * - * @author: Xavier Del Campo - * - * @return: random number between "min" and "max". - * - * @remarks: rand seed must be set before using this function, or - * you will predictable values otherwise! - * - * *****************************************************************/ - -uint32_t SystemRand(uint32_t min, uint32_t max) -{ - return rand() % (max - min + 1) + min; -} - -/* *********************************************************************** - * - * @name volatile bool SystemIsBusy(void) - * - * @author: Xavier Del Campo - * - * @return: returns system busy flag. - * - * ***********************************************************************/ - -volatile bool SystemIsBusy(void) -{ - return system_busy; -} - -bool SystemArrayCompare(unsigned short* arr1, unsigned short* arr2, size_t sz) -{ - size_t i; - - for(i = 0; i < sz; i++) - { - if(arr1[i] != arr2[i]) - { - return false; - } - } - - return true; -} - -void SystemPrintStackPointerAddress(void) -{ -#ifdef PSXSDK_DEBUG // Used to avoid unused variable warning - void * ptr = NULL; - fix16_t used_bytes = fix16_from_int((int)((void*)BEGIN_STACK_ADDRESS - (void*)&ptr)); - fix16_t stackPercent = fix16_sdiv(used_bytes,fix16_from_int((int)STACK_SIZE)); - - stackPercent = fix16_smul(stackPercent, fix16_from_int((int)100)); - - dprintf("stackPercent: %d\n", stackPercent); - - dprintf("Stack begin pointer: 0x%08X\n" - "Stack pointer address: 0x%08X\n" - "Used %d%% of stack size.\n" - "\tUsed bytes: %d\n", - (void*)BEGIN_STACK_ADDRESS, - (void*)&ptr, - fix16_to_int(stackPercent), - fix16_to_int(used_bytes) ); -#endif // PSXSDK_DEBUG - -} - -void SystemCheckStack(void) -{ - uint32_t * ptrStack = BEGIN_STACK_ADDRESS; - uint32_t data; - - ptrStack -= STACK_SIZE; - data = (*ptrStack); - - if(data != END_STACK_PATTERN) - { - dprintf("Stack overflow?\n"); - - while(1); - } -} - -void SystemSetStackPattern(void) -{ - uint32_t * ptrStack = BEGIN_STACK_ADDRESS; - - ptrStack -= STACK_SIZE; - - *ptrStack = END_STACK_PATTERN; -} - -int32_t SystemIndexOfStringArray(char* str, char** array) -{ - int32_t i; - - for(i = 0; array[i] != NULL; i++) - { - dprintf("String to find: %s\nEntry: %s\n", str, array[i]); - - if(strcmp(str, array[i]) == 0) - { - dprintf("Match! Returning index %d...\n", i); - return i; - } - } - - return -1; -} -void SystemCyclicHandler(void) -{ - SystemDisableScreenRefresh(); - SystemCheckStack(); -} - -void SystemDisableVBlankInterrupt(void) -{ - I_MASK &= ~(0x00000001); -} - -void SystemEnableVBlankInterrupt(void) -{ - I_MASK |= (0x00000001); + SerialInit(); + GfxInit(); } @@ -1,51 +1,12 @@ -/* ************************************* - * Includes - * *************************************/ - -#include "Global_Inc.h" -#include "System.h" -#include "Serial.h" -#include "LoadMenu.h" -#include "EndAnimation.h" - -/* ************************************* - * Defines - * *************************************/ - #define PSX_EXE_HEADER_SIZE 2048 #define EXE_DATA_PACKET_SIZE 8 -/* ************************************* - * Local Prototypes - * *************************************/ - -/* ************************************* - * Local Variables - * *************************************/ - - /* Untitled1 (10/07/2017 18:57:47) - StartOffset: 00000000, EndOffset: 0000002F, Length: 00000030 */ - -/* Untitled2 (10/07/2017 21:10:19) - StartOffset: 00000000, EndOffset: 000357FF, Length: 00035800 */ - -extern void _start(void); - - +void _start(void); int main(void) { - uint8_t* inBuffer = SystemGetBufferAddress(); - // int (*exeAddress)(void); - - //System initialization - dprintf("SystemInit()\n"); SystemInit(); - dprintf("LoadMenuInit()\n"); - - LoadMenuInit(); - { uint32_t initPC_Address; uint32_t RAMDest_Address; @@ -57,76 +18,76 @@ int main(void) SerialInit(); - // Read PSX-EXE header (32 bytes will be enough). + /* Read PSX-EXE header (32 bytes will be enough). */ SerialSetState(SERIAL_STATE_READING_HEADER); SerialRead(inBuffer, 32); - // Get initial program counter address from PSX-EXE header. + /* Get initial program counter address from PSX-EXE header. */ initPC_Address = (inBuffer[0x10] | (inBuffer[0x11] << 8) | (inBuffer[0x12] << 16) | (inBuffer[0x13] << 24) ); SerialSetPCAddress(initPC_Address); - //dprintf("initPC_Address = 0x%08X\n", initPC_Address); + /* dprintf("initPC_Address = 0x%08X\n", initPC_Address); */ - // Get destination address in RAM from PSX-EXE header. + /* Get destination address in RAM from PSX-EXE header. */ RAMDest_Address = (inBuffer[0x18] | (inBuffer[0x19] << 8) | (inBuffer[0x1A] << 16) | (inBuffer[0x1B] << 24) ); SerialSetRAMDestAddress(RAMDest_Address); - //dprintf("RAMDest_Address = 0x%08X\n", RAMDest_Address); + /* dprintf("RAMDest_Address = 0x%08X\n", RAMDest_Address); */ - // We have received all data correctly. Send ACK. + /* We have received all data correctly. Send ACK. */ memset(inBuffer, 0, SystemGetBufferSize()); SerialSetState(SERIAL_STATE_WRITING_ACK); - SerialWrite(ACK_BYTE_STRING, sizeof(uint8_t)); // Write ACK + SerialWrite(ACK_BYTE_STRING, sizeof(uint8_t)); /* Write ACK */ - // Get PSX-EXE size, without header, in hexadecimal, little-endian format; + /* Get PSX-EXE size, without header, in hexadecimal, little-endian format; */ SerialSetState(SERIAL_STATE_READING_EXE_SIZE); SerialRead(inBuffer, sizeof(uint32_t) ); - for(i = 0; i < sizeof(uint32_t); i++) + for (i = 0; i < sizeof(uint32_t); i++) { - ExeSize |= inBuffer[i] << (i << 3); // (i << 3) == (i * 8) + ExeSize |= inBuffer[i] << (i << 3); /* (i << 3) == (i * 8) */ } SerialSetExeSize(ExeSize); - //DEBUG_PRINT_VAR(ExeSize); + /* DEBUG_PRINT_VAR(ExeSize); */ SerialSetState(SERIAL_STATE_CLEANING_MEMORY); exeAddress = (void*)initPC_Address; - // Clean memory where EXE data will be loaded, just in case... + /* Clean memory where EXE data will be loaded, just in case... */ memset((void*)RAMDest_Address, 0, (uint32_t)((uint32_t)(&_start) - (uint32_t)(RAMDest_Address) ) ); SerialSetState(SERIAL_STATE_WRITING_ACK); - // We have received PSX-EXE size (without header) correctly. Send ACK. + /* We have received PSX-EXE size (without header) correctly. Send ACK. */ - SerialWrite(ACK_BYTE_STRING, sizeof(uint8_t)); // Write ACK + SerialWrite(ACK_BYTE_STRING, sizeof(uint8_t)); /* Write ACK */ SerialSetState(SERIAL_STATE_READING_EXE_DATA); - while(GfxIsGPUBusy() == true); + while (GfxIsGPUBusy() == true); - for(i = 0; i < ExeSize; i += EXE_DATA_PACKET_SIZE) + for (i = 0; i < ExeSize; i += EXE_DATA_PACKET_SIZE) { uint32_t bytes_to_read; - // Read actual EXE data into proper RAM address. + /* Read actual EXE data into proper RAM address. */ - if( (i + EXE_DATA_PACKET_SIZE) >= ExeSize) + if ( (i + EXE_DATA_PACKET_SIZE) >= ExeSize) { bytes_to_read = ExeSize - i; } @@ -139,20 +100,20 @@ int main(void) SerialSetExeBytesReceived(bytes_to_read); - SerialWrite(ACK_BYTE_STRING, sizeof(uint8_t)); // Write ACK + SerialWrite(ACK_BYTE_STRING, sizeof(uint8_t)); /* Write ACK */ } SetVBlankHandler(&ISR_SystemDefaultVBlank); - // Make a pretty animation before exeting OpenSend application. + /* Make a pretty animation before exeting OpenSend application. */ EndAnimation(); PSX_DeInit(); - // PSX-EXE has been successfully loaded into RAM. Run executable! + /* PSX-EXE has been successfully loaded into RAM. Run executable! */ - //dprintf("Entering exe...\n"); + /* dprintf("Entering exe...\n"); */ exeAddress(); } |
