Compact 64 column print routine

The place for codemasters or beginners to talk about programming any language for the Spectrum.
User avatar
djnzx48
Manic Miner
Posts: 729
Joined: Wed Dec 06, 2017 2:13 am
Location: New Zealand

Compact 64 column print routine

Post by djnzx48 »

Hello everyone, this is my first post on these forums. :)

I started learning Z80 assembly several years ago but I didn't really do anything with it apart from a few flashy screen effects. So now I've decided to come back to it and attempt to make an actual game, starting with this text routine. It's optimized to be as small as possible (34/35 bytes), with the font using 7 bytes for every pair of characters. I thought I'd share it here in the hope that others might find it useful, so feel free to use it, modify it, whatever.

And I just wanted to say thanks for all the hard work that goes into maintaining ZXDB and this site, it's really appreciated :)

Here's a quick demo of the routine. It's not really this slow, :) I just put in a few HALTs so you can see it properly in action.

Image

Code: Select all

; Prints up to 4 lines of text using a 4x8 character font.
;
; IX = points to one beyond last character of string
; HL = screen address to print at
; C  = number of characters to print, maximum 256 (0)
;
; Notes: The left edge of the string is always aligned
; with a character block. If you want a string to start
; halfway along a block, it must begin with a space.
;
; The font is stored with two graphic rows packed into
; a byte, with each of 7 rows stored on a separate
; 256-byte page.
;
; preserves: IY, alternate registers

charloop:
    ld d, font_hi   ; construct font address
    push hl         ; save screen pos

    ld a, c         ; number of chars left to print
    dec a           ; we want to round downwards
    or a            ; clear carry for scroll
    rra             ; divide by two (64 chars to 32)
    add a, l        ; calculate new screen address
    ld l, a

    ld b, 7         ; loop 7 rows

    dec ix          ; read string backwards

if 1
    ld e, (ix+0)    ; get character
    srl e           ; check value of LSB
else
    db $DD, $CB, $00, $3B   ; ld e, srl (ix+0)
                    ; saves one byte and 4 Ts
                    ; Only use for temporary strings
                    ; (string becomes corrupted)
endif

rowloop:
    inc h           ; next screen line (skipping first row)
    ld a, (de)      ; get graphic
    rrd             ; rotate onto screen
    jr c, nextrow   ; done printing?
    rrd             ; rotate again into A
    ld (hl), a      ; display on screen
nextrow:
    inc d           ; next graphic
    djnz rowloop    ; loop for all rows

nextchar:
    pop hl          ; restore screen pos

    dec c           ; any more chars?
    jr nz, charloop ; loop back round
    ret             ; done
User avatar
Einar Saukas
Bugaboo
Posts: 3070
Joined: Wed Nov 15, 2017 2:48 pm

Re: Compact 64 column print routine

Post by Einar Saukas »

djnzx48 wrote: Sun Feb 18, 2018 8:59 pmHello everyone, this is my first post on these forums. :)
Welcome to this forum!

djnzx48 wrote: Sun Feb 18, 2018 8:59 pmI started learning Z80 assembly several years ago but I didn't really do anything with it apart from a few flashy screen effects. So now I've decided to come back to it and attempt to make an actual game, starting with this text routine. It's optimized to be as small as possible (34/35 bytes), with the font using 7 bytes for every pair of characters. I thought I'd share it here in the hope that others might find it useful, so feel free to use it, modify it, whatever.
Nice!

Your idea is similar to 64#4, except you saved several bytes by avoiding those bells and whistles. :)

djnzx48 wrote: Sun Feb 18, 2018 8:59 pmAnd I just wanted to say thanks for all the hard work that goes into maintaining ZXDB and this site, it's really appreciated :)
Thank you very much! Likewise, your support is really appreciated. :)
User avatar
djnzx48
Manic Miner
Posts: 729
Joined: Wed Dec 06, 2017 2:13 am
Location: New Zealand

Re: Compact 64 column print routine

Post by djnzx48 »

Einar Saukas wrote: Sun Feb 18, 2018 10:13 pm
djnzx48 wrote: Sun Feb 18, 2018 8:59 pmI started learning Z80 assembly several years ago but I didn't really do anything with it apart from a few flashy screen effects. So now I've decided to come back to it and attempt to make an actual game, starting with this text routine. It's optimized to be as small as possible (34/35 bytes), with the font using 7 bytes for every pair of characters. I thought I'd share it here in the hope that others might find it useful, so feel free to use it, modify it, whatever.
Nice!

