1.1 --- a/ULA.txt Fri Feb 10 01:07:20 2012 +0100
1.2 +++ b/ULA.txt Mon Feb 13 22:00:09 2012 +0100
1.3 @@ -1,16 +1,13 @@
1.4 Timing
1.5 ------
1.6
1.7 -According to the above (15.3.2 in the AUG), there are 312 scanlines, 256 of
1.8 -which are used to generate pixel data. At 50Hz, this means that 128 cycles are
1.9 -spent on each scanline (2000000 cycles / 50 = 40000 cycles; 40000 cycles / 312
1.10 -~= 128 cycles). This is consistent with the observation that each scanline
1.11 +According to 15.3.2 in the Advanced User Guide, there are 312 scanlines, 256
1.12 +of which are used to generate pixel data. At 50Hz, this means that 128 cycles
1.13 +are spent on each scanline (2000000 cycles / 50 = 40000 cycles; 40000 cycles /
1.14 +312 ~= 128 cycles). This is consistent with the observation that each scanline
1.15 requires at most 80 bytes of data, and that the ULA is apparently busy for 40
1.16 out of 64 microseconds in each scanline.
1.17
1.18 -See: Acorn Electron Advanced User Guide
1.19 -See: http://mdfs.net/Docs/Comp/Electron/Techinfo.htm
1.20 -
1.21 Access to RAM involves accessing four 64Kb dynamic RAM devices (IC4 to IC7,
1.22 each providing two bits of each byte) using two cycles within the 500ns period
1.23 of the 2MHz clock to complete each access operation. Since the CPU and ULA
1.24 @@ -19,9 +16,6 @@
1.25 accessing RAM). The CPU is driven by an external clock (IC8) whose 16MHz
1.26 frequency is divided by the ULA (IC1) depending on the screen mode in use.
1.27
1.28 -See: Acorn Electron Service Manual
1.29 - http://acorn.chriswhy.co.uk/docs/Acorn/Manuals/Acorn_ElectronSM.pdf
1.30 -
1.31 Each 16MHz cycle is approximately 62.5ns. To access the memory, the following
1.32 patterns corresponding to 16MHz cycles are required:
1.33
1.34 @@ -47,11 +41,84 @@
1.35 communicate the latter behaviour. In the TM4164EC4 datasheet, it appears that
1.36 "page mode" provides the appropriate behaviour for that particular product.
1.37
1.38 -See: http://www.datasheetarchive.com/dl/Datasheets-112/DSAP0051030.pdf
1.39 +Video Timing
1.40 +------------
1.41 +
1.42 +According to 8.7 in the Service Manual, and the PAL Wikipedia page,
1.43 +approximately 4.7µs is used for the sync pulse, 5.7µs for the "back porch"
1.44 +(including the "colour burst"), and 1.65µs for the "front porch", totalling
1.45 +12.05µs and thus leaving 51.95µs for the active video signal for each
1.46 +scanline. As the Service Manual suggests in the oscilloscope traces, the
1.47 +display information is transmitted more or less centred within the active
1.48 +video period since the ULA will only be providing pixel data for 40µs in each
1.49 +scanline.
1.50
1.51 Each 62.5ns cycle happens to correspond to 64µs divided by 1024, meaning that
1.52 each scanline can be divided into 1024 cycles, although only 640 at most are
1.53 -actively used to provide pixel data.
1.54 +actively used to provide pixel data. Pixel data production should only occur
1.55 +within a certain period on each scanline, approximately 262 cycles after the
1.56 +start of hsync:
1.57 +
1.58 + active video period = 51.95µs
1.59 + pixel data period = 40µs
1.60 + total silent period = 51.95µs - 40µs = 11.95µs
1.61 + silent periods (before and after) = 11.95µs / 2 = 5.975µs
1.62 + hsync and back porch period = 4.7µs + 5.7µs = 10.4µs
1.63 + time before pixel data period = 10.4µs + 5.975µs = 16.375µs
1.64 + pixel data period start cycle = 16.375µs / 62.5ns = 262
1.65 +
1.66 +By choosing a number divisible by 8, the RAM access mechanism can be
1.67 +synchronised with the pixel production. Thus, 264 is a more appropriate start
1.68 +cycle.
1.69 +
1.70 +The "vertical blanking period", meaning the period before picture information
1.71 +in each field is 25 lines out of 312 (strictly 312.5) and thus lasts for
1.72 +1.6ms. Of this, 2.5 lines occur before the vsync (field sync) which also lasts
1.73 +for 2.5 lines. Thus, the first visible scanline on the first field of a frame
1.74 +occurs half way through the 23rd scanline period measured from the start of
1.75 +vsync:
1.76 +
1.77 + 10 20 23
1.78 + Line in frame: 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8
1.79 + Line from 1: 0 22 3
1.80 + Line on screen: .:::::VVVVV::::: 12233445566
1.81 + |_________________________________________________|
1.82 + 25 line vertical blanking period
1.83 +
1.84 +In the second field of a frame, the first visible scanline coincides with the
1.85 +24th scanline period measured from the start of line 313 in the frame:
1.86 +
1.87 + 310 336
1.88 + Line in frame: 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
1.89 + Line from 313: 0 23
1.90 + Line on screen: 88:::::VVVVV:::: 11223344
1.91 + 288 | |
1.92 + |_________________________________________________|
1.93 + 25 line vertical blanking period
1.94 +
1.95 +In order to consider only full lines, we might consider the start of each
1.96 +frame to occur 23 lines after the start of vsync.
1.97 +
1.98 +Again, it is likely that pixel data production should only occur on scanlines
1.99 +within a certain period on each frame. The "625/50" document indicates that
1.100 +only a certain region is "safe" to use, suggesting a vertically centred region
1.101 +with approximately 15 blank lines above and below the picture. Thus, the start
1.102 +of the picture could be chosen as 38 lines after the start of vsync.
1.103 +
1.104 +See: Acorn Electron Advanced User Guide
1.105 +See: http://mdfs.net/Docs/Comp/Electron/Techinfo.htm
1.106 +See: http://en.wikipedia.org/wiki/PAL
1.107 +See: http://en.wikipedia.org/wiki/Analog_television#Structure_of_a_video_signal
1.108 +See: The 625/50 PAL Video Signal and TV Compatible Graphics Modes
1.109 + http://lipas.uwasa.fi/~f76998/video/modes/
1.110 +See: PAL TV timing and voltages
1.111 + http://www.retroleum.co.uk/electronics-articles/pal-tv-timing-and-voltages/
1.112 +See: Line Standards
1.113 + http://www.pembers.freeserve.co.uk/World-TV-Standards/Line-Standards.html
1.114 +See: TM4164EC4 65,536 by 4-Bit Dynamic RAM Module
1.115 + http://www.datasheetarchive.com/dl/Datasheets-112/DSAP0051030.pdf
1.116 +See: Acorn Electron Service Manual
1.117 + http://acorn.chriswhy.co.uk/docs/Acorn/Manuals/Acorn_ElectronSM.pdf
1.118
1.119 Shadow/Expanded Memory
1.120 ----------------------
2.1 --- a/main.py Fri Feb 10 01:07:20 2012 +0100
2.2 +++ b/main.py Mon Feb 13 22:00:09 2012 +0100
2.3 @@ -52,30 +52,34 @@
2.4
2.5 ula.set_mode(2); ula.reset()
2.6
2.7 - ula.fill(0x3000, 0x5800 - 320, encode((1, 6), 4))
2.8 - ula.fill(0x5800 - 320, 0x8000, encode((2, 7), 4))
2.9 + ula.ram.fill(0x3000, 0x5800 - 320, encode((1, 6), 4))
2.10 + ula.ram.fill(0x5800 - 320, 0x8000, encode((2, 7), 4))
2.11 ula_screen = update(ula)
2.12 update_screen(screen, ula_screen)
2.13 + print "Screen updated."
2.14 mainloop()
2.15
2.16 ula.screen_start = 0x3000 + 2
2.17 ula_screen = update(ula)
2.18 update_screen(screen, ula_screen)
2.19 + print "Screen updated."
2.20 mainloop()
2.21
2.22 # Test MODE 6.
2.23
2.24 ula.set_mode(6); ula.reset()
2.25
2.26 - ula.fill(0x6000, 0x6f00 + 160, encode((1, 0, 1, 1, 0, 0, 1, 1), 1))
2.27 - ula.fill(0x6f00 + 160, 0x7f40, encode((1, 0, 1, 0, 1, 0, 1, 0), 1))
2.28 + ula.ram.fill(0x6000, 0x6f00 + 160, encode((1, 0, 1, 1, 0, 0, 1, 1), 1))
2.29 + ula.ram.fill(0x6f00 + 160, 0x7f40, encode((1, 0, 1, 0, 1, 0, 1, 0), 1))
2.30 ula_screen = update(ula)
2.31 update_screen(screen, ula_screen)
2.32 + print "Screen updated."
2.33 mainloop()
2.34
2.35 ula.screen_start = 0x6f00 + 160
2.36 ula_screen = update(ula)
2.37 update_screen(screen, ula_screen)
2.38 + print "Screen updated."
2.39 mainloop()
2.40
2.41 # vim: tabstop=4 expandtab shiftwidth=4
3.1 --- a/ula.py Fri Feb 10 01:07:20 2012 +0100
3.2 +++ b/ula.py Mon Feb 13 22:00:09 2012 +0100
3.3 @@ -9,11 +9,23 @@
3.4
3.5 LINES_PER_ROW = 8 # the number of pixel lines per character row
3.6 MAX_HEIGHT = 256 # the height of the screen in pixels
3.7 +MAX_WIDTH = 640 # the width of the screen in pixels
3.8 +
3.9 +MAX_CSYNC = 2 # the scanline during which vsync ends
3.10 +MIN_PIXELLINE = 38 # the first scanline involving pixel generation
3.11 MAX_SCANLINE = 312 # the number of scanlines in each frame
3.12 -MAX_WIDTH = 640 # the width of the screen in pixels
3.13 -MAX_SCANPOS = 1024 # the number of positions in each scanline
3.14 +
3.15 +MAX_PIXELLINE = MIN_PIXELLINE + MAX_HEIGHT
3.16 +
3.17 +MAX_HSYNC = 75 # the number of cycles in each hsync period
3.18 +MIN_PIXELPOS = 264 # the first cycle involving pixel generation
3.19 +MAX_SCANPOS = 1024 # the number of cycles in each scanline
3.20 +
3.21 +MAX_PIXELPOS = MIN_PIXELPOS + MAX_WIDTH
3.22 +
3.23 SCREEN_LIMIT = 0x8000 # the first address after the screen memory
3.24 MAX_MEMORY = 0x10000 # the number of addressable memory locations
3.25 +MAX_RAM = 0x10000 # the number of addressable RAM locations (64Kb in each IC)
3.26 BLANK = (0, 0, 0)
3.27
3.28 def update(ula):
3.29 @@ -30,6 +42,7 @@
3.30 ula.update()
3.31 video.update()
3.32 i += 1
3.33 +
3.34 return video.screen
3.35
3.36 class Video:
3.37 @@ -43,19 +56,70 @@
3.38 self.colour = BLANK
3.39 self.csync = 1
3.40 self.hs = 1
3.41 - self.reset()
3.42 + self.x = 0
3.43 + self.y = 0
3.44
3.45 - def reset(self):
3.46 - self.pos = 0
3.47 + def set_csync(self, value):
3.48 + if self.csync and not value:
3.49 + self.y = 0
3.50 + self.pos = 0
3.51 + self.csync = value
3.52 +
3.53 + def set_hs(self, value):
3.54 + if self.hs and not value:
3.55 + self.x = 0
3.56 + self.y += 1
3.57 + self.hs = value
3.58
3.59 def update(self):
3.60 - if self.csync:
3.61 - if self.hs:
3.62 + if MIN_PIXELLINE <= self.y < MAX_PIXELLINE:
3.63 + if MIN_PIXELPOS <= self.x < MAX_PIXELPOS:
3.64 self.screen[self.pos] = self.colour[0]; self.pos += 1
3.65 self.screen[self.pos] = self.colour[1]; self.pos += 1
3.66 self.screen[self.pos] = self.colour[2]; self.pos += 1
3.67 - else:
3.68 - self.pos = 0
3.69 + self.x += 1
3.70 +
3.71 +class RAM:
3.72 +
3.73 + """
3.74 + A class representing the RAM circuits (IC4 to IC7). Each circuit
3.75 + traditionally holds 64 kilobits, with two accesses required to read 2 bits
3.76 + from each in order to obtain a whole byte. Here, we model the circuits with
3.77 + a list of 65536 half-bytes with each bit representing a bit stored on a
3.78 + separate IC.
3.79 + """
3.80 +
3.81 + def __init__(self):
3.82 +
3.83 + "Initialise the RAM circuits."
3.84 +
3.85 + self.memory = [0] * MAX_RAM
3.86 + self.row_address = 0
3.87 + self.column_address = 0
3.88 + self.data = 0
3.89 +
3.90 + def row_select(self, address):
3.91 + self.row_address = address
3.92 +
3.93 + def row_deselect(self):
3.94 + pass
3.95 +
3.96 + def column_select(self, address):
3.97 + self.column_address = address
3.98 +
3.99 + # Read the data.
3.100 +
3.101 + self.data = self.memory[self.row_address << 8 | self.column_address]
3.102 +
3.103 + def column_deselect(self):
3.104 + pass
3.105 +
3.106 + # Convenience methods.
3.107 +
3.108 + def fill(self, start, end, value):
3.109 + for i in xrange(start, end):
3.110 + self.memory[i << 1] = value >> 4
3.111 + self.memory[i << 1 | 0x1] = value & 0xf
3.112
3.113 class ULA:
3.114
3.115 @@ -74,25 +138,29 @@
3.116
3.117 palette = range(0, 8) * 2
3.118
3.119 - def __init__(self, memory, video):
3.120 + def __init__(self, ram, video):
3.121
3.122 - "Initialise the ULA with the given 'memory' and 'video'."
3.123 + "Initialise the ULA with the given 'ram' and 'video' instances."
3.124
3.125 - self.memory = memory
3.126 + self.ram = ram
3.127 self.video = video
3.128 self.set_mode(6)
3.129
3.130 - # Internal state.
3.131 -
3.132 - self.buffer = [0] * 8
3.133 -
3.134 self.reset()
3.135
3.136 def reset(self):
3.137
3.138 "Reset the ULA."
3.139
3.140 - self.vsync()
3.141 + # Internal state.
3.142 +
3.143 + self.cycle = 0 # counter within each 2MHz period
3.144 + self.access = 0 # counter used to determine whether a byte needs reading
3.145 + self.ram_address = 0 # address given to the RAM
3.146 + self.data = 0 # data read from the RAM
3.147 + self.buffer = [0] * 8 # pixel buffer for decoded RAM data
3.148 +
3.149 + self.reset_vertical()
3.150
3.151 def set_mode(self, mode):
3.152
3.153 @@ -116,6 +184,7 @@
3.154 self.width, self.depth, rows = self.modes[mode]
3.155
3.156 columns = (self.width * self.depth) / 8 # bits read -> bytes read
3.157 + self.access_frequency = 80 / columns # cycle frequency for reading bytes
3.158 row_size = columns * LINES_PER_ROW
3.159
3.160 # Memory access configuration.
3.161 @@ -139,7 +208,21 @@
3.162
3.163 self.buffer_limit = 8 / self.depth
3.164
3.165 - def vsync(self):
3.166 + def vsync(self, value=0):
3.167 +
3.168 + "Signal the start of a frame."
3.169 +
3.170 + self.csync = value
3.171 + self.video.set_csync(value)
3.172 +
3.173 + def hsync(self, value=0):
3.174 +
3.175 + "Signal the end of a scanline."
3.176 +
3.177 + self.hs = value
3.178 + self.video.set_hs(value)
3.179 +
3.180 + def reset_vertical(self):
3.181
3.182 "Signal the start of a frame."
3.183
3.184 @@ -147,18 +230,17 @@
3.185 self.line = self.line_start % LINES_PER_ROW
3.186 self.ssub = 0
3.187 self.y = 0
3.188 - self.reset_horizontal()
3.189 -
3.190 - # Signal the video circuit.
3.191 + self.x = 0
3.192
3.193 - self.csync = self.video.csync = 1
3.194 + def reset_horizontal(self):
3.195
3.196 - def hsync(self):
3.197 -
3.198 - "Signal the end of a scanline."
3.199 + "Reset horizontal state within the active region of the frame."
3.200
3.201 self.y += 1
3.202 - self.reset_horizontal()
3.203 + self.x = 0
3.204 +
3.205 + if not self.inside_frame():
3.206 + return
3.207
3.208 # Support spacing between character rows.
3.209
3.210 @@ -193,70 +275,176 @@
3.211
3.212 self.line_start = self.address
3.213
3.214 - def reset_horizontal(self):
3.215 -
3.216 - "Reset horizontal state."
3.217 -
3.218 - self.x = 0
3.219 - self.buffer_index = self.buffer_limit # need refill
3.220 -
3.221 - # Signal the video circuit.
3.222 -
3.223 - self.hs = self.video.hs = 1
3.224 + def in_frame(self): return MIN_PIXELLINE <= self.y < MAX_PIXELLINE
3.225 + def inside_frame(self): return MIN_PIXELLINE < self.y < MAX_PIXELLINE
3.226 + def read_pixels(self): return MIN_PIXELPOS - 8 <= self.x < MAX_PIXELPOS - 8 and self.in_frame()
3.227 + def make_pixels(self): return MIN_PIXELPOS <= self.x < MAX_PIXELPOS and self.in_frame()
3.228
3.229 def update(self):
3.230
3.231 """
3.232 - Update the pixel colour by reading from the pixel buffer.
3.233 + Update the state of the ULA for each clock cycle. This involves updating
3.234 + the pixel colour by reading from the pixel buffer.
3.235 """
3.236
3.237 - # Detect the end of the line.
3.238 + # Detect the end of the scanline.
3.239 +
3.240 + if self.x == MAX_SCANPOS:
3.241 + self.reset_horizontal()
3.242 +
3.243 + # Detect the end of the frame.
3.244 +
3.245 + if self.y == MAX_SCANLINE:
3.246 + self.reset_vertical()
3.247 +
3.248 +
3.249 +
3.250 + # Clock management.
3.251 +
3.252 + access_ram = self.access == 0 and self.read_pixels() and not self.ssub
3.253 +
3.254 + # Set row address (for ULA access only).
3.255 +
3.256 + if self.cycle == 0:
3.257 +
3.258 + # NOTE: Propagate CPU address here.
3.259 +
3.260 + if access_ram:
3.261 + self.ram_address = (self.address & 0xff80) >> 7
3.262 +
3.263 + # Latch row address, set column address (for ULA access only).
3.264 +
3.265 + elif self.cycle == 1:
3.266 +
3.267 + # NOTE: Permit CPU access here.
3.268
3.269 - if self.x >= MAX_WIDTH:
3.270 - if self.x == MAX_WIDTH:
3.271 - self.hs = self.video.hs = 0
3.272 + if access_ram:
3.273 + self.ram.row_select(self.ram_address)
3.274 +
3.275 + # NOTE: Propagate CPU address here.
3.276 +
3.277 + if access_ram:
3.278 + self.ram_address = (self.address & 0x7f) << 1
3.279 +
3.280 + # Latch column address.
3.281 +
3.282 + elif self.cycle == 2:
3.283 +
3.284 + # NOTE: Permit CPU access here.
3.285
3.286 - # Detect the end of the scanline.
3.287 + if access_ram:
3.288 + self.ram.column_select(self.ram_address)
3.289 +
3.290 + # Read 4 bits (for ULA access only).
3.291 + # NOTE: Perhaps map alternate bits, not half-bytes.
3.292 +
3.293 + elif self.cycle == 3:
3.294 +
3.295 + # NOTE: Propagate CPU data here.
3.296 +
3.297 + if access_ram:
3.298 + self.data = self.ram.data << 4
3.299 +
3.300 + # Set column address (for ULA access only).
3.301 +
3.302 + elif self.cycle == 4:
3.303 + self.ram.column_deselect()
3.304
3.305 - elif self.x == MAX_SCANPOS:
3.306 - self.hsync()
3.307 + # NOTE: Propagate CPU address here.
3.308 +
3.309 + if access_ram:
3.310 + self.ram_address = (self.address & 0x7f) << 1 | 0x1
3.311 +
3.312 + # Latch column address.
3.313 +
3.314 + elif self.cycle == 5:
3.315 +
3.316 + # NOTE: Permit CPU access here.
3.317 +
3.318 + if access_ram:
3.319 + self.ram.column_select(self.ram_address)
3.320
3.321 - # Detect the end of the frame.
3.322 + # Read 4 bits (for ULA access only).
3.323 + # NOTE: Perhaps map alternate bits, not half-bytes.
3.324 +
3.325 + elif self.cycle == 6:
3.326 +
3.327 + # NOTE: Propagate CPU data here.
3.328 +
3.329 + if access_ram:
3.330 + self.data = self.data | self.ram.data
3.331 +
3.332 + # Advance to the next column.
3.333 +
3.334 + self.address += LINES_PER_ROW
3.335 + self.wrap_address()
3.336 +
3.337 + # Reset addresses.
3.338
3.339 - if self.y == MAX_SCANLINE:
3.340 - self.vsync()
3.341 + elif self.cycle == 7:
3.342 + self.ram.column_deselect()
3.343 + self.ram.row_deselect()
3.344 +
3.345 + # Update the RAM access controller.
3.346 +
3.347 + self.access = (self.access + 1) % self.access_frequency
3.348 +
3.349 + self.cycle = (self.cycle + 1) % 8
3.350 +
3.351 +
3.352 +
3.353 + # Video signalling.
3.354 +
3.355 + # Detect any sync conditions.
3.356
3.357 - # Detect the end of the screen.
3.358 + if self.x == 0:
3.359 + self.hsync()
3.360 + if self.y == 0:
3.361 + self.vsync()
3.362 +
3.363 + # Detect the end of hsync.
3.364
3.365 - elif self.y == MAX_HEIGHT:
3.366 - self.csync = self.video.csync = 0
3.367 + elif self.x == MAX_HSYNC:
3.368 + self.hsync(1)
3.369 +
3.370 + # Detect the end of vsync.
3.371 +
3.372 + elif self.y == MAX_CSYNC and self.x == MAX_SCANPOS / 2:
3.373 + self.vsync(1)
3.374 +
3.375 +
3.376 +
3.377 + # Pixel production.
3.378
3.379 # Detect spacing between character rows.
3.380
3.381 - if self.ssub:
3.382 + if not self.make_pixels() or self.ssub:
3.383 self.video.colour = BLANK
3.384
3.385 - # Detect horizontal and vertical sync conditions.
3.386 -
3.387 - elif not self.hs or not self.csync:
3.388 - pass
3.389 -
3.390 # For pixels within the frame, obtain and output the value.
3.391
3.392 else:
3.393 + # Detect the start of the pixel generation.
3.394 +
3.395 + if self.x == MIN_PIXELPOS:
3.396 + self.xcounter = self.xscale
3.397 + self.buffer_index = 0
3.398 + self.fill_pixel_buffer()
3.399
3.400 # Scale pixels horizontally, only accessing the next pixel value
3.401 # after the required number of scan positions.
3.402
3.403 - if self.x % self.xscale == 0:
3.404 + elif self.xcounter == 0:
3.405 + self.xcounter = self.xscale
3.406 self.buffer_index += 1
3.407
3.408 - # Fill the buffer once all values have been read.
3.409 + # Fill the pixel buffer, assuming that data is available.
3.410
3.411 - if self.buffer_index >= self.buffer_limit:
3.412 - self.buffer_index = 0
3.413 - self.fill_pixel_buffer()
3.414 + if self.buffer_index >= self.buffer_limit:
3.415 + self.buffer_index = 0
3.416 + self.fill_pixel_buffer()
3.417
3.418 + self.xcounter -= 1
3.419 self.video.colour = self.buffer[self.buffer_index]
3.420
3.421 self.x += 1
3.422 @@ -268,27 +456,17 @@
3.423 mode.
3.424 """
3.425
3.426 - byte_value = self.memory[self.address]
3.427 + byte_value = self.data # which should have been read automatically
3.428
3.429 i = 0
3.430 for colour in decode(byte_value, self.depth):
3.431 self.buffer[i] = get_physical_colour(self.palette[colour])
3.432 i += 1
3.433
3.434 - # Advance to the next column.
3.435 -
3.436 - self.address += LINES_PER_ROW
3.437 - self.wrap_address()
3.438 -
3.439 def wrap_address(self):
3.440 if self.address >= SCREEN_LIMIT:
3.441 self.address -= self.screen_size
3.442
3.443 - # Convenience methods.
3.444 -
3.445 - def fill(self, start, end, value):
3.446 - fill(self.memory, start, end, value)
3.447 -
3.448 def get_physical_colour(value):
3.449
3.450 """
3.451 @@ -345,7 +523,7 @@
3.452
3.453 "Return a ULA initialised with a memory array and video."
3.454
3.455 - return ULA(get_memory(), get_video())
3.456 + return ULA(get_ram(), get_video())
3.457
3.458 def get_video():
3.459
3.460 @@ -353,22 +531,19 @@
3.461
3.462 return Video()
3.463
3.464 -def get_memory():
3.465 -
3.466 - "Return an array representing the computer's memory."
3.467 +def get_ram():
3.468
3.469 - return [0] * MAX_MEMORY
3.470 + "Return an instance representing the computer's RAM hardware."
3.471
3.472 -def fill(memory, start, end, value):
3.473 - for i in xrange(start, end):
3.474 - memory[i] = value
3.475 + return RAM()
3.476
3.477 # Test program providing coverage (necessary for compilers like Shedskin).
3.478
3.479 if __name__ == "__main__":
3.480 ula = get_ula()
3.481 ula.set_mode(2)
3.482 - ula.fill(0x5800 - 320, 0x8000, encode((2, 7), 4))
3.483 + ula.reset()
3.484 + ula.ram.fill(0x5800 - 320, 0x8000, encode((2, 7), 4))
3.485
3.486 # Make a simple two-dimensional array of tuples (three-dimensional in pygame
3.487 # terminology).