View Single Post
Old 4th Jun 2019, 3:04 am   #7
Catkins
Pentode
 
Catkins's Avatar
 
Join Date: Feb 2015
Location: Chepstow, Monmouthshire, UK.
Posts: 234
Default Re: Fun with Z80 Assembler

Quote:
Originally Posted by Duke_Nukem View Post
I had some Z80 fun on a friends Sinclair - cant remember now if it was a ZX81 or a Spectrum (but what I do remember was it had seemingly very peculiar screen memory layout).
Then it was a Spectrum. The ZX81 only supported B/W character mode (text plus some character graphics blocks).

The Spectrum display consisted of a "high resolution" 256x192 display, with 1 bit per pixel, and a parallel 32x24 colour attribute grid. As you said the pixel display was oddly mapped, it was split into 3 separate blocks of 64 pixels in height (top, middle, bottom), and each block was organised where each successive 32 byte pixel line (32*8 = 256 pixels), jumped 8 rows, so the first 32 bytes was row 0, the next 32 bytes row 8, and so on, until it wrapped around, the 9th 32-byte line (8*32 = 256) being row 1, etc. Logically then for the top, middle, and bottom, the display frame organisation was all the first scan lines for each 8-pixel block, all the second scan lines for each 8-pixel block and so on.

To work out the byte position for an arbitrary Y (pixel row), you first worked out whether it was in the top, middle, or bottom, and then basically split it into two numbers representing: which 8-pixel block it was, and the line offset within that 8-pixel block. Armed with that you can work out where in the above organisation it will be:

1. Y REM 8 (Modulus remainder) gives the scan line offset, multipled by 256 gives a byte start position

2. Y / 8 (integer division) gives the 8-pixel block, multipled by 32, gives the byte offset from the above

Or

Address = (Y REM 8) * 256 + (Y / 8) * 32

Obviously, as the operations are all pure powers of 2, they can in practice be replaced by bit shifts.

But on a slow 8-bit processor this literally killed performance. But, once you worked out the byte position, you could make certain optimisations - you probably have noticed the next line down can mostly be found by adding 256. If your address was held in HL, moving to the next line could be achieved by incrementing H. So drawing a vertical line could be done by mostly incrementing H.

But in practice, dealing with the insane mapping was just too slow, despite any optimisations.

I wrote a wire-frame 3D graphics game for the Spectrum which involved drawing a lot of lines per frame, and, I discovered it was far better to draw into a "shadow display" which was sanely mapped, and then copy it to the real display area.

Quote:
Originally Posted by Duke_Nukem View Post

I think Tony may have hit on why I found the Z80 frustrating at the time (as I couldn't remember the details):

Quote:
Anyway, as for the Z80, one thing I hated about it was the indexed addressing modes. To me it was plain 'wrong' for the 8 bit 'offset' to be fixed (one of the instruction bytes) and the 16 bit 'base' to be in a register.
TTFN,
Jon
I hardly ever used the indexed addressing modes, because they were insanely slow, even slower than everything else.

The Z80 had 252 "basic" one byte operand op codes. Anything else, including the indexed addressing, used an opcode prefix byte. If you wanted performance, you simply avoided them.
Catkins is offline