Your idea is similar to 64#4, except you saved several bytes by avoiding those bells and whistles. :)
Thanks for replying, your routine looks very nice :) My routine is purposely made to be simple and restrictive, as I only needed something to print single lines at a time, and I didn't need to use it from BASIC.
A major advantage of your code is that the font is all packed in one place, which is more convenient than having 'holes' in the data. It makes calculating the font address slightly more complicated though.
User avatar
utz
Microbot
Posts: 114
Joined: Wed Nov 15, 2017 9:04 am
Contact:

Re: Compact 64 column print routine

Post by utz »

Woohoo, 35 bytes! Always great to see compact routines like this. Perhaps it could be tweaked for more efficient storage of the font though? I don't mind so much the wasted bits per character pair, but spreading out over 7 256b pages seems worth optimizing. Nevertheless, this is quite an achievement ;)
User avatar
djnzx48
Manic Miner
Posts: 729
Joined: Wed Dec 06, 2017 2:13 am
Location: New Zealand

Re: Compact 64 column print routine

Post by djnzx48 »

utz wrote: Tue Feb 20, 2018 10:20 am Woohoo, 35 bytes! Always great to see compact routines like this. Perhaps it could be tweaked for more efficient storage of the font though? I don't mind so much the wasted bits per character pair, but spreading out over 7 256b pages seems worth optimizing. Nevertheless, this is quite an achievement ;)
Thanks :) It wouldn't be too difficult to modify it so that the font is all in one place, although it would need some extra code to multiply the character byte by 7 and add it to the base address. I personally don't think it's worth it at this stage; for now I'll try to fit some other code or data to fill up the gaps.

I noticed that only a few of the characters in my current font have hanging tails that extend to the bottom, mostly lowercase ones like g, j, p, q, and y. If those tails were removed the font could be made smaller - only 6 bytes per pair of characters or 3 bytes for a single character. Or it could even be made to use 7px high graphics for lowercase and 6px high for uppercase letters.
User avatar
Kweepa
Manic Miner
Posts: 311
Joined: Sat Feb 03, 2018 6:14 pm
Location: Albuquerque, New Mexico

Re: Compact 64 column print routine

Post by Kweepa »

In a proportional font routine I wrote (on the VIC - boo!) I rendered the letters with descenders lower than the others, so they are the same height in the font. Just requires a lookup table for y offset.
User avatar
djnzx48
Manic Miner
Posts: 729
Joined: Wed Dec 06, 2017 2:13 am
Location: New Zealand

Re: Compact 64 column print routine

Post by djnzx48 »

Hmm, that seems like a good idea. I don't think a lookup table would be appropriate in this case, as the extra memory needed for the code and the table itself would outweigh saving 40 bytes or so in the font data. Maybe a hardcoded test or CP instruction would work though. Or the character set could be arranged differently so that similar height characters are grouped together. I'll have a closer look at the font later and try it out.
User avatar
utz
Microbot
Posts: 114
Joined: Wed Nov 15, 2017 9:04 am
Contact:

Re: Compact 64 column print routine

Post by utz »

A tiny optimization: Near the top of charloop, replacing "dec a, or a" with "sub 1" will save 1 t-state.

Edit: Ah, nevermind, it will break on entering with C=0.
User avatar
Kweepa
Manic Miner
Posts: 311
Joined: Sat Feb 03, 2018 6:14 pm
Location: Albuquerque, New Mexico

Re: Compact 64 column print routine

Post by Kweepa »

Back to the descenders - you're right, a look up table is expensive.
I forgot that I dropped the descenders 2 pixels, so it would still be cheaper than adding two pixels to each character in the font.
https://www.youtube.com/watch?v=KEm8pDkFJt4
I also forgot that I just checked for a descender like this:

Code: Select all

static int hasdescender(char c)
{
   char pet = c + 'a' - 97;
   if (pet == 'g' || pet == 'p' || pet == 'q' || pet == 'y')
   {
      return 1;
   }
   return 0;
}
:oops:
User avatar
djnzx48
Manic Miner
Posts: 729
Joined: Wed Dec 06, 2017 2:13 am
Location: New Zealand

