shithub: psxe

Download patch

ref: 9edd01be58e6cb0fd023e396d560a142dddeb0c4
parent: 447b748dee0431007c9ec8899da38768060232e1
author: allkern <lisandroaalarcon@gmail.com>
date: Mon Sep 25 21:26:12 EDT 2023

Initial MCD implementation

--- a/.gitignore
+++ b/.gitignore
@@ -18,4 +18,5 @@
 *.toml
 *.zip
 *.cue
-*.iso
\ No newline at end of file
+*.iso
+*.mcd
\ No newline at end of file
--- a/frontend/main.c
+++ b/frontend/main.c
@@ -67,7 +67,8 @@
     psxi_sda_init(controller, SDA_MODEL_DIGITAL);
     psxi_sda_init_input(controller, input);
 
-    psx_pad_init_slot(psx->pad, 0, input);
+    psx_pad_attach_joy(psx->pad, 0, input);
+    psx_pad_attach_mcd(psx->pad, 0, "slot1.mcd");
 
     if (cfg->exe) {
         while (psx->cpu->pc != 0x80030000) {
@@ -95,9 +96,9 @@
     log_fatal("gp=%08x sp=%08x fp=%08x ra=%08x", cpu->r[28], cpu->r[29], cpu->r[30], cpu->r[31]);
     log_fatal("pc=%08x hi=%08x lo=%08x ep=%08x", cpu->pc, cpu->hi, cpu->lo, cpu->cop0_r[COP0_EPC]);
 
-    psx_input_destroy(input);
+    psx_pad_detach_joy(psx->pad, 0);
     psx_destroy(psx);
-    psxi_sda_destroy(controller);
+    //psxi_sda_destroy(controller);
     psxe_screen_destroy(screen);
 
     return 0;
--- a/psx/dev/input.c
+++ b/psx/dev/input.c
@@ -35,6 +35,7 @@
 }
 
 void psx_input_destroy(psx_input_t* input) {
+    free(input->udata);
     free(input);
 }
 
--- /dev/null
+++ b/psx/dev/mcd.c
@@ -1,0 +1,130 @@
+#include "mcd.h"
+#include "../log.h"
+
+psx_mcd_t* psx_mcd_create() {
+    return (psx_mcd_t*)malloc(sizeof(psx_mcd_t));
+}
+
+void psx_mcd_init(psx_mcd_t* mcd, const char* path) {
+    memset(mcd, 0, sizeof(psx_mcd_t));
+
+    mcd->state = MCD_STATE_TX_HIZ;
+    mcd->flag = 0x08;
+    mcd->path = path;
+    mcd->buf = malloc(MCD_MEMORY_SIZE);
+
+    memset(mcd->buf, 0, MCD_MEMORY_SIZE);
+
+    if (!path)
+        return;
+
+    FILE* file = fopen(path, "rb");
+
+    if (!file)
+        return;
+
+    fread(mcd->buf, 1, MCD_MEMORY_SIZE, file);
+
+    fclose(file);
+}
+
+uint8_t psx_mcd_read(psx_mcd_t* mcd) {
+    switch (mcd->state) {
+        case MCD_STATE_TX_HIZ: mcd->tx_data = 0xff; break;
+        case MCD_STATE_TX_FLG: mcd->tx_data = mcd->flag; break;
+        case MCD_STATE_TX_ID1: mcd->tx_data = 0x5a; break;
+        case MCD_STATE_TX_ID2: {
+            mcd->tx_data_ready = 1;
+            mcd->tx_data = 0x5d;
+
+            switch (mcd->mode) {
+                case 'R': mcd->state = MCD_R_STATE_RX_MSB; break;
+                case 'W': mcd->state = MCD_W_STATE_RX_MSB; break;
+                case 'S': mcd->state = MCD_S_STATE_TX_ACK1; break;
+            }
+
+            // log_set_quiet(0);
+            // log_fatal("mcd read %02x", mcd->tx_data);
+            // log_set_quiet(1);
+
+            return mcd->tx_data;
+        } break;
+
+        // Read states
+        case MCD_R_STATE_RX_MSB: mcd->tx_data = 0x00; break;
+        case MCD_R_STATE_RX_LSB: mcd->tx_data = mcd->msb; break;
+        case MCD_R_STATE_TX_ACK1: mcd->tx_data = 0x5c; break;
+        case MCD_R_STATE_TX_ACK2: mcd->tx_data = 0x5d; break;
+        case MCD_R_STATE_TX_MSB: mcd->tx_data = mcd->msb; mcd->checksum  = mcd->msb; break;
+        case MCD_R_STATE_TX_LSB: mcd->tx_data = mcd->lsb; mcd->checksum ^= mcd->lsb;
+                                 mcd->pending_bytes = 128; break;
+        case MCD_R_STATE_TX_DATA: {
+            --mcd->pending_bytes;
+
+            uint8_t data = mcd->buf[mcd->addr++];
+
+            mcd->checksum ^= data;
+
+            if (!mcd->pending_bytes) {
+                mcd->tx_data = data;
+
+                break;
+            }
+
+            // log_set_quiet(0);
+            // log_fatal("mcd read %02x", data);
+            // log_set_quiet(1);
+
+            return data;
+        } break;
+        case MCD_R_STATE_TX_CHK: mcd->tx_data = mcd->checksum; break;
+        case MCD_R_STATE_TX_MEB: {
+            mcd->tx_data_ready = 0;
+            mcd->state = MCD_STATE_TX_HIZ;
+
+            // log_set_quiet(0);
+            // log_fatal("mcd read %02x", 'G');
+            // log_set_quiet(1);
+
+            return 'G';
+        } break;
+    }
+
+    mcd->tx_data_ready = 1;
+    mcd->state++;
+
+    // log_set_quiet(0);
+    // log_fatal("mcd read %02x", mcd->tx_data);
+    // log_set_quiet(1);
+
+    return mcd->tx_data;
+}
+
+void psx_mcd_write(psx_mcd_t* mcd, uint8_t data) {
+    // log_set_quiet(0);
+    // log_fatal("mcd write %02x", data);
+    // log_set_quiet(1);
+
+    switch (mcd->state) {
+        case MCD_STATE_TX_FLG: mcd->mode = data; break;
+        case MCD_R_STATE_RX_MSB: mcd->msb = data; break;
+        case MCD_R_STATE_RX_LSB: {
+            mcd->lsb = data;
+            mcd->addr = ((mcd->msb << 8) | mcd->lsb) << 7;
+        } break;
+    }
+}
+
+int psx_mcd_query(psx_mcd_t* mcd) {
+    return mcd->tx_data_ready;
+}
+
+void psx_mcd_destroy(psx_mcd_t* mcd) {
+    FILE* file = fopen(mcd->path, "wb");
+
+    fwrite(mcd->buf, 1, MCD_MEMORY_SIZE, file);
+    fclose(file);
+
+    free(mcd->buf);
+    free(mcd);
+}
\ No newline at end of file
--- /dev/null
+++ b/psx/dev/mcd.h
@@ -1,0 +1,62 @@
+#ifndef MCD_H
+#define MCD_H
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#define MCD_MEMORY_SIZE 0x20000 // 128 KB
+
+enum {
+    MCD_STATE_TX_HIZ = 0,
+    MCD_STATE_TX_FLG,
+    MCD_STATE_TX_ID1,
+    MCD_STATE_TX_ID2,
+    MCD_R_STATE_RX_MSB,
+    MCD_R_STATE_RX_LSB,
+    MCD_R_STATE_TX_ACK1,
+    MCD_R_STATE_TX_ACK2,
+    MCD_R_STATE_TX_MSB,
+    MCD_R_STATE_TX_LSB,
+    MCD_R_STATE_TX_DATA,
+    MCD_R_STATE_TX_CHK,
+    MCD_R_STATE_TX_MEB,
+    MCD_W_STATE_RX_MSB,
+    MCD_W_STATE_RX_LSB,
+    MCD_W_STATE_RX_DATA,
+    MCD_W_STATE_RX_CHK,
+    MCD_W_STATE_TX_ACK1,
+    MCD_W_STATE_TX_ACK2,
+    MCD_W_STATE_TX_MEB,
+    MCD_S_STATE_TX_ACK1,
+    MCD_S_STATE_TX_ACK2,
+    MCD_S_STATE_TX_DAT0,
+    MCD_S_STATE_TX_DAT1,
+    MCD_S_STATE_TX_DAT2,
+    MCD_S_STATE_TX_DAT3
+};
+
+typedef struct {
+    const char* path;
+    uint8_t* buf;
+    uint8_t flag;
+    uint16_t msb;
+    uint16_t lsb;
+    uint16_t addr;
+    int pending_bytes;
+    char mode;
+    int state;
+    uint8_t tx_data;
+    int tx_data_ready;
+    uint8_t checksum;
+} psx_mcd_t;
+
+psx_mcd_t* psx_mcd_create();
+void psx_mcd_init(psx_mcd_t*, const char*);
+uint8_t psx_mcd_read(psx_mcd_t*);
+void psx_mcd_write(psx_mcd_t*, uint8_t);
+int psx_mcd_query(psx_mcd_t*);
+void psx_mcd_destroy(psx_mcd_t*);
+
+#endif
\ No newline at end of file
--- a/psx/dev/pad.c
+++ b/psx/dev/pad.c
@@ -6,28 +6,33 @@
 #include "../log.h"
 
 uint32_t pad_read_rx(psx_pad_t* pad) {
-    psx_input_t* current_slot = pad->slot[(pad->ctrl >> 13) & 1];
+    psx_input_t* joy = pad->joy_slot[(pad->ctrl >> 13) & 1];
+    psx_mcd_t* mcd = pad->mcd_slot[(pad->ctrl >> 13) & 1];
 
-    if (!current_slot || !pad->dest)
+    if ((!(joy || mcd)) || !pad->dest)
         return 0xffffffff;
 
-    if ((pad->ctrl & CTRL_JOUT) || (pad->ctrl & CTRL_RXEN)) {
-        switch (pad->dest) {
-            case DEST_JOY: {
-                uint8_t data = current_slot->read_func(current_slot->udata);
+    if (!(pad->ctrl & CTRL_JOUT) && !(pad->ctrl & CTRL_RXEN))
+        return 0xffffffff;
 
-                if (!current_slot->query_fifo_func(current_slot->udata))
-                    pad->dest = 0;
+    switch (pad->dest) {
+        case DEST_JOY: {
+            uint8_t data = joy->read_func(joy->udata);
 
-                return data;
-            } break;
+            if (!joy->query_fifo_func(joy->udata))
+                pad->dest = 0;
 
-            case DEST_MCD: {
+            return data;
+        } break;
+
+        case DEST_MCD: {
+            uint8_t data = psx_mcd_read(mcd);
+
+            if (!psx_mcd_query(mcd))
                 pad->dest = 0;
 
-                /* To-do */
-            } break;
-        }
+            return data;
+        } break;
     }
 
     return 0xffffffff;
@@ -34,9 +39,10 @@
 }
 
 void pad_write_tx(psx_pad_t* pad, uint16_t data) {
-    psx_input_t* current_slot = pad->slot[(pad->ctrl >> 13) & 1];
+    psx_input_t* joy = pad->joy_slot[(pad->ctrl >> 13) & 1];
+    psx_mcd_t* mcd = pad->mcd_slot[(pad->ctrl >> 13) & 1];
 
-    if (!current_slot || !(pad->ctrl & CTRL_TXEN))
+    if ((!(joy || mcd)) || !(pad->ctrl & CTRL_TXEN))
         return;
     
     pad->cycles_until_irq = 512;
@@ -47,29 +53,128 @@
     } else {
         switch (pad->dest) {
             case DEST_JOY: {
-                current_slot->write_func(current_slot->udata, data);
+                joy->write_func(joy->udata, data);
 
-                if (!current_slot->query_fifo_func(current_slot->udata))
+                if (!joy->query_fifo_func(joy->udata))
                     pad->dest = 0;
             } break;
 
             case DEST_MCD: {
-                pad->dest = 0;
+                psx_mcd_write(mcd, data);
 
-                /* To-do */
+                if (!psx_mcd_query(mcd))
+                    pad->dest = 0;
             } break;
         }
     }
 }
 
+// uint32_t pad_read_rx(psx_pad_t* pad) {
+//     // log_set_quiet(0);
+//     // log_fatal("pad read dest=%02x, jout=%u, rxen=%u, slot=%u",
+//     //     pad->dest,
+//     //     !!(pad->ctrl & CTRL_JOUT),
+//     //     !!(pad->ctrl & CTRL_RXEN),
+//     //     (pad->ctrl >> 13) & 1
+//     // );
+//     // log_set_quiet(1);
+
+//     if (!pad->dest || !(pad->ctrl & CTRL_JOUT))
+//         return 0xffffffff;
+
+//     // if ((!(pad->ctrl & CTRL_JOUT)) && (!(pad->ctrl & CTRL_RXEN)))
+//     //     return 0xffffffff;
+
+//     switch (pad->dest) {
+//         case DEST_JOY: {
+//             psx_input_t* joy = pad->joy_slot[(pad->ctrl >> 13) & 1];
+
+//             if (!joy)
+//                 return 0xffffffff;
+
+//             uint8_t data = joy->read_func(joy->udata);
+
+//             if (!joy->query_fifo_func(joy->udata))
+//                 pad->dest = 0;
+
+//             return data;
+//         } break;
+
+//         case DEST_MCD: {
+//             psx_mcd_t* mcd = pad->mcd_slot[(pad->ctrl >> 13) & 1];
+
+//             if (!mcd)
+//                 return 0xffffffff;
+
+//             uint8_t data = psx_mcd_read(mcd);
+
+//             if (!psx_mcd_query(mcd))
+//                 pad->dest = 0;
+
+//             return data;
+//         } break;
+//     }
+
+//     return 0xffffffff;
+// }
+
+// void pad_write_tx(psx_pad_t* pad, uint16_t data) {
+//     if (!(pad->ctrl & CTRL_TXEN))
+//         return;
+
+//     if (!pad->joy_slot[(pad->ctrl >> 13) & 1])
+//         return;
+
+//     log_set_quiet(0);
+//     log_fatal("pad write %02x", data);
+//     log_set_quiet(1);
+
+//     if (!pad->dest) {
+//         if ((data == DEST_JOY) || (data == DEST_MCD))
+//             pad->dest = data;
+
+//         return;
+//     }
+
+//     switch (pad->dest) {
+//         case DEST_JOY: {
+//             psx_input_t* joy = pad->joy_slot[(pad->ctrl >> 13) & 1];
+
+//             if (!joy)
+//                 return;
+
+//             pad->cycles_until_irq = 512;
+
+//             joy->write_func(joy->udata, data);
+
+//             if (!joy->query_fifo_func(joy->udata))
+//                 pad->dest = 0;
+//         } break;
+
+//         case DEST_MCD: {
+//             psx_mcd_t* mcd = pad->mcd_slot[(pad->ctrl >> 13) & 1];
+
+//             if (!mcd)
+//                 return;
+
+//             pad->cycles_until_irq = 512;
+            
+//             psx_mcd_write(mcd, data);
+
+//             if (!psx_mcd_query(mcd))
+//                 pad->dest = 0;
+//         } break;
+//     }
+// }
+
 uint32_t pad_handle_stat_read(psx_pad_t* pad) {
     return 0x07;
-    psx_input_t* current_slot = pad->slot[(pad->ctrl >> 13) & 1];
+    psx_input_t* joy = pad->joy_slot[(pad->ctrl >> 13) & 1];
 
-    if (!current_slot)
+    if (!joy)
         return 0x5 | pad->stat;
 
-    return 0x5 | (current_slot->query_fifo_func(current_slot->udata) << 1);
+    return 0x5 | (joy->query_fifo_func(joy->udata) << 1);
 }
 
 void pad_handle_ctrl_write(psx_pad_t* pad, uint32_t value) {
@@ -165,7 +270,7 @@
 }
 
 void psx_pad_button_press(psx_pad_t* pad, int slot, uint16_t data) {
-    psx_input_t* selected_slot = pad->slot[slot];
+    psx_input_t* selected_slot = pad->joy_slot[slot];
 
     if (selected_slot)
         selected_slot->on_button_press_func(selected_slot->udata, data);
@@ -172,16 +277,47 @@
 }
 
 void psx_pad_button_release(psx_pad_t* pad, int slot, uint16_t data) {
-    psx_input_t* selected_slot = pad->slot[slot];
+    psx_input_t* selected_slot = pad->joy_slot[slot];
 
     if (selected_slot)
         selected_slot->on_button_release_func(selected_slot->udata, data);
 }
 
-void psx_pad_init_slot(psx_pad_t* pad, int slot, psx_input_t* input) {
-    pad->slot[slot] = input;
+void psx_pad_attach_joy(psx_pad_t* pad, int slot, psx_input_t* input) {
+    if (pad->joy_slot[slot])
+        psx_pad_detach_joy(pad, slot);
+
+    pad->joy_slot[slot] = input;
 }
 
+void psx_pad_detach_joy(psx_pad_t* pad, int slot) {
+    if (!pad->joy_slot[slot])
+        return;
+
+    psx_input_destroy(pad->joy_slot[slot]);
+
+    pad->joy_slot[slot] = NULL;
+}
+
+void psx_pad_attach_mcd(psx_pad_t* pad, int slot, const char* path) {
+    if (pad->mcd_slot[slot])
+        psx_pad_detach_mcd(pad, slot);
+
+    psx_mcd_t* mcd = psx_mcd_create();
+    psx_mcd_init(mcd, path);
+
+    pad->mcd_slot[slot] = mcd;
+}
+
+void psx_pad_detach_mcd(psx_pad_t* pad, int slot) {
+    if (!pad->mcd_slot[slot])
+        return;
+
+    psx_mcd_destroy(pad->mcd_slot[slot]);
+
+    pad->mcd_slot[slot] = NULL;
+}
+
 void psx_pad_update(psx_pad_t* pad, int cyc) {
     if (pad->cycles_until_irq) {
         pad->cycles_until_irq -= cyc;
@@ -195,5 +331,10 @@
 }
 
 void psx_pad_destroy(psx_pad_t* pad) {
+    psx_pad_detach_joy(pad, 0);
+    psx_pad_detach_joy(pad, 1);
+    psx_pad_detach_mcd(pad, 0);
+    psx_pad_detach_mcd(pad, 1);
+
     free(pad);
 }
\ No newline at end of file
--- a/psx/dev/pad.h
+++ b/psx/dev/pad.h
@@ -5,6 +5,7 @@
 
 #include "ic.h"
 #include "input.h"
+#include "mcd.h"
 
 #define PSX_PAD_BEGIN 0x1f801040
 #define PSX_PAD_SIZE  0x10
@@ -115,7 +116,8 @@
     uint32_t io_base, io_size;
 
     psx_ic_t* ic;
-    psx_input_t* slot[2];
+    psx_input_t* joy_slot[2];
+    psx_mcd_t* mcd_slot[2];
 
     int enable_once;
     int cycles_until_irq;
@@ -136,7 +138,10 @@
 void psx_pad_destroy(psx_pad_t*);
 void psx_pad_button_press(psx_pad_t*, int, uint16_t);
 void psx_pad_button_release(psx_pad_t*, int, uint16_t);
-void psx_pad_init_slot(psx_pad_t*, int, psx_input_t*);
+void psx_pad_attach_joy(psx_pad_t*, int, psx_input_t*);
+void psx_pad_detach_joy(psx_pad_t*, int);
+void psx_pad_attach_mcd(psx_pad_t*, int, const char*);
+void psx_pad_detach_mcd(psx_pad_t*, int);
 void psx_pad_update(psx_pad_t*, int);
 
 #endif
\ No newline at end of file
--