RFC: 64 column font code

edited September 2014 in Development
In BASIC, type CLEAR 49999 then import the code at 50000. Then type RANDOMIZE USR 50000. This will create a new channel and attach stream #4 to it. After that you just use the PRINT command, e.g.
10 PRINT #4;AT 0,53;"Hello world!"

Besides the normal ASCII characters, only the AT control codes are accepted.
; ---------------
; 4x8 font driver, (c) 2007 Andrew Owen
; ---------------

	org	50000		;

; --------------------------------
; CREATE CHANNEL AND ATTACH STREAM
; --------------------------------
;
; Based on code by Ian Beardsmore from Your Spectrum issue 7, September 1984.

c_chan:	ld	hl,($5c53)	; a channel must be created below basic
				; so look at the system variable PROG
	dec	hl		; move hl down one address

	ld	bc,$0005	; the new channel takes 5 bytes
	call	$1655		; call the MAKE_ROOM routine
	inc	hl		; move HL up one address

	ld	bc,chan_4	; could write the bytes directly but
				; then code would be non-relocatable

	ld	(hl),c		; low byte of the output routine
	inc	hl		; move HL up one address
	push	hl		; save this address for later

	ld	(hl),b		; high byte of the output routine
	inc	hl		; move HL up one address

	ld	bc,$15c4	; address of input routine

	ld	(hl),c		; low byte of the input routine
	inc	hl		; move HL up one address

	ld	(hl),b		; high byte of the input routine
	inc	hl		; move HL up one address 

	ld	(hl),'P'	; channel type; 'K', 'S', 'R' or 'P'

; attach stream

	pop	hl		; the first address plus one of the
				; extra space stored earlier
	ld	de,($5c4f)	; store the contents of CHANS in DE
	and	a		; clear the carry flag before
				; calculation
	sbc	hl,de		; the difference between the start of
				; the channels area and the start of the
				; extra space becomes the offset, stored
				; in HL
	ex	de,hl		; store the offset in DE

	ld	hl,$5c10	; store the contents of STRMS in HL
	ld	a,$04		; stream number 4
	add	a,$03		; take account of streams -3 to -1
	add	a,a		; each of the seven default streams has
				; two bytes of offset data
				; the total number of bytes occupied,
				; held in a, forms the offset for the
				; new stream
	ld	b,$00		; set b to hold $00
	ld	c,a		; set the low byte of the offset
	add	hl,bc		; the offset is added to the base
				; address to give the correct location
				; in the streams table to store the
				; offset
	ld	(hl),e		; the low byte of the offset
	inc	hl		; move HL up one address
	ld	(hl),d		; the high byte of the offset
	ret			; all done

; -----------------
; CHANNEL #4 OUTPUT
; -----------------
;
; Based on code by Tony Samuels from Your Spectrum issue 13, April 1985.
; A channel wrapper for the 64-column display driver.

chan_4:	ld	b,a		; save character
	ld	a,(atflg)	; value of AT flag
	and	a		; test against zero
	jr	nz,getrow	; jump if not
	ld	a,b		; restore character

atchk:	cp	$16		; test for AT
	jr	nz,crchk	; if not test for CR
	ld	a,$ff		; set the AT flag
	ld	(atflg),a	; next character will be row
	ret			; return

getrow:	cp	$fe		; test AT flag
	jr	z,getcol	; jump if setting col
	ld	a,b		; restore character
	cp	$18		; greater than 23?
	jr	nc,err_b	; error if so
	
	ld	(row),a		; store it in row
	ld	hl,atflg	; AT flag
	dec	(hl)		; indicates next character is col
	ret			; return

getcol:	ld	a,b		; restore character
	cp	$40		; greater than 63?
	jr	nc,err_b	; error if so
	ld	(col),a		; store it in col
	xor	a		; set a to zero
	ld	(atflg),a	; store in AT flag
	ret			; return

err_b:	xor	a		; set a to zero
	ld	(atflg),a	; clear AT flag
	rst	08h		;
	defb	$0a		;

crchk:	cp	$0d		; check for return
	jr	z,do_cr		; to carriage return if so
	call	pr_64		; print it

	ld	hl,col		; increment
	inc	(hl)		; the column
	ld	a,(hl)		;
	
	cp	$40		; column 64?
	ret	nz		;

do_cr:	xor	a		; set A to zero
	ld	(col),a		; reset column
	ld	a,(row)		; get the row
	inc	a		; increment it
	cp	$18		; row 24?
	jr	z,wrap		;

zend:	ld	(row),a		; write it back
	ret

wrap:	xor	a		;
	jr	zend		;

; ------------------------
; 64 COLUMN DISPLAY DRIVER
; ------------------------

pr_64:	rra			; divide by two with remainder in carry flag

	ld	h,$00		; clear H
	ld	l,a		; CHAR to low byte of HL

	ex	af,af'		; save the carry flag

	add	hl,hl		; multiply
	add	hl,hl		; by
	add	hl,hl		; eight
	ld	de,font-$80	; offset to FONT
	add	hl,de		; HL holds address of first byte of
				; character map in FONT
	push	hl		; save font address

; convert the row to the base screen address

	ld	a,(row)		; get the row
	ld	b,a		; save it
	and	$18		; mask off bit 3-4
	ld	d,a		; store high byte of offset in D
	ld	a,b		; retrieve it
	and	$07		; mask off bit 0-2
	rlca			; shift
	rlca			; five
	rlca			; bits
	rlca			; to the
	rlca			; left
	ld	e,a		; store low byte of offset in E

; add the column

	ld	a,(col)		; get the column
	rra			; divide by two with remainder in carry flag
	push	af		; store the carry flag

	ld	h,$40		; base location
	ld	l,a		; plus column offset

	add	hl,de		; add the offset

	ex	de,hl		; put the result back in DE

; HL now points to the location of the first byte of char data in FONT_1
; DE points to the first screen byte in SCREEN_1
; C holds the offset to the routine

	pop	af		; restore column carry flag
	pop	hl		; restore the font address

	jr	nc,odd_col	; jump if odd column

even_col:
	ex	af,af'		; restore char position carry flag
	jr	c,l_on_l	; left char on left col
	jr	r_on_l		; right char on left col

odd_col:
	ex	af,af'		; restore char position carry flag
	jr	nc,r_on_r	; right char on right col
	jr	l_on_r		; left char on right col

; -------------------------------
; WRITE A CHARACTER TO THE SCREEN
; -------------------------------
;
; There are four separate routines

; HL points to the first byte of a character in FONT
; DE points to the first byte of the screen address

; left nibble on left hand side

l_on_l:	ld	c,$08		; 8 bytes to write
ll_lp:	ld	a,(de)		; read byte at destination
	and	$f0		; mask area used by new character
	ld	b,a		; store in b
	ld	a,(hl)		; get byte of font
	and	$0f		; mask off unused half
	or	b		; combine with background
	ld	(de),a		; write it back
	inc	d		; point to next screen location
	inc	hl		; point to next font data
	dec	c		; adjust counter
	jr	nz,ll_lp	; loop 8 times
	ret			; done

; right nibble on right hand side

r_on_r:	ld	c,$08		; 8 bytes to write
rr_lp:	ld	a,(de)		; read byte at destination
	and	$0f		; mask area used by new character
	ld	b,a		; store in b
	ld	a,(hl)		; get byte of font
	and	$f0		; mask off unused half
	or	b		; combine with background
	ld	(de),a		; write it back
	inc	d		; point to next screen location
	inc	hl		; point to next font data
	dec	c		; adjust counter
	jr	nz,rr_lp	; loop 8 times
	ret			; done

; left nibble on right hand side

l_on_r:	ld	c,$08		; 8 bytes to write
lr_lp:	ld	a,(de)		; read byte at destination
	and	$0f		; mask area used by new character
	ld	b,a		; store in b
	ld	a,(hl)		; get byte of font
	rrca			; shift right
	rrca			; four bits
	rrca			; leaving 7-4
	rrca			; empty
	and	$f0		;
	or	b		; combine with background
	ld	(de),a		; write it back
	inc	d		; point to next screen location
	inc	hl		; point to next font data
	dec	c		; adjust counter
	jr	nz,lr_lp	; loop 8 times
	ret			; done

; right nibble on left hand side

r_on_l:	ld	c,$08		; 8 bytes to write
rl_lp:	ld	a,(de)		; read byte at destination
	and	$f0		; mask area used by new character
	ld	b,a		; store in b
	ld	a,(hl)		; get byte of font
	rlca			; shift left
	rlca			; four bits
	rlca			; leaving 3-0
	rlca			; empty
	and	$0f		;
	or	b		; combine with background
	ld	(de),a		; write it back
	inc	d		; point to next screen location
	inc	hl		; point to next font data
	dec	c		; adjust counter
	jr	nz,rl_lp	; loop 8 times
	ret			; done

; --------------
; TEXT VARIABLES
; --------------
;
; Used by the 64 column driver

atflg:	defb	$00		; AT flag
row:	defb	$00		; row
col:	defb	$00		; col

; -------------------
; half width 4x8 font
; -------------------
;
; 384 bytes

