diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 00000000..d7f85dfa --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,13 @@ +FROM ghcr.io/n64-tools/gcc-toolchain-mips64:latest + +# Avoid warnings by switching to noninteractive +ENV DEBIAN_FRONTEND=noninteractive + +RUN git clone --branch trunk https://github.com/dragonminded/libdragon.git --depth 1 ./sources/libdragon + +RUN cd ./sources/libdragon && \ + make -j libdragon && \ + make install && \ + make -j tools && \ + make tools-install && \ + make install-mk diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 00000000..21a57648 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,20 @@ +{ + "name": "N64FlashcartMenu", + // If you prefer, you can use the source files and adjust them they are located, with the same names in ./sources. This will alow you to customize them and add anything you may need on top. + "dockerFile": "Dockerfile", + "context": ".", + "mounts": [ + "source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind", + // Keep command history + "source=nano-bashhistory,target=/home/vscode/commandhistory,type=volume", + ], + // Set *default* container specific settings.json values on container create. + "settings": { + }, + // Add the IDs of extensions you want installed when the container is created. + "extensions": [ + "ms-vsliveshare.vsliveshare-pack", + "streetsidesoftware.code-spell-checker", + "ms-vscode.makefile-tools" + ] +} diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..b3fc4706 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text=auto eol=crlf \ No newline at end of file diff --git a/README.md b/README.md index d99535f6..ef1db234 100644 --- a/README.md +++ b/README.md @@ -53,3 +53,9 @@ This will likely replace AltraOSv1 # Developer documentation **Work in progress!** +You can use a dev container in VSCode. + +`ms-vscode.makefile-tools` will help (installed automatically in dev container). +TODO: it does not yet work with `F5`: see https://devblogs.microsoft.com/cppblog/now-announcing-makefile-support-in-visual-studio-code/ +WORKAROUND: in the terminal, use make directly `make all` + diff --git a/src/libs/pixelfx_n64digital/pfxromid.c b/src/libs/pixelfx_n64digital/pfxromid.c new file mode 100644 index 00000000..a76d0d74 --- /dev/null +++ b/src/libs/pixelfx_n64digital/pfxromid.c @@ -0,0 +1,110 @@ +/* + Based on libdragon + This implementation does not disable interrupts during PIF operation! +*/ + +#include +#include +#include "pfxromid.h" +#include "libdragon.h" + +#define SI_STATUS_DMA_BUSY (1 << 0) +#define SI_STATUS_IO_BUSY (1 << 1) + +#define MEMORY_BARRIER() asm volatile ("" : : : "memory") + +#define cache_op(op, linesize) ({ \ + if (length) { \ + void *cur = (void*)((unsigned long)addr & ~(linesize-1)); \ + int count = (int)length + (addr-cur); \ + for (int i = 0; i < count; i += linesize) \ + asm ("\tcache %0,(%1)\n"::"i" (op), "r" (cur+i)); \ + } \ +}) + +#define UncachedAddr(_addr) ((void *)(((unsigned long)(_addr))|0x20000000)) + +typedef struct SI_regs_s { + volatile void * DRAM_addr; + volatile void * PIF_addr_read; + uint32_t reserved1; + uint32_t reserved2; + volatile void * PIF_addr_write; + uint32_t reserved3; + uint32_t status; +} SI_regs_t; + +static volatile struct SI_regs_s * const SI_regs = (struct SI_regs_s *)0xa4800000; +static void * const PIF_RAM = (void *)0x1fc007c0; + +// Uses the libdragon header function!!! +// static void data_cache_hit_writeback_invalidate(volatile void * addr, unsigned long length) +// { +// cache_op(0x15, 16); +// } + +static void __SI_DMA_wait(void) +{ + while (SI_regs->status & (SI_STATUS_DMA_BUSY | SI_STATUS_IO_BUSY)); +} + +static void __controller_exec_PIF(void *inblock) { //TODO: this is (nearly) the same as the RTC code (duplicate) use generic function or just libdragon?!) + volatile uint64_t inblock_temp[8]; + volatile uint64_t outblock_temp[8]; + + data_cache_hit_writeback_invalidate(inblock_temp, 64); + memcpy(UncachedAddr(inblock_temp), inblock, 64); + + /* Be sure another thread doesn't get into a resource fight */ + disable_interrupts(); + + __SI_DMA_wait(); + + SI_regs->DRAM_addr = inblock_temp; // only cares about 23:0 + MEMORY_BARRIER(); + SI_regs->PIF_addr_write = PIF_RAM; // is it really ever anything else? + MEMORY_BARRIER(); + + __SI_DMA_wait(); + + data_cache_hit_writeback_invalidate(outblock_temp, 64); + + SI_regs->DRAM_addr = outblock_temp; + MEMORY_BARRIER(); + SI_regs->PIF_addr_read = PIF_RAM; + MEMORY_BARRIER(); + + __SI_DMA_wait(); + + /* Now that we've copied, its safe to let other threads go */ + enable_interrupts(); +} + +static void send_raw_command(int controller, int command, int bytesout, unsigned char *out) +{ + unsigned long long SI_read_controllers_block[8] = { 0, 0, 0, 0, 0, 0, 0, 1 }; + uint8_t *data = (uint8_t *)SI_read_controllers_block; + + data[controller + 0] = bytesout + 1; + data[controller + 1] = 1; + data[controller + 2] = command; + + memcpy( &data[controller + 3], out, bytesout ); + data[controller + 3 + bytesout] = 0xFE; + data[controller + 3 + bytesout + 1] = 0xFF; + + __controller_exec_PIF(SI_read_controllers_block); +} + +void pfx_send_game_id(uint8_t* crc_hi, uint8_t* crc_lo, uint8_t media_format, uint8_t country_id) +{ + uint8_t out[10]; + + memcpy(out, crc_hi, 4); + memcpy(&out[4], crc_lo, 4); + + out[8] = media_format; + out[9] = country_id; + + send_raw_command(0, 0x1D, sizeof(out), out); +} diff --git a/src/libs/pixelfx_n64digital/pfxromid.h b/src/libs/pixelfx_n64digital/pfxromid.h new file mode 100644 index 00000000..f8a0ff73 --- /dev/null +++ b/src/libs/pixelfx_n64digital/pfxromid.h @@ -0,0 +1,20 @@ +/* +** Copyright 2021 JonesAlmighty & PixelFx +*/ + +#ifndef __PIXELFX_ROMID_H +#define __PIXELFX_ROMID_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +void pfx_send_game_id(uint8_t* crc_hi, uint8_t* crc_lo, uint8_t media_format, uint8_t country_id); + +#ifdef __cplusplus +} +#endif + +#endif