Re: Compact 64 column print routine

Post by djnzx48 »

utz wrote: Wed Feb 21, 2018 12:46 pm A tiny optimization: Near the top of charloop, replacing "dec a, or a" with "sub 1" will save 1 t-state.

Edit: Ah, nevermind, it will break on entering with C=0.
Nice! The C=0 case doesn't matter for me as I'll only be printing single lines at a time, so that I can do word wrapping on them. The routine was never intended to handle multiple lines of text, the fact that it does is just a bonus ;)
Kweepa wrote: Wed Feb 21, 2018 2:23 pm Back to the descenders - you're right, a look up table is expensive.
I forgot that I dropped the descenders 2 pixels, so it would still be cheaper than adding two pixels to each character in the font.
https://www.youtube.com/watch?v=KEm8pDkFJt4
I also forgot that I just checked for a descender like this:

Code: Select all

static int hasdescender(char c)
{
   char pet = c + 'a' - 97;
   if (pet == 'g' || pet == 'p' || pet == 'q' || pet == 'y')
   {
      return 1;
   }
   return 0;
}
Wow, nice looking game! I didn't realise that you were the author of the VIC-20 Manic Miner port either, good work :)

Your suggestion was a good one. I found that if all characters are 6 characters in height, a lookup table can be made using 1 bit per character to indicate whether it is higher or lower. With 96 characters, the table will only take 12 bytes. The code is 21 bytes larger (although it could probably be optimised), but since 48 bytes are saved by making the font data smaller, there is a net saving of 15 bytes.

Currently the table layout suffers from the same problem as the font data; there are gaps in it as the entries are all 8 bytes apart. It could be easily fixed with three RRAs though. Also some letters in my font like Q and j are 7 pixels high, so they'll have to be made smaller somehow.

Here's the new code (untested, 56 bytes):

Code: Select all

; Prints up to 4 lines of text using a 4x8 character font.
;
; IX = points to one beyond last character of string
; HL = screen address to print at
; C  = number of characters to print, maximum 255
;
; Notes: The left edge of the string is always aligned
; with a character block. If you want a string to start
; halfway along a block, it must begin with a space.
;
; The font is stored with two graphic rows packed into
; a byte, with each of 6 rows stored on a separate
; 256-byte page.
;
; preserves: IY, alternate registers

charloop:
    ld d, font_hi   ; construct font address
    push hl         ; save screen pos
    
    dec ix          ; read string backwards
    ld e, (ix+0)    ; get character
    ld a, e
    and %00111000   ; get LSB for lookup table
    
    ld h, font_height_lookup
    ld l, a
    
    ld a, e
    and %00000111   ; get number of bit to retrieve
    ld b, a
    inc b           ; get in range 1-8
    ld a, (hl)      ; get lookup table byte
    
    pop hl          ; restore screen pos
    push hl         ; save it again
    
bitloop:
    add a, a        ; shift until we get the desired bit
    djnz bitloop
    
    jr nc, skip_inc ; check value of bit
    
    inc h           ; next screen line
    inc d           ; next font byte
    
skip_inc:

    ld a, c         ; number of chars left to print
    sub 1           ; we want to round downwards
    rra             ; divide by two (64 chars to 32)
    add a, l        ; calculate new screen address
    ld l, a

    ld b, 6         ; loop 6 rows

    srl e           ; check value of LSB

rowloop:
    inc h           ; next screen line (skipping first row)
    ld a, (de)      ; get graphic
    rrd             ; rotate onto screen
    jr c, nextrow   ; done printing?
    rrd             ; rotate again into A
    ld (hl), a      ; display on screen
nextrow:
    inc d           ; next graphic
    djnz rowloop    ; loop for all rows

nextchar:
    pop hl          ; restore screen pos

    dec c           ; any more chars?
    jr nz, charloop ; loop back round
    ret             ; done
User avatar
utz
Microbot
Posts: 114
Joined: Wed Nov 15, 2017 9:04 am
Contact:

Re: Compact 64 column print routine

Post by utz »

Not the most pretty, but it's a Q I'd say:

Code: Select all

 * 
* *
* *
* *
**
 **
User avatar
utz
Microbot
Posts: 114
Joined: Wed Nov 15, 2017 9:04 am
Contact:

Re: Compact 64 column print routine

Post by utz »

Made a little font that fits completely in 6x3, just in case ;)

