Find a Pixel
Find Pixel is a small routine that sets the basis for plotting pixels on the screen. It takes the x and y coordinates of where you want to put a pixel and transforms those coordinates into an address and a bit offset. The address it gives you is for the byte that that pixel coordinate is in the Video Memory.
Some routines give you
this address relative to zero being the top left of the screen. You might have to add
$fc00 to the address outputted in order to get the exact address in the Video Memory. The
bit offset is stored as a bit set in the accumulator (a
register). The bit
cooresponds to the pixel you want. If you set the same bit in a
as the address in
the video memory given by hl
, you will have a little black dot at the coordinates
you want on the screen. Most routines accept the x coordinate in b
and the y
coordinate in c
.
I've pasted Clem Vasseur's FindPixel.asm Routine here. You can download this along with many other Find Pixel routines that I've come across in the Download Section. Each line in the routine is represented by a number which corresponds to an explanation at the end of the routine. Follow each line and try to picture in your head what it is doing.
- ↓FindPixel:
- ↓ ld h,63
- ↓ ld a,c
- ↓ add a,a
- ↓ add a,a
- ↓ ld l,a
- ↓ ld a,b
- ↓ rra
- ↓ add hl,hl
- ↓ rra
- ↓ add hl,hl
- ↓ rra
- ↓ or l
- ↓ ld l,a
- ↓ ld a,b
- ↓ and %00000111
- ↓ ld bc,FP_Bits
- ↓ add a,c
- ↓ ld c,a
- ↓ adc a,b
- ↓ sub c
- ↓ ld b,a
- ↓ ld a,(bc)
- ↓ ret
- ↓FP_Bits:
- ↓ .db %10000000
- ↓ .db %01000000
- ↓ .db %00100000
- ↓ .db %00010000
- ↓ .db %00001000
- ↓ .db %00000100
- ↓ .db %00000010
- ↓ .db %00000001
Line(s) | Explanation | Bytes |
↑2 | This routine is great because it knows
we are going to want the address relative to the Video Memory
($fc00) and not relative to zero ($0000). We are going to
be multiplying hl times 4. We can think ahead and
see that 63*4 converted to hexadecimal is $fc. That's the
Most Significant Byte (MSB) of what we want. This will
handle for us the adding of the final address to $fc00. The
multiplying by 4 will come in lines 9 and
11.
| 2 |
↑3 | We need to get the y coordinate and multiply
it by 16 (or 24) so we move down 16 bytes (one row)
until we're at the row designated by the y coordinate. We can't
just do 16*c . We can square the y coordinate 4 times so
we have it times 16. We are going to use 'add a,a' for the first 2
squares because we know we won't exceed 256 with just 2 multiplies
since the maximum y value is 64 (64*2*2=256). 'Add a,a' is over
two times faster than 'add hl,hl' which we will have to use
later.
| 1 |
↑4-5 | Now we've got to start multiplying the
y coordinate (which was in c ) by 16. It's nice that
the screen is 16 bytes across because that way it's a power
of 2 so we can figure this stuff out fast with just shifting
bits over to the right once.
| 2 |
↑6 | We put what we've just got into the Least
Significant Byte (LSB) of our final address to be stored in
hl .
| 1 |
↑7 | Now's time to start working with the
x coordinate stored in b . Since it's in terms of
pixels (or bits in each pixel) we need to think of each
byte containing 8 pixels. We need to divide the x coordinate
by 8 to account for each of the 8 pixels in a byte.
| 1 |
↑8 | If this is unfamiliar to you, refer to the Shift and Rotate Section to get a quick lesson. It rotates the bits one to the right with bit 0 being moved to bit 7 and also copied into the carry flag. This also acts as dividing by 2 since we shift over by a power of 2 (21=2). This is the same as lines 10 and 12. | 1 |
↑9 | We need to perform the third multiplication of the y coordinate by 2. This is the same as line 11. | 1 |
↑10 | See explanation for line 8. | 1 |
↑11 | See explanation for line 9. | 1 |
↑12 | See explanation for line 8. | 1 |
↑13-14 | This adds in the result we just found with
whatever is currently in the LSB of hl (l ). Then
we put that result into the LSB. We now have the final
address in the Video Memory in hl ready to be used.
| 2 |
↑15 | Out next task is to figure out the bit offset
needed in a . Let's get back out x coordinate from b
and work with it again.
| 1 |
↑16 | We have already figured out which byte the pixel is in. The remainder of after that calculation tells us where in that byte. The remainder would be the bits we shifted out the right, the last 3 bits (%00000111). If the remainder were 3, then we would know that the pixel is the 3rd from the left. We want to mask off (get rid of) all the bits except for the ones that would be our remainder. | 2 |
↑17 | Lines 25 and following are a set of precalculated bit offsets. We use that table and add the remainder to that to get the correct offset. If the remainder were 3, then we would need the 3rd element in the table which is %00100000. | 3 |
↑18-22 | This is
Simulated 16-bit Addition
which will be covered later in more detail. It's faster than just doing
ld h,0 / ld l,a / add hl,bc to get the offset in the table. It
adds a to the LSB of hl , stores the result in the LSB,
adds the result to the MSB with the carry and subtracts the LSB. The
MSB is either increased by one (if the carry is set) or remains the
same (if the carry is reset).
| 5 |
↑23 | Put that element of the table into a .
| 1 |
↑24 | Done with the routine so return to caller. | 1 |
↑25-33 | Here begins a table with all possible bit offsets
for a . They are in binary to make it easier for viewing. See
lines 15 and following to see how this is used.
| 8 |
More from z80 » Graphics
Find a Pixel // Grayscale // Pixel Manipulation // The Screen // Sprites // SDR8 Routine // Tile Maps // TileGen Routine