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 15, 2022
1 parent 966124a commit 091fac4
Show file tree
Hide file tree
Showing 4 changed files with 88 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 @@ -76,7 +76,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 @@ -96,8 +99,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")

log_level(argv.log_level)

Expand Down
3 changes: 2 additions & 1 deletion pyboy/core/mb.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ def __init__(
profiling=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 @@ -45,7 +46,7 @@ def __init__(
self.bootrom = bootrom.BootROM(bootrom_file, cgb)
self.ram = ram.RAM(cgb, randomize=randomize)
self.cpu = cpu.CPU(self, profiling)
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()
5 changes: 3 additions & 2 deletions pyboy/pyboy.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,9 @@ def __init__(
cgb,
randomize=randomize,
profiling=profiling,
serial_address=kwargs["serial_address"],
serial_bind=kwargs["serial_bind"],
serial_address=kwargs.get("serial_address"),
serial_bind=kwargs.get("serial_bind"),
serial_interrupt_based=kwargs.get("serial_interrupt_based"),
)

# Performance measures
Expand Down

0 comments on commit 091fac4

Please sign in to comment.