Image
User avatar
Alessandro
Dynamite Dan
Posts: 1908
Joined: Wed Nov 15, 2017 11:10 am
Location: Messina, Italy
Contact:

Re: Compact 64 column print routine

Post by Alessandro »

This is the font I designed for the copyright messages of the loading screens for my games. Feel free to employ it if you think it could be useful to you.

Image
User avatar
djnzx48
Manic Miner
Posts: 729
Joined: Wed Dec 06, 2017 2:13 am
Location: New Zealand

Re: Compact 64 column print routine

Post by djnzx48 »

Thanks guys, both those fonts look very nice. I did try making versions of the routine using CP and CPIR so that I could keep the longer tails of some of the letters, but they turned out pretty badly. They both total at 69 bytes, almost twice the size of the original routine, and still only end up saving 13 bytes overall with 96 chars.

Using CPIR:

Code: Select all

charloop:
    push hl         ; save screen pos

    dec ix          ; read string backwards
    ld a, (ix+0)    ; get char

    ld d, c         ; save length temporarily
    ld e, 6         ; assume char is 6px initially

    ld hl, check_table
    ld bc, 2        ; compare two chars
    cpir            ; check if char is Q or j

    jr nz, skip_inc_e
    inc e

skip_inc_e:
    ld l, check_table+2
    ld c, 5         ; compare five chars
    cpir            ; check if char is g p q y ,

    pop hl          ; restore screen pos
    push hl         ; save it again

    jr nz, skip_inc_h
    inc h

skip_inc_h:
    ld b, e         ; load counter for height
    ld c, d         ; restore length
    ld d, font_hi
    ld e, a         ; put character into e

    ; ... rest of code ...

check_table:
    db 'Q', 'j', 'g', 'p', 'q', 'y', ','
Using CP:

Code: Select all

charloop:
    ld d, font_hi
    push hl         ; save screen pos

    dec ix          ; read string backwards
    ld a, (ix+0)    ; get char

    ld b, 6         ; assume char is 6px initially

    cp 'g'
    jr z, inc_h
    cp 'p'
    jr z, inc_h
    cp 'q'
    jr z, inc_h
    cp 'y'
    jr z, inc_h
    cp ','
    jr z, inc_h

    cp 'Q'
    jr z, inc_b
    cp 'j'
    jr nz, skip_inc

inc_b:
    inc b
    jr skip_inc

inc_h:
    inc h

skip_inc:

    ; ... rest of code ...
I think that going 6x3 is the right option to choose here, might not be as readable but you can save up to 48 bytes. I wonder if anything could be done about the wasted zero bits in between the letters...
User avatar
djnzx48
Manic Miner
Posts: 729
Joined: Wed Dec 06, 2017 2:13 am
Location: New Zealand

Re: Compact 64 column print routine

Post by djnzx48 »

About wasted bits in the font data, what about sticking in a RES 4, (HL) at nextrow just after the font row has been written to the screen? This would ensure that only the first three bits of each character are printed, allowing for the spare bits to be used as flags for other code.
User avatar
utz
Microbot
Posts: 114
Joined: Wed Nov 15, 2017 9:04 am
Contact:

Re: Compact 64 column print routine

Post by utz »

djnzx48 wrote: Fri Feb 23, 2018 4:41 am About wasted bits in the font data, what about sticking in a RES 4, (HL) at nextrow just after the font row has been written to the screen? This would ensure that only the first three bits of each character are printed, allowing for the spare bits to be used as flags for other code.
That sounds like an excellent idea, though I don't have any great ideas on what to use those bits for, other than signaling vertical displacement.

Btw [mention]Alessandro[/mention] Man, that is a stylish font! Never noticed it before, but it's a very solid design.
User avatar
Alessandro
Dynamite Dan
Posts: 1908
Joined: Wed Nov 15, 2017 11:10 am
Location: Messina, Italy
Contact:

Re: Compact 64 column print routine

Post by Alessandro »

Thanks a lot [mention]utz[/mention], but your font is great too, and more flexible than mine - it's got lower case characters ;)

I also employ it for the language selection screen for the disk multi-language edition of several of my games. Here is the one from Sophia (notice my attempt at a Cyrillic variant):

Image
User avatar
RMartins
Manic Miner
Posts: 776
Joined: Thu Nov 16, 2017 3:26 pm

