A Playstation One (PS1) emulator fully written in Jam
4.6 kB
146 lines
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2026 Raphael Amorim
3
4const { irqRaise, IC_SIO } = import("irq");
5
6const CTRL_TXEN: u32 = 0x0001;
7const CTRL_DTR: u32 = 0x0002;
8const CTRL_RXEN: u32 = 0x0004;
9const CTRL_ACKN: u32 = 0x0010;
10const CTRL_RESET: u32 = 0x0040;
11const CTRL_TX_IE: u32 = 0x0400;
12const CTRL_RX_IE: u32 = 0x0800;
13const CTRL_DSR_IE: u32 = 0x1000;
14
15const STAT_TXR1: u32 = 0x0001;
16const STAT_RXNE: u32 = 0x0002;
17const STAT_TXR2: u32 = 0x0004;
18const STAT_PERR: u32 = 0x0008;
19const STAT_OVERR: u32 = 0x0010;
20const STAT_BSB: u32 = 0x0020;
21const STAT_IRQ: u32 = 0x0200;
22
23const SIO_IRQ_DELAY: u32 = 200;
24
25pub const Sio1 = struct {
26 stat: u32,
27 mode: u16,
28 ctrl: u16,
29 baud: u16,
30 rxFifo: [8]u8,
31 rxHead: u8,
32 rxTail: u8,
33 txPending: u8,
34 cyclesUntilIrq: u32,
35 pad: [16]u8,
36
37 pub fn init() Self {
38 return Self {
39 stat: 0, mode: 0, ctrl: 0, baud: 0,
40 rxFifo: [0, 0, 0, 0, 0, 0, 0, 0],
41 rxHead: 0, rxTail: 0, txPending: 0,
42 cyclesUntilIrq: 0,
43 pad: [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
44 };
45 }
46
47 pub fn rxPush(self: mut Self, b: u32) {
48 const tail: u32 = self.rxTail as u32;
49 self.rxFifo[tail & 0x07] = (b & 0xFF) as u8;
50 self.rxTail = ((tail + 1) & 0xFF) as u8;
51 }
52
53 pub fn rxPop(self: mut Self) u32 {
54 var head: u32 = self.rxHead as u32;
55 const tail: u32 = self.rxTail as u32;
56 if (head == tail) { return 0xFF; }
57 const b: u32 = self.rxFifo[head & 0x07] as u32;
58 head = (head + 1) & 0xFF;
59 self.rxHead = head as u8;
60 return b;
61 }
62
63 pub fn rxEmpty(self: Self) bool {
64 return self.rxHead == self.rxTail;
65 }
66
67 pub fn readStat(self: Self) u32 {
68 var stat: u32 = self.stat;
69 stat = stat | STAT_TXR1;
70 if (self.txPending == 0) { stat = stat | STAT_TXR2; }
71 if (!self.rxEmpty()) { stat = stat | STAT_RXNE; }
72 return stat;
73 }
74
75 pub fn writeData(self: mut Self, val: u32) {
76 if ((self.ctrl as u32 & CTRL_TXEN) == 0) { return; }
77 self.rxPush(0xFF);
78 self.txPending = 1;
79 self.cyclesUntilIrq = SIO_IRQ_DELAY;
80 }
81
82 pub fn writeCtrl(self: mut Self, val: u32) {
83 const v: u32 = val & 0xFFFF;
84 if ((v & CTRL_RESET) != 0) {
85 const mode: u16 = self.mode;
86 const baud: u16 = self.baud;
87 self.stat = 0;
88 self.ctrl = 0;
89 self.rxFifo = [0, 0, 0, 0, 0, 0, 0, 0];
90 self.rxHead = 0;
91 self.rxTail = 0;
92 self.txPending = 0;
93 self.cyclesUntilIrq = 0;
94 self.mode = mode;
95 self.baud = baud;
96 return;
97 }
98 self.ctrl = v as u16;
99 if ((v & CTRL_ACKN) != 0) {
100 self.stat = self.stat & (~(STAT_PERR | STAT_OVERR | STAT_BSB | STAT_IRQ));
101 self.ctrl = self.ctrl & ((~CTRL_ACKN) as u16);
102 }
103 }
104
105 pub fn read32(self: mut Self, off: u32) u32 {
106 match (off) {
107 0x00 { return self.rxPop(); }
108 0x04 { return self.readStat(); }
109 0x08 { return self.mode as u32; }
110 0x0A { return self.ctrl as u32; }
111 0x0E { return self.baud as u32; }
112 _ { return 0; }
113 }
114 }
115
116 pub fn read16(self: mut Self, off: u32) u32 { return self.read32(off) & 0xFFFF; }
117 pub fn read8(self: mut Self, off: u32) u32 { return self.read32(off) & 0xFF; }
118
119 pub fn write32(self: mut Self, off: u32, val: u32) {
120 match (off) {
121 0x00 { self.writeData(val); }
122 0x08 { self.mode = (val & 0xFFFF) as u16; }
123 0x0A { self.writeCtrl(val); }
124 0x0E { self.baud = (val & 0xFFFF) as u16; }
125 _ {}
126 }
127 }
128
129 pub fn write16(self: mut Self, off: u32, val: u32) { self.write32(off, val & 0xFFFF); }
130 pub fn write8(self: mut Self, off: u32, val: u32) { self.write32(off, val & 0xFF); }
131
132 pub fn update(self: mut Self, ic: *mut[] u32, cop0: *mut[] u32, cyc: u32) {
133 if (self.cyclesUntilIrq == 0) { return; }
134 if (self.cyclesUntilIrq > cyc) {
135 self.cyclesUntilIrq = self.cyclesUntilIrq - cyc;
136 return;
137 }
138 self.cyclesUntilIrq = 0;
139 self.txPending = 0;
140 const ctrl: u32 = self.ctrl as u32;
141 if ((ctrl & (CTRL_TX_IE | CTRL_RX_IE)) != 0) {
142 self.stat = self.stat | STAT_IRQ;
143 irqRaise(ic, cop0, IC_SIO);
144 }
145 }
146};