Print64.bas
The 64 column printing routine allows text to be 4 pixels wide instead of 8. It is NOT proportional printing, but this is still useful for lining things up in columns.
This routine has been adopted as an included library - so you may include it with
Usage
Moves the print64 system's print cursor to row Y, column X. Note that 0 <= x <= 63
- that is the range of values
for X can be up to 63. The range of values for Y is the normal 0-23.
- Note that the print64 system's cursor position is independent from that of the ZX Basic Print routine, or any other, such as the print42 system.
Prints the string to the screen at the current Print64 co-ordinates. It does so in the current permanent colours.
NOTE: The ZX Spectrum's attribute system is encoded into the hardware as a 32 character grid. Print64 does its best, but changing the paper/bright/flash colour from the background is likely to look imperfect as the attribute blocks cannot line up well with the pixel blocks.
CODE
- There is a version of this code included with the compiler (though the version listed here may or may not be more recent). Code converted to ZXBasic by Britlion, based on Andrew Owen's 64 Character code http://www.worldofspectrum.org/forums/showpost.php?p=167447&postcount=1
SUB printat64 (y as uByte, x as uByte)
IF y<24 AND x<64 then
POKE @p64coords,x
POKE @p64coords+1,y
ELSE
asm
rst 8 ; error "5 Out of screen"
defb 4
end asm
END IF
END SUB
SUB print64 (characters$ as String)
ASM
; This frankencode created by Paul Fisher, Andrew Owen, Chris Born and Einar Saukas
; TODO:
; * Inverse
; * Bold (which will use a Second font)
LD L,(IX+4)
LD H,(IX+5) ; Get String address of characters$ into HL.
; Load BC with length of string, and move HL to point to first character.
ld c, (hl) ; 60020 78
inc hl ; 60021 35
ld b, (hl) ; 60022 70
inc hl ; 60023 35
; Test string length. If Zero, exit.
ld a, c ; 60024 121
or b ; 60025 176
jp z, p64_END ; 60026 200
examineChar:
ld a, (hl) ; Grab the character
cp 128 ; too high to print?
jr nc, nextChar ; then we go to next.
newLine:
cp 13 ; Is this a newline character? 60056 254 13
jr nz, p64_isPrintable ; If not, hop to testing to see if we can print this 60058 32 13
push hl
push bc
ld b,0
ld hl, p64_coords ; Get coords 60060 237 91 68 235
call BLp64_NEXT_ROW ; Go to next line. ; 60064 205 58 235
pop bc
pop hl
ld (p64_coords), de ; 60067 237 83 68 235
jr nextChar ; 60071 24 11
p64_isPrintable:
cp 31 ; Bigger than 31? 60073 254 31
jr c, nextChar ; If not, get the next one. 60075 56 7
push hl ; Save position 60077 229
push bc ; Save Count 60078 197
call p64_PrintChar ; Call Print SubRoutine
pop bc ; Recover length count 60082 193
pop hl ; Recover Position 60083 225
nextChar:
inc hl ; Point to next character 60084 35
dec bc ; Count off this character 60085 11
ld a, b ; Did we run out? 60086 120
or c ; 60087 177
jr nz, examineChar ; If not, examine the next one 60088 32 193
jp p64_END ; Otherwise hop to END. 60090 201
p64_PrintChar:
; Arrives with A as a byte to print.
ld hl,p64_coords
push hl ; save COL address for later
ld e, a ; store character value in E
ld b,0
ld c, (hl) ; store current column in BC
; Check if character font must be rotated, self-modifying the code accordingly
xor c ; compare BIT 0 from character value and column
rra
ld a, 256-(BLp64_END_LOOP-BLp64_SKIP_RLC) ; instruction DJNZ skipping rotation
jr nc, BLp64_NOT_RLC ; decide based on BIT 0 comparison
ld a, 256-(BLp64_END_LOOP-BLp64_INIT_RLC) ; instruction DJNZ using rotation
BLp64_NOT_RLC:
ld (BLp64_END_LOOP - 1), a ; modify DJNZ instruction directly
; Check the half screen byte to be changed, self-modifying the code accordingly
srl c ; check BIT 0 from current column
ld a, %00001111 ; mask to change left half of the screen byte
jr nc, BLp64_SCR_LEFT ; decide based on odd or even column
cpl ; mask to change right half of the screen byte
BLp64_SCR_LEFT:
ld (BLp64_SCR_MASK + 1), a ; modify screen mask value directly
cpl
ld (BLp64_FONT_MASK + 1), a ; modify font mask value directly
; Calculate location of the first byte to be changed on screen
; The row value is a 5 bits value (0-23), here represented as %000RRrrr
; The column value is a 6 bits value (0-63), here represented as %00CCCCCc
; Formula: 0x4000 + ((row & 0x18) << 8) + ((row & 0x07) << 5) + (col >> 1)
inc hl ; now HL references ROW address
ld a, (hl) ; now A = %000RRrrr
call 0e9eh ; now HL = %010RR000rrr00000
add hl, bc ; now HL = %010RR000rrrCCCCC
ex de, hl ; now DE = %010RR000rrrCCCCC
; and e=char -> l=char
; Calculate location of the character font data in p64_charset
; Formula: p64_charset + 7 * INT ((char-32)/2) - 1
ld h, b ; now HL = char (because b=0)
srl l ; now HL = INT (char/2)
ld c, l ; now BC = INT (char/2)
add hl, hl ; now HL = 2 * INT (char/2)
add hl, hl ; now HL = 4 * INT (char/2)
add hl, hl ; now HL = 8 * INT (char/2)
sbc hl, bc ; now HL = 7 * INT (char/2)
ld bc, p64_charset - 71h
add hl, bc ; now HL = p64_charset + 7 * INT (char/2) - 0x71
; Main loop to copy 8 font bytes into screen (1 blank + 7 from font data)
xor a ; first font byte is always blank
ld b, 8 ; execute loop 8 times
BLp64_INIT_RLC:
rlca ; switch position between bits 0-3 and bits 4-7
rlca
rlca
rlca
BLp64_SKIP_RLC:
; -----------------------------------------------------------------------------
; STANDARD OR INVERSE
;
BLp64_INV_C: nop ; either 'NOP' or 'CPL' (modified)
; -----------------------------------------------------------------------------
BLp64_FONT_MASK:
and %11110000 ; mask half of the font byte
ld c, a ; store half of the font byte in C
ld a, (de) ; get screen byte
BLp64_SCR_MASK:
and %00001111 ; mask half of the screen byte
or c ; combine half screen and half font
ld (de), a ; write result back to screen
inc d ; next screen location
inc hl ; next font data location
ld a, (hl) ; store next font byte in A
djnz BLp64_INIT_RLC ; repeat loop 8 times (this instruction gets modified)
BLp64_END_LOOP:
; attributes
ld de,(p64_coords) ; grab coords
and a ; clear carry
rr e ; divide x by 2 to get bytes instead of nybbles
ld a, d ; Get Y coord
sra a ;
sra a ;
sra a ; Multiply by 8 60155 203 47
add a, 88 ; Add to attrbute base address
ld h, a ; Put high byte value for attribute into H.
ld a, d ; get y value again
and 7 ; set within third
rrca ;
rrca ;
rrca ;
add a, e ; add in x value
ld l, a ; Put low byte for attribute into l
ld a, (23693) ; Get permanent Colours from System Variable
ld (hl), a ; Write new attribute
pop hl ; restore AT_COL address
inc (hl) ; next column
bit 6, (hl) ; column lower than 64?
ret z ; return if so
BLp64_NEXT_ROW:
ld (hl), b ; reset AT_COL
inc hl ; store AT_ROW address in HL
inc (hl) ; next row
ld a, (hl)
cp 24 ; row lower than 23?
ret c ; return if so
ld (hl), b ; reset AT_ROW
ret ; done!
end asm
p64coords:
asm
p64_coords:
defb 0; X Coordinate store
defb 0; Y Coordinate Store
p64_charset: ; 60230
DEFB 2,2,2,2,0,2,0 ; Space !
DEFB 80,82,7,2,7,2,0 ; " #
DEFB 37,113,66,114,20,117,32 ; $ %
DEFB 34,84,32,96,80,96,0 ; & '
DEFB 36,66,66,66,66,36,0 ; ( )
DEFB 0,82,34,119,34,82,0 ; * +
DEFB 0,0,0,7,32,32,64 ; , -
DEFB 1,1,2,2,100,100,0 ; . /
DEFB 34,86,82,82,82,39,0 ; 0 1
DEFB 34,85,18,33,69,114,0 ; 2 3
DEFB 87,84,118,17,21,18,0 ; 4 5
DEFB 55,65,97,82,84,36,0 ; 6 7
DEFB 34,85,37,83,85,34,0 ; 8 9
DEFB 0,2,32,0,34,2,4 ; : ;
DEFB 0,16,39,64,39,16,0 ; < =
DEFB 2,69,33,18,32,66,0 ; > ?
DEFB 98,149,183,181,133,101,0 ; @ A
DEFB 98,85,100,84,85,98,0 ; B C
DEFB 103,84,86,84,84,103,0 ; D E
DEFB 114,69,116,71,69,66,0 ; F G
DEFB 87,82,114,82,82,87,0 ; H I
DEFB 53,21,22,21,85,37,0 ; J K
DEFB 69,71,71,69,69,117,0 ; L M
DEFB 82,85,117,117,85,82,0 ; N O
DEFB 98,85,85,103,71,67,0 ; P Q
DEFB 98,85,82,97,85,82,0 ; R S
DEFB 117,37,37,37,37,34,0 ; T U
DEFB 85,85,85,87,39,37,0 ; V W
DEFB 85,85,37,82,82,82,0 ; X Y
DEFB 119,20,36,36,68,119,0 ; Z [
DEFB 71,65,33,33,17,23,0 ; \ ]
DEFB 32,112,32,32,32,47,0 ; ^ _
DEFB 32,86,65,99,69,115,0 ; £ a
DEFB 64,66,101,84,85,98,0 ; b c
DEFB 16,18,53,86,84,35,0 ; d e
DEFB 32,82,69,101,67,69,2 ; f g
DEFB 66,64,102,82,82,87,0 ; h i
DEFB 20,4,53,22,21,85,32 ; j k
DEFB 64,69,71,71,85,37,0 ; l m
DEFB 0,98,85,85,85,82,0 ; n o
DEFB 0,99,85,85,99,65,65 ; p q
DEFB 0,99,84,66,65,70,0 ; r s
DEFB 64,117,69,69,85,34,0 ; t u
DEFB 0,85,85,87,39,37,0 ; v w
DEFB 0,85,85,35,81,85,2 ; x y
DEFB 0,113,18,38,66,113,0 ; z {
DEFB 32,36,34,35,34,36,0 ; | {
DEFB 6,169,86,12,6,9,6 ; ~ (c)
p64_END:
End Asm
End Sub
There's an example of usage here: