Skip to content

Commit

Permalink
interrupt-based working. wip
Browse files Browse the repository at this point in the history
  • Loading branch information
Baekalfen committed Sep 6, 2024
1 parent 3fa5cef commit 473a1d5
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 51 deletions.
9 changes: 6 additions & 3 deletions pyboy/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,10 @@ def valid_file_path(path):

parser.add_argument("--serial-bind", action="store_true", help="Bind to this TCP addres for using Link Cable")
parser.add_argument(
"--serial-address", default=None, type=str, help="Connect (or bind) to this TCP addres for using Link Cable"
"--serial-address", default=None, type=str, help="Connect (or bind) to this TCP address for using Link Cable"
)
parser.add_argument(
"--serial-interrupt-based", action="store_true", help="Use only interrupt-based transfers for using Link Cable"
)

gameboy_type_parser = parser.add_mutually_exclusive_group()
Expand All @@ -111,8 +114,8 @@ def valid_file_path(path):
def main():
argv = parser.parse_args()

if argv.serial_bind and not argv.serial_address:
parser.error("--serial-bind requires --serial-address")
if (argv.serial_bind or argv.serial_interrupt_based) and not argv.serial_address:
parser.error("--serial-bind and --serial-interrupt-based requires --serial-address")

print(
"""
Expand Down
3 changes: 2 additions & 1 deletion pyboy/core/mb.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ def __init__(
randomize=False,
serial_address=None,
serial_bind=None,
serial_interrupt_based=False,
):
if bootrom_file is not None:
logger.info("Boot-ROM file provided")
Expand All @@ -44,7 +45,7 @@ def __init__(
self.bootrom = bootrom.BootROM(bootrom_file, cgb)
self.ram = ram.RAM(cgb, randomize=randomize)
self.cpu = cpu.CPU(self)
self.serial = serial.Serial(serial_address, serial_bind)
self.serial = serial.Serial(serial_address, serial_bind, serial_interrupt_based)

if cgb:
self.lcd = lcd.CGBLCD(
Expand Down
122 changes: 77 additions & 45 deletions pyboy/core/serial.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
import logging
import os
import queue
import socket
import sys
import threading

logger = logging.getLogger(__name__)

SERIAL_FREQ = 8192 # Hz
CPU_FREQ = 4213440 # Hz

async_recv = queue.Queue()


def async_comms(socket):
while True:
item = socket.recv(1)
async_recv.put(item)


class Serial:
def __init__(self, serial_address, serial_bind, serial_interrupt_based=True):
def __init__(self, serial_address, serial_bind, serial_interrupt_based):
self.SB = 0
self.SC = 0
self.connection = None
Expand Down Expand Up @@ -44,69 +54,91 @@ def __init__(self, serial_address, serial_bind, serial_interrupt_based=True):
logger.info(f"Connecting to {serial_address}")
self.connection.connect(address_tuple)
logger.info(f"Connection successful!")
# self.connection.setblocking(False)

def tick(self, cycles):
# if self.serial_interrupt_based:
# if self.SC & 1: # Master
# if self.SC & 0x80:
# logger.info(f'Master sending!')
# self.connection.send(bytes([self.SB]))
# # self.connection.setblocking(True)
# data = self.connection.recv(1)
# self.SB = data[0]
# self.SC &= 0b0111_1111
# return True
# else:
# try:
# if self.SC & 0x80:
# # self.connection.setblocking(False)
# logger.info(f'Slave recv!')
# self.connection.send(bytes([self.SB]))
# data = self.connection.recv(1)
# self.SB = data[0]
# self.SC &= 0b0111_1111
# return True
# except BlockingIOError:
# pass
# return False
# return False
# else:
# Check if serial is in progress
# logger.info("Interrupt-based serial emulation active!")
# self.recv_thread = threading.Thread(target=async_comms, args=(self.connection,))
# self.recv_thread.start()

def tick(self, cycles):
if self.connection is None:
return

if self.SC & 0x80 == 0:
# self.cycles_count += 1

if self.serial_interrupt_based:
if self.SC & 0x80 == 0: # Performance optimization. Games might not set this on slave
return False

self.cycles_count += 1

if (self.cycles_to_transmit() == 0):
if self.SC & 1: # Master
if self.SC & 0x80:
logger.info(f"Master sending!")
self.connection.send(bytes([self.SB]))
data = self.connection.recv(1)
self.SB = data[0]
self.SC &= 0b0111_1111
self.cycles_count = 0
return True
else:
# try:
# data = async_recv.get(block=False)
# except queue.Empty:
# return False
try:
data = self.connection.recv(1, socket.MSG_DONTWAIT)
except BlockingIOError:
return False

logger.info(f"Slave recv!")
self.connection.send(bytes([self.SB]))
# data = self.connection.recv(1)
self.SB = data[0]
self.SC &= 0b0111_1111
self.cycles_count = 0
return True
return False
else:
# Check if serial is in progress
if self.SC & 0x80 == 0:
return False

self.cycles_count += 1
self.cycles_count += 1

if (self.cycles_to_transmit() == 0):
# if self.SC & 1: # Master
send_bit = bytes([(self.SB >> 7) & 1])
self.connection.send(send_bit)
if (self.cycles_to_transmit() == 0):
# if self.SC & 1: # Master
send_bit = bytes([(self.SB >> 7) & 1])
self.connection.send(send_bit)

data = self.connection.recv(1)
self.SB = ((self.SB << 1) & 0xFF) | data[0] & 1
data = self.connection.recv(1)
self.SB = ((self.SB << 1) & 0xFF) | data[0] & 1

logger.info(f"recv sb: {self.SB:08b}")
self.trans_bits += 1
logger.info(f"recv sb: {self.SB:08b}")
self.trans_bits += 1

self.cycles_count = 0
self.cycles_count = 0

if self.trans_bits == 8:
self.trans_bits = 0
self.SC &= 0b0111_1111
return True
if self.trans_bits == 8:
self.trans_bits = 0
self.SC &= 0b0111_1111
return True
return False
return False

def cycles_to_transmit(self):
if self.SC & 0x80:
return max(self.cycles_target - self.cycles_count, 0)
if self.connection:
if self.SC & 0x80:
return max(self.cycles_target - self.cycles_count, 0)
# return CPU_FREQ // SERIAL_FREQ
else:
return 1 << 16
else:
return 1 << 16

def stop(self):
if self.connection:
self.connection.close()
# if self.serial_interrupt_based and self.recv_thread:
# self.recv_thread.kill()
8 changes: 6 additions & 2 deletions pyboy/pyboy.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ def __init__(
sound_emulated=False,
cgb=None,
log_level=defaults["log_level"],
serial_address=None,
serial_bind=None,
serial_interrupt_based=False,
**kwargs
):
"""
Expand Down Expand Up @@ -143,8 +146,9 @@ def __init__(
sound_emulated,
cgb,
randomize=randomize,
serial_address=kwargs["serial_address"],
serial_bind=kwargs["serial_bind"],
serial_address=serial_address,
serial_bind=serial_bind,
serial_interrupt_based=serial_interrupt_based,
)

# Validate all kwargs
Expand Down

0 comments on commit 473a1d5

Please sign in to comment.