aboutsummaryrefslogtreecommitdiff
path: root/libpsn00b/psxpress/mdec.c
diff options
context:
space:
mode:
authorJohn "Lameguy" Wilbert Villamor <lameguy64@gmail.com>2022-03-25 09:22:20 +0800
committerGitHub <noreply@github.com>2022-03-25 09:22:20 +0800
commit975e614b3c840e2f717adac1d1cb9cee4e5e561b (patch)
tree6584ce5b0dbe27a466c95c81fac61b0d90f627bd /libpsn00b/psxpress/mdec.c
parent05d44488bd5587786f4bd0286fc0f555c79aa46a (diff)
parent45168ae43e29aa5930ee5a206475ae836078915f (diff)
downloadpsn00bsdk-975e614b3c840e2f717adac1d1cb9cee4e5e561b.tar.gz
Merge pull request #46 from spicyjpeg/psxmdec
Critical ldscript fixes, initial MDEC support and CI updates
Diffstat (limited to 'libpsn00b/psxpress/mdec.c')
-rw-r--r--libpsn00b/psxpress/mdec.c173
1 files changed, 173 insertions, 0 deletions
diff --git a/libpsn00b/psxpress/mdec.c b/libpsn00b/psxpress/mdec.c
new file mode 100644
index 0000000..ca4c75a
--- /dev/null
+++ b/libpsn00b/psxpress/mdec.c
@@ -0,0 +1,173 @@
+/*
+ * PSn00bSDK MDEC library (low-level MDEC/DMA API)
+ * (C) 2022 spicyjpeg - MPL licensed
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <psxapi.h>
+#include <psxpress.h>
+#include <hwregs_c.h>
+
+#define MDEC_SYNC_TIMEOUT 0x1000000
+
+/* 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
+#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 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
+ }
+};
+
+/* 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 DECDCTENV *_env = env ? env : &_default_mdec_env;
+ DecDCTinSync(0);
+
+ MDEC0 = 0x60000000; // Set IDCT matrix
+ DecDCTinRaw((const uint32_t *) _env->dct, 32);
+ DecDCTinSync(0);
+
+ MDEC0 = 0x40000000 | (mono ? 0 : 1); // Set table(s)
+ DecDCTinRaw((const uint32_t *) _env->iq_y, mono ? 16 : 32);
+ 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;
+}