Re: Compact 64 column print routine

Post by RMartins »

Alessandro wrote: Mon Feb 26, 2018 1:56 pm Thanks a lot @utz, but your font is great too, and more flexible than mine - it's got lower case characters ;)

I also employ it for the language selection screen for the disk multi-language edition of several of my games. Here is the one from Sophia (notice my attempt at a Cyrillic variant):

Image
Nice language selection screen.
Is it really Portuguese, or Brasilian Portuguese ?

Is it just me, or the two top corners sprites, are not correctly aligned ?
I mean in the sense that the bottom ones, have the curly parts in an exact diagonal to each other.
User avatar
djnzx48
Manic Miner
Posts: 729
Joined: Wed Dec 06, 2017 2:13 am
Location: New Zealand

Re: Compact 64 column print routine

Post by djnzx48 »

That language selection screen looks good [mention]Alessandro[/mention]. I like the colour scheme; yellow and cyan are a combination that you don't see too often.

[mention]utz[/mention] I was thinking along the lines of using those spare bits whenever I needed a flag or something in another part of the code, not specifically the font routine. Although this does seem like a recipe for unmaintainable spaghetti code before long :)

I've discovered another few optimisations that can be made in the routine to get the size down. The first one is that the two decrements of the counter variable (DEC A & DEC C) can be combined into one, saving a byte, while the sign flag is used to check if there's any more to print. A side effect of this method is that you can't print more than 128 chars at a time, but the routine can't cope with screen thirds anyway so it's no major loss. Also if you call it with the counter set to 0, it exits without printing anything.

Code: Select all

charloop:
    ld d, font_hi   ; construct font address
    push hl         ; save screen pos

    dec c           ; any more chars?
    ret m           ; done
    ld a, c         ; number of chars left to print
    or a            ; clear carry for scroll
    rra             ; divide by two (64 chars to 32)
    add a, l        ; calculate new screen address
    ld l, a

    ld b, 6         ; loop 6 rows

    dec ix          ; read string backwards

if 1
    ld e, (ix+0)    ; get character
    srl e           ; check value of LSB
else
    db $DD, $CB, $00, $3B   ; ld e, srl (ix+0)
                    ; saves one byte and 4 Ts
                    ; Only use for temporary strings
                    ; (string becomes corrupted)
endif

rowloop:
    inc h           ; next screen line (skipping first row)
    ld a, (de)      ; get graphic
    rrd             ; rotate onto screen
    jr c, nextrow   ; done printing?
    rrd             ; rotate again into A
    ld (hl), a      ; display on screen
nextrow:
    inc d           ; next graphic
    djnz rowloop    ; loop for all rows

nextchar:
    pop hl          ; restore screen pos
    jr charloop     ; loop back round
Also, I realised that if the string buffer is aligned on a 256-byte boundary, the low byte of the string address will be equal to the number of bytes to print, since the string is being printed backwards. This allows the two registers to be combined so that BC is used for the address of the string, which eliminates the need for IX. However, BC must still be saved and restored before and after the inner printing loop, since B is also being used as the row counter. SRL A now appears twice, wasting two bytes, but if RRA was used the high bit would be corrupted by the carry flag. Because there is no LD E, (BC) instruction so the character has to be loaded into A first and then into E. So this optimisation ends up saving only one byte overall but it's still better than nothing.

Code: Select all

charloop:
    ld d, font_hi   ; construct font address
    push hl         ; save screen pos

    dec c           ; any more chars?
    ret m           ; done
    ld a, c         ; number of chars left to print
    srl a           ; divide by two (64 chars to 32)
    add a, l        ; calculate new screen address
    ld l, a

    ld a, (bc)      ; read string backwards
    ld e, a         ; get character
    srl e           ; check value of LSB

    push bc         ; save message address
    ld b, 6         ; loop 6 rows

rowloop:
    inc h           ; next screen line (skipping first row)
    ld a, (de)      ; get graphic
    rrd             ; rotate onto screen
    jr c, nextrow   ; done printing?
    rrd             ; rotate again into A
    ld (hl), a      ; display on screen
nextrow:
    inc d           ; next graphic
    djnz rowloop    ; loop for all rows

nextchar:
    pop bc          ; restore message address
    pop hl          ; restore screen pos
    jr charloop     ; loop back round
