From 792e22676786a577b2edc0ed0ed78e51c5b38245 Mon Sep 17 00:00:00 2001 From: Xavi Del Campo Date: Tue, 3 Mar 2020 18:39:09 +0100 Subject: Refactoring --- src/EndAnimation.c | 233 -------------- src/Font.c | 198 ++++++------ src/Gfx.c | 895 ++++++++++++++++++++++++++--------------------------- src/IO.c | 266 ++++++++++++++++ src/Interrupts.c | 126 ++++++++ src/LoadMenu.c | 106 +++---- src/Serial.c | 283 +++-------------- src/System.c | 492 +---------------------------- src/main.c | 85 ++--- 9 files changed, 1053 insertions(+), 1631 deletions(-) delete mode 100644 src/EndAnimation.c create mode 100644 src/IO.c create mode 100644 src/Interrupts.c (limited to 'src') 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(); - } -} diff --git a/src/Font.c b/src/Font.c index c4b1491..d8d1e9e 100644 --- a/src/Font.c +++ b/src/Font.c @@ -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); diff --git a/src/Gfx.c b/src/Gfx.c index b9ffb63..49f0f12 100644 --- a/src/Gfx.c +++ b/src/Gfx.c @@ -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 +#include +#include +#include +#include +#include +#include /* ************************************* - * 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 +#include +#include +#include +#include + +/* ************************************* + * 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 +#include +#include + +/* ************************************* + * 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 +#include +#include /* ************************************* - * 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 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(); } diff --git a/src/main.c b/src/main.c index 6fed452..4e357a2 100644 --- a/src/main.c +++ b/src/main.c @@ -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(); } -- cgit v1.2.3