Skip to content

Commit aaaf446

Browse files
committed
interrupt-based working. wip
1 parent 31e7308 commit aaaf446

File tree

4 files changed

+91
-51
lines changed

4 files changed

+91
-51
lines changed

pyboy/__main__.py

+6-3
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,10 @@ def valid_sample_rate(freq):
109109

110110
parser.add_argument("--serial-bind", action="store_true", help="Bind to this TCP addres for using Link Cable")
111111
parser.add_argument(
112-
"--serial-address", default=None, type=str, help="Connect (or bind) to this TCP addres for using Link Cable"
112+
"--serial-address", default=None, type=str, help="Connect (or bind) to this TCP address for using Link Cable"
113+
)
114+
parser.add_argument(
115+
"--serial-interrupt-based", action="store_true", help="Use only interrupt-based transfers for using Link Cable"
113116
)
114117

115118
gameboy_type_parser = parser.add_mutually_exclusive_group()
@@ -165,8 +168,8 @@ def valid_sample_rate(freq):
165168
def main():
166169
argv = parser.parse_args()
167170

168-
if argv.serial_bind and not argv.serial_address:
169-
parser.error("--serial-bind requires --serial-address")
171+
if (argv.serial_bind or argv.serial_interrupt_based) and not argv.serial_address:
172+
parser.error("--serial-bind and --serial-interrupt-based requires --serial-address")
170173