If the routine needs to be made even smaller, the print buffer can be arranged so that its address has the same high byte as the font address, with the font data placed after the print buffer in memory. This means that the PUSH/POP BC can be removed, and replaced with a LD B, D instruction just after LD D, FONT_HI. Using all these optimisations together, the routine can fit in only 32 bytes.
User avatar
Alessandro
Dynamite Dan
Posts: 1908
Joined: Wed Nov 15, 2017 11:10 am
Location: Messina, Italy
Contact:

Re: Compact 64 column print routine

Post by Alessandro »

Thanks for liking the screen fellas.
RMartins wrote: Mon Feb 26, 2018 9:54 pm Is it really Portuguese, or Brasilian Portuguese ?
Cannot really say, I am unable to distinguish between them because my knowledge of the language is basic to say the least. However, since the initial translations were kindly provided by Brazilian native speakers (Einar, Marcus Garrett Chiado), I guess it's closer to Brazilian, although I suppose the reforms and agreements achieved since 1990 made the two variants more similar than in the past.

But may I ask: why don't you read the documentation and play the games (Sophia, Al's Double Bill, Seto Taisho etc.)? This way you can discover it by yourself - and I hope you like them too ;)
RMartins wrote: Mon Feb 26, 2018 9:54 pm Is it just me, or the two top corners sprites, are not correctly aligned ?
I mean in the sense that the bottom ones, have the curly parts in an exact diagonal to each other.
The picture does not have 4:3 proportions, hence the slight misalignment, which is more evident here; when you watch it on a monitor/TV full screen, it's less noticeable.
User avatar
RMartins
Manic Miner
Posts: 776
Joined: Thu Nov 16, 2017 3:26 pm

Re: Compact 64 column print routine

Post by RMartins »

Alessandro wrote: Tue Feb 27, 2018 8:06 am ...
RMartins wrote: Mon Feb 26, 2018 9:54 pm Is it just me, or the two top corners sprites, are not correctly aligned ?
I mean in the sense that the bottom ones, have the curly parts in an exact diagonal to each other.
The picture does not have 4:3 proportions, hence the slight misalignment, which is more evident here; when you watch it on a monitor/TV full screen, it's less noticeable.
I may have not explained myself well enough.
The top corner sprites, do not appear to be vertical flips of the bottom ones, hence the curly things, seem different.
User avatar
Alessandro
Dynamite Dan
Posts: 1908
Joined: Wed Nov 15, 2017 11:10 am
Location: Messina, Italy
Contact:

Re: Compact 64 column print routine

Post by Alessandro »

Now I understand what you mean. Mind you, I had not noticed that myself.

If you look again at the picture, I revised the "frame", also by adding an inner black line to make it stand out even more. (You might need to erase your browser cache before reloading the page to see the new picture.)

However I won't be adding it to my already existing multi-language files, that would mean uploading them again, then updating the SC database, and it's not worth the hassle. I will use the new "frame" with the next releases and updates.

Now, will you actually play the games? ;)
User avatar
RMartins
Manic Miner
Posts: 776
Joined: Thu Nov 16, 2017 3:26 pm

Re: Compact 64 column print routine

Post by RMartins »

Alessandro wrote: Tue Feb 27, 2018 4:37 pm ...

Now, will you actually play the games? ;)
Nice ...

Fixing that, was not a pre condition for me playing the game :)

I usually keep a list of recently released games, so that when I have some free play time, I can try them.
It's always good to see what others have come up with, either to improve our own game design skills, or learn new tricks, while enjoying playing Spectrum :)
User avatar
arkannoyed
Manic Miner
Posts: 435
Joined: Mon Feb 05, 2018 9:56 am
Location: Northamptonshire

Re: Compact 64 column print routine

Post by arkannoyed »

I like the creative use of RRD/RLD. I just wish they were faster instructions!

Anyway, I thought I'd throw my hat into the ring sort of thing.

I use a method of encoding the characters that stores vertical lines, then adding a vertical 'space' between each character.

Its a similar way to how I store the font in my proportional scroller.

So, routine needs HL with screen address and BC with the message address when CALLed.

the combined print routine and 74 character 'font' based upon the one posted earlier here, is 210 bytes currently, but could be optimised probably a little more.

Certainly slower though.

Image

Code: Select all

org 0fa00h

direct_dat:
          db 19h,25h,3fh,25h,19h,25h,19h,7dh,19h,7dh,51h,41h,79h,05h,7dh,11h
          db 7dh,31h,7dh,25h,19h,25h,3dh,51h,3dh,31h,3dh,21h,1dh,7dh,55h,29h
          db 55h,29h,29h,29h,39h,45h,45h,79h,05h,79h,7dh,45h,39h,45h,5dh,7dh
          db 55h,45h,7dh,45h,7dh,05h,05h,7dh,11h,6dh,11h,6dh,7dh,41h,3dh,0dh
          db 3dh,43h,01h,43h,3dh,39h,45h,39h,05h,3dh,7dh,51h,21h,55h,39h,05h
          db 39h,55h,39h,55h,09h,39h,4dh,35h,7dh,51h,2dh,11h,2dh,35h,25h,55h
          db 49h,41h,7dh,41h,55h,21h,61h,1dh,61h,01h,61h,4dh,55h,65h,19h,25h
          db 25h,19h,2dh,35h,01h,3dh,51h,1bh,2bh,3dh,19h,25h,7dh,21h,1dh,01h
          db 5dh,01h,1dh,21h,13h,5dh,01h,79h,25h,15h,35h,29h,3bh,0bh,3dh,4dh
          db 55h,25h,45h,55h,29h,71h,11h,3dh,75h,55h,49h,4dh,51h,61h,01h,75h
          db 01h,05h,01h,25h,01h,01h,01h,03h,05h,11h,11h,11h,39h,11h,7dh,11h,2dh

          ;177 bytes CHR set

          ;A=16,B=1d,C=24,D=2a,E=2f,F=09,G=2c,H=0e,I=31,J=25,K=37,L=34,M=10,N=3c,O=45,P=4a,Q=55,R=58,S=5e,T=61,U=0c,V=27,W=07,X=39,Y=66,Z=6b
          ;a=14,b=12,c=6e,d=7a,e=71,f=74,g=77,h=7c,i=7f,j=84,k=b0,l=0b,m=18,n=1a,o=04,p=02,q=00,r=81,s=89,t=86,u=47,v=4e,w=3e,x=5a,y=8c,z=5c
          ;0=50,1=33,2=8f,3=92,4=95,5=98,6=52,7=9b,8=1f,9=4c
          ;!=9e,"=68,.=a0,,=a6,:=a2,+=ab,-=a9,(=40,)=42,==21,?=63,SPC=a4

start:
          ld d,0fah             ;Hi-byte of CHR set+ EOM marker
s_rpt:
          ld a,(bc)             ;get CHR code
          ld e,a                ;CHR code is x3 to save having to do it in routine
          cp d                  ;SUB 0FAh, use D reg value to mark the string end
          ret nc                ;RET if 0FAh detected
          push bc               ;save MSG position
          ld b,04h              ;counter

          ld a,01h              ;set space line with end marker
pr_lp0:
          and a                 ;clear Carry
          ld c,h                ;save SCReen position
init0:
          inc h
          rl (hl)               ;bit into (HL)
          add a,a               ;next data BIT
          jr nz,init0           ;repeat if not 00

          ld h,c                ;restore SCReen address
          ld a,(de)             ;get data byte
          inc e                 ;next
          djnz pr_lp0           ;next line

          pop bc                ;restore MGS address
          inc bc                ;next CHR byte
          ld a,c                ;check
          and 01h               ;mask BIT 0
          add a,l               ;add result to L
          ld l,a                ;INC 1 or 0
          jr s_rpt              ;next CHR rpt.
          
target:
          ld hl,3f00h           ;SCReen address
          ld bc,message         ;MSG address
          call start
          ret
          
message:  ;example message 'Hi To All At Spectrum Computing'
          db 0eh,7fh,0a4h,61h,04h,0a4h,16h,0bh,0bh,0a4h,16h,86h,0a4h,5eh,02h,71h,6eh,86h,81h,47h,18h,0a4h,24h,04h,18h,02h,47h,86h,7fh,1ah,77h,0fah
I'll have a further faff around with the character map and see if I can gain a few more bytes 8-)
Nomad
Manic Miner
Posts: 600
Joined: Thu Dec 28, 2017 12:38 pm

Re: Compact 64 column print routine

Post by Nomad »

That is all kinds of awesome. :lol:
Post Reply