Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,75 +16,49 @@ project(
HOMEPAGE_URL "https://github.com/grumpycoders/pcsx-redux"
)

# Set up compiler flags and initialize the Python environment used to run the
# scripts in the tools directory.
# Set up compiler flags, initialize the Python environment used to run the
# scripts in the tools directory and define some helper macros.
include(ps1-bare-metal/cmake/setup.cmake)
include(ps1-bare-metal/cmake/virtualenv.cmake)
include(ps1-bare-metal/cmake/tools.cmake)

# Build a "common" library containing basic support code. We are going to link
# this library into our executable.
# Build a "common" library containing basic support code and link it by default
# into every executable.
add_library(
common OBJECT
ps1-bare-metal/src/libc/clz.s
ps1-bare-metal/src/libc/crt0.c
ps1-bare-metal/src/libc/cxxsupport.cpp
ps1-bare-metal/src/libc/malloc.c
ps1-bare-metal/src/libc/memset.s
ps1-bare-metal/src/libc/misc.c
ps1-bare-metal/src/libc/misc.s
ps1-bare-metal/src/libc/setjmp.s
ps1-bare-metal/src/libc/string.c
ps1-bare-metal/src/libc/string.s
ps1-bare-metal/src/ps1/cache.s
ps1-bare-metal/src/vendor/printf.c
)
target_include_directories(
common PUBLIC
ps1-bare-metal/src
ps1-bare-metal/src/libc
)
link_libraries(common)