font:
	defb	$00,$02,$02,$02,$02,$00,$02,$00,$00,$52,$57,$02,$02,$07,$02,$00;
	defb	$00,$25,$71,$62,$32,$74,$25,$00,$00,$22,$42,$30,$50,$50,$30,$00;
	defb	$00,$14,$22,$41,$41,$41,$22,$14,$00,$20,$70,$22,$57,$02,$00,$00;
	defb	$00,$00,$00,$00,$07,$00,$20,$20,$00,$01,$01,$02,$02,$04,$14,$00;
	defb	$00,$22,$56,$52,$52,$52,$27,$00,$00,$27,$51,$12,$21,$45,$72,$00;
	defb	$00,$57,$54,$56,$71,$15,$12,$00,$00,$17,$21,$61,$52,$52,$22,$00;
	defb	$00,$22,$55,$25,$53,$52,$24,$00,$00,$00,$00,$22,$00,$00,$22,$02;
	defb	$00,$00,$10,$27,$40,$27,$10,$00,$00,$02,$45,$21,$12,$20,$42,$00;
	defb	$00,$23,$55,$75,$77,$45,$35,$00,$00,$63,$54,$64,$54,$54,$63,$00;
	defb	$00,$67,$54,$56,$54,$54,$67,$00,$00,$73,$44,$64,$45,$45,$43,$00;
	defb	$00,$57,$52,$72,$52,$52,$57,$00,$00,$35,$15,$16,$55,$55,$25,$00;
	defb	$00,$45,$47,$45,$45,$45,$75,$00,$00,$62,$55,$55,$55,$55,$52,$00;
	defb	$00,$62,$55,$55,$65,$45,$43,$00,$00,$63,$54,$52,$61,$55,$52,$00;
	defb	$00,$75,$25,$25,$25,$25,$22,$00,$00,$55,$55,$55,$55,$27,$25,$00;
	defb	$00,$55,$55,$25,$22,$52,$52,$00,$00,$73,$12,$22,$22,$42,$72,$03;
	defb	$00,$46,$42,$22,$22,$12,$12,$06,$00,$20,$50,$00,$00,$00,$00,$0F;
	defb	$00,$20,$10,$03,$05,$05,$03,$00,$00,$40,$40,$63,$54,$54,$63,$00;
	defb	$00,$10,$10,$32,$55,$56,$33,$00,$00,$10,$20,$73,$25,$25,$43,$06;
	defb	$00,$42,$40,$66,$52,$52,$57,$00,$00,$14,$04,$35,$16,$15,$55,$20;
	defb	$00,$60,$20,$25,$27,$25,$75,$00,$00,$00,$00,$62,$55,$55,$52,$00;
	defb	$00,$00,$00,$63,$55,$55,$63,$41,$00,$00,$00,$53,$66,$43,$46,$00;
	defb	$00,$00,$20,$75,$25,$25,$12,$00,$00,$00,$00,$55,$55,$27,$25,$00;
	defb	$00,$00,$00,$55,$25,$25,$53,$06,$00,$01,$02,$72,$34,$62,$72,$01;
	defb	$00,$24,$22,$22,$21,$22,$22,$04,$00,$56,$A9,$06,$04,$06,$09,$06;


Post edited by chev on
«13456

Comments

  • edited January 2007
    Hi,

    I assembled it in Pasmo, but how do you use it?
  • edited January 2007
    You can also redirect text to different streams in machine code. Just load the accumulator with the stream number (in this case 4) then call 5633 to open the channel.
    No longer part of the Spectrum scene but still supporting Multi-Platform Arcade Game Designer. I am NOT on Twitter.
    Egghead Website
    Arcade Game Designer
    My itch.io page
  • edited January 2007
    Hi Andrew.
    Just a couple thoughts with regards speed (note I've not tried out the code, just browsed it briefly).
    You can speed things up at the expense of an extra ~300 bytes onto the size. Your font is stored as one character per nibble, which means you need to shift the font for every other character written to the screen. If you store the font as 1 per byte (both nibbles contain the same character data) you can dispense with rotation and just mask out the nibble you don't need. It should in theory make some of the program logic a little cleaner (IMO), as you'll only have two print routines, one for left, one for right - which could be changed to one print routine and a mask selected on the carry of the divided X-position (make sense?). For example, an exclamation mark would be stored as:
    DEFB $00, $22, $22, $22, $22, $00, $22, $00
    
    Also if you ensure that the font is aligned to an 8-byte offset, you can change your "INC HL" within the actual display code with an "INC L" (saves a whopping 24t per character... oooooh).
    Another change you may like to make to regain a couple of those bytes used up in the font *cough* would be to swap your usage of registers C and B when displaying the font... then you can use "DJNZ" rather than "DEC C, JR NZ".

    Those are just thoughts, mind you... the routine looks pretty good as is. I once did something similar (64x32 print routine) but rather than streams is picked up the string from A$. Streams is much neater.
  • edited November 2010
    I think the comments of source code are wrong in all four rountimes
    l_on_l r_on_r l_on_r and r_onl

    ; left nibble on right hand side may be ; right nibble on left hand side
    l_on_r: ld c,$08 ; 8 bytes to write
    lr_lp: ld a,(de) ; read byte at destination
    and $0f ; mask area used by new character
    ld b,a ; store in b
    ld a,(hl) ; get byte of font

    rrca ; shift right
    rrca ; four bits
    rrca ; leaving 7-4
    rrca ; empty
    and $f0 ;

    is rare, bits 7-4 are the bits that use later, and swap RRCA by RLCA look better, and is more easy to understand. And bits 3-0 are not clear. only if use ADD A,A intead of RLCA are clear, and not need to use AND A,#F0
    or b ; combine with background
    ld (de),a ; write it back


    In a Spanish foro http://www.speccy.org/foro/viewtopic.php?f=6&t=2134&p=22568#p22568 I talk about this bugs.
    sromero make a tutorial, and copy, paste, and translate to spanish the comments.

    I only read this section of code, no read all.
  • edited November 2010
    Z80user wrote: »
    I think the comments of source code are wrong in all four routines: l_on_l r_on_r l_on_r and r_onl

    I think you might be right. However it's not possible to edit old posts any more.
  • edited November 2010
    I know I keep saying that, but I really think it is... THAT is definitely going in my assembly collection!!!...

    Oh, and Great to see you present again on the forums... :)

    PS: This is 48k mode only, right?
  • edited November 2010
    kgmcneil wrote: »
    I know I keep saying that, but I really think it is... THAT is definitely going in my assembly collection!!!...

    I'm no great assembly programmer. There's probably a better way of doing it. There's certainly a faster way as Icabod pointed out.
    Oh, and Great to see you present again on the forums... :)

    Thanks. Might stick around, might not. We'll see.
    PS: This is 48k mode only, right?

    No, should work fine in 128 mode too.
  • edited December 2010
    " ld hl,$5c10 ; store the contents of STRMS in HL "

    brackets I supose??
    ;)
    my old website http://home.hccnet.nl/c.born/ has changed to http://www.cborn.nl/zxfiles/ so just click it and select a file
  • edited December 2010
    Crisis wrote: »
    " ld hl,$5c10 ; store the contents of STRMS in HL "

    brackets I supose??
    ;)

    No, that one's correct as it's calculating an offset within the system variable.
  • edited December 2010
    Someone contributed a print64 routine to the ZX BASIC compiler library. I wonder if it was this one in fact! :smile:
    I'm currently evaluating print64 routines (have other from Spanish MicroHobby magazine which looks really compact) to add as much libraries as possible.
  • edited December 2010
    aowen wrote: »
    No, that one's correct as it's calculating an offset within the system variable.

    I see, altough you only use one stream you calculate it.
    So that makes it easier to use the routine for other streams to.
    I have to read the routine insted of 1 line before i comment.
    btw I was/am busy with a 2 in 1 chr as well, its part of my gigaclock routine
    you can find it on my workdisc backup collection from my (new)tornado project.
    http://www.worldofspectrum.org/forums/showthread.php?t=32092
    my old website http://home.hccnet.nl/c.born/ has changed to http://www.cborn.nl/zxfiles/ so just click it and select a file
  • edited March 2011
    do_cr:    xor    a        ; set A to zero
        ld    (col),a        ; reset column
        ld    a,(row)        ; get the row
        inc    a        ; increment it
        cp    $18        ; row 24?
        jr    z,wrap        ;
    
    zend:    ld    (row),a        ; write it back
        ret
    
    wrap:    xor    a        ;
        jr    zend        ;
    
    saving 2 bytes:
    do_cr:    xor    a        ; set A to zero
        ld    (col),a        ; reset column
        ld    a,(row)        ; get the row
        inc    a        ; increment it
        cp    $18        ; row 24?
    [U][I][B][COLOR=Red]    jr   nz,zend        ;[/COLOR][/B][/I][/U]
        xor    a        ;
    zend:    ld    (row),a        ; write it back
        ret
    
    my old website http://home.hccnet.nl/c.born/ has changed to http://www.cborn.nl/zxfiles/ so just click it and select a file
  • edited March 2011
    ; HL now points to the location of the first byte of char data in FONT_1
    ; DE points to the first screen byte in SCREEN_1
    ; C holds the offset to the routine
    
        pop    af        ; restore column carry flag
        pop    hl        ; restore the font address
    
    [COLOR=Red][U][I][B]   ld    c,$08        ; 8 bytes to write[/B][/I][/U][/COLOR]
    
        jr    nc,odd_col    ; jump if odd column
    
    even_col:
        ex    af,af'        ; restore char position carry flag
        jr    c,l_on_l    ; left char on left col
        jr    r_on_l        ; right char on left col
    
    odd_col:
        ex    af,af'        ; restore char position carry flag
        jr    nc,r_on_r    ; right char on right col
        jr    l_on_r        ; left char on right col
    
    now remove the
    l_on_l: ld c,$08 ; 8 bytes to write
    r_on_l: ld c,$08 ; 8 bytes to write
    r_on_r: ld c,$08 ; 8 bytes to write
    l_on_r: ld c,$08 ; 8 bytes to write

    saving 6 bytes
    my old website http://home.hccnet.nl/c.born/ has changed to http://www.cborn.nl/zxfiles/ so just click it and select a file
  • edited March 2011
    ; HL now points to the location of the first byte of char data in FONT_1
    ; DE points to the first screen byte in SCREEN_1
    ; C holds the offset to the routine
    
        pop    af        ; restore column carry flag
        pop    hl        ; restore the font address
    [COLOR=Black] [COLOR=Red][U][I][B]   ld    c,$08        ; 8 bytes to write[/B][/I][/U][/COLOR][/COLOR][COLOR=Red][U][I][B]  !!!!![/B][/I][/U][/COLOR]
        jr    nc,odd_col    ; jump if odd column
    
    even_col:
        ex    af,af'        ; restore char position carry flag
    [COLOR=Red][U][I][B]ld a,0  ; DONT TOUCH FLAGS HERE[/B][/I][/U][/COLOR]
        jr    c,l_on_l    ; left char on left col
        jr    r_on_l        ; right char on left col
    
    odd_col:
        ex    af,af'        ; restore char position carry flag
    [COLOR=Red][U][I][B]ld a,0  ; DONT TOUCH FLAGS HERE[/B][/I][/U][/COLOR]
        jr    nc,r_on_r    ; right char on right col
        jr    l_on_r        ; left char on right col
    
    move the LABEL off all four subroutines like this:
    ll_lp:    ld    a,(de)        ; read byte at destination
    [U][I][B][COLOR=Red]l_on_l:[/COLOR][/B][/I][/U]     and    $f0        ; mask area used by new character
    
    
    now
    the first value of A (before loading with DE) is ALWAYS #0
    so now REMOVE al the first #00 in the font DEFINITION:
    ; -------------------
    ; half width [U][I][B][COLOR=Red]4x7 font[/COLOR][/B][/I][/U]
    ; -------------------
    ;
    [U][I][B][COLOR=Red]; 336 bytes[/COLOR][/B][/I][/U]
    
    font:
        defb   $02,$02,$02,$02,$00,$02,$00, $52,$57,$02,$02,$07,$02,$00;
        defb   $25,$71,$62,$32,$74,$25,$00, $22,$42,$30,$50,$50,$30,$00;
        defb   $14,$22,$41,$41,$41,$22,$14, $20,$70,$22,$57,$02,$00,$00;
        defb   $00,$00,$00,$07,$00,$20,$20, $01,$01,$02,$02,$04,$14,$00;
        defb   $22,$56,$52,$52,$52,$27,$00, $27,$51,$12,$21,$45,$72,$00;
        defb   $57,$54,$56,$71,$15,$12,$00, $17,$21,$61,$52,$52,$22,$00;
        defb   $22,$55,$25,$53,$52,$24,$00, $00,$00,$22,$00,$00,$22,$02;
        defb   $00,$10,$27,$40,$27,$10,$00, $02,$45,$21,$12,$20,$42,$00;
        defb   $23,$55,$75,$77,$45,$35,$00, $63,$54,$64,$54,$54,$63,$00;
        defb   $67,$54,$56,$54,$54,$67,$00, $73,$44,$64,$45,$45,$43,$00;
        defb   $57,$52,$72,$52,$52,$57,$00, $35,$15,$16,$55,$55,$25,$00;
        defb   $45,$47,$45,$45,$45,$75,$00, $62,$55,$55,$55,$55,$52,$00;
        defb   $62,$55,$55,$65,$45,$43,$00, $63,$54,$52,$61,$55,$52,$00;
        defb   $75,$25,$25,$25,$25,$22,$00, $55,$55,$55,$55,$27,$25,$00;
        defb   $55,$55,$25,$22,$52,$52,$00, $73,$12,$22,$22,$42,$72,$03;
        defb   $46,$42,$22,$22,$12,$12,$06, $20,$50,$00,$00,$00,$00,$0F;
        defb   $20,$10,$03,$05,$05,$03,$00, $40,$40,$63,$54,$54,$63,$00;
        defb   $10,$10,$32,$55,$56,$33,$00, $10,$20,$73,$25,$25,$43,$06;
        defb   $42,$40,$66,$52,$52,$57,$00, $14,$04,$35,$16,$15,$55,$20;
        defb   $60,$20,$25,$27,$25,$75,$00, $00,$00,$62,$55,$55,$52,$00;
        defb   $00,$00,$63,$55,$55,$63,$41, $00,$00,$53,$66,$43,$46,$00;
        defb   $00,$20,$75,$25,$25,$12,$00, $00,$00,$55,$55,$27,$25,$00;
        defb   $00,$00,$55,$25,$25,$53,$06, $01,$02,$72,$34,$62,$72,$01;
        defb   $24,$22,$22,$21,$22,$22,$04, $56,$A9,$06,$04,$06,$09,$06;
    
    
    saving 48-4 = 44 bytes

    totaly 44+6+2=52 bytes
    my old website http://home.hccnet.nl/c.born/ has changed to http://www.cborn.nl/zxfiles/ so just click it and select a file
  • edited March 2011
    ; ------------------------
    ; 64 COLUMN DISPLAY DRIVER
    ; ------------------------
    
    pr_64:    rra            ; divide by two with remainder in carry flag
    
        ld    l,a        ; CHAR to low byte of HL
    [U][I][B][COLOR=Red]    XOR A[/COLOR][/B][/I][/U]
    [U][I][B][COLOR=Red]    ld    h,A        ; clear H[/COLOR][/B][/I][/U]
        ex    af,af'        ; save the carry flag
    
    now A=0 in ex af,af'
    so remove the just added:
    ld a,0 ; DONT TOUCH FLAGS HERE
    even_col:
        ex    af,af'        ; restore char position carry flag
    
        jr    c,l_on_l    ; left char on left col
        jr    r_on_l        ; right char on left col
    
    odd_col:
        ex    af,af'        ; restore char position carry flag
      
        jr    nc,r_on_r    ; right char on right col
        jr    l_on_r        ; left char on right col
    
    saving 1+4=5 bytes more
    i did not try it, but i am (as a nono ) 99% sure
    my old website http://home.hccnet.nl/c.born/ has changed to http://www.cborn.nl/zxfiles/ so just click it and select a file
  • edited March 2011
    then you can use "DJNZ" rather than "DEC C, JR NZ".
    true, another 4 bytes saved=52+5+4=61 bytes
    So the four routines should swap use off 'c' and 'b' reg and then cut out 'dec c'
    my old website http://home.hccnet.nl/c.born/ has changed to http://www.cborn.nl/zxfiles/ so just click it and select a file
  • edited March 2011
    And the final version of all those edits will look like...?..
  • edited March 2011
    kgmcneil wrote: »
    And the final version of all those edits will look like...?..

    IF i did not make any mistake :
    (gedit 'killed' the 'tab-size')
    ; ---------------
    ; 4x8 font driver, (c) 2007 Andrew Owen
    ; ---------------
    
        org    50000        ;
    
    ; --------------------------------
    ; CREATE CHANNEL AND ATTACH STREAM
    ; --------------------------------
    ;
    ; Based on code by Ian Beardsmore from Your Spectrum issue 7, September 1984.
    
    c_chan:    ld    hl,($5c53)    ; a channel must be created below basic
                            ; so look at the system variable PROG
        dec    hl        ; move hl down one address
    
        ld    bc,$0005    ; the new channel takes 5 bytes
        call    $1655        ; call the MAKE_ROOM routine
        inc    hl        ; move HL up one address
    
        ld    bc,chan_4    ; could write the bytes directly but
                    ; then code would be non-relocatable
    
        ld    (hl),c        ; low byte of the output routine
        inc    hl        ; move HL up one address
        push    hl        ; save this address for later
    
        ld    (hl),b        ; high byte of the output routine
        inc    hl        ; move HL up one address
    
        ld    bc,$15c4    ; address of input routine
    
        ld    (hl),c        ; low byte of the input routine
        inc    hl        ; move HL up one address
    
        ld    (hl),b        ; high byte of the input routine
        inc    hl        ; move HL up one address 
    
        ld    (hl),'P'    ; channel type; 'K', 'S', 'R' or 'P'
    
    ; attach stream
    
        pop    hl        ; the first address plus one of the
                    ; extra space stored earlier
        ld    de,($5c4f)    ; store the contents of CHANS in DE
        and    a        ; clear the carry flag before
                    ; calculation
        sbc    hl,de        ; the difference between the start of
                    ; the channels area and the start of the
                    ; extra space becomes the offset, stored
                    ; in HL
        ex    de,hl        ; store the offset in DE
    
        ld    hl,$5c10    ; store the contents of STRMS in HL
        ld    a,$04        ; stream number 4
        add    a,$03        ; take account of streams -3 to -1
        add    a,a        ; each of the seven default streams has
                    ; two bytes of offset data
                    ; the total number of bytes occupied,
                    ; held in a, forms the offset for the
                    ; new stream
        ld    b,$00        ; set b to hold $00
        ld    c,a        ; set the low byte of the offset
        add    hl,bc        ; the offset is added to the base
                    ; address to give the correct location
                    ; in the streams table to store the
                    ; offset
        ld    (hl),e        ; the low byte of the offset
        inc    hl        ; move HL up one address
        ld    (hl),d        ; the high byte of the offset
        ret            ; all done
    
    ; -----------------
    ; CHANNEL #4 OUTPUT
    ; -----------------
    ;
    ; Based on code by Tony Samuels from Your Spectrum issue 13, April 1985.
    ; A channel wrapper for the 64-column display driver.
    
    chan_4:    ld    b,a        ; save character
        ld    a,(atflg)    ; value of AT flag
        and    a        ; test against zero
        jr    nz,getrow    ; jump if not
        ld    a,b        ; restore character
    
    atchk:    cp    $16        ; test for AT
        jr    nz,crchk    ; if not test for CR
        ld    a,$ff        ; set the AT flag
        ld    (atflg),a    ; next character will be row
        ret            ; return
    
    getrow:    cp    $fe        ; test AT flag
        jr    z,getcol    ; jump if setting col
        ld    a,b        ; restore character
        cp    $18        ; greater than 23?
        jr    nc,err_b    ; error if so
        
        ld    (row),a        ; store it in row
        ld    hl,atflg    ; AT flag
        dec    (hl)        ; indicates next character is col
        ret            ; return
    
    getcol:    ld    a,b        ; restore character
        cp    $40        ; greater than 63?
        jr    nc,err_b    ; error if so
        ld    (col),a        ; store it in col
        xor    a        ; set a to zero
        ld    (atflg),a    ; store in AT flag
        ret            ; return
    
    err_b:    xor    a        ; set a to zero
        ld    (atflg),a    ; clear AT flag
        rst    08h        ;
        defb    $0a        ;
    
    crchk:    cp    $0d        ; check for return
        jr    z,do_cr        ; to carriage return if so
        call    pr_64        ; print it
    
        ld    hl,col        ; increment
        inc    (hl)        ; the column
        ld    a,(hl)        ;
        
        cp    $40        ; column 64?
        ret    nz        ;
    
    do_cr:  xor    a                ; set A to zero
            ld    (col),a           ; reset column
            ld    a,(row)           ; get the row
            inc    a                ; increment it
            cp    $18               ; row 24?
            jr   nz,zend            ;
            xor    a                ;
    zend:   ld    (row),a           ; write it back
            ret
    
    ; ------------------------
    ; 64 COLUMN DISPLAY DRIVER
    ; ------------------------
    
    pr_64:  rra                     ; divide by two with remainder in carry flag
            ld    l,a               ; CHAR to low byte of HL
            XOR A           
            ld    h,A               ; clear H
            ex    af,af'            ; save the carry flag
    
        add    hl,hl        ; multiply
        add    hl,hl        ; by
        add    hl,hl        ; eight
        ld    de,font-$80    ; offset to FONT
        add    hl,de        ; HL holds address of first byte of
                    ; character map in FONT
        push    hl        ; save font address
    
    ; convert the row to the base screen address
    
        ld    a,(row)        ; get the row
        ld    b,a        ; save it
        and    $18        ; mask off bit 3-4
        ld    d,a        ; store high byte of offset in D
        ld    a,b        ; retrieve it
        and    $07        ; mask off bit 0-2
        rlca            ; shift
        rlca            ; five
        rlca            ; bits
        rlca            ; to the
        rlca            ; left
        ld    e,a        ; store low byte of offset in E
    
    ; add the column
    
        ld    a,(col)        ; get the column
        rra            ; divide by two with remainder in carry flag
        push    af        ; store the carry flag
    
        ld    h,$40        ; base location
        ld    l,a        ; plus column offset
    
        add    hl,de        ; add the offset
    
        ex    de,hl        ; put the result back in DE
    
    ; HL now points to the location of the first byte of char data in FONT_1
    ; DE points to the first screen byte in SCREEN_1
    ; C holds the offset to the routine
    
            pop    af        ; restore column carry flag
            pop    hl        ; restore the font address
            ld     b,$08        ; 8 bytes to write
            jr     nc,odd_col    ; jump if odd column
    
    even_col:
            ex     af,af'        ; restore char position carry flag
            jr     c,l_on_l    ; left char on left col
            jr     r_on_l        ; right char on left col
    
    odd_col:
            ex     af,af'        ; restore char position carry flag
            jr     nc,r_on_r    ; right char on right col
            jr     l_on_r        ; left char on right col
    
    ; -------------------------------
    ; WRITE A CHARACTER TO THE SCREEN
    ; -------------------------------
    ;
    ; There are four separate routines
    
    ; HL points to the first byte of a character in FONT
    ; DE points to the first byte of the screen address
    
    ; left nibble on left hand side
    
    ll_lp:    ld    a,(de)        ; read byte at destination
    l_on_l:    and    $f0        ; mask area used by new character
        ld    c,a        ; store in b
        ld    a,(hl)        ; get byte of font
        and    $0f        ; mask off unused half
        or    c        ; combine with background
        ld    (de),a        ; write it back
        inc    d        ; point to next screen location
        inc    hl        ; point to next font data
        djnz    ll_lp            ; loop 8 times
        ret            ; done
    
    ; right nibble on right hand side
    
    rr_lp:    ld    a,(de)        ; read byte at destination
    r_on_r: and    $0f        ; mask area used by new character
        ld    c,a        ; store in b
        ld    a,(hl)        ; get byte of font
        and    $f0        ; mask off unused half
        or    c        ; combine with background
        ld    (de),a        ; write it back
        inc    d        ; point to next screen location
        inc    hl        ; point to next font data
        djnz    rr_lp        ; loop 8 times
        ret            ; done
    
    ; left nibble on right hand side
    
    lr_lp:    ld    a,(de)        ; read byte at destination
    l_on_r:    and    $0f        ; mask area used by new character
        ld    c,a        ; store in b
        ld    a,(hl)        ; get byte of font
        rrca            ; shift right
        rrca            ; four bits
        rrca            ; leaving 7-4
        rrca            ; empty
        and    $f0        ;
        or    c        ; combine with background
        ld    (de),a        ; write it back
        inc    d        ; point to next screen location
        inc    hl        ; point to next font data
        djnz    lr_lp            ; loop 8 times
        ret            ; done
    
    ; right nibble on left hand side
    
    rl_lp:    ld    a,(de)        ; read byte at destination
    r_on_l:    and    $f0        ; mask area used by new character
        ld    c,a        ; store in b
        ld    a,(hl)        ; get byte of font
        rlca            ; shift left
        rlca            ; four bits
        rlca            ; leaving 3-0
        rlca            ; empty
        and    $0f        ;
        or    c        ; combine with background
        ld    (de),a        ; write it back
        inc    d        ; point to next screen location
        inc    hl        ; point to next font data
        djnz    rl_lp            ; loop 8 times
        ret            ; done
    
    ; --------------
    ; TEXT VARIABLES
    ; --------------
    ;
    ; Used by the 64 column driver
    
    atflg:    defb    $00        ; AT flag
    row:    defb    $00        ; row
    col:    defb    $00        ; col
    
    ; -------------------
    ; half width 4x7 font
    ; -------------------
    ;
    ; 336 bytes
    
    font:
        defb   $02,$02,$02,$02,$00,$02,$00, $52,$57,$02,$02,$07,$02,$00;
        defb   $25,$71,$62,$32,$74,$25,$00, $22,$42,$30,$50,$50,$30,$00;
        defb   $14,$22,$41,$41,$41,$22,$14, $20,$70,$22,$57,$02,$00,$00;
        defb   $00,$00,$00,$07,$00,$20,$20, $01,$01,$02,$02,$04,$14,$00;
        defb   $22,$56,$52,$52,$52,$27,$00, $27,$51,$12,$21,$45,$72,$00;
        defb   $57,$54,$56,$71,$15,$12,$00, $17,$21,$61,$52,$52,$22,$00;
        defb   $22,$55,$25,$53,$52,$24,$00, $00,$00,$22,$00,$00,$22,$02;
        defb   $00,$10,$27,$40,$27,$10,$00, $02,$45,$21,$12,$20,$42,$00;
        defb   $23,$55,$75,$77,$45,$35,$00, $63,$54,$64,$54,$54,$63,$00;
        defb   $67,$54,$56,$54,$54,$67,$00, $73,$44,$64,$45,$45,$43,$00;
        defb   $57,$52,$72,$52,$52,$57,$00, $35,$15,$16,$55,$55,$25,$00;
        defb   $45,$47,$45,$45,$45,$75,$00, $62,$55,$55,$55,$55,$52,$00;
        defb   $62,$55,$55,$65,$45,$43,$00, $63,$54,$52,$61,$55,$52,$00;
        defb   $75,$25,$25,$25,$25,$22,$00, $55,$55,$55,$55,$27,$25,$00;
        defb   $55,$55,$25,$22,$52,$52,$00, $73,$12,$22,$22,$42,$72,$03;
        defb   $46,$42,$22,$22,$12,$12,$06, $20,$50,$00,$00,$00,$00,$0F;
        defb   $20,$10,$03,$05,$05,$03,$00, $40,$40,$63,$54,$54,$63,$00;
        defb   $10,$10,$32,$55,$56,$33,$00, $10,$20,$73,$25,$25,$43,$06;
        defb   $42,$40,$66,$52,$52,$57,$00, $14,$04,$35,$16,$15,$55,$20;
        defb   $60,$20,$25,$27,$25,$75,$00, $00,$00,$62,$55,$55,$52,$00;
        defb   $00,$00,$63,$55,$55,$63,$41, $00,$00,$53,$66,$43,$46,$00;
        defb   $00,$20,$75,$25,$25,$12,$00, $00,$00,$55,$55,$27,$25,$00;
        defb   $00,$00,$55,$25,$25,$53,$06, $01,$02,$72,$34,$62,$72,$01;
        defb   $24,$22,$22,$21,$22,$22,$04, $56,$A9,$06,$04,$06,$09,$06;
    
    my old website http://home.hccnet.nl/c.born/ has changed to http://www.cborn.nl/zxfiles/ so just click it and select a file
  • edited March 2011
    Just tried compiling it with Pasmo. You've broken something. Not sure what but I suspect the offset used to determine the character address needs fixing.
  • edited March 2011
    aowen wrote: »
    Just tried compiling it with Pasmo. You've broken something. Not sure what but I suspect the offset used to determine the character address needs fixing.

    Aha, that will be a step 7 now instead of a step 8.
    I did not check how you calculated it, i dive in it.

    edit:
        add    hl,hl          ; multiply
        add    hl,hl          ; by
        add    hl,hl          ; eight
        ld     de,font-$80    ; offset to FONT
        add    hl,de          ; HL holds address of first byte of
                              ; character map in FONT
        push   hl             ; save font address
    
    this needs to be a different calculation now, its not ment to make a duplicate off my own 64c version but i have a look there.

    edit 2 :
    I think this is it:
    pr_64:  rra                     ; divide by two with remainder in carry flag
            ld    l,a               ; CHAR to low byte of HL
            xor   a          
            ld    h,A               ; clear H
            ex    af,af'            ; save the carry flag
            ld    a,l                 
            ld    b,6
    adl:    add   l                 ; A=L now add L 6 more times  
            djnz  adl               ; multiply by 7
            ld     l,a 
            ld    de,font-$80       ; offset to FONT
            add   hl,de             ; HL holds address of first byte of
                                    ; character map in FONT
            push  hl                ; save font address
    
    
    with 4 bytes extra the shrinking is now 61-4=57 bytes
    my old website http://home.hccnet.nl/c.born/ has changed to http://www.cborn.nl/zxfiles/ so just click it and select a file
  • edited March 2011
    NO
    On entry in pr_64 the value of A is the character from 32 to 127
    the rra gives a MAX value of 63,
    63 x 7 =441 , thats a 16 bit value

    this is the one:
    (and else i pasmo my self)
    pr_64:  rra                     ; divide by two with remainder in carry flag
            ld    l,a               ; CHAR to low byte of HL
            xor   a          
            ld    h,A               ; clear H
            ex    af,af'            ; save the carry flag
    
            push hl
            pop de
            ld    b,6
    adl:    add   hl,de             ; DE=HL now add DE 6 more times  
            djnz  adl               ; multiply by 7
            ld    de,font-$80       ; offset to FONT
            add   hl,de             ; HL holds address of first byte of
                                    ; character map in FONT
            push  hl                ; save font address
    
    
    OK
    OK
    so i pasmo my self...
    :oops:
    my old website http://home.hccnet.nl/c.born/ has changed to http://www.cborn.nl/zxfiles/ so just click it and select a file
  • edited March 2011
    working (BASIC changed)
    the original is 657 bytes
    now its 602 bytes, with exactly the same result, a 8 % reduction
    ; ---------------
    ; 4x8 font driver, (c) 2007 Andrew Owen
    ; ---------------
    
        org    50000        ;
    
    ; --------------------------------
    ; CREATE CHANNEL AND ATTACH STREAM
    ; --------------------------------
    ;
    ; Based on code by Ian Beardsmore from Your Spectrum issue 7, September 1984.
    
    c_chan:    ld    hl,($5c53)    ; a channel must be created below basic
                            ; so look at the system variable PROG
        dec    hl        ; move hl down one address
    
        ld    bc,$0005    ; the new channel takes 5 bytes
        call    $1655        ; call the MAKE_ROOM routine
        inc    hl        ; move HL up one address
    
        ld    bc,chan_4    ; could write the bytes directly but
                    ; then code would be non-relocatable
    
        ld    (hl),c        ; low byte of the output routine
        inc    hl        ; move HL up one address
        push    hl        ; save this address for later
    
        ld    (hl),b        ; high byte of the output routine
        inc    hl        ; move HL up one address
    
        ld    bc,$15c4    ; address of input routine
    
        ld    (hl),c        ; low byte of the input routine
        inc    hl        ; move HL up one address
    
        ld    (hl),b        ; high byte of the input routine
        inc    hl        ; move HL up one address 
    
        ld    (hl),'P'    ; channel type; 'K', 'S', 'R' or 'P'
    
    ; attach stream
    
        pop    hl        ; the first address plus one of the
                    ; extra space stored earlier
        ld    de,($5c4f)    ; store the contents of CHANS in DE
        and    a        ; clear the carry flag before
                    ; calculation
        sbc    hl,de        ; the difference between the start of
                    ; the channels area and the start of the
                    ; extra space becomes the offset, stored
                    ; in HL
        ex    de,hl        ; store the offset in DE
    
        ld    hl,$5c10    ; store the contents of STRMS in HL
        ld    a,$04        ; stream number 4
        add    a,$03        ; take account of streams -3 to -1
        add    a,a        ; each of the seven default streams has
                    ; two bytes of offset data
                    ; the total number of bytes occupied,
                    ; held in a, forms the offset for the
                    ; new stream
        ld    b,$00        ; set b to hold $00
        ld    c,a        ; set the low byte of the offset
        add    hl,bc        ; the offset is added to the base
                    ; address to give the correct location
                    ; in the streams table to store the
                    ; offset
        ld    (hl),e        ; the low byte of the offset
        inc    hl        ; move HL up one address
        ld    (hl),d        ; the high byte of the offset
        ret            ; all done
    
    ; -----------------
    ; CHANNEL #4 OUTPUT
    ; -----------------
    ;
    ; Based on code by Tony Samuels from Your Spectrum issue 13, April 1985.
    ; A channel wrapper for the 64-column display driver.
    
    chan_4:    ld    b,a        ; save character
        ld    a,(atflg)    ; value of AT flag
        and    a        ; test against zero
        jr    nz,getrow    ; jump if not
        ld    a,b        ; restore character
    
    atchk:    cp    $16        ; test for AT
        jr    nz,crchk    ; if not test for CR
        ld    a,$ff        ; set the AT flag
        ld    (atflg),a    ; next character will be row
        ret            ; return
    
    getrow:    cp    $fe        ; test AT flag
        jr    z,getcol    ; jump if setting col
        ld    a,b        ; restore character
        cp    $18        ; greater than 23?
        jr    nc,err_b    ; error if so
        
        ld    (row),a        ; store it in row
        ld    hl,atflg    ; AT flag
        dec    (hl)        ; indicates next character is col
        ret            ; return
    
    getcol:    ld    a,b        ; restore character
        cp    $40        ; greater than 63?
        jr    nc,err_b    ; error if so
        ld    (col),a        ; store it in col
        xor    a        ; set a to zero
        ld    (atflg),a    ; store in AT flag
        ret            ; return
    
    err_b:    xor    a        ; set a to zero
        ld    (atflg),a    ; clear AT flag
        rst    08h        ;
        defb    $0a        ;
    
    crchk:    cp    $0d        ; check for return
        jr    z,do_cr        ; to carriage return if so
        call    pr_64        ; print it
    
        ld    hl,col        ; increment
        inc    (hl)        ; the column
        ld    a,(hl)        ;
        
        cp    $40        ; column 64?
        ret    nz        ;
    
    do_cr:  xor    a                ; set A to zero
            ld    (col),a           ; reset column
            ld    a,(row)           ; get the row
            inc    a                ; increment it
            cp    $18               ; row 24?
            jr   nz,zend            ;
            xor    a                ;
    zend:   ld    (row),a           ; write it back
            ret
    
    ; ------------------------
    ; 64 COLUMN DISPLAY DRIVER
    ; ------------------------
    
    pr_64:  rra                     ; divide by two with remainder in carry flag
            ld    l,a               ; CHAR to low byte of HL
            ld    a,0               ; dont touch carry flag      
            ld    h,A               ; clear H
            ex    af,af'            ; save the carry flag
    
            push hl
            pop de
            ld    b,6
    adl:    add   hl,de             ; DE=HL now add DE 6 more times  
            djnz  adl               ; multiply by 7
            ld    de,font-$71       ; offset to FONT
            add   hl,de             ; HL holds address of first byte of
                                    ; character map in FONT
            push  hl                ; save font address
    
    ; convert the row to the base screen address
    
        ld    a,(row)        ; get the row
        ld    b,a        ; save it
        and    $18        ; mask off bit 3-4
        ld    d,a        ; store high byte of offset in D
        ld    a,b        ; retrieve it
        and    $07        ; mask off bit 0-2
        rlca            ; shift
        rlca            ; five
        rlca            ; bits
        rlca            ; to the
        rlca            ; left
        ld    e,a        ; store low byte of offset in E
    
    ; add the column
    
        ld    a,(col)        ; get the column
        rra            ; divide by two with remainder in carry flag
        push    af        ; store the carry flag
    
        ld    h,$40        ; base location
        ld    l,a        ; plus column offset
    
        add    hl,de        ; add the offset
    
        ex    de,hl        ; put the result back in DE
    
    ; HL now points to the location of the first byte of char data in FONT_1
    ; DE points to the first screen byte in SCREEN_1
    ; C holds the offset to the routine
    
            pop    af        ; restore column carry flag
            pop    hl        ; restore the font address
            ld     b,$08        ; 8 bytes to write
            jr     nc,odd_col    ; jump if odd column
    
    even_col:
            ex     af,af'        ; restore char position carry flag
            jr     c,l_on_l    ; left char on left col
            jr     r_on_l        ; right char on left col
    
    odd_col:
            ex     af,af'        ; restore char position carry flag
            jr     nc,r_on_r    ; right char on right col
            jr     l_on_r        ; left char on right col
    
    ; -------------------------------
    ; WRITE A CHARACTER TO THE SCREEN
    ; -------------------------------
    ;
    ; There are four separate routines
    
    ; HL points to the first byte of a character in FONT
    ; DE points to the first byte of the screen address
    
    ; left nibble on left hand side
    
    ll_lp:    ld    a,(hl)        ; get byte of font
    l_on_l:    and    $0f        ; mask area used by new character
        ld    c,a        ; store in c
        ld    a,(de)        ; read byte at destination
        and    $f0        ; mask off unused half
        or    c        ; combine with background
        ld    (de),a        ; write it back
        inc    d        ; point to next screen location
        inc    hl        ; point to next font data
        djnz    ll_lp            ; loop 8 times
        ret            ; done
    
    ; right nibble on right hand side
    
    rr_lp:    ld    a,(hl)        ; read byte at destination
    r_on_r: and    $f0        ; mask area used by new character
        ld    c,a        ; store in c
        ld    a,(de)        ; get byte of font
        and    $0f        ; mask off unused half
        or    c        ; combine with background
        ld    (de),a        ; write it back
        inc    d        ; point to next screen location
        inc    hl        ; point to next font data
        djnz    rr_lp        ; loop 8 times
        ret            ; done
    
    ; left nibble on right hand side
    
    lr_lp:    ld    a,(hl)        ; read byte at destination
        rrca            ; shift right
        rrca            ; four bits
        rrca            ; leaving 7-4
        rrca            ; empty
    l_on_r:    and    $f0        ; mask area used by new character
        ld    c,a        ; store in c
        ld    a,(de)        ; get byte of font
    
        and    $0f        ;
        or    c        ; combine with background
        ld    (de),a        ; write it back
        inc    d        ; point to next screen location
        inc    hl        ; point to next font data
        djnz    lr_lp            ; loop 8 times
        ret            ; done
    
    ; right nibble on left hand side
    
    rl_lp:    ld    a,(hl)        ; read byte at destination
        rlca            ; shift left
        rlca            ; four bits
        rlca            ; leaving 3-0
        rlca            ; empty
    r_on_l:    and    $0f        ; mask area used by new character
        ld    c,a        ; store in c
        ld    a,(de)        ; get byte of font
    
        and    $f0        ;
        or    c        ; combine with background
        ld    (de),a        ; write it back
        inc    d        ; point to next screen location
        inc    hl        ; point to next font data
        djnz    rl_lp            ; loop 8 times
        ret            ; done
    
    ; --------------
    ; TEXT VARIABLES
    ; --------------
    ;
    ; Used by the 64 column driver
    
    atflg:    defb    $00        ; AT flag
    row:    defb    $00        ; row
    col:    defb    $00        ; col
    
    ; -------------------
    ; half width 4x7 font
    ; -------------------
    ;
    ; 336 bytes
    
    font:
        defb   $02,$02,$02,$02,$00,$02,$00, $52,$57,$02,$02,$07,$02,$00;
        defb   $25,$71,$62,$32,$74,$25,$00, $22,$42,$30,$50,$50,$30,$00;
        defb   $14,$22,$41,$41,$41,$22,$14, $20,$70,$22,$57,$02,$00,$00;
        defb   $00,$00,$00,$07,$00,$20,$20, $01,$01,$02,$02,$04,$14,$00;
        defb   $22,$56,$52,$52,$52,$27,$00, $27,$51,$12,$21,$45,$72,$00;
        defb   $57,$54,$56,$71,$15,$12,$00, $17,$21,$61,$52,$52,$22,$00;
        defb   $22,$55,$25,$53,$52,$24,$00, $00,$00,$22,$00,$00,$22,$02;
        defb   $00,$10,$27,$40,$27,$10,$00, $02,$45,$21,$12,$20,$42,$00;
        defb   $23,$55,$75,$77,$45,$35,$00, $63,$54,$64,$54,$54,$63,$00;
        defb   $67,$54,$56,$54,$54,$67,$00, $73,$44,$64,$45,$45,$43,$00;
        defb   $57,$52,$72,$52,$52,$57,$00, $35,$15,$16,$55,$55,$25,$00;
        defb   $45,$47,$45,$45,$45,$75,$00, $62,$55,$55,$55,$55,$52,$00;
        defb   $62,$55,$55,$65,$45,$43,$00, $63,$54,$52,$61,$55,$52,$00;
        defb   $75,$25,$25,$25,$25,$22,$00, $55,$55,$55,$55,$27,$25,$00;
        defb   $55,$55,$25,$22,$52,$52,$00, $73,$12,$22,$22,$42,$72,$03;
        defb   $46,$42,$22,$22,$12,$12,$06, $20,$50,$00,$00,$00,$00,$0F;
        defb   $20,$10,$03,$05,$05,$03,$00, $40,$40,$63,$54,$54,$63,$00;
        defb   $10,$10,$32,$55,$56,$33,$00, $10,$20,$73,$25,$25,$43,$06;
        defb   $42,$40,$66,$52,$52,$57,$00, $14,$04,$35,$16,$15,$55,$20;
        defb   $60,$20,$25,$27,$25,$75,$00, $00,$00,$62,$55,$55,$52,$00;
        defb   $00,$00,$63,$55,$55,$63,$41, $00,$00,$53,$66,$43,$46,$00;
        defb   $00,$20,$75,$25,$25,$12,$00, $00,$00,$55,$55,$27,$25,$00;
        defb   $00,$00,$55,$25,$25,$53,$06, $01,$02,$72,$34,$62,$72,$01;
        defb   $24,$22,$22,$21,$22,$22,$04, $56,$A9,$06,$04,$06,$09,$06;
    
    Its always easier to change some one else existing code than to create your own non exsisting code,
    Thanks for the code Andrew
    my old website http://home.hccnet.nl/c.born/ has changed to http://www.cborn.nl/zxfiles/ so just click it and select a file
  • edited March 2011
    boriel wrote: »
    Someone contributed a print64 routine to the ZX BASIC compiler library. I wonder if it was this one in fact! :smile:
    I'm currently evaluating print64 routines (have other from Spanish MicroHobby magazine which looks really compact) to add as much libraries as possible.

    That someone was me. I grabbed it from somewhere some months back, and I honestly can't remember if it was Aowens. It was rewritten quite a bit to make it zxbasic compatible, but I definitely did some stealing initially. The 42 char code came from the same source.

    *scratches head* I hate to not credit the original author, but honestly, it became a text file on my computer that lost the original. If it was you Aowen, I do apologise. I'm certain that your routine here was one of the inspirations.
  • edited March 2011
    Crisis wrote: »
    Its always easier to change some one else existing code than to create your own non exsisting code, Thanks for the code Andrew

    You're welcome. I'm glad someone found it useful after all this time. I was inspired to write it by the knowledge that YS MegaBASIC stored the font in the same way. I borrowed the outline code from Your Spectrum. All the routines you'll ever need were in that mag.
  • edited March 2011
    Gedlion wrote: »
    I hate to not credit the original author, but honestly, it became a text file on my computer that lost the original. If it was you Aowen, I do apologise. I'm certain that your routine here was one of the inspirations.

    The easy way to check if it's mine or not is to compare the font. I designed it myself and you'll notice it has taller ascenders than most other 4x8 typefaces.

    If you used it without crediting me don't worry about it. Once I've put my code out there I don't mind what people do with it. If it turns out it was mine you can always add the credit later.
  • edited March 2011
    Z80user wrote: »
    I think the comments of source code are wrong in all four runtimes l_on_l r_on_r l_on_r and r_on_l

    I double checked and the comments are correct. I've updated the code to use binary masks so it's easier to see what's going on. I've reformatted the last version from Crisis and made a slight change so that multiplying by 7 no-longer uses the stack or a loop. The code still comes in at 602 bytes. I've also changed the default location to just below the UDGs.
    ; 4x8 FONT DRIVER
    ; (c) 2007, 2011 Andrew Owen
    ; optimized by Crisis (to 602 bytes)
    
    	org	64166		; any address will do but this is just
    				; before the UDGs
    
    ; CREATE CHANNEL AND ATTACH STREAM
    ; Based on code by Ian Beardsmore from Your Spectrum issue 7, September 84.
    
    c_chan:
    	ld	hl, (0x5c53)	; a channel must be created below basic
    				; so look at the system variable PROG
    	dec	hl		; move hl down one address
    	ld	bc, 5		; the new channel takes 5 bytes
    	call	0x1655		; call the MAKE-ROOM routine
    	inc	hl		; move HL up one address
    	ld	bc, chan_4	; could write the bytes directly but
    				; then code would be non-relocatable
    	ld	(hl), c		; low byte of the output routine
    	inc	hl		; move HL up one address
    	push	hl		; save this address for later
    	ld	(hl), b		; high byte of the output routine
    	inc	hl		; move HL up one address
    	ld	bc, 0x15c4	; address of input routine
    	ld	(hl), c		; low byte of the input routine
    	inc	hl		; move HL up one address
    	ld	(hl), b		; high byte of the input routine
    	inc	hl		; move HL up one address 
    	ld	(hl), 'P'	; channel type; 'K', 'S', 'R' or 'P'
    
    ; attach stream
    
    	pop	hl		; the first address plus one of the
    				; extra space stored earlier
    	ld	de, (0x5c4f)	; store the contents of CHANS in DE
    	and	a		; clear the carry flag before calculation
    	sbc	hl, de		; the difference between the start of
    				; the channels area and the start of the
    				; extra space becomes the offset, stored
    				; in HL
    	ex	de, hl		; store the offset in DE
    	ld	hl, 0x5c10	; store the contents of STRMS in HL
    	ld	a, 4		; stream number 4
    	add	a, 3		; take account of streams -3 to -1
    	add	a, a		; each of the seven default streams has
    				; two bytes of offset data
    				; the total number of bytes occupied, 
    				; held in a, forms the offset for the
    				; new stream
    	ld	b, 0		; set b to hold 0
    	ld	c, a		; set the low byte of the offset
    	add	hl, bc		; the offset is added to the base
    				; address to give the correct location
    				; in the streams table to store the offset
    	ld	(hl), e		; the low byte of the offset
    	inc	hl		; move HL up one address
    	ld	(hl), d		; the high byte of the offset
    	ret
    
    ; CHANNEL #4 OUTPUT
    ; Based on code by Tony Samuels from Your Spectrum issue 13, April 85.
    ; A channel wrapper for the 64-column display driver.
    
    chan_4:
    	ld	b, a		; save character
    	ld	a, (atflg)	; value of AT flag
    	and	a		; test against zero
    	jr	nz, getrow	; jump if not
    	ld	a, b		; restore character
    
    atchk:
    	cp	0x16		; test for AT
    	jr	nz, crchk	; if not test for CR
    	ld	a, 0xff		; set the AT flag
    	ld	(atflg), a	; next character will be row
    	ret
    
    getrow:
    	cp	0xfe		; test AT flag
    	jr	z, getcol	; jump if setting col
    	ld	a, b		; restore character
    	cp	24 		; greater than 23?
    	jr	nc, err_b	; error if so
    	ld	(row), a	; store it in row
    	ld	hl, atflg	; AT flag
    	dec 	(hl)		; indicates next character is col
    	ret
    
    getcol:
    	ld	a, b		; restore character
    	cp	64		; greater than 63?
    	jr	nc, err_b	; error if so
    	ld	(col), a	; store it in col
    	xor	a		; set a to zero
    	ld	(atflg), a	; store in AT flag
    	ret
    
    err_b:
    	xor	a		; set a to zero
    	ld	(atflg), a	; clear AT flag
    	rst	8h		; error
    	defb	10 		; B: integer out of range
    
    crchk:
    	cp	0x0d		; check for return
    	jr	z, do_cr	; to carriage return if so
    	call	pr_64		; print it
    	ld	hl, col		; increment
    	inc	(hl)		; the column
    	ld	a, (hl)		; get it
    	cp	64		; column 64?
    	ret	nz		; return if not
    
    do_cr:
    	xor	a		; set A to zero
    	ld	(col), a	; reset column
    	ld	a, (row)	; get the row
    	inc	a		; increment it
    	cp	24		; row 24?
    	jr	nz, zend	;
    	xor	a		; reset if so
    
    zend:
    	ld	(row), a	; write it back
    	ret
    
    ; 64 COLUMN DISPLAY DRIVER
    
    pr_64:
    	rra			; divide by two with remainder in carry
    				; flag
    	ld	l, a		; CHAR to low byte of HL
    	ld	a, 0		; don't touch carry flag
    	ld	h, a		; clear H
    	ex	af, af'		; save the carry flag
    	ld	d, h		; store HL in DE
    	ld	e, l		; without using the stack
    	add	hl, hl		; multiply
    	add	hl, hl		; by
    	add	hl, hl		; eight
    	sbc	hl, de		; subtract DE to get original x7
    	ld	de, font - 0x71 ; offset to FONT
    	add	hl, de		; HL holds address of first byte of
    				; character map in FONT
    	push	hl		; save font address
    
    ; convert the row to the base screen address
    
    	ld	a, (row)	; get the row
    	ld	b, a		; save it
    	and	%00011000	; mask off bit 3-4
    	ld	d, a		; store high byte of offset in D
    	ld	a, b		; retrieve it
    	and 	%00000111	; mask off bit 0-2
    	rlca			; shift
    	rlca			; five
    	rlca			; bits
    	rlca			; to the
    	rlca			; left
    	ld	e, a		; store low byte of offset in E
    
    ; add the column
    
    	ld	a, (col)	; get the column
    	rra			; divide by two with remainder in carry
    				; flag
    	push	af		; store the carry flag
    	ld	h, 0x40		; base location
    	ld	l, a		; plus column offset
    	add	hl, de		; add the offset
    	ex	de, hl		; put the result back in DE
    
    ; HL now points to the location of the first byte of char data in FONT
    ; DE points to the first byte of the screen address
    ; C holds the offset to the routine
    
    	pop	af		; restore column carry flag
    	pop	hl		; restore the font address
    	ld	b, 8		; 8 bytes to write
    	jr	nc, odd_col	; jump if odd column
    
    even_col:
    	ex	af, af' 	; restore char position carry flag
    	jr	c, l_on_l	; left char on left col
    	jr	r_on_l		; right char on left col
    
    odd_col:
    	ex	af, af'		; restore char position carry flag
    	jr	nc, r_on_r	; right char on right col
    	jr	l_on_r		; left char on right col
    
    ; WRITE A CHARACTER TO THE SCREEN
    ; There are four separate routines
    ; HL points to the first byte of a character in FONT
    ; DE points to the first byte of the screen address
    
    ; left nibble on left hand side
    
    ll_lp:
    	ld	a, (hl)		; get byte of font
    
    l_on_l:
    	and	%00001111	; mask area used by new character
    	ld	c, a		; store in c
    	ld	a, (de)		; read byte at destination
    	and	%11110000	; mask off unused half
    	or	c		; combine with background
    	ld	(de), a		; write it back
    	inc	d		; point to next screen location
    	inc	hl		; point to next font data
    	djnz	ll_lp		; loop 8 times
    	ret
    
    ; right nibble on right hand side
    
    rr_lp:
    	ld	a, (hl)		; read byte at destination
    
    r_on_r:
    	and	%11110000	; mask area used by new character
    	ld	c, a		; store in c
    	ld	a, (de)		; get byte of font
    	and 	%00001111	; mask off unused half
    	or	c		; combine with background
    	ld	(de), a		; write it back
    	inc	d		; point to next screen location
    	inc	hl		; point to next font data
    	djnz	rr_lp		; loop 8 times
    	ret
    
    ; left nibble on right hand side
    
    lr_lp:
    	ld	a, (hl)		; read byte at destination
    	rrca 			; shift right
    	rrca			; four bits
    	rrca			; leaving 7-4
    	rrca			; empty
    
    l_on_r:
    	and	%11110000	; mask area used by new character
    	ld	c, a		; store in c
    	ld	a, (de)		; get byte of font
    	and	%00001111	; mask off unused half
    	or	c		; combine with background
    	ld	(de), a		; write it back
    	inc	d		; point to next screen location
    	inc	hl		; point to next font data
    	djnz	lr_lp		; loop 8 times
    	ret
    
    ; right nibble on left hand side
    
    rl_lp:
    	ld	a, (hl)		; read byte at destination
    	rlca			; shift left
    	rlca			; four bits
    	rlca			; leaving 3-0
    	rlca			; empty
    
    r_on_l:
    	and	%00001111	; mask area used by new character
    	ld	c, a		; store in c
    	ld	a, (de)		; get byte of font
    	and	%11110000	; mask off unused half
    	or	c		; combine with background
    	ld	(de), a		; write it back
    	inc	d		; point to next screen location
    	inc	hl		; point to next font data
    	djnz	rl_lp		; loop 8 times
    	ret
    
    ; TEXT VARIABLES
    ; Used by the 64 column driver
    
    atflg:
    	defb	0		; AT flag
    
    row:
    	defb	0		; row
    
    col:
    	defb	0		; col
    
    ; HALF WIDTH 4x8 FONT
    ; Top row is always zero and not stored (336 bytes)
    
    font:
    	defb	0x02, 0x02, 0x02, 0x02, 0x00, 0x02, 0x00	; !
    	defb	0x52, 0x57, 0x02, 0x02, 0x07, 0x02, 0x00	;"#
    	defb	0x25, 0x71, 0x62, 0x32, 0x74, 0x25, 0x00	;$%
    	defb	0x22, 0x42, 0x30, 0x50, 0x50, 0x30, 0x00	;&'
    	defb	0x14, 0x22, 0x41, 0x41, 0x41, 0x22, 0x14	;()
    	defb	0x20, 0x70, 0x22, 0x57, 0x02, 0x00, 0x00	;*+
    	defb	0x00, 0x00, 0x00, 0x07, 0x00, 0x20, 0x20	;,-
    	defb	0x01, 0x01, 0x02, 0x02, 0x04, 0x14, 0x00	;./
    	defb	0x22, 0x56, 0x52, 0x52, 0x52, 0x27, 0x00	;01
    	defb	0x27, 0x51, 0x12, 0x21, 0x45, 0x72, 0x00	;23
    	defb	0x57, 0x54, 0x56, 0x71, 0x15, 0x12, 0x00	;45
    	defb	0x17, 0x21, 0x61, 0x52, 0x52, 0x22, 0x00	;67
    	defb	0x22, 0x55, 0x25, 0x53, 0x52, 0x24, 0x00	;89
    	defb	0x00, 0x00, 0x22, 0x00, 0x00, 0x22, 0x02	;:;
    	defb	0x00, 0x10, 0x27, 0x40, 0x27, 0x10, 0x00	;<=
    	defb	0x02, 0x45, 0x21, 0x12, 0x20, 0x42, 0x00	;>?
    	defb	0x23, 0x55, 0x75, 0x77, 0x45, 0x35, 0x00	;@A
    	defb	0x63, 0x54, 0x64, 0x54, 0x54, 0x63, 0x00	;BC
    	defb	0x67, 0x54, 0x56, 0x54, 0x54, 0x67, 0x00	;DE
    	defb	0x73, 0x44, 0x64, 0x45, 0x45, 0x43, 0x00	;FG
    	defb	0x57, 0x52, 0x72, 0x52, 0x52, 0x57, 0x00	;HI
    	defb	0x35, 0x15, 0x16, 0x55, 0x55, 0x25, 0x00	;JK
    	defb	0x45, 0x47, 0x45, 0x45, 0x45, 0x75, 0x00	;LM
    	defb	0x62, 0x55, 0x55, 0x55, 0x55, 0x52, 0x00	;NO
    	defb	0x62, 0x55, 0x55, 0x65, 0x45, 0x43, 0x00	;PQ
    	defb	0x63, 0x54, 0x52, 0x61, 0x55, 0x52, 0x00	;RS
    	defb	0x75, 0x25, 0x25, 0x25, 0x25, 0x22, 0x00	;TU
    	defb	0x55, 0x55, 0x55, 0x55, 0x27, 0x25, 0x00	;VW
    	defb	0x55, 0x55, 0x25, 0x22, 0x52, 0x52, 0x00	;XY
    	defb	0x73, 0x12, 0x22, 0x22, 0x42, 0x72, 0x03	;Z[
    	defb	0x46, 0x42, 0x22, 0x22, 0x12, 0x12, 0x06	;\]
    	defb	0x20, 0x50, 0x00, 0x00, 0x00, 0x00, 0x0f	;^_
    	defb	0x20, 0x10, 0x03, 0x05, 0x05, 0x03, 0x00	;?a
    	defb	0x40, 0x40, 0x63, 0x54, 0x54, 0x63, 0x00	;bc
    	defb	0x10, 0x10, 0x32, 0x55, 0x56, 0x33, 0x00	;de
    	defb	0x10, 0x20, 0x73, 0x25, 0x25, 0x43, 0x06	;fg
    	defb	0x42, 0x40, 0x66, 0x52, 0x52, 0x57, 0x00	;hi
    	defb	0x14, 0x04, 0x35, 0x16, 0x15, 0x55, 0x20	;jk
    	defb	0x60, 0x20, 0x25, 0x27, 0x25, 0x75, 0x00	;lm
    	defb	0x00, 0x00, 0x62, 0x55, 0x55, 0x52, 0x00	;no
    	defb	0x00, 0x00, 0x63, 0x55, 0x55, 0x63, 0x41	;pq
    	defb	0x00, 0x00, 0x53, 0x66, 0x43, 0x46, 0x00	;rs
    	defb	0x00, 0x20, 0x75, 0x25, 0x25, 0x12, 0x00	;tu
    	defb	0x00, 0x00, 0x55, 0x55, 0x27, 0x25, 0x00	;vw
    	defb	0x00, 0x00, 0x55, 0x25, 0x25, 0x53, 0x06	;xy
    	defb	0x01, 0x02, 0x72, 0x34, 0x62, 0x72, 0x01	;z{
    	defb	0x24, 0x22, 0x22, 0x21, 0x22, 0x22, 0x04	;|}
    	defb	0x56, 0xa9, 0x06, 0x04, 0x06, 0x09, 0x06	;~?
    
  • edited March 2011
    Its very readable now, smooth.
    Thanks for putting my name in, that might be the first time such happens.
    "I Am Noticed" (were is that megalomania icon)

    If programspace is more importend then speed, which is importend in an overtaking print routine, then you still could consider to use all bits off the ATflg eg for the dubble left and right storage. The 4 times used routine can be reduced to one little bit bigger routine, but will slow down with the use of BIT and SET commands. But a nice AND 8 will check BIT 3 of course.

    one little thing any way:
        ld    (atflg), a    ; store in AT flag
        ret
    
    these 4 bytes are used twice, so you can replace one set with a 2 byte JR adres. Space is alway importend on a Speccy :smile:
    Some time I explain it to people by pionting to a colorfull screen:
    "do you see that icon??
    That's the COMPLETE memory size off my hobby"

    NEXT IS NOT TRUE! shifts are 2 bytes:
    >>>
    and since i am talking about my hobby here, there is another optimisation posible which can lose 2 more byte, with out speed loss.
    Use 'Shift .. Logical' , SLL and SRL, insted of rotate, shift set 0 bits while moving the byte so a cleaning mask is not needed in that case.
    <<<
    my old website http://home.hccnet.nl/c.born/ has changed to http://www.cborn.nl/zxfiles/ so just click it and select a file
  • edited March 2011
    Crisis wrote: »
    NEXT IS NOT TRUE! shifts are 2 bytes:
    >>>
    and since i am talking about my hobby here, there is another optimisation posible which can lose 2 more byte, with out speed loss.
    Use 'Shift .. Logical' , SLL and SRL, insted of rotate, shift set 0 bits while moving the byte so a cleaning mask is not needed in that case.
    <<<

    You're right it's not true. SLL is broken (by Zilog) and will leave an unwanted trail of 1s rather than zeroing the bits as it's supposed to.
  • edited March 2011
    Actualy I ment an SLA insted of SLL, which WAS undocumented.
    Rotating is possible with 1 byte and takes 1 M(4t) while a Shift is Always a 2 byte instruction and more M-cycly. So for a very much used routine you realy dont want that to slow down any thing else.
    4rotates+2bytes mask is stil shorter and faster

    I red your change back and it shows how much i am running a round for doing 1 step
        add    hl, hl        ; multiply
        add    hl, hl        ; by
        add    hl, hl        ; eight
        sbc    hl, de        ; subtract DE to get original x7
    
    to reach that last line i made a 'real' calculation, but not.
    it is so simple....
    my old website http://home.hccnet.nl/c.born/ has changed to http://www.cborn.nl/zxfiles/ so just click it and select a file
  • edited March 2011
    How can I use this from a MC program?

    Is it chan_4 that I need to call with bytes read into 'a' from something like this?
    	defb 22, 30, 11		; AT 30,11
    	defm "Some text..."
    	defb 13			; ENTER
    

    Its a nice readable font for such a small size. I tried to make a 4x6 font for 32 rows x 64 columns but no lower case letters. I stored the characters twice in the same byte. I was wanting to create something similar to Zub's menu.
    WIP Tritone Demo
    No more html on dropbox. :(
Sign In or Register to comment.