1.1 --- a/ula.py Mon Jun 20 21:32:22 2016 +0200
1.2 +++ b/ula.py Mon Jun 20 23:17:48 2016 +0200
1.3 @@ -112,6 +112,7 @@
1.4 self.row_address = 0
1.5 self.column_address = 0
1.6 self.data = 0
1.7 + self.read_not_write = 1
1.8
1.9 def row_select(self, address):
1.10
1.11 @@ -130,11 +131,20 @@
1.12
1.13 # Read the data.
1.14
1.15 - self.data = self.memory[self.row_address << 8 | self.column_address]
1.16 + if self.read_not_write:
1.17 + self.data = self.memory[self.row_address << 8 | self.column_address]
1.18 + else:
1.19 + self.memory[self.row_address << 8 | self.column_address] = self.data
1.20
1.21 def column_deselect(self):
1.22 pass
1.23
1.24 + def read_select(self):
1.25 + self.read_not_write = 1
1.26 +
1.27 + def write_select(self):
1.28 + self.read_not_write = 0
1.29 +
1.30 # Convenience methods.
1.31
1.32 def fill(self, start, end, value):
1.33 @@ -142,6 +152,14 @@
1.34 self.memory[i << 1] = value >> 4
1.35 self.memory[i << 1 | 0x1] = value & 0xf
1.36
1.37 +class CPU:
1.38 +
1.39 + "A CPU abstraction."
1.40 +
1.41 + def __init__(self):
1.42 + self.address = 0x1000
1.43 + self.read_not_write = 1
1.44 +
1.45 class ULA:
1.46
1.47 """
1.48 @@ -157,10 +175,11 @@
1.49 (320, 1, 25)
1.50 ]
1.51
1.52 - def __init__(self, ram, video):
1.53 + def __init__(self, cpu, ram, video):
1.54
1.55 - "Initialise the ULA with the given 'ram' and 'video' instances."
1.56 + "Initialise the ULA with the given 'cpu', 'ram' and 'video' instances."
1.57
1.58 + self.cpu = cpu
1.59 self.ram = ram
1.60 self.video = video
1.61 self.set_mode(6)
1.62 @@ -176,6 +195,7 @@
1.63
1.64 self.nmi = 0 # no NMI asserted initially
1.65 self.irq_vsync = 0 # no IRQ asserted initially
1.66 + self.cpu_clock = 0 # drive the CPU clock low
1.67
1.68 # Communication.
1.69
1.70 @@ -390,6 +410,13 @@
1.71
1.72 self.ram.column_select(self.ram_address)
1.73
1.74 + # Assert the RAM write enable if appropriate.
1.75 +
1.76 + if access_ram:
1.77 + self.ram.read_select()
1.78 + else:
1.79 + self.cpu_transfer_select()
1.80 +
1.81 # Read 4 bits (for ULA access only).
1.82
1.83 elif self.cycle == 8:
1.84 @@ -448,6 +475,11 @@
1.85
1.86 self.access = (self.access + 1) % self.access_frequency
1.87
1.88 + # Read the CPU address, if appropriate.
1.89 +
1.90 + if not access_ram:
1.91 + self.cpu_update_clock()
1.92 +
1.93
1.94
1.95 # Pixel production.
1.96 @@ -512,10 +544,37 @@
1.97 def cpu_transfer_high(self):
1.98 if self.cpu_read:
1.99 self.cpu_data = self.ram.data << 4
1.100 + else:
1.101 + self.ram.data = self.cpu_data >> 4
1.102
1.103 def cpu_transfer_low(self):
1.104 if self.cpu_read:
1.105 self.cpu_data = self.data | self.ram.data
1.106 + else:
1.107 + self.ram.data = self.cpu_data & 0b00001111
1.108 +
1.109 + def cpu_read_address(self):
1.110 + self.cpu_address = self.cpu.address
1.111 +
1.112 + def cpu_transfer_data(self):
1.113 + if self.cpu_read:
1.114 + self.cpu.data = self.cpu_data
1.115 + else:
1.116 + self.cpu_data = self.cpu.data
1.117 +
1.118 + def cpu_update_clock(self):
1.119 + self.cpu_clock = not self.cpu_clock
1.120 + if self.cpu_clock:
1.121 + self.cpu_transfer_data()
1.122 + else:
1.123 + self.cpu_read_address()
1.124 +
1.125 + def cpu_transfer_select(self):
1.126 + self.cpu_read = self.cpu.read_not_write
1.127 + if self.cpu_read:
1.128 + self.ram.read_select()
1.129 + else:
1.130 + self.ram.write_select()
1.131
1.132 def rotate(value, depth, width=8, zero=False):
1.133
1.134 @@ -595,7 +654,7 @@
1.135
1.136 "Return a ULA initialised with a memory array and video."
1.137
1.138 - return ULA(get_ram(), get_video())
1.139 + return ULA(get_cpu(), get_ram(), get_video())
1.140
1.141 def get_video():
1.142
1.143 @@ -609,6 +668,12 @@
1.144
1.145 return RAM()
1.146
1.147 +def get_cpu():
1.148 +
1.149 + "Return an instance representing the CPU."
1.150 +
1.151 + return CPU()
1.152 +
1.153 # Test program providing coverage (necessary for compilers like Shedskin).
1.154
1.155 if __name__ == "__main__":