From 3f43c466ca282ba14473d974659b5423c7067b08 Mon Sep 17 00:00:00 2001 From: spicyjpeg <88942473+spicyjpeg@users.noreply.github.com> Date: Mon, 7 Feb 2022 01:11:35 +0100 Subject: Rewrite psxapi with BIOS API stub generator script --- libpsn00b/include/psxapi.h | 5 +++++ libpsn00b/include/stdlib.h | 3 --- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'libpsn00b/include') diff --git a/libpsn00b/include/psxapi.h b/libpsn00b/include/psxapi.h index ec0dfea..e7c2e1e 100644 --- a/libpsn00b/include/psxapi.h +++ b/libpsn00b/include/psxapi.h @@ -213,6 +213,11 @@ void FlushCache(void); // Misc functions int GetSystemInfo(int index); +void *GetB0Table(void); +void *GetC0Table(void); + +void *_kernel_malloc(int size); +void _kernel_free(void *ptr); void _boot(void); diff --git a/libpsn00b/include/stdlib.h b/libpsn00b/include/stdlib.h index de3ab47..b187a6f 100644 --- a/libpsn00b/include/stdlib.h +++ b/libpsn00b/include/stdlib.h @@ -38,9 +38,6 @@ long labs(long i); long long strtoll(const char *nptr, char **endptr, int base); long strtol(const char *nptr, char **endptr, int base); long double strtold(const char *nptr, char **endptr); -// BIOS temporary -int atoi(const char *s); -long atol(const char *s); // Note: these use floats internally! double strtod(const char *nptr, char **endptr); -- cgit v1.2.3 From aca79b2a75c9a6106bc0047f767a475a2c3aaf8e Mon Sep 17 00:00:00 2001 From: spicyjpeg <88942473+spicyjpeg@users.noreply.github.com> Date: Wed, 9 Feb 2022 22:59:16 +0100 Subject: Rename hwregs_a definitions, add hwregs_c, fix io/pads --- examples/io/pads/main.c | 57 ++++++------ examples/io/pads/spi.c | 103 +++++++++------------ examples/io/pads/spi.h | 15 ++- examples/sound/spustream/main.c | 46 +++------ libpsn00b/include/hwregs_a.h | 174 ++++++++++++++++++++--------------- libpsn00b/include/hwregs_c.h | 129 ++++++++++++++++++++++++++ libpsn00b/psxapi/_initcd.s | 6 +- libpsn00b/psxcd/cdgetsector.s | 8 +- libpsn00b/psxcd/psxcd_asm.s | 8 +- libpsn00b/psxetc/dmacallback.s | 16 ++-- libpsn00b/psxetc/interruptcallback.s | 8 +- libpsn00b/psxetc/isr.s | 8 +- libpsn00b/psxetc/restartcallback.s | 4 +- libpsn00b/psxgpu/clearotagr.s | 6 +- libpsn00b/psxgpu/drawotag.s | 6 +- libpsn00b/psxgpu/drawsync.s | 4 +- libpsn00b/psxgpu/drawsynccallback.s | 2 +- libpsn00b/psxgpu/loadimage.s | 6 +- libpsn00b/psxgpu/resetgraph.s | 18 ++-- libpsn00b/psxgpu/storeimage.s | 6 +- libpsn00b/psxspu/spuinit.s | 57 +++++------- libpsn00b/psxspu/spureverbon.s | 2 +- libpsn00b/psxspu/spusetreverb.s | 7 +- libpsn00b/psxspu/spusetreverbaddr.s | 8 +- libpsn00b/psxspu/transfer.s | 16 ++-- 25 files changed, 426 insertions(+), 294 deletions(-) create mode 100644 libpsn00b/include/hwregs_c.h (limited to 'libpsn00b/include') diff --git a/examples/io/pads/main.c b/examples/io/pads/main.c index d100482..17bf331 100644 --- a/examples/io/pads/main.c +++ b/examples/io/pads/main.c @@ -15,12 +15,12 @@ * but the code in spi.c can be used to read/write sectors on a memory card and * combined with a higher-level filesystem driver for full support. * - * IMPORTANT: this example hasn't yet been tested on real hardware and/or with - * unofficial controllers, which might behave differently at higher poll rates. - * Also keep in mind that many emulators emulate controllers and memory cards - * inaccurately. It is thus recommended to test controller I/O code extensively - * and handle as many edge cases as possible (e.g. partial but valid responses, - * zerofilled responses, slow replies) for maximum compatibility. + * IMPORTANT: some controller models seem to be unable to respond to config + * mode commands reliably, even though simple high-speed polling usually works + * without issues. Also keep in mind that many emulators emulate controllers + * and memory cards inaccurately. It is thus recommended to test controller I/O + * code extensively and handle as many edge cases as possible (e.g. partial but + * valid responses, zerofilled responses, slow replies) for best compatibility. */ #include @@ -116,7 +116,7 @@ void display(CONTEXT *ctx) { static volatile uint8_t pad_buff[2][34]; static volatile size_t pad_buff_len[2]; -static volatile uint32_t pad_digital_only[2] = { 0, 0 }; +static volatile uint32_t pad_config_attempt[2] = { 0, 0 }; // Just a wrapper around SPI_CreateRequest(). This does not send the command // immediately but adds it to the driver's request queue. @@ -148,7 +148,8 @@ void send_pad_cmd( // This callback determines whether a pad that identified as digital is // actually a DualShock in digital mode by checking if it started identifying -// as CONFIG_MODE after receiving a configuration command. +// as CONFIG_MODE after receiving a configuration command. Calls to printf() +// had to be commented out due to them being too slow. void dualshock_init_cb(uint32_t port, const volatile uint8_t *buff, size_t rx_len) { PadResponse *pad = (PadResponse *) buff; @@ -157,13 +158,13 @@ void dualshock_init_cb(uint32_t port, const volatile uint8_t *buff, size_t rx_le (pad->prefix != 0x5a) || (pad->type != PAD_ID_CONFIG_MODE) ) { - printf("no, pad is digital-only (len = %d)\n", rx_len); + //printf("no, pad is digital-only (len = %d)\n", rx_len); - pad_digital_only[port] = 1; + pad_config_attempt[port]++; return; } - printf("yes, forcing analog mode (len = %d)\n", rx_len); + //printf("yes, forcing analog mode (len = %d)\n", rx_len); // Issue further commands to force analog mode on, unlock rumble (not used // in this example) and enable longer responses containing button pressure @@ -171,6 +172,7 @@ void dualshock_init_cb(uint32_t port, const volatile uint8_t *buff, size_t rx_le // TODO: find out if passing 0x03 instead of 0x02 in PAD_CMD_SET_ANALOG // locks the analog button, as emulated by DuckStation... // https://gist.github.com/scanlime/5042071 + send_pad_cmd(port, PAD_CMD_CONFIG_MODE, 0x01, 0x00, 0); send_pad_cmd(port, PAD_CMD_SET_ANALOG, 0x01, 0x02, 0); send_pad_cmd(port, PAD_CMD_INIT_PRESSURE, 0x00, 0x00, 0); // Ignored by DualShock 1 send_pad_cmd(port, PAD_CMD_REQUEST_CONFIG, 0x00, 0x01, 0); @@ -189,29 +191,37 @@ void poll_cb(uint32_t port, const volatile uint8_t *buff, size_t rx_len) { PadResponse *pad = (PadResponse *) buff; - // If this pad identifies as a digital pad and hasn't been flagged as a - // digital-only pad already, attempt to put it into analog mode by entering - // configuration mode. It this fails, it will be flagged as digital-only. - // The digital-only flag is reset when the controller is unplugged or stops + // If this pad identifies as a digital pad, attempt to put it into analog + // mode up to 3 times by entering configuration mode. Once the attempt + // counter exceeds the threshold, it will be treated as digital-only. The + // attempt counter is reset when the controller is unplugged or stops // returning digital pad responses. + // NOTE: according to nocash docs, there is a hardware bug in DualShock + // controllers that causes the prefix byte (normally 0x5a) to turn into + // 0x00 if the analog button is pressed after config commands have been + // used. if ( rx_len && - (pad->prefix == 0x5a) && + ((pad->prefix == 0x5a) || !(pad->prefix)) && (pad->type == PAD_ID_DIGITAL) ) { - if (!pad_digital_only[port]) { - printf("Detecting if pad %d supports config mode... ", port + 1); + if (pad_config_attempt[port] < 3) { + /*printf( + "Detecting if pad %d supports config mode: attempt %d... ", + port + 1, + pad_config_attempt[port] + 1 + );*/ // The pad only identifies as CONFIG_MODE after at least another // command is sent. send_pad_cmd(port, PAD_CMD_CONFIG_MODE, 0x01, 0x00, 0); - send_pad_cmd(port, PAD_CMD_CONFIG_MODE, 0x01, 0x00, &dualshock_init_cb); + send_pad_cmd(port, PAD_CMD_READ, 0x00, 0x00, &dualshock_init_cb); } } else { - //printf("Clearing digital-only flag for pad %d\n", port + 1); + //printf("Clearing attempt counter for pad %d\n", port + 1); - pad_digital_only[port] = 0; + pad_config_attempt[port] = 0; } } @@ -240,11 +250,6 @@ int main(int argc, const char* argv[]) { PadResponse *pad = (PadResponse *) pad_buff[port]; - // According to nocash docs, there is a hardware bug in DualShock - // controllers that causes the prefix byte (normally 0x5a) to turn - // into 0x00 if the analog button is pressed after configuration - // commands have been used. Thus making sure the prefix is 0x5a - // isn't enough to reliably detect pads. /*if ((pad->prefix != 0x5a) && (pad->type != PAD_ID_ANALOG)) { FntPrint(-1, "\n\nPORT %d: INVALID RESPONSE\n", port + 1); if ((counter % 64) < 32) diff --git a/examples/io/pads/spi.c b/examples/io/pads/spi.c index ef75ffc..05a0e59 100644 --- a/examples/io/pads/spi.c +++ b/examples/io/pads/spi.c @@ -32,43 +32,27 @@ #include #include #include +#include #include "spi.h" -/* Register definitions */ - -#define F_CPU 33868800UL - -#define TIM_VALUE(N) *((volatile uint32_t *) 0x1f801100 + 4 * (N)) -#define TIM_CTRL(N) *((volatile uint32_t *) 0x1f801104 + 4 * (N)) -#define TIM_RELOAD(N) *((volatile uint32_t *) 0x1f801108 + 4 * (N)) - -// IMPORTANT: even though JOY_TXRX is a 32-bit register, it should only be -// accessed as 8-bit. Reading it as 16 or 32-bit works fine on real hardware, -// but leads to problems in some emulators. -#define JOY_TXRX *((volatile uint8_t *) 0x1f801040) -#define JOY_STAT *((volatile uint16_t *) 0x1f801044) -#define JOY_MODE *((volatile uint16_t *) 0x1f801048) -#define JOY_CTRL *((volatile uint16_t *) 0x1f80104a) -#define JOY_BAUD *((volatile uint16_t *) 0x1f80104e) - /* Internal structures and globals */ -typedef struct _SPI_CONTEXT { +typedef struct _SPI_Context { uint8_t tx_buff[SPI_BUFF_LEN]; uint8_t rx_buff[SPI_BUFF_LEN]; uint32_t tx_len, rx_len, port; SPI_Callback callback; } SPI_Context; -static volatile SPI_Context ctx; -static volatile SPI_Request volatile *current_req; -static SPI_Callback default_cb; +static volatile SPI_Context _context; +static volatile SPI_Request volatile *_current_req; +static volatile SPI_Callback _default_cb; /* Request queue management */ static void _spi_create_poll_req(void) { - PadRequest *req = (PadRequest *) ctx.tx_buff; + PadRequest *req = (PadRequest *) _context.tx_buff; req->addr = 0x01; req->cmd = PAD_CMD_READ; @@ -76,27 +60,31 @@ static void _spi_create_poll_req(void) { req->motor_l = 0x00; req->motor_r = 0x00; - ctx.tx_len = 4; - ctx.rx_len = 0; - ctx.port ^= 1; - ctx.callback = default_cb; + _context.tx_len = 4; + _context.rx_len = 0; + _context.port ^= 1; + _context.callback = _default_cb; } static void _spi_next_req(void) { // Copy the contents of the first request in the queue into the TX buffer. - memcpy((void *) ctx.tx_buff, (void *) current_req->data, current_req->len); + memcpy( + (void *) _context.tx_buff, + (void *) _current_req->data, + _current_req->len + ); - ctx.tx_len = current_req->len; - ctx.rx_len = 0; - ctx.port = current_req->port; - ctx.callback = current_req->callback; + _context.tx_len = _current_req->len; + _context.rx_len = 0; + _context.port = _current_req->port; + _context.callback = _current_req->callback; // Pop the first request from the queue by deallocating it and adjusting // the pointer to the first queue item. - SPI_Request *next = current_req->next; + SPI_Request *next = _current_req->next; - free((void *) current_req); - current_req = next; + free((void *) _current_req); + _current_req = next; } /* Interrupt handlers */ @@ -105,13 +93,13 @@ static void _spi_poll_irq_handler(void) { // Fetch the last response byte, which wasn't followed by a pulse on /ACK, // from the RX FIFO. if (JOY_STAT & 0x0002) - ctx.rx_buff[ctx.rx_len - 1] = (uint8_t) JOY_TXRX; + _context.rx_buff[_context.rx_len - 1] = (uint8_t) JOY_TXRX; - if (ctx.callback) - ctx.callback(ctx.port, ctx.rx_buff, ctx.rx_len); + if (_context.callback) + _context.callback(_context.port, _context.rx_buff, _context.rx_len); // If the request queue is empty, create a pad polling request. - if (current_req) + if (_current_req) _spi_next_req(); else _spi_create_poll_req(); @@ -119,17 +107,18 @@ static void _spi_poll_irq_handler(void) { // Prepare the SPI port by clearing any pending IRQ, pulling /CS high and // enabling the /ACK IRQ. In order to communicate with controllers, /CS has // to be driven low again for about 20 us before sending the first byte. + // TODO: these delays can be probably tweaked for better performance JOY_CTRL = 0x0010; - for (uint32_t i = 0; i < 50; i++) - __asm__("nop"); + for (uint32_t i = 0; i < 1000; i++) + __asm__ volatile(""); - JOY_CTRL = 0x1003 | (ctx.port << 13); - for (uint32_t i = 0; i < 500; i++) - __asm__("nop"); + JOY_CTRL = 0x1003 | (_context.port << 13); + for (uint32_t i = 0; i < 2000; i++) + __asm__ volatile(""); // Send the first byte indicating which device to address. If the matching // device is connected, it will reply by triggering the /ACK IRQ. - JOY_TXRX = ctx.tx_buff[0]; + JOY_TXRX = _context.tx_buff[0]; } static void _spi_ack_irq_handler(void) { @@ -137,29 +126,29 @@ static void _spi_ack_irq_handler(void) { // byte. According to nocash docs, this has to be done before resetting the // IRQ. while (JOY_STAT & 0x0080) - __asm__("nop"); + __asm__ volatile(""); // Keep /CS pulled low and acknowledge the IRQ (bit 4) to ensure it can be // triggered again. - JOY_CTRL = 0x1013 | (ctx.port << 13); + JOY_CTRL = 0x1013 | (_context.port << 13); - if (!ctx.rx_len) { + if (!_context.rx_len) { // We just sent the first address byte. Obviously the response we // received was read from an open bus, so the SPI port's internal FIFO // must be flushed (by performing dummy reads) to ensure we are only // going to read valid data from now on. JOY_TXRX; - } else if (ctx.rx_len <= SPI_BUFF_LEN) { + } else if (_context.rx_len <= SPI_BUFF_LEN) { // If this is not the first byte, put it in the RX buffer. - ctx.rx_buff[ctx.rx_len - 1] = (uint8_t) JOY_TXRX; + _context.rx_buff[_context.rx_len - 1] = (uint8_t) JOY_TXRX; } // Send the next byte, or a null byte if there is no more data to send and // we're just reading a response. - ctx.rx_len++; - if (ctx.rx_len < ctx.tx_len) - JOY_TXRX = (uint32_t) ctx.tx_buff[ctx.rx_len]; + _context.rx_len++; + if (_context.rx_len < _context.tx_len) + JOY_TXRX = (uint32_t) _context.tx_buff[_context.rx_len]; else JOY_TXRX = 0x00; } @@ -176,10 +165,10 @@ SPI_Request *SPI_CreateRequest(void) { // Find the last queued request by traversing the linked list and append a // pointer to the new request. - if (!current_req) { - current_req = req; + if (!_current_req) { + _current_req = req; } else { - volatile SPI_Request *volatile last = current_req; + volatile SPI_Request *volatile last = _current_req; while (last->next) last = last->next; @@ -213,6 +202,6 @@ void SPI_Init(SPI_Callback callback) { JOY_BAUD = 0x0088; // 250000 bps SPI_SetPollRate(250); - current_req = 0; - default_cb = callback; + _current_req = 0; + _default_cb = callback; } diff --git a/examples/io/pads/spi.h b/examples/io/pads/spi.h index c50e065..7d4d75b 100644 --- a/examples/io/pads/spi.h +++ b/examples/io/pads/spi.h @@ -9,8 +9,9 @@ #include #include -// Maximum request/response length (34 bytes for pads, 140 for memory cards) -//#define SPI_BUFF_LEN 34 +// Maximum request/response length (34 bytes for pads, 140 for memory cards). +// Must be a multiple of 4 to avoid memory alignment issues. +//#define SPI_BUFF_LEN 36 #define SPI_BUFF_LEN 140 /* Request structures */ @@ -30,6 +31,10 @@ typedef struct _SPI_Request { /* Public API */ +#ifdef __cplusplus +extern "C" { +#endif + /** * @brief Allocates a new request object and adds it to the request queue. The * object must be populated afterwards by setting the length, callback and @@ -49,7 +54,7 @@ void SPI_SetPollRate(uint32_t value); /** * @brief Installs the SPI and timer 2 interrupt handlers and starts the poll * timer. By default the polling rate is set to 250 Hz (125 Hz per port), - * however it can be changed at any time by calling spi_set_poll_rate(). + * however it can be changed at any time by calling SPI_SetPollRate(). * * The provided callback (if any) is called to report the result of poll * requests, which are issued automatically when no other request is in the @@ -59,4 +64,8 @@ void SPI_SetPollRate(uint32_t value); */ void SPI_Init(SPI_Callback callback); +#ifdef __cplusplus +} +#endif + #endif diff --git a/examples/sound/spustream/main.c b/examples/sound/spustream/main.c index be095cb..6284c6d 100644 --- a/examples/sound/spustream/main.c +++ b/examples/sound/spustream/main.c @@ -11,8 +11,8 @@ * SPU ADPCM data (one for each channel, so a stereo stream would have 2 * buffers per chunk). All buffers in a chunk are played simultaneously using * multiple SPU channels; each buffer has the loop flag set at the end, so each - * channel will jump to its loop address (SPU_CHANNELS[n].loop_addr) once the - * chunk is played. + * channel will jump to its loop address (SPU_CH_LOOP_ADDR(n)) once the chunk + * is played. * * Since the loop point doesn't necessarily have to be within the chunk itself, * we can abuse it to "queue" another set of buffers to be played immediately @@ -94,6 +94,7 @@ #include #include #include +#include // To maximize STREAM.BIN packing efficiency and get rid of padding between // chunks, buffer size should be a multiple of sector size (2048 bytes). Buffer @@ -105,27 +106,6 @@ #define NUM_CHANNELS 2 #define CHANNEL_MASK 0x03 -/* Register definitions */ - -// For some reason SpuVoiceRaw doesn't actually match the layout of SPU -// registers, so here we go. -typedef struct { - uint16_t vol_left; - uint16_t vol_right; - uint16_t freq; - uint16_t addr; - uint32_t adsr_param; - uint16_t _reserved; - uint16_t loop_addr; -} SPUChannel; - -#define SPU_CTRL *((volatile uint16_t *) 0x1f801daa) -#define SPU_IRQ_ADDR *((volatile uint16_t *) 0x1f801da4) -#define SPU_KEY_ON *((volatile uint32_t *) 0x1f801d88) -#define SPU_KEY_OFF *((volatile uint32_t *) 0x1f801d8c) - -// SPU RAM is addressed in 8-byte units, using 16-bit pointers. -#define SPU_CHANNELS ((volatile SPUChannel *) 0x1f801c00) #define SPU_RAM_ADDR(x) ((uint16_t) (((uint32_t) (x)) >> 3)) /* Display/GPU context utilities */ @@ -252,7 +232,7 @@ void spu_irq_handler(void) { SPU_IRQ_ADDR = SPU_RAM_ADDR(str_ctx.spu_addr); for (uint32_t i = 0; i < NUM_CHANNELS; i++) - SPU_CHANNELS[i].loop_addr = SPU_RAM_ADDR(str_ctx.spu_addr + BUFFER_SIZE * i); + SPU_CH_LOOP_ADDR(i) = SPU_RAM_ADDR(str_ctx.spu_addr + BUFFER_SIZE * i); // Start loading the next chunk. cd_event_handler() will be called // repeatedly for each sector until the entire chunk is read. @@ -317,7 +297,7 @@ void init_spu_channels(void) { SPU_KEY_OFF = 0x00ffffff; for (uint32_t i = 0; i < 24; i++) - SPU_CHANNELS[i].addr = SPU_RAM_ADDR(DUMMY_BLOCK_ADDR); + SPU_CH_ADDR(i) = SPU_RAM_ADDR(DUMMY_BLOCK_ADDR); SPU_KEY_ON = 0x00ffffff; } @@ -347,18 +327,18 @@ void start_stream(void) { SPU_KEY_OFF = CHANNEL_MASK; for (uint32_t i = 0; i < NUM_CHANNELS; i++) { - SPU_CHANNELS[i].addr = SPU_RAM_ADDR(BUFFER_START_ADDR + BUFFER_SIZE * i); - SPU_CHANNELS[i].freq = SAMPLE_RATE; - SPU_CHANNELS[i].adsr_param = 0x1fee80ff; // or 0x9fc080ff, 0xdff18087 + SPU_CH_ADDR(i) = SPU_RAM_ADDR(BUFFER_START_ADDR + BUFFER_SIZE * i); + SPU_CH_FREQ(i) = SAMPLE_RATE; + SPU_CH_ADSR(i) = 0x1fee80ff; // or 0x9fc080ff, 0xdff18087 } // Unmute the channels and route them for stereo output. You'll want to // edit this if you are using more than 2 channels, and/or if you want to // provide an option to output mono audio instead of stereo. - SPU_CHANNELS[0].vol_left = 0x3fff; - SPU_CHANNELS[0].vol_right = 0x0000; - SPU_CHANNELS[1].vol_left = 0x0000; - SPU_CHANNELS[1].vol_right = 0x3fff; + SPU_CH_VOL_L(0) = 0x3fff; + SPU_CH_VOL_R(0) = 0x0000; + SPU_CH_VOL_L(1) = 0x0000; + SPU_CH_VOL_R(1) = 0x3fff; SPU_KEY_ON = CHANNEL_MASK; spu_irq_handler(); @@ -446,7 +426,7 @@ int main(int argc, const char* argv[]) { // Only set the sample rate registers if necessary. if (pad->btn != 0xffff) { for (uint32_t i = 0; i < NUM_CHANNELS; i++) - SPU_CHANNELS[i].freq = sample_rate; + SPU_CH_FREQ(i) = sample_rate; } last_buttons = pad->btn; diff --git a/libpsn00b/include/hwregs_a.h b/libpsn00b/include/hwregs_a.h index 0680679..4d0bade 100644 --- a/libpsn00b/include/hwregs_a.h +++ b/libpsn00b/include/hwregs_a.h @@ -6,11 +6,13 @@ .set IOBASE, 0x1f80 # IO segment base -# GPU +## GPU + .set GP0, 0x1810 # Also GPUREAD .set GP1, 0x1814 # Also GPUSTAT -# CD +## CD drive + .set CD_STAT, 0x1800 .set CD_CMD, 0x1801 # Also response FIFO .set CD_DATA, 0x1802 # Also parameters @@ -21,14 +23,14 @@ .set CD_REG2, 0x1802 .set CD_REG3, 0x1803 -.set SBUS_5, 0x1018 -.set COM_DELAY, 0x1020 +## SPU -# SPU (must be used with 16-bit load/store instructions) .set SPU_VOICE_BASE, 0x1c00 -.set SPU_MASTER_VOL, 0x1d80 -.set SPU_REVERB_VOL, 0x1d84 +.set SPU_MASTER_VOL_L, 0x1d80 +.set SPU_MASTER_VOL_R, 0x1d82 +.set SPU_REVERB_VOL_L, 0x1d84 +.set SPU_REVERB_VOL_R, 0x1d86 .set SPU_KEY_ON, 0x1d88 .set SPU_KEY_OFF, 0x1d8c .set SPU_FM_MODE, 0x1d90 @@ -41,81 +43,107 @@ .set SPU_ADDR, 0x1da6 .set SPU_DATA, 0x1da8 -.set SPUCNT, 0x1daa -.set SPUDTCNT, 0x1dac -.set SPUSTAT, 0x1dae +.set SPU_CTRL, 0x1daa +.set SPU_DMA_CTRL, 0x1dac +.set SPU_STAT, 0x1dae -.set SPU_CD_VOL, 0x1db0 -.set SPU_EXT_VOL, 0x1db4 -.set SPU_CURRENT_VOL, 0x1db8 +.set SPU_CD_VOL_L, 0x1db0 +.set SPU_CD_VOL_R, 0x1db2 +.set SPU_EXT_VOL_L, 0x1db4 +.set SPU_EXT_VOL_R, 0x1db6 +.set SPU_CURRENT_VOL_L, 0x1db8 +.set SPU_CURRENT_VOL_R, 0x1dba .set SPU_VOICE_VOL_L, 0x00 .set SPU_VOICE_VOL_R, 0x02 .set SPU_VOICE_FREQ, 0x04 .set SPU_VOICE_ADDR, 0x06 .set SPU_VOICE_ADSR_L, 0x08 -.set SPU_VOICE_ADSR_H, 0x0a +.set SPU_VOICE_ADSR_H, 0x0a .set SPU_VOICE_LOOP, 0x0e -# MDEC +## MDEC + .set MDEC0, 0x1820 .set MDEC1, 0x1824 -# Pads -.set JOY_TXRX, 0x1040 -.set JOY_STAT, 0x1044 -.set JOY_MODE, 0x1048 -.set JOY_CTRL, 0x104A -.set JOY_BAUD, 0x104E - -# Serial -.set SIO_TXRX, 0x1050 -.set SIO_STAT, 0x1054 -.set SIO_MODE, 0x1058 -.set SIO_CTRL, 0x105a -.set SIO_BAUD, 0x105e - -# IRQ -.set ISTAT, 0x1070 -.set IMASK, 0x1074 - -# DMA -.set DPCR, 0x10f0 -.set DICR, 0x10f4 - -.set D0_MADR, 0x1080 -.set D0_BCR, 0x1084 -.set D0_CHCR, 0x1088 - -.set D1_MADR, 0x1090 -.set D1_BCR, 0x1094 -.set D1_CHCR, 0x1098 - -.set D2_MADR, 0x10a0 -.set D2_BCR, 0x10a4 -.set D2_CHCR, 0x10a8 - -.set D3_MADR, 0x10b0 -.set D3_BCR, 0x10b4 -.set D3_CHCR, 0x10b8 - -.set D4_MADR, 0x10c0 -.set D4_BCR, 0x10c4 -.set D4_CHCR, 0x10c8 - -.set D6_MADR, 0x10e0 -.set D6_BCR, 0x10e4 -.set D6_CHCR, 0x10e8 - -# Timers -.set T0_CNT, 0x1100 -.set T0_MODE, 0x1104 -.set T0_TGT, 0x1108 - -.set T1_CNT, 0x1110 -.set T1_MODE, 0x1114 -.set T1_TGT, 0x1118 - -.set T2_CNT, 0x1120 -.set T2_MODE, 0x1124 -.set T2_TGT, 0x1128 +## SPI controller port + +.set JOY_TXRX, 0x1040 +.set JOY_STAT, 0x1044 +.set JOY_MODE, 0x1048 +.set JOY_CTRL, 0x104a +.set JOY_BAUD, 0x104e + +## Serial port + +.set SIO_TXRX, 0x1050 +.set SIO_STAT, 0x1054 +.set SIO_MODE, 0x1058 +.set SIO_CTRL, 0x105a +.set SIO_BAUD, 0x105e + +## IRQ controller + +.set IRQ_STAT, 0x1070 +.set IRQ_MASK, 0x1074 + +## DMA + +.set DMA_DPCR, 0x10f0 +.set DMA_DICR, 0x10f4 + +.set DMA0_MADR, 0x1080 +.set DMA0_BCR, 0x1084 +.set DMA0_CHCR, 0x1088 + +.set DMA1_MADR, 0x1090 +.set DMA1_BCR, 0x1094 +.set DMA1_CHCR, 0x1098 + +.set DMA2_MADR, 0x10a0 +.set DMA2_BCR, 0x10a4 +.set DMA2_CHCR, 0x10a8 + +.set DMA3_MADR, 0x10b0 +.set DMA3_BCR, 0x10b4 +.set DMA3_CHCR, 0x10b8 + +.set DMA4_MADR, 0x10c0 +.set DMA4_BCR, 0x10c4 +.set DMA4_CHCR, 0x10c8 + +.set DMA5_MADR, 0x10d0 +.set DMA5_BCR, 0x10d4 +.set DMA5_CHCR, 0x10d8 + +.set DMA6_MADR, 0x10e0 +.set DMA6_BCR, 0x10e4 +.set DMA6_CHCR, 0x10e8 + +## Timers + +.set TIM0_VALUE, 0x1100 +.set TIM0_CTRL, 0x1104 +.set TIM0_RELOAD, 0x1108 + +.set TIM1_VALUE, 0x1110 +.set TIM1_CTRL, 0x1114 +.set TIM1_RELOAD, 0x1118 + +.set TIM2_VALUE, 0x1120 +.set TIM2_CTRL, 0x1124 +.set TIM2_RELOAD, 0x1128 + +## Memory control + +.set EXP1_ADDR, 0x1000 +.set EXP2_ADDR, 0x1004 +.set EXP1_DELAY_SIZE, 0x1008 +.set EXP3_DELAY_SIZE, 0x100c +.set BIOS_DELAY_SIZE, 0x1010 +.set SPU_DELAY_SIZE, 0x1014 +.set CD_DELAY_SIZE, 0x1018 +.set EXP2_DELAY_SIZE, 0x101c +.set COM_DELAY_CFG, 0x1020 +.set RAM_SIZE_CFG, 0x1060 diff --git a/libpsn00b/include/hwregs_c.h b/libpsn00b/include/hwregs_c.h new file mode 100644 index 0000000..4222a22 --- /dev/null +++ b/libpsn00b/include/hwregs_c.h @@ -0,0 +1,129 @@ +/* + * PSn00bSDK hardware registers definitions + * (C) 2022 spicyjpeg - MPL licensed + */ + +#ifndef __HWREGS_C_H +#define __HWREGS_C_H + +#include + +#define _MMIO8(addr) *((volatile uint8_t *) (addr)) +#define _MMIO16(addr) *((volatile uint16_t *) (addr)) +#define _MMIO32(addr) *((volatile uint32_t *) (addr)) + +/* Constants */ + +#define F_CPU 33868800UL +#define F_GPU 53222400UL + +/* GPU */ + +#define GP0 _MMIO32(0x1f801810) +#define GP1 _MMIO32(0x1f801814) + +/* CD drive */ + +#define CD_STAT _MMIO8(0x1f801800) +#define CD_CMD _MMIO8(0x1f801801) +#define CD_DATA _MMIO8(0x1f801802) +#define CD_IRQ _MMIO8(0x1f801803) + +#define CD_REG(N) _MMIO8(0x1f801800 + (N)) + +/* SPU */ + +#define SPU_MASTER_VOL_L _MMIO16(0x1f801d80) +#define SPU_MASTER_VOL_R _MMIO16(0x1f801d82) +#define SPU_REVERB_VOL_L _MMIO16(0x1f801d84) +#define SPU_REVERB_VOL_R _MMIO16(0x1f801d86) +#define SPU_KEY_ON _MMIO32(0x1f801d88) +#define SPU_KEY_OFF _MMIO32(0x1f801d8c) +#define SPU_FM_MODE _MMIO32(0x1f801d90) +#define SPU_NOISE_MODE _MMIO32(0x1f801d94) +#define SPU_REVERB_ON _MMIO32(0x1f801d98) +#define SPU_CHAN_STATUS _MMIO32(0x1f801d9c) + +#define SPU_REVERB_ADDR _MMIO16(0x1f801da2) +#define SPU_IRQ_ADDR _MMIO16(0x1f801da4) +#define SPU_ADDR _MMIO16(0x1f801da6) +#define SPU_DATA _MMIO16(0x1f801da8) + +#define SPU_CTRL _MMIO16(0x1f801daa) +#define SPU_DMA_CTRL _MMIO16(0x1f801dac) +#define SPU_STAT _MMIO16(0x1f801dae) + +#define SPU_CD_VOL_L _MMIO16(0x1f801db0) +#define SPU_CD_VOL_R _MMIO16(0x1f801db2) +#define SPU_EXT_VOL_L _MMIO16(0x1f801db4) +#define SPU_EXT_VOL_R _MMIO16(0x1f801db6) +#define SPU_CURRENT_VOL_L _MMIO16(0x1f801db8) +#define SPU_CURRENT_VOL_R _MMIO16(0x1f801dba) + +// These are not named SPU_VOICE_* to avoid name clashes with SPU attribute +// flags defined in psxspu.h. +#define SPU_CH_VOL_L(N) _MMIO16(0x1f801c00 + 16 * (N)) +#define SPU_CH_VOL_R(N) _MMIO16(0x1f801c02 + 16 * (N)) +#define SPU_CH_FREQ(N) _MMIO16(0x1f801c04 + 16 * (N)) +#define SPU_CH_ADDR(N) _MMIO16(0x1f801c06 + 16 * (N)) +#define SPU_CH_ADSR(N) _MMIO32(0x1f801c08 + 16 * (N)) +#define SPU_CH_LOOP_ADDR(N) _MMIO16(0x1f801c0e + 16 * (N)) + +/* MDEC */ + +#define MDEC0 _MMIO32(0x1f801820) +#define MDEC1 _MMIO32(0x1f801824) + +/* SPI controller port */ + +// IMPORTANT: even though JOY_TXRX is a 32-bit register, it should only be +// accessed as 8-bit. Reading it as 16 or 32-bit works fine on real hardware, +// but leads to problems in some emulators. +#define JOY_TXRX _MMIO8(0x1f801040) +#define JOY_STAT _MMIO16(0x1f801044) +#define JOY_MODE _MMIO16(0x1f801048) +#define JOY_CTRL _MMIO16(0x1f80104a) +#define JOY_BAUD _MMIO16(0x1f80104e) + +/* Serial port */ + +#define SIO_TXRX _MMIO8(0x1f801050) +#define SIO_STAT _MMIO16(0x1f801054) +#define SIO_MODE _MMIO16(0x1f801058) +#define SIO_CTRL _MMIO16(0x1f80105a) +#define SIO_BAUD _MMIO16(0x1f80105e) + +/* IRQ controller */ + +#define IRQ_STAT _MMIO32(0x1f801070) +#define IRQ_MASK _MMIO32(0x1f801074) + +/* DMA */ + +#define DMA_DPCR _MMIO32(0x1f8010f0) +#define DMA_DICR _MMIO32(0x1f8010f4) + +#define DMA_MADR(N) _MMIO32(0x1f801080 + 16 * (N)) +#define DMA_BCR(N) _MMIO32(0x1f801084 + 16 * (N)) +#define DMA_CHCR(N) _MMIO32(0x1f801088 + 16 * (N)) + +/* Timers */ + +#define TIM_VALUE(N) _MMIO32(0x1f801100 + 16 * (N)) +#define TIM_CTRL(N) _MMIO32(0x1f801104 + 16 * (N)) +#define TIM_RELOAD(N) _MMIO32(0x1f801108 + 16 * (N)) + +/* Memory control */ + +#define EXP1_ADDR _MMIO32(0x1f801000) +#define EXP2_ADDR _MMIO32(0x1f801004) +#define EXP1_DELAY_SIZE _MMIO32(0x1f801008) +#define EXP3_DELAY_SIZE _MMIO32(0x1f80100c) +#define BIOS_DELAY_SIZE _MMIO32(0x1f801010) +#define SPU_DELAY_SIZE _MMIO32(0x1f801014) +#define CD_DELAY_SIZE _MMIO32(0x1f801018) +#define EXP2_DELAY_SIZE _MMIO32(0x1f80101c) +#define COM_DELAY_CFG _MMIO32(0x1f801020) +#define RAM_SIZE_CFG _MMIO32(0x1f801060) + +#endif diff --git a/libpsn00b/psxapi/_initcd.s b/libpsn00b/psxapi/_initcd.s index decf2bd..c3a2861 100644 --- a/libpsn00b/psxapi/_initcd.s +++ b/libpsn00b/psxapi/_initcd.s @@ -11,7 +11,7 @@ _InitCd: lui $a0, IOBASE # Load IOBASE value - lw $v0, DPCR($a0) # Get current DMA settings + lw $v0, DMA_DPCR($a0) # Get current DMA settings nop sw $v0, 4($sp) # Save to stack @@ -21,14 +21,14 @@ _InitCd: lui $a0, IOBASE # Load IOBASE again lw $v0, 4($sp) # Get old DMA control settings - lw $v1, DPCR($a0) # Get DMA settings by _96_init() + lw $v1, DMA_DPCR($a0) # Get DMA settings by _96_init() lui $a1, 0xffff # Mask out settings for CD DMA ori $a1, 0x0f00 and $v0, $a1 or $v0, $v1 # Merge and set new DMA settings - sw $v0, DPCR($a0) + sw $v0, DMA_DPCR($a0) lw $ra, 0($sp) addiu $sp, 8 diff --git a/libpsn00b/psxcd/cdgetsector.s b/libpsn00b/psxcd/cdgetsector.s index dbe95cb..9f38e7a 100644 --- a/libpsn00b/psxcd/cdgetsector.s +++ b/libpsn00b/psxcd/cdgetsector.s @@ -21,16 +21,16 @@ CdGetSector: # srl $a1, 2 # (the official implementation expects $a1/size # to be in 32-bit words rather than bytes) or $v0, $a1 - sw $a0, D3_MADR($a2) # Set DMA base address and transfer length - sw $v0, D3_BCR($a2) + sw $a0, DMA3_MADR($a2) # Set DMA base address and transfer length + sw $v0, DMA3_BCR($a2) lui $v0, 0x1100 # Start DMA transfer - sw $v0, D3_CHCR($a2) + sw $v0, DMA3_CHCR($a2) nop nop .Ldma_wait: # Ensure DMA transfer has completed - lw $v0, D3_CHCR($a2) + lw $v0, DMA3_CHCR($a2) nop srl $v0, 24 andi $v0, 0x1 diff --git a/libpsn00b/psxcd/psxcd_asm.s b/libpsn00b/psxcd/psxcd_asm.s index 1dbf542..129bc89 100644 --- a/libpsn00b/psxcd/psxcd_asm.s +++ b/libpsn00b/psxcd/psxcd_asm.s @@ -17,9 +17,9 @@ _cd_init: lui $a3, IOBASE # Acknowledge all CD IRQs li $v0, 0x20943 # Set CD-ROM Delay/Size and common delay - sw $v0, SBUS_5($a3) + sw $v0, CD_DELAY_SIZE($a3) li $v0, 0x1325 - sw $v0, COM_DELAY($a3) + sw $v0, COM_DELAY_CFG($a3) li $v0, 1 sb $v0, CD_REG0($a3) @@ -71,10 +71,10 @@ _cd_init: la $v0, _cd_read_cb sw $0 , 0($v0) - lw $v0, DPCR($a3) + lw $v0, DMA_DPCR($a3) li $v1, 0xB000 or $v0, $v1 - sw $v0, DPCR($a3) + sw $v0, DMA_DPCR($a3) jal ExitCriticalSection nop diff --git a/libpsn00b/psxetc/dmacallback.s b/libpsn00b/psxetc/dmacallback.s index b2f86cf..8ea8ec0 100644 --- a/libpsn00b/psxetc/dmacallback.s +++ b/libpsn00b/psxetc/dmacallback.s @@ -46,13 +46,13 @@ DMACallback: lui $a2, IOBASE - lw $v0, DICR($a2) # Enable DMA interrupt + lw $v0, DMA_DICR($a2) # Enable DMA interrupt lui $v1, 0x1 sll $v1, $a0 or $v0, $v1 lui $v1, 0x80 or $v0, $v1 - sw $v0, DICR($a2) + sw $v0, DMA_DICR($a2) b .Lskip_remove nop @@ -67,7 +67,7 @@ DMACallback: sw $v1, 4($sp) lui $a2, IOBASE # Disable DMA interrupt - lw $v0, DICR($a2) + lw $v0, DMA_DICR($a2) lui $v1, 0x1 sll $v1, $a0 .set noat @@ -78,13 +78,13 @@ DMACallback: xor $v1, $at and $v0, $v1 .set at - sw $v0, DICR($a2) + sw $v0, DMA_DICR($a2) jal _dma_has_cb # Check if callbacks are present nop bnez $v0, .Lskip_remove nop - sw $0 , DICR($a2) + sw $0 , DMA_DICR($a2) jal GetInterruptCallback # Check if callback is the DMA handler li $a0, 3 @@ -143,7 +143,7 @@ _dma_handler: .Lhandler_loop: lui $a0, IOBASE - lw $v0, DICR($a0) + lw $v0, DMA_DICR($a0) li $v1, 24 addu $v1, $s0 srl $v0, $v1 @@ -166,9 +166,9 @@ _dma_handler: addi $s0, 1 lui $a0, IOBASE - lw $v0, DICR($a0) + lw $v0, DMA_DICR($a0) nop - sw $v0, DICR($a0) + sw $v0, DMA_DICR($a0) lw $ra, 0($sp) lw $s0, 4($sp) diff --git a/libpsn00b/psxetc/interruptcallback.s b/libpsn00b/psxetc/interruptcallback.s index 8e912d8..78e5e6e 100644 --- a/libpsn00b/psxetc/interruptcallback.s +++ b/libpsn00b/psxetc/interruptcallback.s @@ -16,25 +16,25 @@ InterruptCallback: beqz $a1, .Ldisable_irq nop - lw $v0, IMASK($a2) # Enable interrupt mask + lw $v0, IRQ_MASK($a2) # Enable interrupt mask li $v1, 1 sll $v1, $a0 or $v0, $v1 b .Lcont - sw $v0, IMASK($a2) + sw $v0, IRQ_MASK($a2) .Ldisable_irq: .set noat - lw $v0, IMASK($a2) # Disable interrupt mask + lw $v0, IRQ_MASK($a2) # Disable interrupt mask li $v1, 1 sll $v1, $a0 addiu $at, $0 , -1 xor $v1, $at .set at and $v0, $v1 - sw $v0, IMASK($a2) + sw $v0, IRQ_MASK($a2) .Lcont: diff --git a/libpsn00b/psxetc/isr.s b/libpsn00b/psxetc/isr.s index 00428a4..440be50 100644 --- a/libpsn00b/psxetc/isr.s +++ b/libpsn00b/psxetc/isr.s @@ -20,7 +20,7 @@ _global_isr: # changed elsewhere sometimes lui $a0, IOBASE # Get IRQ status - lw $v0, IMASK($a0) + lw $v0, IRQ_MASK($a0) nop srl $v0, $s1 # Check IRQ mask bit if set @@ -29,7 +29,7 @@ _global_isr: beqz $v0, .Lno_irq # Don't execute callback if IRQ not enabled nop - lw $v0, ISTAT($a0) + lw $v0, IRQ_STAT($a0) nop srl $v0, $s1 # Check IRQ status bit if set andi $v0, 0x1 @@ -39,12 +39,12 @@ _global_isr: lw $v1, 0($s0) # Load IRQ callback function nop - lw $v0, ISTAT($a0) # Acknowledge the IRQ (by writing a 0 bit) + lw $v0, IRQ_STAT($a0) # Acknowledge the IRQ (by writing a 0 bit) li $a1, 1 sll $a1, $s1 addiu $a2, $0 , -1 xor $a1, $a2 - sw $a1, ISTAT($a0) + sw $a1, IRQ_STAT($a0) beqz $v1, .Lno_irq # Don't execute if callback is not set nop diff --git a/libpsn00b/psxetc/restartcallback.s b/libpsn00b/psxetc/restartcallback.s index 151d78e..036a5a0 100644 --- a/libpsn00b/psxetc/restartcallback.s +++ b/libpsn00b/psxetc/restartcallback.s @@ -44,8 +44,8 @@ RestartCallback: addiu $a1, 1 lui $a0, IOBASE - sw $0 , ISTAT($a0) - sw $v0, IMASK($a0) + sw $0 , IRQ_STAT($a0) + sw $v0, IRQ_MASK($a0) lw $ra, 0($sp) addiu $sp, 4 diff --git a/libpsn00b/psxgpu/clearotagr.s b/libpsn00b/psxgpu/clearotagr.s index 3e888f1..832e54c 100644 --- a/libpsn00b/psxgpu/clearotagr.s +++ b/libpsn00b/psxgpu/clearotagr.s @@ -12,10 +12,10 @@ ClearOTagR: addi $v0, $a1, -1 sll $v0, 2 addu $a0, $v0 - sw $a0, D6_MADR($a2) + sw $a0, DMA6_MADR($a2) andi $a1, 0xffff - sw $a1, D6_BCR($a2) + sw $a1, DMA6_BCR($a2) lui $v0, 0x1100 addiu $v0, 2 jr $ra - sw $v0, D6_CHCR($a2) + sw $v0, DMA6_CHCR($a2) diff --git a/libpsn00b/psxgpu/drawotag.s b/libpsn00b/psxgpu/drawotag.s index ba771fc..595fcd5 100644 --- a/libpsn00b/psxgpu/drawotag.s +++ b/libpsn00b/psxgpu/drawotag.s @@ -25,12 +25,12 @@ DrawOTag: beqz $v0, .Lgpu_wait nop - sw $a0, D2_MADR($a3) # Set DMA base address to specified OT - sw $0 , D2_BCR($a3) + sw $a0, DMA2_MADR($a3) # Set DMA base address to specified OT + sw $0 , DMA2_BCR($a3) lui $v0, 0x0100 # Begin OT transfer! ori $v0, 0x0401 - sw $v0, D2_CHCR($a3) + sw $v0, DMA2_CHCR($a3) lw $ra, 0($sp) addiu $sp, 4 diff --git a/libpsn00b/psxgpu/drawsync.s b/libpsn00b/psxgpu/drawsync.s index 2e29381..b671b03 100644 --- a/libpsn00b/psxgpu/drawsync.s +++ b/libpsn00b/psxgpu/drawsync.s @@ -24,7 +24,7 @@ DrawSync: nop .Ldma_wait: - lw $v0, D2_CHCR($a0) + lw $v0, DMA2_CHCR($a0) nop srl $v0, 24 andi $v0, 0x1 @@ -59,7 +59,7 @@ DrawSync: .Lgetwords: - lw $v0, D2_BCR($a0) + lw $v0, DMA2_BCR($a0) nop jr $ra diff --git a/libpsn00b/psxgpu/drawsynccallback.s b/libpsn00b/psxgpu/drawsynccallback.s index 37c0375..2b2c172 100644 --- a/libpsn00b/psxgpu/drawsynccallback.s +++ b/libpsn00b/psxgpu/drawsynccallback.s @@ -64,7 +64,7 @@ _drawsync_handler: addiu $sp, -4 sw $ra, 0($sp) - lw $v0, D2_CHCR($a0) + lw $v0, DMA2_CHCR($a0) nop srl $v0, 24 andi $v0, 0x1 diff --git a/libpsn00b/psxgpu/loadimage.s b/libpsn00b/psxgpu/loadimage.s index 4a3b4e0..e2a5be5 100644 --- a/libpsn00b/psxgpu/loadimage.s +++ b/libpsn00b/psxgpu/loadimage.s @@ -56,12 +56,12 @@ LoadImage: sll $v1, 0x10 ori $v1, 0x8 - sw $a1, D2_MADR($s0) # Set DMA base address and transfer length - sw $v1, D2_BCR($s0) + sw $a1, DMA2_MADR($s0) # Set DMA base address and transfer length + sw $v1, DMA2_BCR($s0) lui $v0, 0x100 # Start DMA transfer ori $v0, 0x201 - sw $v0, D2_CHCR($s0) + sw $v0, DMA2_CHCR($s0) lw $ra, 0($sp) lw $s0, 4($sp) diff --git a/libpsn00b/psxgpu/resetgraph.s b/libpsn00b/psxgpu/resetgraph.s index f469fbe..eae854c 100644 --- a/libpsn00b/psxgpu/resetgraph.s +++ b/libpsn00b/psxgpu/resetgraph.s @@ -42,10 +42,10 @@ ResetGraph: lui $v0, 0x3b33 # Enables DMA channel 6 (for ClearOTag) ori $v0, 0x3b33 # Enables DMA channel 2 - sw $v0, DPCR($a3) - sw $0 , DICR($a3) # Clear DICR (not needed) + sw $v0, DMA_DPCR($a3) + sw $0 , DMA_DICR($a3) # Clear DICR (not needed) - sw $0 , IMASK($a3) # Clear IRQ settings + sw $0 , IRQ_MASK($a3) # Clear IRQ settings la $v0, _hooks_installed # Set installed flag li $v1, 0x1 @@ -102,7 +102,7 @@ ResetGraph: # by previous calls) li $v0, 0x1d00 # Configure timer 1 as Hblank counter - sw $v0, T1_MODE($a3) # Set timer 1 value + sw $v0, TIM1_CTRL($a3) # Set timer 1 value beq $a0, 1, .Lgpu_init_1 nop @@ -116,7 +116,7 @@ ResetGraph: .Lgpu_init_1: - sw $0 , D2_CHCR($a3) # Stop any DMA + sw $0 , DMA2_CHCR($a3) # Stop any DMA .Lgpu_init_3: @@ -143,9 +143,9 @@ VSync: lw $s0, GP1($a3) .Lhwait_loop: # Get Hblank time - lw $v0, T1_CNT($a3) + lw $v0, TIM1_VALUE($a3) nop - lw $v1, T1_CNT($a3) + lw $v1, TIM1_VALUE($a3) nop bne $v0, $v1, .Lhwait_loop nop @@ -208,9 +208,9 @@ VSync: la $a2, _vsync_lasthblank .Lhwait2_loop: - lw $v0, T1_CNT($a3) + lw $v0, TIM1_VALUE($a3) nop - lw $v1, T1_CNT($a3) + lw $v1, TIM1_VALUE($a3) sw $v0, 0($a2) bne $v0, $v1, .Lhwait2_loop nop diff --git a/libpsn00b/psxgpu/storeimage.s b/libpsn00b/psxgpu/storeimage.s index 5d4c793..933b14c 100644 --- a/libpsn00b/psxgpu/storeimage.s +++ b/libpsn00b/psxgpu/storeimage.s @@ -54,8 +54,8 @@ StoreImage: sll $v1, 0x10 ori $v1, 0x8 - sw $a1, D2_MADR($s0) # Set DMA base address and transfer length - sw $v1, D2_BCR($s0) + sw $a1, DMA2_MADR($s0) # Set DMA base address and transfer length + sw $v1, DMA2_BCR($s0) .Lgpu_wait_2: # Wait for GPU to be ready for commands and DMA jal ReadGPUstat @@ -67,7 +67,7 @@ StoreImage: lui $v0, 0x100 # Start DMA transfer ori $v0, 0x200 - sw $v0, D2_CHCR($s0) + sw $v0, DMA2_CHCR($s0) lw $ra, 0($sp) lw $s0, 4($sp) diff --git a/libpsn00b/psxspu/spuinit.s b/libpsn00b/psxspu/spuinit.s index 42f302a..6966213 100644 --- a/libpsn00b/psxspu/spuinit.s +++ b/libpsn00b/psxspu/spuinit.s @@ -17,30 +17,25 @@ SpuInit: # Stop and mute everything - sh $0 , SPUCNT($v1) # Clear control settings + sh $0 , SPU_CTRL($v1) # Clear control settings jal SpuCtrlSync move $a0, $0 - sh $0 , SPU_MASTER_VOL($v1) # Clear master volume - sh $0 , SPU_MASTER_VOL+2($v1) + sh $0 , SPU_MASTER_VOL_L($v1) # Clear master volume + sh $0 , SPU_MASTER_VOL_R($v1) - sh $0 , SPU_REVERB_VOL($v1) # Clear reverb volume - sh $0 , SPU_REVERB_VOL+2($v1) + sh $0 , SPU_REVERB_VOL_L($v1) # Clear reverb volume + sh $0 , SPU_REVERB_VOL_R($v1) - sh $0 , SPU_CD_VOL($v1) # Clear CD volume - sh $0 , SPU_CD_VOL+2($v1) + sh $0 , SPU_CD_VOL_L($v1) # Clear CD volume + sh $0 , SPU_CD_VOL_R($v1) - sh $0 , SPU_EXT_VOL($v1) # Clear external audio volume - sh $0 , SPU_EXT_VOL+2($v1) + sh $0 , SPU_EXT_VOL_L($v1) # Clear external audio volume + sh $0 , SPU_EXT_VOL_R($v1) - sh $0 , SPU_FM_MODE($v1) # Turn off FM modes - sh $0 , SPU_FM_MODE+2($v1) - - sh $0 , SPU_NOISE_MODE($v1) # Turn off noise modes - sh $0 , SPU_NOISE_MODE+2($v1) - - sh $0 , SPU_REVERB_ON($v1) # Turn off reverb modes - sh $0 , SPU_REVERB_ON+2($v1) + sw $0 , SPU_FM_MODE($v1) # Turn off FM modes + sw $0 , SPU_NOISE_MODE($v1) # Turn off noise modes + sw $0 , SPU_REVERB_ON($v1) # Turn off reverb modes li $v0, 0xfffe sh $v0, SPU_REVERB_ADDR($v1) @@ -65,32 +60,28 @@ SpuInit: bgez $a2, .Lclear_voices nop - li $v0, 0xffff # Set all keys to off - sh $v0, SPU_KEY_OFF($v1) - sh $v0, SPU_KEY_OFF+2($v1) + addiu $v0, $0, -1 # Set all keys to off + sw $v0, SPU_KEY_OFF($v1) li $v0, 0x4 # Set SPU data transfer control - sh $v0, SPUDTCNT($v1) # (usually always 0x4) + sh $v0, SPU_DMA_CTRL($v1) # (usually always 0x4) - lw $v0, DPCR($v1) # Enable DMA channel 4 (SPU DMA) + lw $v0, DMA_DPCR($v1) # Enable DMA channel 4 (SPU DMA) lui $at, 0xb or $v0, $at - sw $v0, DPCR($v1) + sw $v0, DMA_DPCR($v1) li $v0, 0xC001 # Enable SPU - sh $v0, SPUCNT($v1) + sh $v0, SPU_CTRL($v1) jal SpuCtrlSync move $a0, $v0 li $v0, 0x3fff # Activate master volume - sh $v0, SPU_MASTER_VOL($v1) - sh $v0, SPU_MASTER_VOL+2($v1) - - sh $v0, SPU_CD_VOL($v1) # Activate CD volume - sh $v0, SPU_CD_VOL+2($v1) + sh $v0, SPU_MASTER_VOL_L($v1) + sh $v0, SPU_MASTER_VOL_R($v1) - sh $v0, SPU_CD_VOL($v1) # Activate CD volume - sh $v0, SPU_CD_VOL+2($v1) + sh $v0, SPU_CD_VOL_L($v1) # Activate CD volume + sh $v0, SPU_CD_VOL_R($v1) lw $ra, 0($sp) addiu $sp, 4 @@ -108,7 +99,7 @@ SpuCtrlSync: lui $v1, IOBASE andi $a0, 0x3f .Lctrl_wait: - lhu $v0, SPUSTAT($v1) # Get SPUSTAT value + lhu $v0, SPU_STAT($v1) # Get SPUSTAT value nop andi $v0, 0x3f bne $v0, $a0, .Lctrl_wait # Wait until SPUCNT and SPUSTAT are equal @@ -123,7 +114,7 @@ SpuCtrlSync: .type SpuWait, @function SpuWait: lui $v0, IOBASE - lhu $v0, SPUSTAT($v0) + lhu $v0, SPU_STAT($v0) nop andi $v0, 0x400 bnez $v0, SpuWait diff --git a/libpsn00b/psxspu/spureverbon.s b/libpsn00b/psxspu/spureverbon.s index 852bff3..635fac3 100644 --- a/libpsn00b/psxspu/spureverbon.s +++ b/libpsn00b/psxspu/spureverbon.s @@ -11,6 +11,6 @@ SpuReverbOn: lui $v1, IOBASE li $v0, 1 sll $v0, $a0 - sh $v0, SPU_REVERB_ON($v1) + sw $v0, SPU_REVERB_ON($v1) jr $ra nop \ No newline at end of file diff --git a/libpsn00b/psxspu/spusetreverb.s b/libpsn00b/psxspu/spusetreverb.s index 993b166..8257812 100644 --- a/libpsn00b/psxspu/spusetreverb.s +++ b/libpsn00b/psxspu/spusetreverb.s @@ -10,11 +10,12 @@ SpuSetReverb: addiu $sp, -4 sw $ra, 0($sp) - - lhu $v0, SPUCNT($v1) + + lui $v1, IOBASE + lhu $v0, SPU_CTRL($v1) nop ori $v0, 0x80 # Enable reverb - sh $v0, SPUCNT($v1) + sh $v0, SPU_CTRL($v1) jal SpuCtrlSync move $a0, $v0 diff --git a/libpsn00b/psxspu/spusetreverbaddr.s b/libpsn00b/psxspu/spusetreverbaddr.s index 6ddbf44..089a91a 100644 --- a/libpsn00b/psxspu/spusetreverbaddr.s +++ b/libpsn00b/psxspu/spusetreverbaddr.s @@ -8,7 +8,7 @@ .global SpuSetReverbAddr .type SpuSetReverbAddr, @function SpuSetReverbAddr: - lui $a3, 0x1f80 + lui $a3, IOBASE srl $a0, 3 sh $a0, SPU_REVERB_ADDR($a3) jr $ra @@ -18,8 +18,8 @@ SpuSetReverbAddr: .global SpuSetReverbVolume .type SpuSetReverbVolume, @function SpuSetReverbVolume: - lui $a3, 0x1f80 - sh $a0, SPU_REVERB_VOL($a3) - sh $a1, SPU_REVERB_VOL+2($a3) + lui $a3, IOBASE + sh $a0, SPU_REVERB_VOL_L($a3) + sh $a1, SPU_REVERB_VOL_R($a3) jr $ra nop \ No newline at end of file diff --git a/libpsn00b/psxspu/transfer.s b/libpsn00b/psxspu/transfer.s index 5b62c28..adcdb33 100644 --- a/libpsn00b/psxspu/transfer.s +++ b/libpsn00b/psxspu/transfer.s @@ -46,10 +46,10 @@ SpuWrite: lui $a3, IOBASE - lhu $v0, SPUCNT($a3) # Set transfer mode to Stop + lhu $v0, SPU_CTRL($a3) # Set transfer mode to Stop nop andi $v0, 0xffcf - sh $v0, SPUCNT($a3) + sh $v0, SPU_CTRL($a3) jal SpuCtrlSync move $a0, $v0 @@ -58,10 +58,10 @@ SpuWrite: nop sh $v1, SPU_ADDR($a3) - lhu $v0, SPUCNT($a3) # Set transfer mode to DMA write + lhu $v0, SPU_CTRL($a3) # Set transfer mode to DMA write nop ori $v0, 0x20 - sh $v0, SPUCNT($a3) + sh $v0, SPU_CTRL($a3) #jal SpuCtrlSync # Locks up on most emulators (bit 5 in #move $a0, $v0 # SPUSTAT likely not updating, seems to # be okay to not wait for it on real HW) @@ -69,13 +69,13 @@ SpuWrite: lw $a0, 4($sp) .Ldma_wait: # Wait for SPU to be ready for DMA - lhu $v0, SPUSTAT($a3) + lhu $v0, SPU_STAT($a3) nop andi $v0, 0x400 # Bit 8 in SPUSTAT never changes to 1 on bnez $v0, .Ldma_wait # emulators so use bit 10 instead nop - sw $a0, D4_MADR($a3) # Set DMA source address + sw $a0, DMA4_MADR($a3) # Set DMA source address li $v0, 0x10 # 16 words per block (64 bytes) addiu $a1, 63 # Add by 63 to ensure all bytes get sent @@ -83,11 +83,11 @@ SpuWrite: andi $a1, 0xffff sll $a1, 16 or $v0, $a1 - sw $v0, D4_BCR($a3) + sw $v0, DMA4_BCR($a3) lui $v0, 0x0100 # Commence transfer ori $v0, 0x0201 - sw $v0, D4_CHCR($a3) + sw $v0, DMA4_CHCR($a3) lw $ra, 0($sp) addiu $sp, 8 -- cgit v1.2.3 From 72db767f5a5bdb958bb11bcb6fe6b9b332a2b195 Mon Sep 17 00:00:00 2001 From: spicyjpeg <88942473+spicyjpeg@users.noreply.github.com> Date: Sun, 20 Feb 2022 12:31:31 +0100 Subject: Rewrite assert() and DL_CALL(), update mkpsxiso --- examples/system/dynlink/main.c | 19 ++++++++++++------- libpsn00b/include/assert.h | 22 ++++++++++++++++++---- libpsn00b/include/dlfcn.h | 7 +++---- libpsn00b/libc/abort.c | 14 ++++++++++---- libpsn00b/libc/c++-support.cxx | 22 +++++++++++----------- libpsn00b/psxetc/dl.c | 6 ++++-- tools/mkpsxiso | 2 +- 7 files changed, 59 insertions(+), 33 deletions(-) (limited to 'libpsn00b/include') diff --git a/examples/system/dynlink/main.c b/examples/system/dynlink/main.c index 690371e..9b94b30 100644 --- a/examples/system/dynlink/main.c +++ b/examples/system/dynlink/main.c @@ -57,7 +57,7 @@ // call them. Placing this array in the .dummy section (as defined in the // PSn00bSDK linker script) ensures it won't be stripped away until all // functions are in place. -const void *const DO_NOT_STRIP[] __attribute__((section(".dummy"))) = { +void *DO_NOT_STRIP[] __attribute__((section(".dummy"))) = { &rand, &InitGeom, &RotMatrix, @@ -244,14 +244,18 @@ void load_dll(const char *filename) { printf("DLL init() @ %08x, render() @ %08x\n", dll_api.init, dll_api.render); // Unfortunately, due to how position-independent code works, function - // pointers returned by DL_GetDLLSymbol() can't be called directly. We have - // to use the DL_CALL() macro instead, which sets up register $t9 to ensure - // the function can locate and reference the DLL's relocation table. - DL_CALL(dll_api.init, &ctx); - + // pointers returned by DL_GetDLLSymbol() can't be called without first + // initializing register $t9. We have to use the DL_PRE_CALL() macro, which + // sets up $t9 to ensure the function can locate and reference the DLL's + // relocation table. + DL_PRE_CALL(dll_api.init); + dll_api.init(&ctx); } int main(int argc, const char* argv[]) { + // Reference the dummy array to prevent it from being stripped. + void **dummy = DO_NOT_STRIP; + init_context(&ctx); SHOW_STATUS("INITIALIZING CD\n"); @@ -289,7 +293,8 @@ int main(int argc, const char* argv[]) { while (1) { // Use the currently loaded DLL to render a frame. - DL_CALL(dll_api.render, &ctx, last_buttons); + DL_PRE_CALL(dll_api.render); + dll_api.render(&ctx, last_buttons); FntPrint(-1, "MAIN: DLL ADDR=%08x SIZE=%d\n", dll->ptr, dll->size); FntPrint(-1, "MAIN: %d FUNCTIONS RESOLVED\n", resolve_counter); diff --git a/libpsn00b/include/assert.h b/libpsn00b/include/assert.h index 3114b57..e27f2ed 100644 --- a/libpsn00b/include/assert.h +++ b/libpsn00b/include/assert.h @@ -1,6 +1,20 @@ -#ifndef _ASSERT_H -#define _ASSERT_H +/* + * PSn00bSDK assert macro + * (C) 2022 spicyjpeg - MPL licensed + */ -void assert(int e); +#ifndef __ASSERT_H +#define __ASSERT_H -#endif \ No newline at end of file +void _assert_abort(const char *file, int line, const char *expr); + +#ifdef DEBUG +#define assert(expr) { \ + if (!(expr)) \ + _assert_abort(__FILE__, __LINE__, #expr); \ +} +#else +#define assert(x) +#endif + +#endif diff --git a/libpsn00b/include/dlfcn.h b/libpsn00b/include/dlfcn.h index 6874d06..5848a95 100644 --- a/libpsn00b/include/dlfcn.h +++ b/libpsn00b/include/dlfcn.h @@ -1,19 +1,18 @@ /* * PSn00bSDK dynamic linker - * (C) 2021 spicyjpeg - MPL licensed + * (C) 2021-2022 spicyjpeg - MPL licensed */ #ifndef __DLFCN_H #define __DLFCN_H -#include +#include #include /* Helper macro for setting $t9 before calling a function */ -#define DL_CALL(func, ...) { \ +#define DL_PRE_CALL(func) { \ __asm__ volatile("move $t9, %0;" :: "r"(func) : "$t9"); \ - func(__VA_ARGS__); \ } /* Types */ diff --git a/libpsn00b/libc/abort.c b/libpsn00b/libc/abort.c index ca5ab1d..1d07037 100644 --- a/libpsn00b/libc/abort.c +++ b/libpsn00b/libc/abort.c @@ -1,9 +1,15 @@ #include void abort() { - printf("abort()\n"); - - while(1); -} \ No newline at end of file + for (;;) + __asm__ volatile(""); +} + +void _assert_abort(const char *file, int line, const char *expr) { + printf("%s:%d: assert(%s)\n", file, line, expr); + + for (;;) + __asm__ volatile(""); +} diff --git a/libpsn00b/libc/c++-support.cxx b/libpsn00b/libc/c++-support.cxx index d169fdb..d0c0f3a 100644 --- a/libpsn00b/libc/c++-support.cxx +++ b/libpsn00b/libc/c++-support.cxx @@ -1,28 +1,28 @@ -#include #include #include +#include -extern "C" +extern "C" void __cxa_pure_virtual(void) { + printf("__cxa_pure_virtual()\n"); -void __cxa_pure_virtual(void) { - /* Pure C++ virtual call; abort! */ - assert(false); + for (;;) + __asm__ volatile(""); } void* operator new(size_t size) { - return malloc(size); + return malloc(size); } void* operator new[](size_t size) { - return malloc(size); + return malloc(size); } void operator delete(void* ptr) { - free(ptr); + free(ptr); } void operator delete[](void* ptr) { - free(ptr); + free(ptr); } /*- @@ -35,5 +35,5 @@ void operator delete[](void* ptr) { * * A memory allocator can use the given size to be more efficient */ void operator delete(void* ptr, unsigned int) { - free(ptr); -} \ No newline at end of file + free(ptr); +} diff --git a/libpsn00b/psxetc/dl.c b/libpsn00b/psxetc/dl.c index cbdcb66..6d37605 100644 --- a/libpsn00b/psxetc/dl.c +++ b/libpsn00b/psxetc/dl.c @@ -587,7 +587,8 @@ DLL *DL_CreateDLL(void *ptr, size_t size, DL_ResolveMode mode) { if (ctor_list) { for (uint32_t i = ((uint32_t) ctor_list[0]); i >= 1; i--) { void (*ctor)(void) = (void (*)(void)) ctor_list[i]; - DL_CALL(ctor); + DL_PRE_CALL(ctor); + ctor(); } } @@ -619,7 +620,8 @@ void DL_DestroyDLL(DLL *dll) { if (dtor_list) { for (uint32_t i = 0; i < ((uint32_t) dtor_list[0]); i++) { void (*dtor)(void) = (void (*)(void)) dtor_list[i + 1]; - DL_CALL(dtor); + DL_PRE_CALL(dtor); + dtor(); } } } diff --git a/tools/mkpsxiso b/tools/mkpsxiso index 75b3da9..f07f5e6 160000 --- a/tools/mkpsxiso +++ b/tools/mkpsxiso @@ -1 +1 @@ -Subproject commit 75b3da9701dc57e0f23a8c7414237198285ef6c3 +Subproject commit f07f5e6002beccfa95e88a841a16b8ace456c613 -- cgit v1.2.3 From 69a364049a3958396d2d083c660591dad9ec257d Mon Sep 17 00:00:00 2001 From: spicyjpeg <88942473+spicyjpeg@users.noreply.github.com> Date: Sun, 27 Feb 2022 19:45:38 +0100 Subject: Rename some hwregs_c.h and hwregs.a definitions --- examples/graphics/rgb24/bunpattern.png | Bin 0 -> 59932 bytes examples/io/pads/spi.c | 6 +++--- examples/system/timer/main.c | 5 +++-- libpsn00b/include/hwregs_a.h | 22 +++++++++++----------- libpsn00b/include/hwregs_c.h | 10 +++++----- libpsn00b/psxgpu/clearotagr.s | 2 +- libpsn00b/psxgpu/drawotag.s | 4 ++-- libpsn00b/psxgpu/drawprim.s | 4 ++-- libpsn00b/psxgpu/drawsynccallback.s | 2 +- libpsn00b/psxgpu/loadimage.s | 14 +++++++------- libpsn00b/psxgpu/putdispenv.s | 8 ++++---- libpsn00b/psxgpu/putdispenvraw.s | 10 +++++----- libpsn00b/psxgpu/readgpustat.s | 4 ++-- libpsn00b/psxgpu/resetgraph.s | 28 ++++++++++++++-------------- libpsn00b/psxgpu/setdispmask.s | 4 ++-- libpsn00b/psxgpu/setvideomode.s | 2 +- libpsn00b/psxgpu/storeimage.s | 14 +++++++------- 17 files changed, 70 insertions(+), 69 deletions(-) create mode 100644 examples/graphics/rgb24/bunpattern.png (limited to 'libpsn00b/include') diff --git a/examples/graphics/rgb24/bunpattern.png b/examples/graphics/rgb24/bunpattern.png new file mode 100644 index 0000000..61524f8 Binary files /dev/null and b/examples/graphics/rgb24/bunpattern.png differ diff --git a/examples/io/pads/spi.c b/examples/io/pads/spi.c index 05a0e59..43b5bc3 100644 --- a/examples/io/pads/spi.c +++ b/examples/io/pads/spi.c @@ -179,12 +179,12 @@ SPI_Request *SPI_CreateRequest(void) { } void SPI_SetPollRate(uint32_t value) { - TIM_CTRL(2) = 0x0258; // CLK/8 input, IRQ on reload, disable one-shot IRQ + TIMER_CTRL(2) = 0x0258; // CLK/8 input, IRQ on reload, disable one-shot IRQ if (value < 65) - TIM_RELOAD(2) = 0xffff; + TIMER_RELOAD(2) = 0xffff; else - TIM_RELOAD(2) = (F_CPU / 8) / value; + TIMER_RELOAD(2) = (F_CPU / 8) / value; } void SPI_Init(SPI_Callback callback) { diff --git a/examples/system/timer/main.c b/examples/system/timer/main.c index 8153581..eb62712 100644 --- a/examples/system/timer/main.c +++ b/examples/system/timer/main.c @@ -3,6 +3,7 @@ #include #include #include +#include /* OT and Packet Buffer sizes */ #define OT_LEN 256 @@ -34,7 +35,7 @@ void display(); volatile int timer_calls = 0; -volatile short *timer2_ctrl = (short*)0x1F801124; + void timer_func() { timer_calls++; @@ -74,7 +75,7 @@ int main() { //counter = 5163000/560; SetRCnt(RCntCNT2, counter, RCntMdINTR); - *timer2_ctrl = 0x1E58; + TIMER_CTRL(2) = 0x1E58; InterruptCallback(6, timer_func); StartRCnt(RCntCNT2); ChangeClearRCnt(2, 0); diff --git a/libpsn00b/include/hwregs_a.h b/libpsn00b/include/hwregs_a.h index 4d0bade..8a504f5 100644 --- a/libpsn00b/include/hwregs_a.h +++ b/libpsn00b/include/hwregs_a.h @@ -8,8 +8,8 @@ ## GPU -.set GP0, 0x1810 # Also GPUREAD -.set GP1, 0x1814 # Also GPUSTAT +.set GPU_GP0, 0x1810 # Also GPUREAD +.set GPU_GP1, 0x1814 # Also GPUSTAT ## CD drive @@ -123,17 +123,17 @@ ## Timers -.set TIM0_VALUE, 0x1100 -.set TIM0_CTRL, 0x1104 -.set TIM0_RELOAD, 0x1108 +.set TIMER0_VALUE, 0x1100 +.set TIMER0_CTRL, 0x1104 +.set TIMER0_RELOAD, 0x1108 -.set TIM1_VALUE, 0x1110 -.set TIM1_CTRL, 0x1114 -.set TIM1_RELOAD, 0x1118 +.set TIMER1_VALUE, 0x1110 +.set TIMER1_CTRL, 0x1114 +.set TIMER1_RELOAD, 0x1118 -.set TIM2_VALUE, 0x1120 -.set TIM2_CTRL, 0x1124 -.set TIM2_RELOAD, 0x1128 +.set TIMER2_VALUE, 0x1120 +.set TIMER2_CTRL, 0x1124 +.set TIMER2_RELOAD, 0x1128 ## Memory control diff --git a/libpsn00b/include/hwregs_c.h b/libpsn00b/include/hwregs_c.h index 4222a22..e533c56 100644 --- a/libpsn00b/include/hwregs_c.h +++ b/libpsn00b/include/hwregs_c.h @@ -19,8 +19,8 @@ /* GPU */ -#define GP0 _MMIO32(0x1f801810) -#define GP1 _MMIO32(0x1f801814) +#define GPU_GP0 _MMIO32(0x1f801810) +#define GPU_GP1 _MMIO32(0x1f801814) /* CD drive */ @@ -109,9 +109,9 @@ /* Timers */ -#define TIM_VALUE(N) _MMIO32(0x1f801100 + 16 * (N)) -#define TIM_CTRL(N) _MMIO32(0x1f801104 + 16 * (N)) -#define TIM_RELOAD(N) _MMIO32(0x1f801108 + 16 * (N)) +#define TIMER_VALUE(N) _MMIO32(0x1f801100 + 16 * (N)) +#define TIMER_CTRL(N) _MMIO32(0x1f801104 + 16 * (N)) +#define TIMER_RELOAD(N) _MMIO32(0x1f801108 + 16 * (N)) /* Memory control */ diff --git a/libpsn00b/psxgpu/clearotagr.s b/libpsn00b/psxgpu/clearotagr.s index 832e54c..562cad4 100644 --- a/libpsn00b/psxgpu/clearotagr.s +++ b/libpsn00b/psxgpu/clearotagr.s @@ -8,7 +8,7 @@ .global ClearOTagR .type ClearOTagR, @function ClearOTagR: - lui $a2, 0x1f80 + lui $a2, IOBASE addi $v0, $a1, -1 sll $v0, 2 addu $a0, $v0 diff --git a/libpsn00b/psxgpu/drawotag.s b/libpsn00b/psxgpu/drawotag.s index 595fcd5..3cb0db0 100644 --- a/libpsn00b/psxgpu/drawotag.s +++ b/libpsn00b/psxgpu/drawotag.s @@ -11,11 +11,11 @@ DrawOTag: addiu $sp, -4 sw $ra, 0($sp) - lui $a3, 0x1f80 # I/O segment base + lui $a3, IOBASE # I/O segment base lui $v0, 0x0400 # Set DMA direction to CPUtoGPU ori $v0, 0x2 - sw $v0, GP1($a3) + sw $v0, GPU_GP1($a3) .Lgpu_wait: # Wait for GPU to be ready for commands & DMA jal ReadGPUstat diff --git a/libpsn00b/psxgpu/drawprim.s b/libpsn00b/psxgpu/drawprim.s index de5afbd..d62c202 100644 --- a/libpsn00b/psxgpu/drawprim.s +++ b/libpsn00b/psxgpu/drawprim.s @@ -18,7 +18,7 @@ DrawPrim: lui $a3, IOBASE lui $v0, 0x0400 # Set transfer direction to off - sw $v0, GP1($a3) + sw $v0, GPU_GP1($a3) move $a0, $s0 lbu $a1, 3($a0) # Get length of primitive packet @@ -28,7 +28,7 @@ DrawPrim: .Ltransfer_loop: lw $v0, 0($a0) addiu $a0, 4 - sw $v0, GP0($a3) + sw $v0, GPU_GP0($a3) bgtz $a1, .Ltransfer_loop addiu $a1, -1 diff --git a/libpsn00b/psxgpu/drawsynccallback.s b/libpsn00b/psxgpu/drawsynccallback.s index 2b2c172..22cfb7d 100644 --- a/libpsn00b/psxgpu/drawsynccallback.s +++ b/libpsn00b/psxgpu/drawsynccallback.s @@ -84,7 +84,7 @@ _drawsync_handler: lw $v1, 0($v1) lui $v0, 0x0400 # Set DMA direction to off - sw $v0, GP1($a0) + sw $v0, GPU_GP1($a0) jalr $v1 nop diff --git a/libpsn00b/psxgpu/loadimage.s b/libpsn00b/psxgpu/loadimage.s index e2a5be5..45f152f 100644 --- a/libpsn00b/psxgpu/loadimage.s +++ b/libpsn00b/psxgpu/loadimage.s @@ -17,7 +17,7 @@ LoadImage: sw $ra, 0($sp) sw $s0, 4($sp) - lui $s0, 0x1f80 # Set I/O segment base address + lui $s0, IOBASE # Set I/O segment base address .Lgpu_wait: # Wait for GPU to be ready for commands and DMA jal ReadGPUstat @@ -31,21 +31,21 @@ LoadImage: nop lui $v0, 0x400 # Set DMA direction to off - sw $v0, GP1($s0) + sw $v0, GPU_GP1($s0) lui $v0, 0x0100 # Clear GPU cache - sw $v0, GP0($s0) + sw $v0, GPU_GP0($s0) lui $v1, 0xa000 # Load image to VRAM - sw $v1, GP0($s0) + sw $v1, GPU_GP0($s0) lw $v0, RECT_x($a0) # Set XY and dimensions of image lw $v1, RECT_w($a0) - sw $v0, GP0($s0) - sw $v1, GP0($s0) + sw $v0, GPU_GP0($s0) + sw $v1, GPU_GP0($s0) lui $v0, 0x400 # Set DMA direction to CPUtoVRAM ori $v0, 0x2 - sw $v0, GP1($s0) + sw $v0, GPU_GP1($s0) lhu $v0, RECT_w($a0) # Get rectangle size lhu $v1, RECT_h($a0) diff --git a/libpsn00b/psxgpu/putdispenv.s b/libpsn00b/psxgpu/putdispenv.s index 4baa20e..fc09454 100644 --- a/libpsn00b/psxgpu/putdispenv.s +++ b/libpsn00b/psxgpu/putdispenv.s @@ -102,7 +102,7 @@ PutDispEnv: or $a2, $v0 lui $v0, 0x0600 or $v0, $a2 - sw $v0, GP1($a3) + sw $v0, GPU_GP1($a3) # Vertical resolution @@ -127,7 +127,7 @@ PutDispEnv: or $v1, $a2 lui $v0, 0x0700 or $v1, $v0 - sw $v1, GP1($a3) + sw $v1, GPU_GP1($a3) # Video mode @@ -159,7 +159,7 @@ PutDispEnv: lui $v0, 0x800 # Apply mode or $a1, $v0 - sw $a1, GP1($a3) + sw $a1, GPU_GP1($a3) lhu $v0, DISP_dx($a0) # Set VRAM XY offset lhu $v1, DISP_dy($a0) @@ -171,4 +171,4 @@ PutDispEnv: or $v0, $v1 jr $ra - sw $v0, GP1($a3) + sw $v0, GPU_GP1($a3) diff --git a/libpsn00b/psxgpu/putdispenvraw.s b/libpsn00b/psxgpu/putdispenvraw.s index 157150d..747796f 100644 --- a/libpsn00b/psxgpu/putdispenvraw.s +++ b/libpsn00b/psxgpu/putdispenvraw.s @@ -19,7 +19,7 @@ PutDispEnvRaw: sw $ra, 0($sp) sw $s0, 4($sp) - lui $s0, 0x1f80 + lui $s0, IOBASE lh $at, DISP_vxpos($a0) # Set horizontal display range li $v0, 608 @@ -30,7 +30,7 @@ PutDispEnvRaw: or $v0, $v1 lui $v1, 0x600 or $v1, $v0 - sw $v1, GP1($s0) + sw $v1, GPU_GP1($s0) lh $at, DISP_vypos($a0) # Set vertical display range (for NTSC) li $v1, 120 # (values differet for PAL modes) @@ -47,12 +47,12 @@ PutDispEnvRaw: or $v0, $at lui $at, 0x700 or $v0, $at - sw $v0, GP1($s0) + sw $v0, GPU_GP1($s0) lw $v0, DISP_mode($a0) # Set video mode lui $at, 0x800 or $v0, $at - sw $v0, GP1($s0) + sw $v0, GPU_GP1($s0) lhu $v0, DISP_fbx($a0) # Set VRAM XY offset lhu $v1, DISP_fby($a0) @@ -62,7 +62,7 @@ PutDispEnvRaw: or $v0, $v1 lui $v1, 0x500 or $v0, $v1 - sw $v0, GP1($s0) + sw $v0, GPU_GP1($s0) lw $ra, 0($sp) lw $s0, 4($sp) diff --git a/libpsn00b/psxgpu/readgpustat.s b/libpsn00b/psxgpu/readgpustat.s index c587cfb..ffff4d7 100644 --- a/libpsn00b/psxgpu/readgpustat.s +++ b/libpsn00b/psxgpu/readgpustat.s @@ -8,7 +8,7 @@ .global ReadGPUstat .type ReadGPUstat, @function ReadGPUstat: - lui $v0, 0x1f80 - lw $v0, GP1($v0) + lui $v0, IOBASE + lw $v0, GPU_GP1($v0) jr $ra nop diff --git a/libpsn00b/psxgpu/resetgraph.s b/libpsn00b/psxgpu/resetgraph.s index eae854c..6327f02 100644 --- a/libpsn00b/psxgpu/resetgraph.s +++ b/libpsn00b/psxgpu/resetgraph.s @@ -38,7 +38,7 @@ ResetGraph: nop # interrupts enabled when transferring # execution to the loaded program - lui $a3, 0x1f80 # Base address for I/O + lui $a3, IOBASE # Base address for I/O lui $v0, 0x3b33 # Enables DMA channel 6 (for ClearOTag) ori $v0, 0x3b33 # Enables DMA channel 2 @@ -84,9 +84,9 @@ ResetGraph: .Lskip_hook_init: - lui $a3, 0x1f80 + lui $a3, IOBASE - lw $v0, GP1($a3) # Get video standard + lw $v0, GPU_GP1($a3) # Get video standard lui $v1, 0x0010 and $v0, $v1 la $v1, _gpu_standard @@ -98,18 +98,18 @@ ResetGraph: lw $a0, 4($sp) # Get argument value - lui $a3, 0x1f80 # Set base I/O again (likely destroyed + lui $a3, IOBASE # Set base I/O again (likely destroyed # by previous calls) li $v0, 0x1d00 # Configure timer 1 as Hblank counter - sw $v0, TIM1_CTRL($a3) # Set timer 1 value + sw $v0, TIMER1_CTRL($a3) # Set timer 1 value beq $a0, 1, .Lgpu_init_1 nop beq $a0, 3, .Lgpu_init_3 nop - sw $0 , GP1($a3) # Reset the GPU + sw $0 , GPU_GP1($a3) # Reset the GPU b .Linit_done nop @@ -121,7 +121,7 @@ ResetGraph: .Lgpu_init_3: li $v0, 0x1 # Reset the command buffer - sw $v0, GP1($a3) + sw $v0, GPU_GP1($a3) .Linit_done: @@ -140,12 +140,12 @@ VSync: sw $s0, 4($sp) lui $a3, IOBASE # Get GPU status (for interlace sync) - lw $s0, GP1($a3) + lw $s0, GPU_GP1($a3) .Lhwait_loop: # Get Hblank time - lw $v0, TIM1_VALUE($a3) + lw $v0, TIMER1_VALUE($a3) nop - lw $v1, TIM1_VALUE($a3) + lw $v1, TIMER1_VALUE($a3) nop bne $v0, $v1, .Lhwait_loop nop @@ -189,14 +189,14 @@ VSync: lui $a3, IOBASE # Interlace wait logic - lw $v0, GP1($a3) + lw $v0, GPU_GP1($a3) nop xor $v0, $s0, $v0 bltz $v0, .Lhblank_exit lui $a0, 0x8000 .Linterlace_wait: - lw $v0, GP1($a3) + lw $v0, GPU_GP1($a3) nop xor $v0, $s0, $v0 and $v0, $a0 @@ -208,9 +208,9 @@ VSync: la $a2, _vsync_lasthblank .Lhwait2_loop: - lw $v0, TIM1_VALUE($a3) + lw $v0, TIMER1_VALUE($a3) nop - lw $v1, TIM1_VALUE($a3) + lw $v1, TIMER1_VALUE($a3) sw $v0, 0($a2) bne $v0, $v1, .Lhwait2_loop nop diff --git a/libpsn00b/psxgpu/setdispmask.s b/libpsn00b/psxgpu/setdispmask.s index 77ceb04..d79006c 100644 --- a/libpsn00b/psxgpu/setdispmask.s +++ b/libpsn00b/psxgpu/setdispmask.s @@ -8,12 +8,12 @@ .global SetDispMask .type SetDispMask, @function SetDispMask: - lui $v1, 0x1f80 + lui $v1, IOBASE andi $a0, 0x1 lui $v0, 0x300 ori $v0, 0x1 sub $v0, $a0 - sw $v0, GP1($v1) + sw $v0, GPU_GP1($v1) jr $ra nop diff --git a/libpsn00b/psxgpu/setvideomode.s b/libpsn00b/psxgpu/setvideomode.s index 4395f0a..b89b285 100644 --- a/libpsn00b/psxgpu/setvideomode.s +++ b/libpsn00b/psxgpu/setvideomode.s @@ -41,7 +41,7 @@ SetVideoMode: lui $v0, 0x800 # Apply new mode or $a1, $v0 lui $v0, IOBASE - sw $a1, GP1($v0) + sw $a1, GPU_GP1($v0) lw $ra, 0($sp) addiu $sp, 4 diff --git a/libpsn00b/psxgpu/storeimage.s b/libpsn00b/psxgpu/storeimage.s index 933b14c..554e83c 100644 --- a/libpsn00b/psxgpu/storeimage.s +++ b/libpsn00b/psxgpu/storeimage.s @@ -17,7 +17,7 @@ StoreImage: sw $ra, 0($sp) sw $s0, 4($sp) - lui $s0, 0x1f80 # Set I/O segment base address + lui $s0, IOBASE # Set I/O segment base address .Lgpu_wait: # Wait for GPU to be ready for commands and DMA jal ReadGPUstat @@ -29,21 +29,21 @@ StoreImage: nop lui $v0, 0x400 # Set DMA direction to off - sw $v0, GP1($s0) + sw $v0, GPU_GP1($s0) lui $v0, 0x0100 # Clear GPU cache - sw $v0, GP0($s0) + sw $v0, GPU_GP0($s0) lui $v1, 0xc000 # Store image from VRAM - sw $v1, GP0($s0) + sw $v1, GPU_GP0($s0) lw $v0, RECT_x($a0) # Set XY and dimensions of image lw $v1, RECT_w($a0) - sw $v0, GP0($s0) - sw $v1, GP0($s0) + sw $v0, GPU_GP0($s0) + sw $v1, GPU_GP0($s0) lui $v0, 0x400 # Set DMA direction to VRAMtoCPU ori $v0, 0x3 - sw $v0, GP1($s0) + sw $v0, GPU_GP1($s0) lhu $v0, RECT_w($a0) # Get rectangle size lhu $v1, RECT_h($a0) -- cgit v1.2.3 From c297c02652575e2affccbba16be0176d30d5ff06 Mon Sep 17 00:00:00 2001 From: spicyjpeg <88942473+spicyjpeg@users.noreply.github.com> Date: Sun, 27 Feb 2022 19:47:47 +0100 Subject: Add psxpress MDEC API and psn00bsdk_target_incbin_a --- doc/cmake_reference.md | 36 +++++--- libpsn00b/cmake/internal_setup.cmake | 48 +++++++--- libpsn00b/include/psxpress.h | 152 +++++++++++++++++++++++++++++++ libpsn00b/psxpress/mdec.c | 172 +++++++++++++++++++++++++++++++++++ 4 files changed, 383 insertions(+), 25 deletions(-) create mode 100644 libpsn00b/include/psxpress.h create mode 100644 libpsn00b/psxpress/mdec.c (limited to 'libpsn00b/include') diff --git a/doc/cmake_reference.md b/doc/cmake_reference.md index 60c46c0..25a89ec 100644 --- a/doc/cmake_reference.md +++ b/doc/cmake_reference.md @@ -4,17 +4,17 @@ ## Setup The only requirement to use the SDK in CMake is to set the -`CMAKE_TOOLCHAIN_FILE` variable to `INSTALL_PATH/lib/libpsn00b/cmake/sdk.cmake` -(where `INSTALL_PATH` is the install prefix PSn00bSDK is installed to). This -can be done on the command line (`-DCMAKE_TOOLCHAIN_FILE=...`), in -`CMakeLists.txt` (before calling `project()`) or using a -[preset](https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html). +`CMAKE_TOOLCHAIN_FILE` variable to the absolute path to +`lib/libpsn00b/cmake/sdk.cmake` within the PSn00bSDK installation directory. +This can be done on the command line (`-DCMAKE_TOOLCHAIN_FILE=...`), in +`CMakeLists.txt` (`set(CMAKE_TOOLCHAIN_FILE ...)` before `project()`) or using +[presets](https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html). It's suggested to have a default preset that sets `CMAKE_TOOLCHAIN_FILE` to -`$env{PSN00BSDK_LIBS}/cmake/sdk.cmake`, so the `PSN00BSDK_LIBS` environment -variable (used by former PSn00bSDK versions) is respected. Such a preset can be -created by placing a `CMakePresets.json` file in the project's root with the -following contents: +`$env{PSN00BSDK_LIBS}/cmake/sdk.cmake`, taking advantage of the +`PSN00BSDK_LIBS` environment variable (used by former PSn00bSDK versions) to +automatically find the SDK. Such a preset can be created by placing a +`CMakePresets.json` file in the project's root with the following contents: ```json { @@ -135,9 +135,12 @@ of these names. A new symbol/object will be created with the given name, escaped by replacing non-alphanumeric characters with underscores. The contents of the file will - be aligned to 4 bytes and placed in the `.data` section. Once added the file - and its size can be accessed by C/C++ code by declaring the symbol as an - extern array and `_size` as an integer, like this: + be aligned to 4 bytes and placed in the `.data` section. An unsigned 32-bit + integer named `_size` will also be defined and set to the length + of the file in bytes (without taking alignment/padding into account). + + Once added the file and its size can be accessed by C/C++ code by declaring + the respective symbols as an extern array and as an integer, like this: ```c extern const uint8_t my_file[]; @@ -154,6 +157,13 @@ of these names. must be enabled by specifying `LANGUAGES C ASM` (or `LANGUAGES C CXX ASM` if C++ is also used) when invoking `project()`. +- `psn00bsdk_target_incbin_a( )` + + Advanced variant of `psn00bsdk_target_incbin()` that allows specifying a + custom name for the size symbol and changing the default alignment setting. + Note that the size integer is always aligned to a multiple of 4 bytes as the + MIPS architecture doesn't support unaligned reads. + ## Definitions When compiling executables and libraries using the above commands the following @@ -259,4 +269,4 @@ the build script. LZP archives as part of the build pipeline. ----------------------------------------- -_Last updated on 2021-12-29 by spicyjpeg_ +_Last updated on 2022-02-26 by spicyjpeg_ diff --git a/libpsn00b/cmake/internal_setup.cmake b/libpsn00b/cmake/internal_setup.cmake index 8fb6482..d293127 100644 --- a/libpsn00b/cmake/internal_setup.cmake +++ b/libpsn00b/cmake/internal_setup.cmake @@ -32,7 +32,7 @@ set( psxgte psxspu psxcd - #psxpress + psxpress psxsio psxetc psxapi @@ -186,7 +186,7 @@ function(psn00bsdk_add_cd_image name image_name config_file) add_custom_target( ${name} ALL - COMMAND ${MKPSXISO} -y -q ${CD_CONFIG_FILE} + COMMAND ${MKPSXISO} -y ${CD_CONFIG_FILE} BYPRODUCTS ${image_name}.bin ${image_name}.cue COMMENT "Building CD image ${image_name}" ${ARGN} @@ -195,13 +195,17 @@ endfunction() ## Helper functions for assets -# psn00bsdk_target_incbin( +# psn00bsdk_target_incbin_a( # -# +# +# # +# +# # ) -function(psn00bsdk_target_incbin name type symbol_name path) +function(psn00bsdk_target_incbin_a name type symbol_name size_name path section align) string(MAKE_C_IDENTIFIER ${symbol_name} _id) + string(MAKE_C_IDENTIFIER ${size_name} _size) cmake_path(ABSOLUTE_PATH path OUTPUT_VARIABLE _path) # Generate an assembly source file that includes the binary file and add it @@ -212,26 +216,27 @@ function(psn00bsdk_target_incbin name type symbol_name path) CONFIGURE OUTPUT ${_asm_file} CONTENT [[ -.section .data.${_id} -.balign 4 +.section ${section} +.balign ${align} .global ${_id} .type ${_id}, @object -${_id}: +${_id}: .incbin "${_path}" .local ${_id}_end ${_id}_end: +.balign ${align} .balign 4 -.global ${_id}_size -.type ${_id}_size, @object -${_id}_size: +.global ${_size} +.type ${_size}, @object +${_size}: .int (${_id}_end - ${_id}) .size ${_id}, (${_id}_end - ${_id}) -.size ${_id}_size, 4 +.size ${_size}, 4 ]] ESCAPE_QUOTES NEWLINE_STYLE LF @@ -240,3 +245,22 @@ ${_id}_size: target_sources(${name} ${type} ${_asm_file}) set_source_files_properties(${_asm_file} PROPERTIES OBJECT_DEPENDS ${_path}) endfunction() + +# psn00bsdk_target_incbin( +# +# +# +# ) +function(psn00bsdk_target_incbin name type symbol_name path) + string(MAKE_C_IDENTIFIER ${symbol_name} _id) + + psn00bsdk_target_incbin_a( + ${name} + ${type} + ${_id} + ${_id}_size + ${path} + .data.${_id} + 4 + ) +endfunction() diff --git a/libpsn00b/include/psxpress.h b/libpsn00b/include/psxpress.h new file mode 100644 index 0000000..ad5f6a3 --- /dev/null +++ b/libpsn00b/include/psxpress.h @@ -0,0 +1,152 @@ +/* + * PSn00bSDK MDEC library + * (C) 2022 spicyjpeg - MPL licensed + */ + +#ifndef __PSXPRESS_H +#define __PSXPRESS_H + +#include + +/* Structure definitions */ + +typedef struct _DECDCTENV { + uint8_t iq_y[64]; // Luma quantization table, stored in zigzag order + uint8_t iq_c[64]; // Chroma quantization table, stored in zigzag order + int16_t dct[64]; // Inverse DCT matrix (2.14 fixed-point) +} DECDCTENV; + +typedef enum _DECDCTMODE { + DECDCT_MODE_24BPP = 1, + DECDCT_MODE_16BPP = 0, + DECDCT_MODE_16BPP_BIT15 = 2, + DECDCT_MODE_RAW = -1 +} DECDCTMODE; + +/* Public API */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Resets the MDEC and aborts any MDEC DMA transfers. If mode = 0, the + * default IDCT matrix and quantization tables are also loaded and the MDEC is + * put into color output mode, discarding any custom environment previously set + * with DecDCTPutEnv(). + * + * DecDCTReset(0) must be called at least once prior to using the MDEC. + * + * @param mode + */ +void DecDCTReset(int32_t mode); + +/** + * @brief Uploads the specified decoding environment's quantization tables and + * IDCT matrix to the MDEC, or restores the default tables if a null pointer is + * passed. Calling this function is normally not required as DecDCTReset(0) + * initializes the MDEC with the default tables, but it may be useful for e.g. + * decoding JPEG or a format with custom quantization tables. + * + * The second argument, not present in the official SDK, specifies whether the + * MDEC shall be put into color (0) or monochrome (1) output mode. In + * monochrome mode each DCT block decoded from the input stream is transformed + * into an 8x8x8bpp bitmap, while in color mode each group of 6 DCT blocks (Cr, + * Cb, Y1-4) is used to form a 16x16 RGB bitmap. + * + * This function uses DecDCTinSync() to wait for the MDEC to become ready and + * should not be called during decoding or after calling DecDCTin(). + * + * @param env Pointer to DECDCTENV or 0 for default tables + * @param mono 0 for color (normal), 1 for monochrome + */ +void DecDCTPutEnv(const DECDCTENV *env, int32_t mono); + +/** + * @brief Sets up the MDEC to start fetching and decoding a stream from the + * given address in main RAM. The first 32-bit word is initially copied to the + * MDEC0 register, then all subsequent data is read in 128-byte (32-word) + * chunks. The length of the stream (in 32-bit units, minus the first word) + * must be encoded in the lower 16 bits of the first word, as expected by the + * MDEC. + * + * The mode argument optionally specifies the output color depth (0 for 16bpp, + * 1 for 24bpp) if not already set in the first word. Passing -1 will result in + * DecDCTin() copying the first word as-is to MDEC0 without manipulating any of + * its bits. + * + * @param data + * @param mode DECDCT_MODE_* or -1 + */ +void DecDCTin(const uint32_t *data, int32_t mode); + +/** + * @brief Configures the MDEC to automatically fetch data (the input stream, + * IDCT matrix or quantization tables) in 128-byte (32-word) chunks from the + * specified address in main RAM. The transfer is stopped, and any callback + * registered with DMACallback(0) is fired, once a certain number of 32-bit + * words have been read; usually the length should match the number of input + * words expected by the MDEC. If the MDEC expects more data its operation will + * be paused and can be resumed by calling DecDCTinRaw() again. + * + * This is a low-level variant of DecDCTin() that only sets up the DMA transfer + * and does not write anything to the MDEC0 register. The actual transfer won't + * start until the MDEC is given a valid command. + * + * @param data + * @param length Number of 32-bit words to read (must be multiple of 32) + */ +void DecDCTinRaw(const uint32_t *data, size_t length); + +/** + * @brief Waits for the MDEC to finish decoding the input stream (if mode = 0) + * or returns whether it is busy (if mode = 1). MDEC commands can be issued + * only when the MDEC isn't busy. + * + * WARNING: DecDCTinSync(0) might time out and return -1 if the MDEC can't + * output decoded data, e.g. if the length passed DecDCTout() was too small and + * no callback is registered to set up further transfers. DecDCTinSync(0) shall + * only be used alongside DMACallback(1) or if the entirety of the decoded + * stream (usually a whole frame) is being written to main RAM. + * + * @param mode + * @return 0 or -1 in case of a timeout (mode = 0) / MDEC busy flag (mode = 1) + */ +int32_t DecDCTinSync(int32_t mode); + +/** + * @brief Configures the MDEC to automatically transfer decoded image data in + * 128-byte (32-word) chunks to the specified address in main RAM. MDEC + * operation is paused once a certain number of 32-bit words have been output + * and can be resumed by calling DecDCTout() again: the MDEC will continue + * decoding the input stream from where it left off. Any callback registered + * with DMACallback(1) is also fired whenever the transfer ends. + * + * This behavior allows the MDEC's output to be buffered into 16-pixel-wide + * vertical strips in main RAM, which can then be uploaded to VRAM using + * LoadImage(). + * + * @param data + * @param length Number of 32-bit words to output (must be multiple of 32) + */ +void DecDCTout(uint32_t *data, size_t length); + +/** + * @brief Waits until the transfer set up by DecDCTout() finishes (if mode = 0) + * or returns whether it is still in progress (if mode = 1). + * + * WARNING: DecDCToutSync(0) might time out and return -1 if the MDEC is unable + * to consume enough input data in order to produce the desired amount of data. + * If the input stream isn't contiguous in memory, DMACallback(0) shall be used + * to register a callback that calls DecDCTin() to feed the MDEC. + * + * @param mode + * @return 0 or -1 in case of a timeout (mode = 0) / DMA busy flag (mode = 1) + */ +int32_t DecDCToutSync(int32_t mode); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libpsn00b/psxpress/mdec.c b/libpsn00b/psxpress/mdec.c new file mode 100644 index 0000000..82e2465 --- /dev/null +++ b/libpsn00b/psxpress/mdec.c @@ -0,0 +1,172 @@ +/* + * PSn00bSDK MDEC library (low-level MDEC/DMA API) + * (C) 2022 spicyjpeg - MPL licensed + */ + +#include +#include +#include +#include +#include + +#define MDEC_SYNC_TIMEOUT 0x1000000 + +/* Default IDCT matrix */ + +#define S0 0x5a82 // 0x4000 * cos(0/16 * pi) * sqrt(2) +#define S1 0x7d8a // 0x4000 * cos(1/16 * pi) * 2 +#define S2 0x7641 // 0x4000 * cos(2/16 * pi) * 2 +#define S3 0x6a6d // 0x4000 * cos(3/16 * pi) * 2 +#define S4 0x5a82 // 0x4000 * cos(4/16 * pi) * 2 +#define S5 0x471c // 0x4000 * cos(5/16 * pi) * 2 +#define S6 0x30fb // 0x4000 * cos(6/16 * pi) * 2 +#define S7 0x18f8 // 0x4000 * cos(7/16 * pi) * 2 + +static const int16_t _default_idct_matrix[] = { + S0, S0, S0, S0, S0, S0, S0, S0, + S1, S3, S5, S7, -S7, -S5, -S3, -S1, + S2, S6, -S6, -S2, -S2, -S6, S6, S2, + S3, -S7, -S1, -S5, S5, S1, S7, -S3, + S4, -S4, -S4, S4, S4, -S4, -S4, S4, + S5, -S1, S7, S3, -S3, -S7, S1, -S5, + S6, -S2, S2, -S6, -S6, S2, -S2, S6, + S7, -S5, S3, -S1, S1, -S3, S5, -S7 +}; + +/* Default quantization tables */ + +// The default luma and chroma quantization table is based on the MPEG-1 +// quantization table, with the only difference being the first value (2 +// instead of 8). Note that quantization tables are stored in zigzag order +// rather than row- or column-major. +// https://problemkaputt.de/psx-spx.htm#mdecdecompression +static const uint8_t _default_quant_table[] = { + 2, 16, 16, 19, 16, 19, 22, 22, + 22, 22, 22, 22, 26, 24, 26, 27, + 27, 27, 26, 26, 26, 26, 27, 27, + 27, 29, 29, 29, 34, 34, 34, 29, + 29, 29, 27, 27, 29, 29, 32, 32, + 34, 34, 37, 38, 37, 35, 35, 34, + 35, 38, 38, 40, 40, 40, 48, 48, + 46, 46, 56, 56, 58, 69, 69, 83 +}; +/*static const uint8_t _jpeg_y_quant_table[] = { + 16, 11, 12, 14, 12, 10, 16, 14, + 13, 14, 18, 17, 16, 19, 24, 40, + 26, 24, 22, 22, 24, 49, 35, 37, + 29, 40, 58, 51, 61, 60, 57, 51, + 56, 55, 64, 72, 92, 78, 64, 68, + 87, 69, 55, 56, 80, 109, 81, 87, + 95, 98, 103, 104, 103, 62, 77, 113, + 121, 112, 100, 120, 92, 101, 103, 99 +}; +static const uint8_t _jpeg_c_quant_table[] = { + 17, 18, 18, 24, 21, 24, 47, 26, + 26, 47, 99, 66, 56, 66, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99 +};*/ + +/* Public API */ + +void DecDCTReset(int32_t mode) { + EnterCriticalSection(); + + DMA_DPCR |= 0x000000bb; // Enable DMA0 and DMA1 + DMA_CHCR(0) = 0x00000201; // Stop DMA0 + DMA_CHCR(1) = 0x00000200; // Stop DMA1 + MDEC1 = 0x80000000; // Reset MDEC + MDEC1 = 0x60000000; // Enable DMA in/out requests + + ExitCriticalSection(); + if (!mode) + DecDCTPutEnv(0, 0); +} + +void DecDCTPutEnv(const DECDCTENV *env, int32_t mono) { + const int16_t *dct = env ? env->dct : _default_idct_matrix; + const uint8_t *iq_y = env ? env->iq_y : _default_quant_table; + const uint8_t *iq_c = env ? env->iq_c : _default_quant_table; + + DecDCTinSync(0); + + MDEC0 = 0x60000000; // Set IDCT matrix + DecDCTinRaw((const uint32_t *) dct, 32); + DecDCTinSync(0); + + MDEC0 = 0x40000000 | (mono ? 0 : 1); // Set table(s) + DecDCTinRaw((const uint32_t *) iq_y, 16); + DecDCTinSync(0); + + if (!mono) { + DecDCTinRaw((const uint32_t *) iq_c, 16); + DecDCTinSync(0); + } +} + +void DecDCTin(const uint32_t *data, int32_t mode) { + uint32_t header = *data; + if (mode == DECDCT_MODE_RAW) + MDEC0 = header; + else if (mode & DECDCT_MODE_24BPP) + MDEC0 = header | 0x30000000; + else + MDEC0 = header | 0x38000000 | ((mode & 2) << 24); // Bit 25 = mask + + DecDCTinRaw((const uint32_t *) &(data[1]), header & 0xffff); +} + +// This is a PSn00bSDK-only function that behaves like DecDCTout(), taking the +// data length as an argument rather than parsing it from the first 4 bytes of +// the stream. +void DecDCTinRaw(const uint32_t *data, size_t length) { + DMA_MADR(0) = (uint32_t) data; + if (length < 32) + DMA_BCR(0) = 0x00010000 | length; + else + DMA_BCR(0) = 0x00000020 | ((length / 32) << 16); + + DMA_CHCR(0) = 0x01000201; +} + +int32_t DecDCTinSync(int32_t mode) { + if (mode) + return (MDEC1 >> 29) & 1; + + for (uint32_t i = MDEC_SYNC_TIMEOUT; i; i--) { + if (!(MDEC1 & (1 << 29))) + return 0; + } + + printf("psxpress: DecDCTinSync() timeout\n"); + return -1; +} + +void DecDCTout(uint32_t *data, size_t length) { + DecDCToutSync(0); + + DMA_MADR(1) = (uint32_t) data; + if (length < 32) + DMA_BCR(1) = 0x00010000 | length; + else + DMA_BCR(1) = 0x00000020 | ((length / 32) << 16); + + DMA_CHCR(1) = 0x01000200; +} + +int32_t DecDCToutSync(int32_t mode) { + if (mode) + return (DMA_CHCR(1) >> 24) & 1; + + for (uint32_t i = MDEC_SYNC_TIMEOUT; i; i--) { + if (!(DMA_CHCR(1) & (1 << 24))) + return 0; + } + + printf("psxpress: DecDCToutSync() timeout\n"); + return -1; +} -- cgit v1.2.3 From 93f0a6d23ebed50833f565f949f351c2b80853ac Mon Sep 17 00:00:00 2001 From: spicyjpeg <88942473+spicyjpeg@users.noreply.github.com> Date: Mon, 7 Mar 2022 22:17:50 +0100 Subject: Fix critical ldscript bug and CI, add BIOS setjmp --- .github/workflows/build.yml | 28 ++++++------------ examples/io/system573/k573io.c | 5 ++-- examples/io/system573/k573io.h | 3 -- libpsn00b/include/psxapi.h | 12 ++++++++ libpsn00b/ldscripts/dll.ld | 1 + libpsn00b/ldscripts/exe.ld | 11 +++---- libpsn00b/psxapi/stubs.json | 12 ++++++++ libpsn00b/psxapi/sys.s | 18 +++++++++++- libpsn00b/readme.txt | 67 +++++++++++++++++++++--------------------- 9 files changed, 94 insertions(+), 63 deletions(-) (limited to 'libpsn00b/include') diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b2ca311..6f42e41 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,6 +16,9 @@ env: jobs: # This is based on doc/toolchain.md, no surprises here other than the cache. + # Since actions/cache@v2 has bugs when restoring on Windows caches created on + # Linux, v1 is used instead. + # https://github.com/actions/cache/issues/576 build-gcc: name: Build GCC toolchain runs-on: ubuntu-latest @@ -23,7 +26,7 @@ jobs: steps: - name: Initialize toolchain cache id: _cache - uses: actions/cache@v2 + uses: actions/cache@v1 with: key: gcc-${{ env.GCC_TARGET }}-${{ env.GCC_VERSION }} path: gcc @@ -83,25 +86,19 @@ jobs: # No surprises here either. The GitHub Actions VMs even come with most of the # dependencies required to build PSn00bSDK preinstalled. - # NOTE: the workaround to allow the toolchain cache to be loaded (see below) - # doesn't seem to work on Windows Server 2022 currently. build-sdk-windows: name: Build PSn00bSDK on Windows - runs-on: windows-2019 + runs-on: windows-2022 needs: build-gcc steps: - # Due to a bug in the cache action (and in order to use Ninja and pacman) - # the directories MSys2 stores binaries in must be added to PATH. For - # some reason they are not present in PATH by default. - # https://github.com/actions/cache/issues/576 - name: Add MSys2 to PATH run: | echo "C:\msys64\mingw64\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append echo "C:\msys64\usr\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - name: Initialize toolchain cache - uses: actions/cache@v2 + uses: actions/cache@v1 with: key: gcc-${{ env.GCC_TARGET }}-${{ env.GCC_VERSION }} path: gcc @@ -118,7 +115,7 @@ jobs: - name: Build and package PSn00bSDK run: | - cmake --preset ci -S sdk -G "Visual Studio 16 2019" -DPSN00BSDK_TC=${{ github.workspace }}\gcc\windows + cmake --preset ci -S sdk -G "Visual Studio 17 2022" -DPSN00BSDK_TC=${{ github.workspace }}\gcc\windows cmake --build build cmake --build build -t package @@ -144,7 +141,7 @@ jobs: steps: - name: Initialize toolchain cache - uses: actions/cache@v2 + uses: actions/cache@v1 with: key: gcc-${{ env.GCC_TARGET }}-${{ env.GCC_VERSION }} path: gcc @@ -178,12 +175,6 @@ jobs: name: psn00bsdk-linux-deb path: build/packages/*.deb - - name: Upload build artifacts (RPM) - uses: actions/upload-artifact@v2 - with: - name: psn00bsdk-linux-rpm - path: build/packages/*.rpm - # This job takes care of creating a new release and upload the build # artifacts if the last commit is associated to a tag. create-release: @@ -194,7 +185,7 @@ jobs: steps: - name: Initialize toolchain cache if: ${{ github.ref_type == 'tag' }} - uses: actions/cache@v2 + uses: actions/cache@v1 with: key: gcc-${{ env.GCC_TARGET }}-${{ env.GCC_VERSION }} path: gcc @@ -236,4 +227,3 @@ jobs: psn00bsdk-windows-nsis/* psn00bsdk-linux/* psn00bsdk-linux-deb/* - psn00bsdk-linux-rpm/* diff --git a/examples/io/system573/k573io.c b/examples/io/system573/k573io.c index a8748d6..bc13852 100644 --- a/examples/io/system573/k573io.c +++ b/examples/io/system573/k573io.c @@ -11,6 +11,7 @@ #include #include +#include #include "k573io.h" @@ -116,8 +117,8 @@ void K573_SetBoardType(K573_IOBoardType type) { //K573_DDRStageCommand(0x000001, 22); void K573_Init(void) { - EXP1_ADDR = 0x1f000000; - EXP1_CTRL = 0x24173f47; // 573 BIOS uses this value + EXP1_ADDR = 0x1f000000; + EXP1_DELAY_SIZE = 0x24173f47; // 573 BIOS uses this value K573_RESET_WATCHDOG(); } diff --git a/examples/io/system573/k573io.h b/examples/io/system573/k573io.h index cf125e2..7095a7c 100644 --- a/examples/io/system573/k573io.h +++ b/examples/io/system573/k573io.h @@ -10,9 +10,6 @@ /* Register definitions */ -#define EXP1_ADDR *((volatile uint32_t *) 0x1f801000) -#define EXP1_CTRL *((volatile uint32_t *) 0x1f801008) - #define K573_BANK_SWITCH *((volatile uint16_t *) 0x1f500000) #define K573_IDE_RESET *((volatile uint16_t *) 0x1f560000) #define K573_WATCHDOG *((volatile uint16_t *) 0x1f5c0000) diff --git a/libpsn00b/include/psxapi.h b/libpsn00b/include/psxapi.h index e7c2e1e..1298d29 100644 --- a/libpsn00b/include/psxapi.h +++ b/libpsn00b/include/psxapi.h @@ -121,6 +121,12 @@ struct EXEC { unsigned int sp,fp,rp,ret,base; }; +struct JMP_BUF { + unsigned int ra, sp, fp; + unsigned int s0, s1, s2, s3, s4, s5, s6, s7; + unsigned int gp; +}; + // Not recommended to use these functions to install IRQ handlers typedef struct { @@ -211,6 +217,12 @@ void ChangeClearRCnt(int t, int m); int Exec(struct EXEC *exec, int argc, char **argv); void FlushCache(void); +// BIOS setjmp functions +void b_setjmp(struct JMP_BUF *buf); +void b_longjmp(struct JMP_BUF *buf, int param); +void SetDefaultExitFromException(void); +void SetCustomExitFromException(struct JMP_BUF *buf); + // Misc functions int GetSystemInfo(int index); void *GetB0Table(void); diff --git a/libpsn00b/ldscripts/dll.ld b/libpsn00b/ldscripts/dll.ld index a03a504..15158e4 100644 --- a/libpsn00b/ldscripts/dll.ld +++ b/libpsn00b/ldscripts/dll.ld @@ -86,6 +86,7 @@ SECTIONS { * as we don't have to worry about managing .bss separately from the * main DLL blob. */ + . = ALIGN((. != 0) ? 4 : 1); __bss_start = .; *(.bss .bss.* .gnu.linkonce.b.*) diff --git a/libpsn00b/ldscripts/exe.ld b/libpsn00b/ldscripts/exe.ld index c6b9f29..583d76a 100644 --- a/libpsn00b/ldscripts/exe.ld +++ b/libpsn00b/ldscripts/exe.ld @@ -82,6 +82,11 @@ SECTIONS { /* BSS sections, i.e. uninitialized variables */ + /* + * Align all BSS sections to 4 bytes to ensure _start() doesn't perform + * unaligned memory accesses when clearing them. + */ + . = ALIGN((. != 0) ? 4 : 1); __bss_start = .; .sbss (NOLOAD) : { @@ -91,13 +96,9 @@ SECTIONS { .bss (NOLOAD) : { *(.bss .bss.* .gnu.linkonce.b.*) *(COMMON) - - /* - * This crap was in the stock GCC linker script. - */ - . = ALIGN((. != 0) ? 4 : 1); } > APP_RAM + . = ALIGN((. != 0) ? 4 : 1); _end = .; /* Dummy section */ diff --git a/libpsn00b/psxapi/stubs.json b/libpsn00b/psxapi/stubs.json index 14ef935..9198b06 100644 --- a/libpsn00b/psxapi/stubs.json +++ b/libpsn00b/psxapi/stubs.json @@ -47,6 +47,18 @@ "name": "putc", "file": "stdio.s" }, + { + "type": "a", + "id": 19, + "name": "b_setjmp", + "file": "sys.s" + }, + { + "type": "a", + "id": 20, + "name": "b_longjmp", + "file": "sys.s" + }, { "type": "a", "id": 57, diff --git a/libpsn00b/psxapi/sys.s b/libpsn00b/psxapi/sys.s index ef57124..e54bd98 100644 --- a/libpsn00b/psxapi/sys.s +++ b/libpsn00b/psxapi/sys.s @@ -6,7 +6,23 @@ .set noreorder -## A0 table functions (5) +## A0 table functions (7) + +.section .text.b_setjmp +.global b_setjmp +.type b_setjmp, @function +b_setjmp: + li $t2, 0xa0 + jr $t2 + li $t1, 0x13 + +.section .text.b_longjmp +.global b_longjmp +.type b_longjmp, @function +b_longjmp: + li $t2, 0xa0 + jr $t2 + li $t1, 0x14 .section .text.b_InitHeap .global b_InitHeap diff --git a/libpsn00b/readme.txt b/libpsn00b/readme.txt index cfff733..6a6be5a 100644 --- a/libpsn00b/readme.txt +++ b/libpsn00b/readme.txt @@ -18,33 +18,39 @@ recommended version as that is what LibPSn00b is most tested most on. Brief summary of libraries: - libc - Standard C library. Covers only a small subset of the full - standard C library such as basic string and memory manipulation - functions. Should include libgcc to avoid libc/libgcc linker - hell (endless cross referencing). - - psxgpu - GPU library for video, graphics control, and interrupt service - subsystem that other libraries that uses interrupts depend on. - - psxgte - GTE library for hardware accelerated vector transformations - that are integral for high performance 3D graphics on the PS1 - (it is a Geometry Transformation Engine, NOT Transfer Engine). - - psxapi - Provides function calls for using functions provided by the PS1 - BIOS. - - psxetc - Provides some miscellaneous features used by the other libraries - as well as a dynamic linker for loading DLLs at runtime. - - psxspu - SPU library (work in progress). Currently supports hardware - init, sample data upload via DMA and playing sound samples. - Lacks support for reverb and a sequenced music subsystem. - - psxcd - CD-ROM library for loading files, parsing directories - (PSn00bSDK addition), CD Audio/XA playback with provisions for - data streaming. Also supports multi-session discs (must be - selected manually). - + libc - Standard C library. Covers only a small subset of the full + standard C library such as basic string and memory manipulation + functions. Should include libgcc to avoid libc/libgcc linker + hell (endless cross referencing). + + psxgpu - GPU library for video, graphics control, and interrupt service + subsystem that other libraries that uses interrupts depend on. + + psxgte - GTE library for hardware accelerated vector transformations + that are integral for high performance 3D graphics on the PS1 + (it is a Geometry Transformation Engine, NOT Transfer Engine). + + psxapi - Provides function calls for using functions provided by the PS1 + BIOS. + + psxetc - Provides some miscellaneous features used by the other libraries + as well as a dynamic linker for loading DLLs at runtime. + + psxspu - SPU library (work in progress). Currently supports hardware + init, sample data upload via DMA and playing sound samples. + Lacks support for reverb and a sequenced music subsystem. + + psxcd - CD-ROM library for loading files, parsing directories + (PSn00bSDK addition), CD Audio/XA playback with provisions for + data streaming. Also supports multi-session discs (must be + selected manually). + + psxpress - Experimental MDEC library. Currently provides APIs to feed data + to the MDEC and retrieve decoded images, as well as a + decompressor for the Huffman encoding used in FMVs encoded using + Sony tools. A custom decompressor based on arithmetic coding + might be implemented in the future. + Each library has its own readme file that contains a todo list, credits and some additional details of the library. Changes of all the libraries must be covered in the changelog.txt file. @@ -52,7 +58,7 @@ Brief summary of libraries: Compiling: - Refer to INSTALL.md in the parent directory for up-to-date installation + Refer to installation.md in the doc directory for up-to-date installation instructions. --- THE SECTION BELOW IS OUTDATED AND ONLY KEPT FOR REFERENCE --- @@ -144,11 +150,6 @@ LibPSn00b Library to-do list: psxmcrd - Better and faster memory card library with provisions for low-level card access. The psxpad library would provide communication routines for the card library. - - psxpress - MDEC and data decompression library. May use DEFLATE or LZ77 - for compressing MDEC data instead of Huffman as used in the - official libraries. It may yield better compression which may - potentially result in higher quality FMVs. psxexp - Support library for various devices connected to the serial or expansion port, including both official ones (e.g. PCMCIA cards -- cgit v1.2.3 From 8c68b4b8a5bf7757b8e4d6bc2f68f10584b0deb1 Mon Sep 17 00:00:00 2001 From: spicyjpeg <88942473+spicyjpeg@users.noreply.github.com> Date: Sat, 12 Mar 2022 14:28:11 +0100 Subject: Minor fixes, add C++ placement new, n00bdemo 573 support --- examples/demos/n00bdemo/main.c | 46 ++++++++++++++++++++++++++++---- examples/io/system573/CMakeLists.txt | 2 +- examples/lowlevel/cartrom/CMakeLists.txt | 2 +- examples/sound/spustream/main.c | 4 +++ libpsn00b/include/elf.h | 2 +- libpsn00b/libc/abort.c | 14 ++++++++++ libpsn00b/libc/c++-support.cxx | 39 ++++++++++++++++----------- libpsn00b/libc/putchar.s | 10 ------- 8 files changed, 85 insertions(+), 34 deletions(-) delete mode 100644 libpsn00b/libc/putchar.s (limited to 'libpsn00b/include') diff --git a/examples/demos/n00bdemo/main.c b/examples/demos/n00bdemo/main.c index d2fe317..cb64c42 100644 --- a/examples/demos/n00bdemo/main.c +++ b/examples/demos/n00bdemo/main.c @@ -11,14 +11,19 @@ * * Changelog: * + * Mar 12, 2022 - Added Konami System 573 support. + * * May 10, 2021 - Variable types updated for psxgpu.h changes. * * Apr 4, 2019 - Some code clean-up and added more comments. * - * Mar 20, 2019 - Initial completed version. + * Mar 20, 2019 - Initial completed version. * */ - + +// Comment to disable 573 support +#define SYSTEM_573_SUPPORT + #include #include #include @@ -27,7 +32,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -64,6 +71,34 @@ SPRT psn00b_sprite; void sort_overlay(int showlotl); void lightdemo(); +#ifdef SYSTEM_573_SUPPORT +#define K573_WATCHDOG *((volatile uint16_t *) 0x1f5c0000) +#define K573_EXP1_CFG 0x24173f47 + +/* + The only thing required to support the 573 is to periodically reset the + watchdog. Hooking the vblank IRQ (through VSyncCallback) is the "right" way + to do it, however using a hardware timer running at a higher rate (100 Hz) + seems to improve stability. +*/ +void reset573Watchdog() { + K573_WATCHDOG = 0; +} + +void system573Setup() { + EnterCriticalSection(); + + EXP1_ADDR = 0x1f000000; + EXP1_DELAY_SIZE = K573_EXP1_CFG; + TIMER_CTRL(2) = 0x0258; // CLK/8 input, IRQ on reload + TIMER_RELOAD(2) = (F_CPU / 8) / 100; // 100 Hz + + // Configure timer 2 IRQ + ChangeClearRCnt(2, 0); + InterruptCallback(6, &reset573Watchdog); + ExitCriticalSection(); +} +#endif void UploadTIM(TIM_IMAGE *tim) { @@ -197,9 +232,10 @@ void unpackModels() { } void init() { - - int i; - +#ifdef SYSTEM_573_SUPPORT + system573Setup(); +#endif + // Init display initDisplay(); diff --git a/examples/io/system573/CMakeLists.txt b/examples/io/system573/CMakeLists.txt index 1c74347..2a362e8 100644 --- a/examples/io/system573/CMakeLists.txt +++ b/examples/io/system573/CMakeLists.txt @@ -1,7 +1,7 @@ # PSn00bSDK example CMake script # (C) 2021 spicyjpeg - MPL licensed -cmake_minimum_required(VERSION 3.21) +cmake_minimum_required(VERSION 3.20) project( system573 diff --git a/examples/lowlevel/cartrom/CMakeLists.txt b/examples/lowlevel/cartrom/CMakeLists.txt index 107cc3d..7d5e86e 100644 --- a/examples/lowlevel/cartrom/CMakeLists.txt +++ b/examples/lowlevel/cartrom/CMakeLists.txt @@ -1,7 +1,7 @@ # PSn00bSDK example CMake script # (C) 2021 spicyjpeg - MPL licensed -cmake_minimum_required(VERSION 3.21) +cmake_minimum_required(VERSION 3.20) project( cartrom diff --git a/examples/sound/spustream/main.c b/examples/sound/spustream/main.c index 6284c6d..6b9db93 100644 --- a/examples/sound/spustream/main.c +++ b/examples/sound/spustream/main.c @@ -308,6 +308,10 @@ void init_stream(CdlFILE *file) { CdReadyCallback(&cd_event_handler); ExitCriticalSection(); + // Configure the CD drive to read 2048-byte sectors at 2x speed. + uint8_t mode = CdlModeSpeed; + CdControl(CdlSetmode, (const uint8_t *) &mode, 0); + // Set the initial LBA of the stream file, which is going to be incremented // as the stream is played. str_ctx.lba = CdPosToInt(&(file->pos)); diff --git a/libpsn00b/include/elf.h b/libpsn00b/include/elf.h index b4c4408..abfb3d5 100644 --- a/libpsn00b/include/elf.h +++ b/libpsn00b/include/elf.h @@ -12,7 +12,7 @@ #ifndef __ELF_H #define __ELF_H -#include +#include typedef enum { DT_NULL = 0, /* Marks end of dynamic section */ diff --git a/libpsn00b/libc/abort.c b/libpsn00b/libc/abort.c index 1d07037..de4323d 100644 --- a/libpsn00b/libc/abort.c +++ b/libpsn00b/libc/abort.c @@ -1,5 +1,8 @@ + #include +/* Standard abort */ + void abort() { printf("abort()\n"); @@ -7,9 +10,20 @@ void abort() { __asm__ volatile(""); } +/* Internal function used by assert() macro */ + void _assert_abort(const char *file, int line, const char *expr) { printf("%s:%d: assert(%s)\n", file, line, expr); for (;;) __asm__ volatile(""); } + +/* Pure virtual function call (C++) */ + +void __cxa_pure_virtual(void) { + printf("__cxa_pure_virtual()\n"); + + for (;;) + __asm__ volatile(""); +} diff --git a/libpsn00b/libc/c++-support.cxx b/libpsn00b/libc/c++-support.cxx index d0c0f3a..38354dd 100644 --- a/libpsn00b/libc/c++-support.cxx +++ b/libpsn00b/libc/c++-support.cxx @@ -1,39 +1,46 @@ + #include #include #include -extern "C" void __cxa_pure_virtual(void) { - printf("__cxa_pure_virtual()\n"); - - for (;;) - __asm__ volatile(""); -} +/* Default new/delete operators */ -void* operator new(size_t size) { +void *operator new(size_t size) noexcept { return malloc(size); } -void* operator new[](size_t size) { +void *operator new[](size_t size) noexcept { return malloc(size); } -void operator delete(void* ptr) { +void operator delete(void *ptr) noexcept { free(ptr); } -void operator delete[](void* ptr) { +void operator delete[](void *ptr) noexcept { free(ptr); } -/*- - * +/* + * https://en.cppreference.com/w/cpp/memory/new/operator_delete * * Called if a user-defined replacement is provided, except that it's * unspecified whether other overloads or this overload is called when deleting - * objects of incomplete type and arrays of non-class and trivially-destructible - * class types. + * objects of incomplete type and arrays of non-class and trivially + * destructible class types. * - * A memory allocator can use the given size to be more efficient */ -void operator delete(void* ptr, unsigned int) { + * A memory allocator can use the given size to be more efficient. + */ +void operator delete(void *ptr, size_t size) noexcept { free(ptr); } + +/* Placement new operators */ + +void *operator new(size_t size, void *ptr) noexcept { + return ptr; +} + +void *operator new[](size_t size, void *ptr) noexcept { + return ptr; +} diff --git a/libpsn00b/libc/putchar.s b/libpsn00b/libc/putchar.s deleted file mode 100644 index a3f6c57..0000000 --- a/libpsn00b/libc/putchar.s +++ /dev/null @@ -1,10 +0,0 @@ -.set noreorder -.section .text - -.global putchar -.type putchar, @function -putchar: - addiu $t2, $0, 0xa0 - jr $t2 - addiu $t1, $0, 0x3c - \ No newline at end of file -- cgit v1.2.3 From 4bbfe640a8c357137524e797a8d2bd0a94d3abfa Mon Sep 17 00:00:00 2001 From: spicyjpeg <88942473+spicyjpeg@users.noreply.github.com> Date: Sun, 20 Mar 2022 10:56:23 +0100 Subject: Remove stdint.h, fix n00bdemo crashing --- examples/demos/n00bdemo/logo.c | 4 +++- examples/demos/n00bdemo/main.c | 5 ++--- examples/io/pads/spi.c | 1 + examples/io/pads/spi.h | 1 + libpsn00b/include/stdint.h | 16 ---------------- libpsn00b/include/stdlib.h | 2 +- libpsn00b/libc/start.c | 23 ++++++++++++----------- 7 files changed, 20 insertions(+), 32 deletions(-) delete mode 100644 libpsn00b/include/stdint.h (limited to 'libpsn00b/include') diff --git a/examples/demos/n00bdemo/logo.c b/examples/demos/n00bdemo/logo.c index 40160e7..784c9e1 100644 --- a/examples/demos/n00bdemo/logo.c +++ b/examples/demos/n00bdemo/logo.c @@ -51,9 +51,11 @@ typedef struct { int size; } NODE; +extern NODE _end[]; + void DumpHeap() { - NODE *n = (NODE*)GetBSSend(); + NODE *n = _end; printf( "--\n" ); diff --git a/examples/demos/n00bdemo/main.c b/examples/demos/n00bdemo/main.c index cb64c42..439bccc 100644 --- a/examples/demos/n00bdemo/main.c +++ b/examples/demos/n00bdemo/main.c @@ -232,12 +232,11 @@ void unpackModels() { } void init() { + // Init display + initDisplay(); #ifdef SYSTEM_573_SUPPORT system573Setup(); #endif - - // Init display - initDisplay(); FntLoad( 960, 0 ); diff --git a/examples/io/pads/spi.c b/examples/io/pads/spi.c index 43b5bc3..133782c 100644 --- a/examples/io/pads/spi.c +++ b/examples/io/pads/spi.c @@ -27,6 +27,7 @@ */ #include +#include #include #include #include diff --git a/examples/io/pads/spi.h b/examples/io/pads/spi.h index 7d4d75b..8c17df3 100644 --- a/examples/io/pads/spi.h +++ b/examples/io/pads/spi.h @@ -7,6 +7,7 @@ #define __SPI_H #include +#include #include // Maximum request/response length (34 bytes for pads, 140 for memory cards). diff --git a/libpsn00b/include/stdint.h b/libpsn00b/include/stdint.h deleted file mode 100644 index 83acb00..0000000 --- a/libpsn00b/include/stdint.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef _STDINT_H -#define _STDINT_H - -typedef unsigned int size_t; - -typedef char int8_t; -typedef short int16_t; -typedef int int32_t; -typedef long long int64_t; - -typedef unsigned char uint8_t; -typedef unsigned short uint16_t; -typedef unsigned int uint32_t; -typedef unsigned long long uint64_t; - -#endif // _STDINT_H \ No newline at end of file diff --git a/libpsn00b/include/stdlib.h b/libpsn00b/include/stdlib.h index b187a6f..4c4fcd3 100644 --- a/libpsn00b/include/stdlib.h +++ b/libpsn00b/include/stdlib.h @@ -44,7 +44,7 @@ double strtod(const char *nptr, char **endptr); float strtof(const char *nptr, char **endptr); // Memory allocation functions -unsigned int *GetBSSend(); +void _mem_init(int ram_size, int stack_max_size); void InitHeap(unsigned int *addr, int size); int SetHeapSize(int size); void *malloc(int size); diff --git a/libpsn00b/libc/start.c b/libpsn00b/libc/start.c index f190794..fd6fe33 100644 --- a/libpsn00b/libc/start.c +++ b/libpsn00b/libc/start.c @@ -6,19 +6,20 @@ #include #include #include +#include -#define KERNEL_ARG_STRING ((const char *) 0x80000180) -#define KERNEL_RETURN_VALUE ((volatile int *) 0x8000dffc) +#define KERNEL_ARG_STRING ((const char *) 0x80000180) +#define KERNEL_RETURN_VALUE ((volatile int *) 0x8000dffc) /* Argument parsing */ -int32_t __argc; -const char **__argv; +int __argc; +const char **__argv; #define ARGC_MAX 16 -static const char *_argv_buffer[ARGC_MAX]; -static char _arg_string_buffer[132]; +static const char *_argv_buffer[ARGC_MAX]; +static char _arg_string_buffer[132]; static void _parse_kernel_args() { // Copy the argument string from kernel memory into a private buffer (which @@ -61,10 +62,10 @@ extern uint8_t _end[]; // useful though to change the stack size and/or reinitialize the heap on // systems that have more than 2 MB of RAM (e.g. emulators, devkits, PS1-based // arcade boards). -void _mem_init(size_t ram_size, size_t stack_max_size) { - void *exe_end = _end + 4; - size_t exe_size = (size_t) exe_end - (size_t) __text_start; - size_t ram_used = (0x10000 + exe_size + stack_max_size) & 0xfffffffc; +void _mem_init(int ram_size, int stack_max_size) { + void *exe_end = _end + 4; + int exe_size = (int) exe_end - (int) __text_start; + int ram_used = (0x10000 + exe_size + stack_max_size) & 0xfffffffc; InitHeap(exe_end, ram_size - ram_used); } @@ -74,7 +75,7 @@ void _mem_init(size_t ram_size, size_t stack_max_size) { extern void (*__CTOR_LIST__[])(void); extern void (*__DTOR_LIST__[])(void); -extern int32_t main(int32_t argc, const char* argv[]); +extern int main(int argc, const char* argv[]); // Even though _start() usually takes no arguments, this implementation allows // parent executables to pass args directly to child executables without having -- cgit v1.2.3 From 6c19e712e2588b52791f604feb31273acb074d41 Mon Sep 17 00:00:00 2001 From: spicyjpeg <88942473+spicyjpeg@users.noreply.github.com> Date: Sun, 20 Mar 2022 14:02:42 +0100 Subject: Add mdec/mdecimage example, psxpress fixes --- examples/mdec/mdecimage/CMakeLists.txt | 20 +++ examples/mdec/mdecimage/bunpattern.png | Bin 0 -> 59932 bytes examples/mdec/mdecimage/encode_image.py | 218 ++++++++++++++++++++++++++++++++ examples/mdec/mdecimage/image.bin | Bin 0 -> 163072 bytes examples/mdec/mdecimage/main.c | 82 ++++++++++++ libpsn00b/include/psxpress.h | 1 + libpsn00b/psxpress/mdec.c | 119 ++++++++--------- 7 files changed, 381 insertions(+), 59 deletions(-) create mode 100644 examples/mdec/mdecimage/CMakeLists.txt create mode 100644 examples/mdec/mdecimage/bunpattern.png create mode 100644 examples/mdec/mdecimage/encode_image.py create mode 100644 examples/mdec/mdecimage/image.bin create mode 100644 examples/mdec/mdecimage/main.c (limited to 'libpsn00b/include') diff --git a/examples/mdec/mdecimage/CMakeLists.txt b/examples/mdec/mdecimage/CMakeLists.txt new file mode 100644 index 0000000..b76adb4 --- /dev/null +++ b/examples/mdec/mdecimage/CMakeLists.txt @@ -0,0 +1,20 @@ +# PSn00bSDK example CMake script +# (C) 2021 spicyjpeg - MPL licensed + +cmake_minimum_required(VERSION 3.20) + +project( + mdecimage + LANGUAGES C ASM + VERSION 1.0.0 + DESCRIPTION "PSn00bSDK MDEC static image example" + HOMEPAGE_URL "http://lameguy64.net/?page=psn00bsdk" +) + +file(GLOB _sources *.c) +psn00bsdk_add_executable(mdecimage STATIC ${_sources}) +#psn00bsdk_add_cd_image(mdecimage_iso mdecimage iso.xml DEPENDS mdecimage) + +psn00bsdk_target_incbin(mdecimage PRIVATE mdec_image image.bin) + +install(FILES ${PROJECT_BINARY_DIR}/mdecimage.exe TYPE BIN) diff --git a/examples/mdec/mdecimage/bunpattern.png b/examples/mdec/mdecimage/bunpattern.png new file mode 100644 index 0000000..61524f8 Binary files /dev/null and b/examples/mdec/mdecimage/bunpattern.png differ diff --git a/examples/mdec/mdecimage/encode_image.py b/examples/mdec/mdecimage/encode_image.py new file mode 100644 index 0000000..3a5bcea --- /dev/null +++ b/examples/mdec/mdecimage/encode_image.py @@ -0,0 +1,218 @@ +#!/usr/bin/env python3 +# Simple MDEC image encoder (requires PIL/Pillow and NumPy to be installed) +# (C) 2022 spicyjpeg - MPL licensed + +import math +from warnings import warn +from argparse import ArgumentParser, FileType + +import numpy +from PIL import Image + +LUMA_SCALE = 8 +CHROMA_SCALE = 16 + +## Tables + +ZIGZAG_TABLE = numpy.array(( + 0, 1, 5, 6, 14, 15, 27, 28, + 2, 4, 7, 13, 16, 26, 29, 42, + 3, 8, 12, 17, 25, 30, 41, 43, + 9, 11, 18, 24, 31, 40, 44, 53, + 10, 19, 23, 32, 39, 45, 52, 54, + 20, 22, 33, 38, 46, 51, 55, 60, + 21, 34, 37, 47, 50, 56, 59, 61, + 35, 36, 48, 49, 57, 58, 62, 63 +), numpy.uint8).argsort() + +# The default luma and chroma quantization table is based on the MPEG-1 +# quantization table, with the only difference being the first value (2 instead +# of 8). +QUANT_TABLE = numpy.array(( + 2, 16, 19, 22, 26, 27, 29, 34, + 16, 16, 22, 24, 27, 29, 34, 37, + 19, 22, 26, 27, 29, 34, 34, 38, + 22, 22, 26, 27, 29, 34, 37, 40, + 22, 26, 27, 29, 32, 35, 40, 48, + 26, 27, 29, 32, 35, 40, 48, 58, + 26, 27, 29, 34, 38, 46, 56, 69, + 27, 29, 35, 38, 46, 56, 69, 83 +), numpy.uint8).reshape(( 8, 8 )) + +S = [ math.cos((i or 4) / 16 * math.pi) / 2 for i in range(8) ] + +DCT_MATRIX = numpy.array(( + S[0], S[0], S[0], S[0], S[0], S[0], S[0], S[0], + S[1], S[3], S[5], S[7], -S[7], -S[5], -S[3], -S[1], + S[2], S[6], -S[6], -S[2], -S[2], -S[6], S[6], S[2], + S[3], -S[7], -S[1], -S[5], S[5], S[1], S[7], -S[3], + S[4], -S[4], -S[4], S[4], S[4], -S[4], -S[4], S[4], + S[5], -S[1], S[7], S[3], -S[3], -S[7], S[1], -S[5], + S[6], -S[2], S[2], -S[6], -S[6], S[2], -S[2], S[6], + S[7], -S[5], S[3], -S[1], S[1], -S[3], S[5], -S[7] +), numpy.float32).reshape(( 8, 8 )) + +## Helpers + +def to_int10(value): + clamped = min(max(int(value), -0x200), 0x1ff) + + return clamped + (0 if clamped >= 0 else 0x400) + +def rgb_to_ycbcr_planar(image): + scaled = image.astype(numpy.float32) / 255.0 + r, g, b = scaled.transpose(( 2, 0, 1 )) + + # https://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.601_conversion + y = 16 + r * 65.481 + g * 128.553 + b * 24.966 + cb = 128 - r * 37.797 - g * 74.203 + b * 112.000 + cr = 128 + r * 112.000 - g * 93.786 - b * 18.214 + + return y, cb, cr + +## Block encoder + +def encode_block(buffer, block, scale): + # Perform discrete cosine transform on the block, divide the coefficients by + # the quantization table and reorder them in zigzag order. + _block = block.astype(numpy.float32) - 128.0 + coeffs = (DCT_MATRIX @ _block @ DCT_MATRIX.T) / QUANT_TABLE + coeffs = coeffs.reshape(( 64, ))[ZIGZAG_TABLE] + + buffer[0] = (scale << 10) | to_int10(round(coeffs[0])) + offset = 1 + + # Divide the AC coefficients by the given quantization scale and encode them + # as run-length pairs by counting how many zeroes there are between each + # non-zero value. + ac_values = coeffs[1:] * 8.0 / scale + encoded = [] + run_length = 0 + + for ac in ac_values.round().astype(numpy.int32): + if ac: + buffer[offset] = (run_length << 10) | to_int10(ac) + offset += 1 + + run_length = 0 + else: + run_length += 1 + + # Flush any remaining zeroes. + if run_length: + buffer[offset] = (run_length - 1) << 10 + offset += 1 + + # Add 1 or 2 end-of-block codes depending on whether the number of 16-bit + # values output so far is odd or even. Some emulators will break if blocks + # are not 32-bit aligned. + buffer[offset] = 0xfe00 + offset += 1 + if offset % 2: + buffer[offset] = 0xfe00 + offset += 1 + + return offset + +def encode_macroblock(buffer, block, y_scale, c_scale): + #y, cb, cr = rgb_to_ycbcr_planar(block) + y, cb, cr = block.transpose(( 2, 0, 1 )) + offset = 0 + + # Split the macroblock into 6 monochrome 8x8 blocks (Cr, Cb at half + # resolution + Y1-4). The MDEC uses 4:2:0 chroma subsampling. + # TODO: use bilinear sampling instead of nearest-neighbor for chroma + offset += encode_block(buffer[offset:], cr[0:16:2, 0:16:2], c_scale) + offset += encode_block(buffer[offset:], cb[0:16:2, 0:16:2], c_scale) + offset += encode_block(buffer[offset:], y[0: 8, 0: 8], y_scale) + offset += encode_block(buffer[offset:], y[0: 8, 8:16], y_scale) + offset += encode_block(buffer[offset:], y[8:16, 0: 8], y_scale) + offset += encode_block(buffer[offset:], y[8:16, 8:16], y_scale) + + return offset + +## Main + +def get_args(): + parser = ArgumentParser( + description = "Generates uncompressed MDEC bitstream data from an image." + ) + parser.add_argument( + "input_file", + type = FileType("rb"), + help = "input image file" + ) + parser.add_argument( + "-o", "--output", + type = FileType("wb"), + default = "image.bin", + help = "where to output converted image data (image.bin by default)", + metavar = "file" + ) + parser.add_argument( + "-m", "--monochrome", + action = "store_true", + help = "encode image as monochrome (8x8 blocks) instead of color (16x16 macroblocks)" + ) + parser.add_argument( + "-y", "--luma", + type = int, + default = LUMA_SCALE, + help = f"quantization scale for luma/monochrome blocks (0-63, default {LUMA_SCALE})", + metavar = "scale" + ) + parser.add_argument( + "-c", "--chroma", + type = int, + default = CHROMA_SCALE, + help = f"quantization scale for chroma blocks (0-63, default {CHROMA_SCALE})", + metavar = "scale" + ) + + return parser.parse_args() + +def main(): + args = get_args() + if args.luma < 0 or args.luma > 63: + raise ValueError("luma quantization scale must be in 0-63 range") + if args.chroma < 0 or args.chroma > 63: + raise ValueError("chroma quantization scale must be in 0-63 range") + + image = Image.open(args.input_file, "r") + data = numpy.array(image.convert("YCbCr"), numpy.uint8) + size = 8 if args.monochrome else 16 + + if image.width % size: + warn(RuntimeWarning(f"image width is not a multiple of {size}, trimming")) + if image.height % size: + warn(RuntimeWarning(f"image height is not a multiple of {size}, trimming")) + + # Preallocate 1 MB for the converted image data (faster than expanding an + # array dynamically -- this script is too slow already). + buffer = numpy.empty(0x80000, numpy.uint16) + offset = 0 + + # Split the image into 8x8 or 16x16 blocks and encode them in column-major + # order. + for x in range(0, image.width, size): + for y in range(0, image.height, size): + block = data[y:(y + size), x:(x + size)] + + if args.monochrome: + offset += encode_block(buffer[offset:], block[:, :, 0], args.luma) + else: + offset += encode_macroblock(buffer[offset:], block, args.luma, args.chroma) + + # Pad the generated data to the size of a DMA chunk (32x 32-bit words or + # 128 bytes). + length = (offset + 63) & 0xffffffc0 + buffer[offset:length] = 0xfe00 + + if length > (0xffff * 2): + warn(RuntimeWarning("image is too large to be decoded with a single DecDCTin() call")) + + with args.output as _file: + buffer[0:length].tofile(_file) + +if __name__ == "__main__": + main() diff --git a/examples/mdec/mdecimage/image.bin b/examples/mdec/mdecimage/image.bin new file mode 100644 index 0000000..976b4b6 Binary files /dev/null and b/examples/mdec/mdecimage/image.bin differ diff --git a/examples/mdec/mdecimage/main.c b/examples/mdec/mdecimage/main.c new file mode 100644 index 0000000..b59fdaf --- /dev/null +++ b/examples/mdec/mdecimage/main.c @@ -0,0 +1,82 @@ +/* + * PSn00bSDK MDEC static image example + * (C) 2022 spicyjpeg - MPL licensed + * + * This is a modified version of the graphics/rgb24 example showing how to feed + * run-length encoded data into the MDEC and retrieve a decoded 24bpp image. To + * keep the example simple no additional compression is applied (usually MDEC + * data would be Huffman encoded to save more space, with the initial + * decompression being done in software). A Python script is included to encode + * an image into the format expected by the MDEC; quality and file size can be + * tweaked by changing the quantization scales with the -y and -c arguments. + * + * Using the MDEC to decode static images can be useful for e.g. menu + * backgrounds or loading screens, where smaller file sizes are desirable even + * if quality is sacrificed. + */ + +#include +#include +#include +#include +#include + +extern const uint32_t mdec_image[]; +extern const size_t mdec_image_size; + +#define SCREEN_XRES 640 +#define SCREEN_YRES 480 + +//#define BLOCK_SIZE 8 // Monochrome (8x8), 15bpp display +//#define BLOCK_SIZE 12 // Monochrome (8x8), 24bpp display +//#define BLOCK_SIZE 16 // Color (16x16), 15bpp display +#define BLOCK_SIZE 24 // Color (16x16), 24bpp display + +int main(int argc, const char* argv[]) { + DISPENV disp; + + ResetGraph(0); + DecDCTReset(0); + + // Set up the GPU for 640x480 interlaced 24bpp output. + SetDefDispEnv(&disp, 0, 0, SCREEN_XRES, SCREEN_YRES); + disp.isrgb24 = 1; + disp.isinter = 1; + + PutDispEnv(&disp); + SetDispMask(1); + + // Start feeding image data to the MDEC. This doesn't immediately start the + // decoding, instead the MDEC will wait until a destination buffer is also + // set up. + MDEC0 = 0x30000000 | (mdec_image_size / 4); // 0x38000000 for 15bpp + DecDCTinRaw(mdec_image, mdec_image_size / 4); + + // Fetch decoded data from the MDEC in vertical 8x480 or 16x480 "slices". + // This is necessary as the MDEC doesn't buffer an entire frame but only + // returns a series of square macroblocks, which can't be placed into VRAM + // with a single LoadImage() call. + //for (uint32_t x = 0; x < SCREEN_XRES; x += BLOCK_SIZE) { // 15bpp + for (uint32_t x = 0; x < (SCREEN_XRES * 3 / 2); x += BLOCK_SIZE) { // 24bpp + RECT rect; + uint32_t slice[BLOCK_SIZE * SCREEN_YRES / 2]; + + rect.x = x; + rect.y = 0; + rect.w = BLOCK_SIZE; + rect.h = SCREEN_YRES; + + // Configure the MDEC to output to the slice buffer and let it finish + // decoding a slice, then upload it to the framebuffer. + DecDCTout(slice, BLOCK_SIZE * SCREEN_YRES / 2); + DecDCToutSync(0); + + LoadImage(&rect, (u_long *) slice); + DrawSync(0); + } + + for (;;) + __asm__ volatile(""); + + return 0; +} diff --git a/libpsn00b/include/psxpress.h b/libpsn00b/include/psxpress.h index ad5f6a3..b060170 100644 --- a/libpsn00b/include/psxpress.h +++ b/libpsn00b/include/psxpress.h @@ -7,6 +7,7 @@ #define __PSXPRESS_H #include +#include /* Structure definitions */ diff --git a/libpsn00b/psxpress/mdec.c b/libpsn00b/psxpress/mdec.c index 82e2465..ca4c75a 100644 --- a/libpsn00b/psxpress/mdec.c +++ b/libpsn00b/psxpress/mdec.c @@ -11,7 +11,7 @@ #define MDEC_SYNC_TIMEOUT 0x1000000 -/* Default IDCT matrix */ +/* Default IDCT matrix and quantization tables */ #define S0 0x5a82 // 0x4000 * cos(0/16 * pi) * sqrt(2) #define S1 0x7d8a // 0x4000 * cos(1/16 * pi) * 2 @@ -22,54 +22,63 @@ #define S6 0x30fb // 0x4000 * cos(6/16 * pi) * 2 #define S7 0x18f8 // 0x4000 * cos(7/16 * pi) * 2 -static const int16_t _default_idct_matrix[] = { - S0, S0, S0, S0, S0, S0, S0, S0, - S1, S3, S5, S7, -S7, -S5, -S3, -S1, - S2, S6, -S6, -S2, -S2, -S6, S6, S2, - S3, -S7, -S1, -S5, S5, S1, S7, -S3, - S4, -S4, -S4, S4, S4, -S4, -S4, S4, - S5, -S1, S7, S3, -S3, -S7, S1, -S5, - S6, -S2, S2, -S6, -S6, S2, -S2, S6, - S7, -S5, S3, -S1, S1, -S3, S5, -S7 -}; - -/* Default quantization tables */ - -// The default luma and chroma quantization table is based on the MPEG-1 -// quantization table, with the only difference being the first value (2 -// instead of 8). Note that quantization tables are stored in zigzag order -// rather than row- or column-major. -// https://problemkaputt.de/psx-spx.htm#mdecdecompression -static const uint8_t _default_quant_table[] = { - 2, 16, 16, 19, 16, 19, 22, 22, - 22, 22, 22, 22, 26, 24, 26, 27, - 27, 27, 26, 26, 26, 26, 27, 27, - 27, 29, 29, 29, 34, 34, 34, 29, - 29, 29, 27, 27, 29, 29, 32, 32, - 34, 34, 37, 38, 37, 35, 35, 34, - 35, 38, 38, 40, 40, 40, 48, 48, - 46, 46, 56, 56, 58, 69, 69, 83 -}; -/*static const uint8_t _jpeg_y_quant_table[] = { - 16, 11, 12, 14, 12, 10, 16, 14, - 13, 14, 18, 17, 16, 19, 24, 40, - 26, 24, 22, 22, 24, 49, 35, 37, - 29, 40, 58, 51, 61, 60, 57, 51, - 56, 55, 64, 72, 92, 78, 64, 68, - 87, 69, 55, 56, 80, 109, 81, 87, - 95, 98, 103, 104, 103, 62, 77, 113, - 121, 112, 100, 120, 92, 101, 103, 99 +static const DECDCTENV _default_mdec_env = { + // The default luma and chroma quantization table is based on the MPEG-1 + // quantization table, with the only difference being the first value (2 + // instead of 8). Note that quantization tables are stored in zigzag order + // rather than row- or column-major. + // https://problemkaputt.de/psx-spx.htm#mdecdecompression + .iq_y = { + 2, 16, 16, 19, 16, 19, 22, 22, + 22, 22, 22, 22, 26, 24, 26, 27, + 27, 27, 26, 26, 26, 26, 27, 27, + 27, 29, 29, 29, 34, 34, 34, 29, + 29, 29, 27, 27, 29, 29, 32, 32, + 34, 34, 37, 38, 37, 35, 35, 34, + 35, 38, 38, 40, 40, 40, 48, 48, + 46, 46, 56, 56, 58, 69, 69, 83 + }, + .iq_c = { + 2, 16, 16, 19, 16, 19, 22, 22, + 22, 22, 22, 22, 26, 24, 26, 27, + 27, 27, 26, 26, 26, 26, 27, 27, + 27, 29, 29, 29, 34, 34, 34, 29, + 29, 29, 27, 27, 29, 29, 32, 32, + 34, 34, 37, 38, 37, 35, 35, 34, + 35, 38, 38, 40, 40, 40, 48, 48, + 46, 46, 56, 56, 58, 69, 69, 83 + }, + /*.iq_y = { + 16, 11, 12, 14, 12, 10, 16, 14, + 13, 14, 18, 17, 16, 19, 24, 40, + 26, 24, 22, 22, 24, 49, 35, 37, + 29, 40, 58, 51, 61, 60, 57, 51, + 56, 55, 64, 72, 92, 78, 64, 68, + 87, 69, 55, 56, 80, 109, 81, 87, + 95, 98, 103, 104, 103, 62, 77, 113, + 121, 112, 100, 120, 92, 101, 103, 99 + }, + .iq_c = { + 17, 18, 18, 24, 21, 24, 47, 26, + 26, 47, 99, 66, 56, 66, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99 + },*/ + .dct = { + S0, S0, S0, S0, S0, S0, S0, S0, + S1, S3, S5, S7, -S7, -S5, -S3, -S1, + S2, S6, -S6, -S2, -S2, -S6, S6, S2, + S3, -S7, -S1, -S5, S5, S1, S7, -S3, + S4, -S4, -S4, S4, S4, -S4, -S4, S4, + S5, -S1, S7, S3, -S3, -S7, S1, -S5, + S6, -S2, S2, -S6, -S6, S2, -S2, S6, + S7, -S5, S3, -S1, S1, -S3, S5, -S7 + } }; -static const uint8_t _jpeg_c_quant_table[] = { - 17, 18, 18, 24, 21, 24, 47, 26, - 26, 47, 99, 66, 56, 66, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99 -};*/ /* Public API */ @@ -88,24 +97,16 @@ void DecDCTReset(int32_t mode) { } void DecDCTPutEnv(const DECDCTENV *env, int32_t mono) { - const int16_t *dct = env ? env->dct : _default_idct_matrix; - const uint8_t *iq_y = env ? env->iq_y : _default_quant_table; - const uint8_t *iq_c = env ? env->iq_c : _default_quant_table; - + const DECDCTENV *_env = env ? env : &_default_mdec_env; DecDCTinSync(0); MDEC0 = 0x60000000; // Set IDCT matrix - DecDCTinRaw((const uint32_t *) dct, 32); + DecDCTinRaw((const uint32_t *) _env->dct, 32); DecDCTinSync(0); MDEC0 = 0x40000000 | (mono ? 0 : 1); // Set table(s) - DecDCTinRaw((const uint32_t *) iq_y, 16); + DecDCTinRaw((const uint32_t *) _env->iq_y, mono ? 16 : 32); DecDCTinSync(0); - - if (!mono) { - DecDCTinRaw((const uint32_t *) iq_c, 16); - DecDCTinSync(0); - } } void DecDCTin(const uint32_t *data, int32_t mode) { -- cgit v1.2.3 From 45168ae43e29aa5930ee5a206475ae836078915f Mon Sep 17 00:00:00 2001 From: spicyjpeg <88942473+spicyjpeg@users.noreply.github.com> Date: Wed, 23 Mar 2022 23:40:15 +0100 Subject: Add FPS counter to n00bdemo, more psxpad commands --- examples/demos/n00bdemo/main.c | 57 ++++++++++++++++++++++++--------------- examples/demos/n00bdemo/overlay.c | 33 +++++++++++++++++++++++ libpsn00b/include/psxpad.h | 10 ++++--- 3 files changed, 75 insertions(+), 25 deletions(-) (limited to 'libpsn00b/include') diff --git a/examples/demos/n00bdemo/main.c b/examples/demos/n00bdemo/main.c index 439bccc..069b549 100644 --- a/examples/demos/n00bdemo/main.c +++ b/examples/demos/n00bdemo/main.c @@ -11,6 +11,8 @@ * * Changelog: * + * Mar 24, 2022 - Added FPS counter. + * * Mar 12, 2022 - Added Konami System 573 support. * * May 10, 2021 - Variable types updated for psxgpu.h changes. @@ -21,8 +23,9 @@ * */ -// Comment to disable 573 support -#define SYSTEM_573_SUPPORT +// Uncomment to enable Konami System 573 support +// (seems to break the demo when loading it using Caetla on a cheat cartridge) +//#define SYSTEM_573_SUPPORT #include #include @@ -66,39 +69,50 @@ unsigned short font_tpage,font_clut; SPRT llotl_sprite; SPRT psn00b_sprite; +// Timer and FPS counter +volatile int timer_counter = 0, frame_counter = 0, frame_rate = 0; // Some function definition void sort_overlay(int showlotl); void lightdemo(); -#ifdef SYSTEM_573_SUPPORT -#define K573_WATCHDOG *((volatile uint16_t *) 0x1f5c0000) +#define K573_WATCHDOG *((volatile unsigned short *) 0x1f5c0000) #define K573_EXP1_CFG 0x24173f47 -/* - The only thing required to support the 573 is to periodically reset the - watchdog. Hooking the vblank IRQ (through VSyncCallback) is the "right" way - to do it, however using a hardware timer running at a higher rate (100 Hz) - seems to improve stability. -*/ -void reset573Watchdog() { +void timerTick() { + if (!(--timer_counter)) { + timer_counter = 100; + frame_rate = frame_counter; + frame_counter = 0; + } + +#ifdef SYSTEM_573_SUPPORT + /* + The only thing required to support the 573 is to periodically reset the + watchdog. Hooking the vblank IRQ (through VSyncCallback) is the "right" + way to do it, however using a hardware timer running at a higher rate + (100 Hz) seems to improve stability. + */ K573_WATCHDOG = 0; +#endif } -void system573Setup() { +void timerSetup() { EnterCriticalSection(); +#ifdef SYSTEM_573_SUPPORT EXP1_ADDR = 0x1f000000; EXP1_DELAY_SIZE = K573_EXP1_CFG; +#endif + TIMER_CTRL(2) = 0x0258; // CLK/8 input, IRQ on reload TIMER_RELOAD(2) = (F_CPU / 8) / 100; // 100 Hz // Configure timer 2 IRQ ChangeClearRCnt(2, 0); - InterruptCallback(6, &reset573Watchdog); + InterruptCallback(6, &timerTick); ExitCriticalSection(); } -#endif void UploadTIM(TIM_IMAGE *tim) { @@ -234,9 +248,7 @@ void unpackModels() { void init() { // Init display initDisplay(); -#ifdef SYSTEM_573_SUPPORT - system573Setup(); -#endif + timerSetup(); FntLoad( 960, 0 ); @@ -652,11 +664,11 @@ void transition() { if( comp >= 16 ) break; - // FIXME: for some reason this loop glitches out and hangs indefinitely - // in no$psx, *unless* there's a function somewhere that gets called - // with a pointer/string as first argument... wtf. It works fine in - // other emulators. If you are reading this, please help and enlighten - // me. -- spicyjpeg + /* + I haven't yet managed to figure out why this loop hangs on no$psx + if I comment out this completely useless call to puts(). Some + alignment or timing crap perhaps? -- spicyjpeg + */ puts("."); } @@ -681,6 +693,7 @@ int main(int argc, const char *argv[]) { unpackModels(); // Demo sequence loop + timer_counter = 100; while( 1 ) { lightdemo(); diff --git a/examples/demos/n00bdemo/overlay.c b/examples/demos/n00bdemo/overlay.c index 847bc96..0d2691f 100644 --- a/examples/demos/n00bdemo/overlay.c +++ b/examples/demos/n00bdemo/overlay.c @@ -7,6 +7,8 @@ extern const char scroll_text[]; extern unsigned short lamelotl_tpage,psn00b_tpage; extern unsigned short font_tpage,font_clut; +extern volatile int frame_counter, frame_rate; + extern SPRT llotl_sprite; extern SPRT psn00b_sprite; @@ -23,6 +25,35 @@ int scrolltext_pos = 640; int scrolltext_cpos = 0; int overlay_count = 0; +void sort_fps_counter() { + int tens = frame_rate / 10, units = frame_rate % 10; + int x = 10; + + SPRT_16 *spr16 = (SPRT_16 *) nextpri; + + setSprt16(spr16); + setSemiTrans(spr16, 1); + setXY0(spr16, x, 56); + setUV0(spr16, tens << 4, 16); + setRGB0(spr16, 20, 20, 20); + spr16->clut = font_clut; + addPrim(ot[db], spr16); + spr16++; + x += font_width[16 | tens]; + + setSprt16(spr16); + setSemiTrans(spr16, 1); + setXY0(spr16, x, 56); + setUV0(spr16, units << 4, 16); + setRGB0(spr16, 20, 20, 20); + spr16->clut = font_clut; + addPrim(ot[db], spr16); + spr16++; + + nextpri = (char *) spr16; + frame_counter++; +} + void sort_overlay(int showlotl) { SPRT *spr; @@ -31,6 +62,8 @@ void sort_overlay(int showlotl) { POLY_G4 *quad; LINE_G2 *line; + sort_fps_counter(); + int i = scrolltext_cpos; int j, k, tx, par_end = 0; diff --git a/libpsn00b/include/psxpad.h b/libpsn00b/include/psxpad.h index 9638ec1..32f7f8a 100644 --- a/libpsn00b/include/psxpad.h +++ b/libpsn00b/include/psxpad.h @@ -75,12 +75,16 @@ typedef enum { typedef enum { PAD_CMD_INIT_PRESSURE = '@', // Initialize DS2 button pressure sensors (in config mode) - PAD_CMD_READ = 'B', // Read pad state and set rumble + PAD_CMD_READ = 'B', // Read pad state (exchange poll request/response) PAD_CMD_CONFIG_MODE = 'C', // Toggle DualShock configuration mode PAD_CMD_SET_ANALOG = 'D', // Set analog mode/LED state (in config mode) PAD_CMD_GET_ANALOG = 'E', // Get analog mode/LED state (in config mode) - PAD_CMD_REQUEST_CONFIG = 'M', // Configure request/unlock vibration (in config mode) - PAD_CMD_RESPONSE_CONFIG = 'O', // Configure response/unlock DS2 pressure (in config mode) + PAD_CMD_GET_MOTOR_INFO = 'F', // Get information about a vibration motor (in config mode) + PAD_CMD_GET_MOTOR_LIST = 'G', // Get list of all vibration motors (in config mode) + PAD_CMD_GET_MOTOR_STATE = 'H', // Get current state of vibration motors (in config mode) + PAD_CMD_GET_MODE = 'L', // Get list of supported controller modes? (in config mode) + PAD_CMD_REQUEST_CONFIG = 'M', // Configure poll request format (in config mode) + PAD_CMD_RESPONSE_CONFIG = 'O', // Configure poll response format (in config mode) MCD_CMD_READ_SECTOR = 'R', // Read 128-byte sector MCD_CMD_IDENTIFY = 'S', // Retrieve ID and card size information (Sony cards only) -- cgit v1.2.3