summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorXavi Del Campo <xavi.dcr@tutanota.com>2020-03-03 18:39:09 +0100
committerXavi Del Campo <xavi.dcr@tutanota.com>2020-03-03 19:40:00 +0100
commit792e22676786a577b2edc0ed0ed78e51c5b38245 (patch)
tree3a5b1092af322003be3189bf6d58f362dcfe1dca /src
parent62adc2edd17cbd39272715d29d1b4c8650ef7dde (diff)
downloadopensend-792e22676786a577b2edc0ed0ed78e51c5b38245.tar.gz
Refactoring
Diffstat (limited to 'src')
-rw-r--r--src/EndAnimation.c233
-rw-r--r--src/Font.c198
-rw-r--r--src/Gfx.c895
-rw-r--r--src/IO.c266
-rw-r--r--src/Interrupts.c126
-rw-r--r--src/LoadMenu.c106
-rw-r--r--src/Serial.c283
-rw-r--r--src/System.c492
-rw-r--r--src/main.c85
9 files changed, 1053 insertions, 1631 deletions
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 <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();
}
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();
}