# Compile the main executable. You may add more source files by listing them
# here.
add_executable(
# Compile the main executable; you may add more source files by listing them
# here. The addPS1Executable() macro is defined in tools.cmake and automatically
# takes care of converting the built ELF file into a PS1 executable (.psexe)
# which can run be run on emulators or real hardware.
addPS1Executable(
{{projectName}}
src/font.c
src/gpu.c
src/main.c
src/trig.c
)
target_link_libraries({{projectName}} PRIVATE common)

# Define a CMake macro that invokes convertImage.py in order to generate VRAM
# texture data from an image file.
function(convertImage input bpp)
add_custom_command(
OUTPUT ${ARGN}
DEPENDS "${PROJECT_SOURCE_DIR}/${input}"
COMMAND
"${Python3_EXECUTABLE}"
"${PROJECT_SOURCE_DIR}/ps1-bare-metal/tools/convertImage.py"
-b ${bpp}
"${PROJECT_SOURCE_DIR}/${input}"
${ARGN}
VERBATIM
)
endfunction()

# Convert the font spritesheet to a 4bpp texture and palette, then embed them
# into the executable. The addBinaryFile() macro is defined in setup.cmake; you
# may call it multiple times to embed other data into the binary.
# into the executable. The convertImage() and addBinaryFile() macros are defined
# in tools.cmake and setup.cmake respectively. You may call them multiple times
# to embed other images or data into the binary.
convertImage(assets/font.png 4 fontTexture.dat fontPalette.dat)
addBinaryFile({{projectName}} fontTexture "${PROJECT_BINARY_DIR}/fontTexture.dat")
addBinaryFile({{projectName}} fontPalette "${PROJECT_BINARY_DIR}/fontPalette.dat")

# Add a step to run convertExecutable.py after the executable is compiled in
# order to convert it into a PS1 executable. By default all custom commands run
# from the build directory, so paths to files in the source directory must be
# prefixed with ${PROJECT_SOURCE_DIR}.
add_custom_command(
TARGET {{projectName}} POST_BUILD
BYPRODUCTS {{projectName}}.psexe
COMMAND
"${Python3_EXECUTABLE}"
"${PROJECT_SOURCE_DIR}/ps1-bare-metal/tools/convertExecutable.py"
"$<TARGET_FILE:{{projectName}}>"
{{projectName}}.psexe
VERBATIM
)
23 changes: 13 additions & 10 deletions tools/vscode-extension/templates/bare-metal/cmake-cube/src/font.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,12 @@ static const SpriteInfo fontSprites[] = {
};

void printString(
DMAChain *chain, const TextureInfo *font, int x, int y, int zIndex,
const char *str
GPUDMAChain *chain,
const TextureInfo *font,
int x,
int y,
int zIndex,
const char *str
) {
int currentX = x, currentY = y;

Expand Down Expand Up @@ -145,7 +149,7 @@ void printString(
// VRAM to those of the sprite itself within the sheet. Enable blending
// to make sure any semitransparent pixels in the font get rendered
// correctly.
ptr = allocatePacket(chain, zIndex, 4);
ptr = allocateGP0Packet(chain, zIndex, 4);
ptr[0] = gp0_rectangle(true, true, true);
ptr[1] = gp0_xy(currentX, currentY);
ptr[2] = gp0_uv(font->u + sprite->x, font->v + sprite->y, font->clut);
Expand All @@ -155,11 +159,10 @@ void printString(
currentX += sprite->width;
}

// Finish by sending a texpage command to tell the GPU to use the font's
// spritesheet (keep in mind that DMA sends ordering table packets in
// last-to-first order). Note that the texpage command before a drawing
// command can be omitted when reusing the same texture, so sending it here
// just once is enough.
ptr = allocatePacket(chain, zIndex, 1);
ptr[0] = gp0_texpage(font->page, false, false);
// Finish by sending a texture page command to tell the GPU to use the
// font's spritesheet (keep in mind that DMA sends ordering table packets in
// last-to-first order). The page setting persists when drawing rectangles,
// so sending it here just once is enough.
ptr = allocateGP0Packet(chain, zIndex, 1);
ptr[0] = gp0_setPage(font->page, false, false);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include "gpu.h"

#define FONT_FIRST_TABLE_CHAR '!'
#define FONT_SPACE_WIDTH 4
#define FONT_SPACE_WIDTH 4
#define FONT_TAB_WIDTH 32
#define FONT_LINE_HEIGHT 10

Expand All @@ -18,8 +18,12 @@ extern "C" {
#endif

void printString(
DMAChain *chain, const TextureInfo *font, int x, int y, int zIndex,
const char *str
GPUDMAChain *chain,
const TextureInfo *font,
int x,
int y,
int zIndex,
const char *str
);

#ifdef __cplusplus
Expand Down
106 changes: 79 additions & 27 deletions tools/vscode-extension/templates/bare-metal/cmake-cube/src/gpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#include "ps1/gpucmd.h"
#include "ps1/registers.h"

#define DMA_MAX_CHUNK_SIZE 16

void setupGPU(GP1VideoMode mode, int width, int height) {
int x = 0x760;
int y = (mode == GP1_MODE_PAL) ? 0xa3 : 0x88;
Expand All @@ -20,16 +22,29 @@ void setupGPU(GP1VideoMode mode, int width, int height) {
GPU_GP1 = gp1_fbRangeH(x - offsetX, x + offsetX);
GPU_GP1 = gp1_fbRangeV(y - offsetY, y + offsetY);
GPU_GP1 = gp1_fbMode(
horizontalRes, verticalRes, mode, false, GP1_COLOR_16BPP
horizontalRes,
verticalRes,
mode,
false,
GP1_COLOR_16BPP
);
GPU_GP1 = gp1_dispBlank(false);

DMA_DPCR |= 0
| DMA_DPCR_CH_ENABLE(DMA_GPU)
| DMA_DPCR_CH_ENABLE(DMA_OTC);
DMA_CHCR(DMA_GPU) = 0;
DMA_CHCR(DMA_OTC) = 0;

GPU_GP1 = gp1_dmaRequestMode(GP1_DREQ_GP0_WRITE);
}

void waitForGP0Ready(void) {
while (!(GPU_GP1 & GP1_STAT_CMD_READY))
__asm__ volatile("");
}

void waitForDMADone(void) {
void waitForGPUDMADone(void) {
while (DMA_CHCR(DMA_GPU) & DMA_CHCR_ENABLE)
__asm__ volatile("");
}
Expand All @@ -41,19 +56,28 @@ void waitForVSync(void) {
IRQ_STAT = ~(1 << IRQ_VSYNC);
}

void sendLinkedList(const void *data) {
waitForDMADone();
void sendGPULinkedList(const void *data) {
waitForGPUDMADone();
assert(!((uint32_t) data % 4));

DMA_MADR(DMA_GPU) = (uint32_t) data;
DMA_CHCR(DMA_GPU) = DMA_CHCR_WRITE | DMA_CHCR_MODE_LIST | DMA_CHCR_ENABLE;
DMA_CHCR(DMA_GPU) = 0
| DMA_CHCR_WRITE
| DMA_CHCR_MODE_LIST
| DMA_CHCR_ENABLE;
}

void sendVRAMData(const void *data, int x, int y, int width, int height) {
waitForDMADone();
void sendVRAMData(
const void *data,
int x,
int y,
int width,
int height
) {
waitForGPUDMADone();
assert(!((uint32_t) data % 4));

size_t length = (width * height) / 2;
size_t length = (width * height + 1) / 2;
size_t chunkSize, numChunks;

if (length < DMA_MAX_CHUNK_SIZE) {
Expand All @@ -73,55 +97,79 @@ void sendVRAMData(const void *data, int x, int y, int width, int height) {

DMA_MADR(DMA_GPU) = (uint32_t) data;
DMA_BCR (DMA_GPU) = chunkSize | (numChunks << 16);
DMA_CHCR(DMA_GPU) = DMA_CHCR_WRITE | DMA_CHCR_MODE_SLICE | DMA_CHCR_ENABLE;
DMA_CHCR(DMA_GPU) = 0
| DMA_CHCR_WRITE
| DMA_CHCR_MODE_SLICE
| DMA_CHCR_ENABLE;
}

void clearOrderingTable(uint32_t *table, int numEntries) {
DMA_MADR(DMA_OTC) = (uint32_t) &table[numEntries - 1];
DMA_BCR (DMA_OTC) = numEntries;
DMA_CHCR(DMA_OTC) = 0
| DMA_CHCR_READ | DMA_CHCR_REVERSE | DMA_CHCR_MODE_BURST
| DMA_CHCR_ENABLE | DMA_CHCR_TRIGGER;
| DMA_CHCR_READ
| DMA_CHCR_REVERSE
| DMA_CHCR_MODE_BURST
| DMA_CHCR_ENABLE
| DMA_CHCR_TRIGGER;

while (DMA_CHCR(DMA_OTC) & DMA_CHCR_ENABLE)
__asm__ volatile("");
}

uint32_t *allocatePacket(DMAChain *chain, int zIndex, int numCommands) {
uint32_t *allocateGP0Packet(GPUDMAChain *chain, int zIndex, int numCommands) {
assert((numCommands >= 0) && (numCommands <= DMA_MAX_CHUNK_SIZE));
assert((zIndex >= 0) && (zIndex < GPU_ORDERING_TABLE_SIZE));

uint32_t *ptr = chain->nextPacket;
chain->nextPacket += numCommands + 1;

assert((zIndex >= 0) && (zIndex < ORDERING_TABLE_SIZE));

*ptr = gp0_tag(numCommands, (void *) chain->orderingTable[zIndex]);
chain->orderingTable[zIndex] = gp0_tag(0, ptr);

assert(chain->nextPacket < &(chain->data)[CHAIN_BUFFER_SIZE]);
assert(chain->nextPacket < &(chain->data)[GPU_CHAIN_BUFFER_SIZE]);

return &ptr[1];
}

void uploadTexture(
TextureInfo *info, const void *data, int x, int y, int width, int height
TextureInfo *info,
const void *data,
int x,
int y,
int width,
int height
) {
assert((width <= 256) && (height <= 256));

sendVRAMData(data, x, y, width, height);
waitForDMADone();
waitForGPUDMADone();
GPU_GP0 = gp0_flushCache();

info->page = gp0_page(
x / 64, y / 256, GP0_BLEND_SEMITRANS, GP0_COLOR_16BPP
x / 64,
y / 256,
GP0_BLEND_SEMITRANS,
GP0_COLOR_16BPP
);
info->clut = 0;
info->u = (uint8_t) (x % 64);
info->u = (uint8_t) (x % 64);
info->v = (uint8_t) (y % 256);
info->width = (uint16_t) width;
info->height = (uint16_t) height;
}

void uploadIndexedTexture(
TextureInfo *info, const void *image, const void *palette, int x, int y,
int paletteX, int paletteY, int width, int height, GP0ColorDepth colorDepth
TextureInfo *info,
const void *image,
const void *palette,
int imageX,
int imageY,
int paletteX,
int paletteY,
int width,
int height,
GP0ColorDepth colorDepth
) {
assert((width <= 256) && (height <= 256));

Expand All @@ -130,17 +178,21 @@ void uploadIndexedTexture(

assert(!(paletteX % 16) && ((paletteX + numColors) <= 1024));

sendVRAMData(image, x, y, width / widthDivider, height);
waitForDMADone();
sendVRAMData(image, imageX, imageY, width / widthDivider, height);
waitForGPUDMADone();
sendVRAMData(palette, paletteX, paletteY, numColors, 1);
waitForDMADone();
waitForGPUDMADone();
GPU_GP0 = gp0_flushCache();

info->page = gp0_page(
x / 64, y / 256, GP0_BLEND_SEMITRANS, colorDepth
imageX / 64,
imageY / 256,
GP0_BLEND_SEMITRANS,
colorDepth
);
info->clut = gp0_clut(paletteX / 16, paletteY);
info->u = (uint8_t) ((x % 64) * widthDivider);
info->v = (uint8_t) (y % 256);
info->u = (uint8_t) ((imageX % 64) * widthDivider);
info->v = (uint8_t) (imageY % 256);
info->width = (uint16_t) width;
info->height = (uint16_t) height;
}
Loading
Loading