171174
print(
172175
"""

pyboy/core/mb.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ def __init__(
3434
randomize=False,
3535
serial_address=None,
3636
serial_bind=None,
37+
serial_interrupt_based=False,
3738
):
3839
if bootrom_file is not None:
3940
logger.info("Boot-ROM file provided")
@@ -54,7 +55,7 @@ def __init__(
5455
self.interaction = interaction.Interaction()
5556
self.ram = ram.RAM(cgb, randomize=randomize)
5657
self.cpu = cpu.CPU(self)
57-
self.serial = serial.Serial(serial_address, serial_bind)
58+
self.serial = serial.Serial(serial_address, serial_bind, serial_interrupt_based)
5859

5960
if cgb:
6061
self.lcd = lcd.CGBLCD(

pyboy/core/serial.py

+77-45
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,26 @@
11
import logging
22
import os
3+
import queue
34
import socket
45
import sys
6+
import threading
57

68
logger = logging.getLogger(__name__)
79

810
SERIAL_FREQ = 8192 # Hz
911
CPU_FREQ = 4213440 # Hz
1012

13+
async_recv = queue.Queue()
14+
15+
16+
def async_comms(socket):
17+
while True:
18+
item = socket.recv(1)
19+
async_recv.put(item)
20+
1121

1222
class Serial:
13-
def __init__(self, serial_address, serial_bind, serial_interrupt_based=True):
23+
def __init__(self, serial_address, serial_bind, serial_interrupt_based):
1424
self.SB = 0
1525
self.SC = 0
1626
self.connection = None
@@ -44,69 +54,91 @@ def __init__(self, serial_address, serial_bind, serial_interrupt_based=True):
4454
logger.info(f"Connecting to {serial_address}")
4555
self.connection.connect(address_tuple)
4656
logger.info(f"Connection successful!")
47-
# self.connection.setblocking(False)
4857

49-
def tick(self, cycles):
5058
# if self.serial_interrupt_based:
51-
# if self.SC & 1: # Master
52-
# if self.SC & 0x80:
53-
# logger.info(f'Master sending!')
54-
# self.connection.send(bytes([self.SB]))
55-
# # self.connection.setblocking(True)
56-
# data = self.connection.recv(1)
57-
# self.SB = data[0]
58-
# self.SC &= 0b0111_1111
59-
# return True
60-
# else:
61-
# try:
62-
# if self.SC & 0x80:
63-
# # self.connection.setblocking(False)
64-
# logger.info(f'Slave recv!')
65-
# self.connection.send(bytes([self.SB]))
66-
# data = self.connection.recv(1)
67-
# self.SB = data[0]
68-
# self.SC &= 0b0111_1111
69-
# return True
70-
# except BlockingIOError:
71-
# pass
72-
# return False
73-
# return False
74-
# else:
75-
# Check if serial is in progress
59+
# logger.info("Interrupt-based serial emulation active!")
60+
# self.recv_thread = threading.Thread(target=async_comms, args=(self.connection,))
61+
# self.recv_thread.start()
7662

63+
def tick(self, cycles):
7764
if self.connection is None:
7865
return
7966

80-
if self.SC & 0x80 == 0:
67+
# self.cycles_count += 1
68+
69+
if self.serial_interrupt_based:
70+
if self.SC & 0x80 == 0: # Performance optimization. Games might not set this on slave
71+
return False
72+
73+
self.cycles_count += 1
74+
75+
if (self.cycles_to_transmit() == 0):
76+
if self.SC & 1: # Master
77+
if self.SC & 0x80:
78+
logger.info(f"Master sending!")
79+
self.connection.send(bytes([self.SB]))
80+
data = self.connection.recv(1)
81+
self.SB = data[0]
82+
self.SC &= 0b0111_1111
83+
self.cycles_count = 0
84+
return True
85+
else:
86+
# try:
87+
# data = async_recv.get(block=False)
88+
# except queue.Empty:
89+
# return False
90+
try:
91+
data = self.connection.recv(1, socket.MSG_DONTWAIT)
92+
except BlockingIOError:
93+
return False
94+
95+
logger.info(f"Slave recv!")
96+
self.connection.send(bytes([self.SB]))
97+
# data = self.connection.recv(1)
98+
self.SB = data[0]
99+
self.SC &= 0b0111_1111
100+
self.cycles_count = 0
101+
return True
81102
return False
103+
else:
104+
# Check if serial is in progress
105+
if self.SC & 0x80 == 0:
106+
return False
82107

83-
self.cycles_count += 1
108+
self.cycles_count += 1
84109

85-
if (self.cycles_to_transmit() == 0):
86-
# if self.SC & 1: # Master
87-
send_bit = bytes([(self.SB >> 7) & 1])
88-
self.connection.send(send_bit)
110+
if (self.cycles_to_transmit() == 0):
111+
# if self.SC & 1: # Master
112+
send_bit = bytes([(self.SB >> 7) & 1])
113+
self.connection.send(send_bit)
89114

90-
data = self.connection.recv(1)
91-
self.SB = ((self.SB << 1) & 0xFF) | data[0] & 1
115+
data = self.connection.recv(1)
116+
self.SB = ((self.SB << 1) & 0xFF) | data[0] & 1
92117

93-
logger.info(f"recv sb: {self.SB:08b}")
94-
self.trans_bits += 1
118+
logger.info(f"recv sb: {self.SB:08b}")
119+
self.trans_bits += 1
95120

96-
self.cycles_count = 0
121+
self.cycles_count = 0
97122

98-
if self.trans_bits == 8:
99-
self.trans_bits = 0
100-
self.SC &= 0b0111_1111
101-
return True
123+
if self.trans_bits == 8:
124+
self.trans_bits = 0
125+
self.SC &= 0b0111_1111
126+
return True
127+
return False
102128
return False
103129

104130
def cycles_to_transmit(self):
105-
if self.SC & 0x80:
106-
return max(self.cycles_target - self.cycles_count, 0)
131+
if self.connection:
132+
if self.SC & 0x80:
133+
return max(self.cycles_target - self.cycles_count, 0)
134+
# return CPU_FREQ // SERIAL_FREQ
135+
else:
136+
return 1 << 16
107137
else:
108138
return 1 << 16
109139

110140
def stop(self):
111141
if self.connection:
112142
self.connection.close()
143+
# if self.serial_interrupt_based and self.recv_thread:
144+
# self.recv_thread.kill()

pyboy/pyboy.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ def __init__(
9292
color_palette=defaults["color_palette"],
9393
cgb_color_palette=defaults["cgb_color_palette"],
9494
title_status=False,
95+
serial_address=None,
96+
serial_bind=None,
97+
serial_interrupt_based=False,
9598
**kwargs,
9699
):
97100
"""
@@ -209,8 +212,9 @@ def __init__(
209212
sound_sample_rate,
210213
cgb,
211214
randomize=randomize,
212-
serial_address=kwargs["serial_address"],
213-
serial_bind=kwargs["serial_bind"],
215+
serial_address=serial_address,
216+
serial_bind=serial_bind,
217+
serial_interrupt_based=serial_interrupt_based,
214218
)
215219

216220
# Validate all kwargs

0 commit comments

Comments
 (0)