1.1 --- a/ula.py Sun Feb 26 23:19:22 2012 +0100
1.2 +++ b/ula.py Sun Apr 28 23:01:53 2013 +0200
1.3 @@ -82,10 +82,10 @@
1.4
1.5 """
1.6 A class representing the RAM circuits (IC4 to IC7). Each circuit
1.7 - traditionally holds 64 kilobits, with two accesses required to read 2 bits
1.8 - from each in order to obtain a whole byte. Here, we model the circuits with
1.9 - a list of 65536 half-bytes with each bit representing a bit stored on a
1.10 - separate IC.
1.11 + traditionally holds 64 kilobits, with each access obtaining 1 bit from each
1.12 + IC, and thus two accesses being required to obtain a whole byte. Here, we
1.13 + model the circuits with a list of 65536 half-bytes with each bit in a
1.14 + half-byte representing a bit stored on a separate IC.
1.15 """
1.16
1.17 def __init__(self):
1.18 @@ -98,12 +98,18 @@
1.19 self.data = 0
1.20
1.21 def row_select(self, address):
1.22 +
1.23 + "The operation of asserting a row 'address' via RA0...RA7."
1.24 +
1.25 self.row_address = address
1.26
1.27 def row_deselect(self):
1.28 pass
1.29
1.30 def column_select(self, address):
1.31 +
1.32 + "The operation of asserting a column 'address' via RA0...RA7."
1.33 +
1.34 self.column_address = address
1.35
1.36 # Read the data.
1.37 @@ -158,15 +164,22 @@
1.38 self.nmi = 0 # no NMI asserted initially
1.39 self.irq_vsync = 0 # no IRQ asserted initially
1.40
1.41 + # Communication.
1.42 +
1.43 + self.ram_address = 0 # address given to the RAM via RA0...RA7
1.44 + self.data = 0 # data read from the RAM via RAM0...RAM3
1.45 + self.cpu_address = 0 # address selected by the CPU via A0...A15
1.46 + self.cpu_read = 0 # data read/write by the CPU selected using R/W
1.47 +
1.48 # Internal state.
1.49
1.50 - self.cycle = 0 # counter within each 2MHz period
1.51 + self.cycle = [0]*8 # counter within each 2MHz period represented by 8 latches
1.52 self.access = 0 # counter used to determine whether a byte needs reading
1.53 - self.ram_address = 0 # address given to the RAM
1.54 - self.data = 0 # data read from the RAM
1.55 - self.buffer = [BLANK]*8 # pixel buffer for decoded RAM data
1.56 self.have_pixels = 0 # whether pixel data has been read
1.57 self.writing_pixels = 0 # whether pixel data can be written
1.58 + self.buffer = [BLANK]*8 # pixel buffer for decoded RAM data
1.59 +
1.60 + self.cycle[7] = 1 # assert the final latch (asserting the first on update)
1.61
1.62 self.reset_vertical()
1.63
1.64 @@ -310,14 +323,25 @@
1.65
1.66 access_ram = not self.nmi and self.access == 0 and self.read_pixels() and not self.ssub
1.67
1.68 + # Update the state of the device.
1.69 + # NOTE: This is not meant to be "nice" Python, but instead models the
1.70 + # NOTE: propagation of state through the latches.
1.71 +
1.72 + self.cycle[0], self.cycle[1], self.cycle[2], self.cycle[3], \
1.73 + self.cycle[4], self.cycle[5], self.cycle[6], self.cycle[7] = \
1.74 + self.cycle[7], self.cycle[0], self.cycle[1], self.cycle[2], \
1.75 + self.cycle[3], self.cycle[4], self.cycle[5], self.cycle[6]
1.76 +
1.77 # Set row address (for ULA access only).
1.78
1.79 - if self.cycle == 0:
1.80 + if self.cycle[0]:
1.81
1.82 - # NOTE: Propagate CPU address here.
1.83 + # Either assert a required address or propagate the CPU address.
1.84
1.85 if access_ram:
1.86 - self.ram_address = (self.address & 0xff80) >> 7
1.87 + self.init_row_address(self.address)
1.88 + else:
1.89 + self.init_row_address(self.cpu_address)
1.90
1.91 # Initialise the pixel buffer if appropriate.
1.92
1.93 @@ -329,62 +353,65 @@
1.94
1.95 # Latch row address, set column address (for ULA access only).
1.96
1.97 - elif self.cycle == 1:
1.98 + elif self.cycle[1]:
1.99 +
1.100 + # Select an address needed by the ULA or CPU.
1.101
1.102 - # NOTE: Permit CPU access here.
1.103 + self.ram.row_select(self.ram_address)
1.104 +
1.105 + # Either assert a required address or propagate the CPU address.
1.106
1.107 if access_ram:
1.108 - self.ram.row_select(self.ram_address)
1.109 -
1.110 - # NOTE: Propagate CPU address here.
1.111 -
1.112 - if access_ram:
1.113 - self.ram_address = (self.address & 0x7f) << 1
1.114 + self.init_column_address(self.address, 0)
1.115 + else:
1.116 + self.init_column_address(self.cpu_address, 0)
1.117
1.118 # Latch column address.
1.119
1.120 - elif self.cycle == 2:
1.121 + elif self.cycle[2]:
1.122
1.123 - # NOTE: Permit CPU access here.
1.124 + # Select an address needed by the ULA or CPU.
1.125
1.126 - if access_ram:
1.127 - self.ram.column_select(self.ram_address)
1.128 + self.ram.column_select(self.ram_address)
1.129
1.130 # Read 4 bits (for ULA access only).
1.131 # NOTE: Perhaps map alternate bits, not half-bytes.
1.132
1.133 - elif self.cycle == 3:
1.134 + elif self.cycle[3]:
1.135
1.136 - # NOTE: Propagate CPU data here.
1.137 + # Either read from a required address or transfer CPU data.
1.138
1.139 if access_ram:
1.140 self.data = self.ram.data << 4
1.141 + else:
1.142 + self.cpu_transfer_high()
1.143
1.144 # Set column address (for ULA access only).
1.145
1.146 - elif self.cycle == 4:
1.147 + elif self.cycle[4]:
1.148 self.ram.column_deselect()
1.149
1.150 - # NOTE: Propagate CPU address here.
1.151 + # Either assert a required address or propagate the CPU address.
1.152
1.153 if access_ram:
1.154 - self.ram_address = (self.address & 0x7f) << 1 | 0x1
1.155 + self.init_column_address(self.address, 1)
1.156 + else:
1.157 + self.init_column_address(self.cpu_address, 1)
1.158
1.159 # Latch column address.
1.160
1.161 - elif self.cycle == 5:
1.162 + elif self.cycle[5]:
1.163
1.164 - # NOTE: Permit CPU access here.
1.165 + # Select an address needed by the ULA or CPU.
1.166
1.167 - if access_ram:
1.168 - self.ram.column_select(self.ram_address)
1.169 + self.ram.column_select(self.ram_address)
1.170
1.171 # Read 4 bits (for ULA access only).
1.172 # NOTE: Perhaps map alternate bits, not half-bytes.
1.173
1.174 - elif self.cycle == 6:
1.175 + elif self.cycle[6]:
1.176
1.177 - # NOTE: Propagate CPU data here.
1.178 + # Either read from a required address or transfer CPU data.
1.179
1.180 if access_ram:
1.181 self.data = self.data | self.ram.data
1.182 @@ -394,10 +421,12 @@
1.183
1.184 self.address += LINES_PER_ROW
1.185 self.wrap_address()
1.186 + else:
1.187 + self.cpu_transfer_low()
1.188
1.189 # Reset addresses.
1.190
1.191 - elif self.cycle == 7:
1.192 + elif self.cycle[7]:
1.193 self.ram.column_deselect()
1.194 self.ram.row_deselect()
1.195
1.196 @@ -405,8 +434,6 @@
1.197
1.198 self.access = (self.access + 1) % self.access_frequency
1.199
1.200 - self.cycle = (self.cycle + 1) % 8
1.201 -
1.202
1.203
1.204 # Video signalling.
1.205 @@ -479,6 +506,20 @@
1.206 if self.address >= SCREEN_LIMIT:
1.207 self.address -= self.screen_size
1.208
1.209 + def init_row_address(self, address):
1.210 + self.ram_address = (address & 0xff80) >> 7
1.211 +
1.212 + def init_column_address(self, address, offset):
1.213 + self.ram_address = (address & 0x7f) << 1 | offset
1.214 +
1.215 + def cpu_transfer_high(self):
1.216 + if self.cpu_read:
1.217 + self.cpu_data = self.ram.data << 4
1.218 +
1.219 + def cpu_transfer_low(self):
1.220 + if self.cpu_read:
1.221 + self.cpu_data = self.data | self.ram.data
1.222 +
1.223 def get_physical_colour(value):
1.224
1.225 """