ATTRibute port

The attribute port (255) is part of SAM’s Spectrum compatibility, and implements a quirk of the original hardware. On the Spectrum it returns the last value on the ULA side of the bus — an attribute byte over the main screen or 255 during the border. A handful of Spectrum titles use it to synchronise with the top of the main screen, giving the maximum the amount of time to draw sprites without raster shearing.

To my knowledge no SAM software uses it, so it’s remained near to the bottom of my SimCoupe ToDo list for many years. I made do with a dummy implementation, returning zero over the main screen and 255 during the border. Though a bug in the border test meant even that functionality was broken, so port reads have always returned zero!

Velesoft recently released a SAM-mouse enhanced version of the Spectrum title Galactic Gunners. It uses the ATTR port to synchronise drawing with the top of the main screen, and the broken SimCoupe implementation caused sprites in the upper 2/3 of the screen to flicker. In this case fixing the border test bug cured the flicker, but full ATTR support was needed to ensure other titles behaved correctly.

The SAM Technical Manual contains some details of SAM’s ATTR port behaviour:

This register enables the programmer to read the attributes of the currently displayed character cell in modes 1 and 2, and the third byte in every four displayed in modes 3 and 4.

There’s no mention of what happens in the border, thought a quick test was enough to show it didn’t match the Spectrum’s behaviour. In fact it seemed to only return attribute bytes from the main screen. Time for a test program! My usual approach with these tests is to make whatever I’m probing as visible as possible, so the emulation will only match the real thing once everything is perfect. In this case I used a tight loop reading from the ATTR port and writing the result to CLUT entry 0:

 ld hl,loop ld bc,&00f8 loop: in a,(255) out (c),a jp (hl)   

This code must be run with interrupts disabled, and started from a fixed position in the frame to ensure it’s the same on each run. Both are most easily achieved by placing the code at the IM 1 handler address of &0038 and using a HALT to guarantee the current instruction is a fixed 4 tstates when the interrupt handler is invoked. The 4-cycle rounding from the HALT opcode fetch ensures the test begins on the same frame cycle each time.

To make the most of the test output I created a test pattern containing a range of colours, and interleaved with columns of palette colour 0 where the test colour would show through. Here’s what I came up with:

And here’s what it looks like on SAM running in screen mode 1:

The time between the port read and the palette write causes the output to be shifted a few screen blocks to the right of the main screen position, reaching into the right border area. The screens above were taken with the SimCoupe border area set to Complete, to show what would be seen if the ASIC generated the display over the full frame. This doesn’t happen on a real machine but is useful to see video changes outside the visible TV area.

The stripes on the main screen and the jagged edges in the lower border are caused by the loop timing not being an exact multiple of the 384 tstates per display line. The actual timing is complicated by the display memory fetches, mode 1 contention delays, and ASIC port I/O delays, but if you look closely you can see three repeating line end positions.

If SAM’s border behaviour matched the Spectrum, the border colour should be bright white (colour 127, since the top bit is not used) everywhere except to the right of the main screen where the colour bleeds from the main screen. To the left of the main screen the colour is actually off-white (colour 120), which matches the right-most attribute on the scanline — bright white paper with black ink is 01111000 binary, 120 decimal.

To test the right-most attribute observation with the lower border I added a bright white paper with white ink (01111000 binary, 127 decimal) block to the bottom right of the screen. As expected this caused the lower and upper border to be coloured bright white. So during the border areas SAM was returning the last attribute value fetched to draw the main screen area.

As a further test I coloured the screen attributes red, set the screen-off bit to disable the display, coloured the screen attributes green, then read from the ATTR port. As expected the port returned the red colour, since that was the last screen byte the ASIC read when drawing the display. Here’s the BASIC code for the test:

10 PAPER 2 : BORDER 2 : MODE 4
20 BORDER 4 : OUT 254,132 : PAPER 4 : CLS
30 PAUSE 5 : PRINT IN 255 : REM should be 34 for red
40 BORDER 0

Once the port behaviour was understood the SimCoupe implementation could be enhanced. When the port is read it uses the current raster position to determine the last on-screen location that the ASIC would have read, and the memory address of the screen data (which depends on the current screen mode). The existing mode-change ASIC artefact implementation did a lot of this already so the same code could be re-used.

An additional complication is the value returned when the display is disabled, which may no longer be part of the current display. It requires the ATTR value to be determined when the screen goes from enabled to disabled, giving a value to return for as long as the screen remains disabled.

The test program and source code are available for download (9K). Pressing the NMI button returns you to basic, allowing the screen mode/contents to be changed to see different patterns. It won’t work in SimCoupe 1.0, so you’ll need to wait until the next release!