A Playstation One (PS1) emulator fully written in Jam
0

Configure Feed

Select the types of activity you want to include in your feed.

jamstation / sio1.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};