Compact 64 column print routine
Re: Compact 64 column print routine
Ah nice, so you basically store the font 'sideways' and draw it column by column. Solves the problem of wasted gaps in between letters, and a simple AND could be used to mask off the unused top and bottom pixels to use them for other stuff. Having to preprocess the text before printing is a downside but at least it gives you an easy way of checking whether L needs to be incremented or not. I'll definitely be giving your routine a closer look.
- arkannoyed
- Manic Miner
- Posts: 438
- Joined: Mon Feb 05, 2018 9:56 am
- Location: Northamptonshire
Re: Compact 64 column print routine
Bit 0 of each data byte is set as and end market for the print loop. Whereas we could use 3 bytes for each character, there are some that can be found within the data as a sort of bonus. As we’re only addressing the data within a 256 byte area, there’s the possibility to use direct address lo-bytes as the character codes. With some additional manual rearrangement of the data, I managed to save 45 bytes. I’m sure with some more tweaking I could more efficiently pack the data and find a few more matches within it, saving even more.
The way it decides when to inc to the next screen byte is a bit crude. We check the message position and inc to the next right byte when it’s on an even byte. There might be a better way to do it, I haven’t found one....yet.
So the main routine is 33 bytes and can manage to print within screen thirds, so could potentially do 512 characters at once.
The way it decides when to inc to the next screen byte is a bit crude. We check the message position and inc to the next right byte when it’s on an even byte. There might be a better way to do it, I haven’t found one....yet.
So the main routine is 33 bytes and can manage to print within screen thirds, so could potentially do 512 characters at once.
- arkannoyed
- Manic Miner
- Posts: 438
- Joined: Mon Feb 05, 2018 9:56 am
- Location: Northamptonshire
Re: Compact 64 column print routine
I knew there was a better way of deciding when to increment the screen address. Really its obvious!!
If we just /2 (SRA L) the screen address, then we divide the Lo-byte by 2, as we've 2 characters per byte printed.
The only downside is that we can now only print 256 characters in a single string, but thats still 4 lines of continuous text, so probably not much of a problem.
So now down to 31 bytes!
If we just /2 (SRA L) the screen address, then we divide the Lo-byte by 2, as we've 2 characters per byte printed.
The only downside is that we can now only print 256 characters in a single string, but thats still 4 lines of continuous text, so probably not much of a problem.
So now down to 31 bytes!
Code: Select all
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 z ;RET if 0FAh detected
push bc ;save MSG position
ld b,04h ;counter
ld a,01h ;set space line with end marker
pr_lp0:
push hl
sra l
and a ;clear Carry
init0:
inc h
rl (hl) ;bit into (HL)
add a,a ;next data BIT
jr nz,init0 ;repeat if not 00
pop hl ;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
inc l ;next SCR addr
jr s_rpt ;next CHR rpt.
Re: Compact 64 column print routine
Copied and Pasted your latest change and with a message string that is an odd length in size (like the example message used previously) the last character is printed in the wrong place. This might be down to my bad typing but can you check it out? Ta.
"He made eloquent speeches to an audience consisting of a few depressed daffodil roots, and sometimes the cat from next door."
- arkannoyed
- Manic Miner
- Posts: 438
- Joined: Mon Feb 05, 2018 9:56 am
- Location: Northamptonshire
Re: Compact 64 column print routine
Yes, in cases where the last character gets spaced apart from the rest of the text, then add a space at the end (code A4h in this case), before the terminating code (FAh)
Sorry, should've mentioned that!
Sorry, should've mentioned that!
- arkannoyed
- Manic Miner
- Posts: 438
- Joined: Mon Feb 05, 2018 9:56 am
- Location: Northamptonshire
Re: Compact 64 column print routine
Should also mention that you can of course change the address where the code is, and as long as the CHR set is within a 256 byte window, it doesn't even have to start at xx00.
The D register holds the CHR set Hi-byte and is also the message end marker. So any messages must end with whatever value D holds.
The D register holds the CHR set Hi-byte and is also the message end marker. So any messages must end with whatever value D holds.
- arkannoyed
- Manic Miner
- Posts: 438
- Joined: Mon Feb 05, 2018 9:56 am
- Location: Northamptonshire
Re: Compact 64 column print routine
...And..30 bytes!
If we replace the B,04 loop, therefore getting rid of the need for Push/Pop BC, we can rather cheekily use the top line of the character square, as its not printed on, to temporarily store the counter, just doing a DEC (HL) with each pass.
I do however now need to refactor the CHR set, and move everything left one BIT to make it work, but thats not too much hassle.
Might struggle to save any more bytes!
If we replace the B,04 loop, therefore getting rid of the need for Push/Pop BC, we can rather cheekily use the top line of the character square, as its not printed on, to temporarily store the counter, just doing a DEC (HL) with each pass.
I do however now need to refactor the CHR set, and move everything left one BIT to make it work, but thats not too much hassle.
Code: Select all
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 z ;RET if 0FAh detected
ld (hl),04h
ld a,01h ;set space line with end marker
pr_lp0:
push hl ;save HL SCReen address
sra l ;/2 L
and a ;clear Carry
init0:
inc h
rl (hl) ;bit into (HL)
add a,a ;next data BIT
jr nz,init0 ;repeat if not 00
pop hl ;restore SCReen address
ld a,(de) ;get data byte
inc e ;next
dec (hl)
jr nz,pr_lp0
inc bc ;next CHR byte
inc l ;next SCR addr
jr s_rpt ;next CHR rpt.
- arkannoyed
- Manic Miner
- Posts: 438
- Joined: Mon Feb 05, 2018 9:56 am
- Location: Northamptonshire
Re: Compact 64 column print routine
And heres the updates CHR set code
30 bytes +177 = 207 bytes
Enjoy
Code: Select all
direct_dat:
db 31h,49h,7dh,49h,31h,49h,31h,0f9h,31h,0f9h,0a1h,81h,0f1h,09h,0f9h,21h
db 0f9h,61h,0f9h,49h,31h,49h,79h,0a1h,79h,61h,79h,41h,39h,0f9h,0a9h,51h
db 0a9h,51h,51h,51h,71h,89h,89h,0f1h,09h,0f1h,0f9h,89h,71h,89h,0b9h,0f9h
db 0a9h,89h,0f9h,89h,0f9h,09h,09h,0f9h,21h,0d9h,21h,0d9h,0f9h,81h,79h,19h
db 79h,85h,01h,85h,79h,71h,89h,71h,09h,79h,0f9h,0a1h,41h,0a9h,71h,09h
db 71h,0a9h,71h,0a9h,11h,71h,99h,69h,0f9h,0a1h,59h,21h,59h,69h,49h,0a9h
db 91h,81h,0f9h,81h,0a9h,41h,0c1h,39h,0c1h,01h,0c1h,99h,0a9h,0c9h,31h,49h
db 49h,31h,59h,69h,01h,79h,0a1h,35h,55h,79h,31h,49h,0f9h,41h,39h,01h
db 0b9h,01h,39h,41h,25h,0b9h,01h,0f1h,49h,29h,69h,51h,75h,15h,79h,99h
db 0a9h,49h,89h,0a9h,51h,0e1h,21h,79h,0e9h,0a9h,91h,99h,0a1h,0c1h,01h,0e9h
db 01h,09h,01h,49h,01h,01h,01h,05h,09h,21h,21h,21h,71h,21h,0f9h,21h,59h
;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
Enjoy
Re: Compact 64 column print routine
Well, looks like my routine's become obsolete already! That's some impressive stuff there; I didn't realise at first glance that you were interleaving the font bytes of the characters together to save space. One thing though, since L is being divided by two won't that affect both the X and Y coordinates of the screen address, causing the text to be drawn in the wrong place? Additionally the counter looks like it corrupts random parts of the screen as it's using the normal value of L, not the halved value that is being drawn to. Maybe an additional PUSH/POP HL and a SLA L on entry could be added to compensate?
- arkannoyed
- Manic Miner
- Posts: 438
- Joined: Mon Feb 05, 2018 9:56 am
- Location: Northamptonshire
Re: Compact 64 column print routine
As far as I can see, there isn't any screen corruption, but you may have tested it more fully than I have.
The screen address Lo-byte is halved for printing the actual characters, but restored afterwards.
You are right though, in the 30 byte version, it may cause corruption elsewhere, so probably in most cases, using B as the counter is safer, therefore 31 bytes.
There may yet be a way to achieve a smaller routine, as I've another data structure to investigate.
The CHR data is treated sort of as a 'pool' to dip into at any point. With no spaces to worry about, as they're added by the routine, it gives rise to that flexibility.
The screen address Lo-byte is halved for printing the actual characters, but restored afterwards.
You are right though, in the 30 byte version, it may cause corruption elsewhere, so probably in most cases, using B as the counter is safer, therefore 31 bytes.
There may yet be a way to achieve a smaller routine, as I've another data structure to investigate.
The CHR data is treated sort of as a 'pool' to dip into at any point. With no spaces to worry about, as they're added by the routine, it gives rise to that flexibility.
- arkannoyed
- Manic Miner
- Posts: 438
- Joined: Mon Feb 05, 2018 9:56 am
- Location: Northamptonshire
Re: Compact 64 column print routine
Ok, reverted back to the 31 bytes, but a new version, and this perhaps could be considered the 'Ultra Compact Version' or UCV64! The CHR set is 79 bytes and contains all capital letters and numbers and Space. Total size 110 bytes.
Use as follows;
HL=SCReen address
DE=message address
Message end marker must be the Hi-byte of wherever you decide to locate the routine, in this case FAh.
The character codes are shown in the ASM and theres an example message in there too.
Might be of use if someone needs an ultra compact print routine for 64 characters per line.
Use as follows;
HL=SCReen address
DE=message address
Message end marker must be the Hi-byte of wherever you decide to locate the routine, in this case FAh.
The character codes are shown in the ASM and theres an example message in there too.
Code: Select all
org 0fa00h
direct_dat:
db 0dh,05h,7dh,1dh,7dh,31h,7dh,11h,7dh,41h,7dh,51h,71h,11h,7dh,45h
db 7dh,05h,7dh,55h,5dh,55h,75h,55h,5dh,45h,55h,7dh,55h,7dh,51h,7dh
db 51h,41h,4dh,71h,51h,7dh,51h,6dh,11h,6dh,7dh,11h,6dh,79h,4dh,79h
db 0dh,79h,41h,7dh,41h,7dh,55h,2dh,7dh,45h,45h,7dh,55h,45h,7dh,45h
db 3dh,7dh,45h,4dh,7dh,05h,05h,65h,15h,79h,4dh,55h,65h,01h,01h;01h use 01 from first byte of routine
;79 bytes CHR set super small
;A=1d,B=35,C=38,D=3e,E=3b,F=1f,G=41,H=06,I=3d,J=00,K=2a,L=44,M=04,N=33,O=0e,P=0a,Q=2d,R=25,S=16,T=32,U=10,V=2f,W=02,X=27,Y=47,Z=4a
;0=0e,1=0f,2=14,3=19,4=0c,5=16,6=12,7=21,8=1b,9=23
;SPC=4d
start:
ld bc,04fah ;Counter + Hi-byte of CHR set+ EOM marker
ld a,(de) ;get CHR code
cp c ;SUB 0FAh, use C reg value to mark the string end
ret z ;RET if 0FAh detected
push de ;save message position
ld e,a ;CHR code into E
ld a,01h ;set space line with end marker
pr_lp0:
push hl ;save HL SCReen address
srl l ;/2 L
and a ;clear Carry
init0:
inc h
rl (hl) ;bit into (HL)
add a,a ;next data BIT
jr nz,init0 ;repeat if not 00
pop hl ;restore SCReen address
ld d,c ;D=FAh
ld a,(de) ;get data byte
inc e ;next
djnz pr_lp0 ;repeat
pop de ;restore message address
inc de ;next CHR byte
inc l ;next SCR addr
jr start ;next CHR rpt.
target:
ld hl,4010h ;SCReen address
ld de,message ;MSG address
call start
ret
message: ;example message 'Hi To All At Spectrum Computing'
db 06h,3dh,4dh,32h,0eh,4dh,1dh,44h,44h,4dh,1dh,32h,4dh,16h,0ah,3bh,38h,32h,25h,10h,04h,4dh,38h,0eh,04h,0ah,10h,32h,3dh,33h,41h,4dh,0fah
Last edited by arkannoyed on Wed Mar 07, 2018 2:04 pm, edited 1 time in total.
- arkannoyed
- Manic Miner
- Posts: 438
- Joined: Mon Feb 05, 2018 9:56 am
- Location: Northamptonshire
Re: Compact 64 column print routine
Now I suppose I need to write a little message encoding routine to interpret ascii into these custom codes
- arkannoyed
- Manic Miner
- Posts: 438
- Joined: Mon Feb 05, 2018 9:56 am
- Location: Northamptonshire
Re: Compact 64 column print routine
So here it is.
Probably quite a crude attempt, but if you give this a go, it'll convert an ascii message (as long as it contains characters printable using the Ultra Compact Print 64 routine) into a printable one with the end marker too.
Just saves a lot of time really!
Oh yes, and your ascii message needs to terminate with FAh
Probably quite a crude attempt, but if you give this a go, it'll convert an ascii message (as long as it contains characters printable using the Ultra Compact Print 64 routine) into a printable one with the end marker too.
Just saves a lot of time really!
Oh yes, and your ascii message needs to terminate with FAh
Code: Select all
encoder:
ld hl,ascii ;ascii message
ld d,0fbh ;256 byte aligned interpreter table
enc_lp0:
ld e,(hl)
ld a,e
cp 0fah
ret z
ld a,(de)
ld (hl),a
inc hl
jr enc_lp0
padding:
db 00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h
db 00h
enc_data:
db 4dh,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h,00h
db 0eh,0fh,14h,19h,0ch,16h,12h,21h,1bh,23h,00h,00h,00h,00h,00h,00h
db 00h,1dh,35h,38h,3eh,3bh,1fh,41h,06h,3dh,00h,2ah,44h,04h,33h,0eh
db 0ah,2dh,25h,16h,32h,10h,2fh,02h,27h,47h,4ah
ascii:
db 'HELLO THERE SO LETS SEE IF WE CAN CONVERT THIS TO BEGIN WITH'
- arkannoyed
- Manic Miner
- Posts: 438
- Joined: Mon Feb 05, 2018 9:56 am
- Location: Northamptonshire
Re: Compact 64 column print routine
We can save another byte on the data if we move everything forward 1 byte, so the first data byte (J) occurs at xx01h addresses.
Change the message end marker to FFh, then test the message end with INC A/ RET Z.
The 2 trailing 01's on the end of the data create the instruction LD BC,0401h at the start of the routine.
So the routine is as follows and will give a total size of 31+78 = 109 bytes.
Change the message end marker to FFh, then test the message end with INC A/ RET Z.
The 2 trailing 01's on the end of the data create the instruction LD BC,0401h at the start of the routine.
So the routine is as follows and will give a total size of 31+78 = 109 bytes.
Code: Select all
start:
ld bc,0401h ;Counter + Hi-byte of CHR set+ EOM marker
ld a,(de) ;get CHR code
inc a ;SUB 0FAh, use C reg value to mark the string end
ret z ;RET if 0FAh detected
push de ;save message position
ld e,a ;CHR code into E
ld a,c ;set space line with end marker
pr_lp0:
push hl ;save HL SCReen address
srl l ;/2 L
and a ;clear Carry
init0:
inc h
rl (hl) ;bit into (HL)
add a,a ;next data BIT
jr nz,init0 ;repeat if not 00
pop hl ;restore SCReen address
ld d,0ffh ;D=FAh
ld a,(de) ;get data byte
inc e ;next
djnz pr_lp0 ;repeat
pop de ;restore message address
inc de ;next CHR byte
inc l ;next SCR addr
jr start ;next CHR rpt.
- arkannoyed
- Manic Miner
- Posts: 438
- Joined: Mon Feb 05, 2018 9:56 am
- Location: Northamptonshire
Re: Compact 64 column print routine
So, I thought I'd play around with the idea of encoding the actual character data in a more efficient way, to create a super compact version in as few bytes as possible.
As we really only need characters A-Z and 0-9 plus space, thats 37 characters in total.
If we use the normal way of encoding them we'd end up with data of about 148 bytes with a print routine/ decoder on top of that.
I've managed to squeeze everything into 99 bytes! Technically 101 bytes, but the space character only consists of two 00 bytes at the end of the block, so in many instances they could be ignored.
The character set is a custom one that lets me share some data between characters.
Annoyingly the routine is a whopping 35 bytes, and I can't seem to find a decent way of reducing that, but with some more investigation, you never know.
As we really only need characters A-Z and 0-9 plus space, thats 37 characters in total.
If we use the normal way of encoding them we'd end up with data of about 148 bytes with a print routine/ decoder on top of that.
I've managed to squeeze everything into 99 bytes! Technically 101 bytes, but the space character only consists of two 00 bytes at the end of the block, so in many instances they could be ignored.
The character set is a custom one that lets me share some data between characters.
Code: Select all
;15 bit 64 column format
;
;super compact 5 byte high characters
;
;DE holds screen address
;BC is message address
;End of Message byte is any value with BIT 7 set
;message must be an even number of characters long (padded with space if reqd.)
;Call routine at 0FA00h (64000d)
;
;101 bytes if we include the trailing 00h,00h (space CHR)
;99 bytes otherwise
;
;Characters A-Z...0-9..spc.
;
;Arkannoyed March 2018
org 0f9f3h
ld bc,example_message
ld de,4300h
call start
inc bc
ld de,4340h
start:
ld a,(bc)
ld l,a
add a,a
ret c
ld h,0fah
push de
ld a,(hl)
inc l
ld l,(hl)
ld h,a
lp0:
ld a,(de)
or 10h
add a,a
lp1:
add hl,hl
rla
jr nc,lp1
ld (de),a
inc d
ld a,d
and 07h
jr nz,lp0
pop de
inc bc
ld a,c
and 01h
add a,e
ld e,a
jr start
db %01010111,%11011010 ;A code 23h ;57h,0dah
db %11010111,%01011100 ;B code 25h ;0d7h,5ch
db %01110010,%01000110 ;C code 27h ;72h,46h
db %11010110,%11011100 ;D code 29h ;0d6h,0dch
db %01110011,%11000110 ;E code 2bh ;73h,0c6h
db %01110011,%01001001 ;F code 2dh ;73h,49h
db %00100100 ;I code 2eh * ;49h,24h
db %01110010,%01010110 ;G code 30h ;72h,56h
db %11010100 ;O code 31h * ;56h,0d4h
db %10110111,%11011010 ;H code 33h ;0b7h,0dah
db %10110110,%11101001 ;V code 35h ;0b6h,0e9h
db %00100100 ;T code 36h * ;0e9h,24h
db %11100100,%11011100 ;J code 38h ;0e4h,0dch
db %10110111,%01011010 ;K code 3ah ;0b7h,5ah
db %10010010,%01001110 ;L code 3ch ;92h,4eh
db %10111111,%11011010 ;M code 3eh ;0bfh,0dah
db %11010111,%01001000 ;P code 40h ;0d7h,48h
db %01010110,%11010111 ;Q code 42h ;56h,0d7h
db %01011010 ;R code 43h * ;0d7h,5ah
db %01110001,%00011100 ;S code 45h ;71h,1ch
db %10110110,%11010100 ;U code 47h ;0b6h,0d4h
db %10110111,%11111010 ;W code 49h ;0b7h,0fah
db %10110101,%01011010 ;X code 4bh ;0b5h,5ah
db %10110101,%00100100 ;Y code 4dh ;0b5h,24h
db %11100101,%01001110 ;Z code 4fh ;0e5h,4eh
db %11010110,%11010110 ;0 code 51h ;0d6h,0d6h
db %11011010 ;N code 52h * ;0d6h,0dah
db %01011001,%00101110 ;1 code 54h ;59h,2eh
db %11000101,%01001110 ;2 code 56h ;0c5h,4eh
db %11000101,%10011100 ;3 code 58h ;0c5h,9ch
db %10010010,%11110011 ;4 code 5ah ;92h,0f3h
db %00011100 ;5 code 5bh * ;0f3h,1ch
db %11100100,%10100100 ;7 code 5dh ;0e4h,0a4h
db %01010011,%01010101 ;6 code 5fh ;0e3h,55h
db %01010101 ;8 code 60h * ;55h,55h
db %10010100 ;9 code 61h * ;55h,9ch
db %00000000,%00000000 ;spc cd 63h ;00h,00h
example_message:
db 23h,25h,27h,29h,2bh,2dh,30h,33h,2eh,38h,3ah,3ch,3eh,52h,31h,40h,42h,43h,45h,36h,47h,35h,49h,4bh,4dh,4fh,51h,54h,56h,58h,5ah,5bh,5fh,5dh,60h,61h,63h,0ffh
message_2:
db 33h,2eh,63h,36h,31h,63h,23h,3ch,3ch,63h,23h,36h,63h,45h,40h,2bh,27h,36h,43h,47h,3eh,63h,27h,31h,3eh,40h,47h,36h,2eh,52h,30h,63h,0ffh
Re: Compact 64 column print routine
I love it when you get your teeth into a project
Robin Verhagen-Guest
SevenFFF / Threetwosevensixseven / colonel32
NXtel • NXTP • ESP Update • ESP Reset • CSpect Plugins
SevenFFF / Threetwosevensixseven / colonel32
NXtel • NXTP • ESP Update • ESP Reset • CSpect Plugins
Re: Compact 64 column print routine
It is compact code porn.
Re: Compact 64 column print routine
Not that I have anything useful to say, but I do want to join the choir of appreciation. This is a piece of art.
Re: Compact 64 column print routine
(Sorry, I should've replied to this sooner but I've been sick the last few days.)
99 bytes, now that's impressive! My first attempt at a text routine was 89 bytes for the code alone! At first I couldn't figure out how you were getting five graphic rows from two bytes but then I realised that you're only shifting three bits at a time into A, that's quite clever. I take it that the routine doesn't work properly if the screen isn't blank? Probably not a major problem. And it's a shame that lowercase letters are gone, but at 100 bytes you can't really complain
About the size issue, perhaps the last part that increments the screen pointer could be made smaller somehow? Maybe changing the routine to print the string backwards and using a counter, say in A', instead of the 'end of string' marker would simplify it a bit? Then you could use (initial screen position) + counter/2 to get the screen position of the next character. I don't know if this would make the routine any smaller though.
How did you decide on the character ordering so that adjacent font rows can be merged; was it just manual trial and error? I came up with an algorithm for the last version that got optimal or close to optimal results most of the time - for a small amount of characters. I don't think you could ensure the results were optimal without brute-forcing it, which would take far too long to compute if you had a lot of characters. The time can be reduced by only considering the characters with overlapping parts, so if there aren't many, it might be a feasible solution.
For this version of the code, it doesn't look like you could get much more optimal than this, since each character is only 2 bytes.
Although I just remembered that changing the character set from the default won't work too well if it needs to be used with key redefine or keyboard input routines, since it'll require a 40 byte table mapping the keys to the new character values. And if lower case letters are needed then that's another 26 bytes for an uppercase->lowercase table. Still, there's always RST 16 if you're really desperate.
99 bytes, now that's impressive! My first attempt at a text routine was 89 bytes for the code alone! At first I couldn't figure out how you were getting five graphic rows from two bytes but then I realised that you're only shifting three bits at a time into A, that's quite clever. I take it that the routine doesn't work properly if the screen isn't blank? Probably not a major problem. And it's a shame that lowercase letters are gone, but at 100 bytes you can't really complain
About the size issue, perhaps the last part that increments the screen pointer could be made smaller somehow? Maybe changing the routine to print the string backwards and using a counter, say in A', instead of the 'end of string' marker would simplify it a bit? Then you could use (initial screen position) + counter/2 to get the screen position of the next character. I don't know if this would make the routine any smaller though.
How did you decide on the character ordering so that adjacent font rows can be merged; was it just manual trial and error? I came up with an algorithm for the last version that got optimal or close to optimal results most of the time - for a small amount of characters. I don't think you could ensure the results were optimal without brute-forcing it, which would take far too long to compute if you had a lot of characters. The time can be reduced by only considering the characters with overlapping parts, so if there aren't many, it might be a feasible solution.
For this version of the code, it doesn't look like you could get much more optimal than this, since each character is only 2 bytes.
Although I just remembered that changing the character set from the default won't work too well if it needs to be used with key redefine or keyboard input routines, since it'll require a 40 byte table mapping the keys to the new character values. And if lower case letters are needed then that's another 26 bytes for an uppercase->lowercase table. Still, there's always RST 16 if you're really desperate.
- arkannoyed
- Manic Miner
- Posts: 438
- Joined: Mon Feb 05, 2018 9:56 am
- Location: Northamptonshire
Re: Compact 64 column print routine
Many different methods were tried before I decided to go with the 15 bit (2 byte) data format. Even now, I'm mortified that it wastes a whole BIT per character, though in a few instances, its worked to my advantage, where that trailing unused BIT can be any value in order to allow if to be shared as the first byte of the next Character.
I've tried all sorts to get the screen address to increment. In the previous routine I did, It does an SRL L to effectively /2, but that only leaves it possible to print on the upper 4 lines of each screen 3rd, maybe ok in some cases, but for the sake of 2 bytes, I thought it better to give full access to the screen area.
I have 2 further formats to try out, and though the actual routine will be a bit larger, hopefully a few more bytes might get shaved off.
The reason I use an end marker in the text string is the avoid having to specify the length before the routine is called. At the moment, with an initial address of BC (message) given, we only need specify the new screen address in DE before each CALL to the print routine. If we were to put a few extra decoding bytes in the routine, its possible to make the string contain the screen address too, with separate line end and message end markers.
The advantage of trying out these encoding methods on a minimal character set is that it can be done quicker to test.
I do intend to do a full CHR set with lower case and all the other characters. Maybe not the full 96 characters, but perhaps 75-80-ish.
When it became apparent that sub 100 bytes was possible, it became a sort of crusade to achieve it with the 37 characters needed for most text.
I also have a bit based format that if I can get the CHR data to sub 32 bytes (half its current size), 32 bytes=256 bits, then if the routine allows, we might go sub 90 bytes.
I've tried all sorts to get the screen address to increment. In the previous routine I did, It does an SRL L to effectively /2, but that only leaves it possible to print on the upper 4 lines of each screen 3rd, maybe ok in some cases, but for the sake of 2 bytes, I thought it better to give full access to the screen area.
I have 2 further formats to try out, and though the actual routine will be a bit larger, hopefully a few more bytes might get shaved off.
The reason I use an end marker in the text string is the avoid having to specify the length before the routine is called. At the moment, with an initial address of BC (message) given, we only need specify the new screen address in DE before each CALL to the print routine. If we were to put a few extra decoding bytes in the routine, its possible to make the string contain the screen address too, with separate line end and message end markers.
The advantage of trying out these encoding methods on a minimal character set is that it can be done quicker to test.
I do intend to do a full CHR set with lower case and all the other characters. Maybe not the full 96 characters, but perhaps 75-80-ish.
When it became apparent that sub 100 bytes was possible, it became a sort of crusade to achieve it with the 37 characters needed for most text.
I also have a bit based format that if I can get the CHR data to sub 32 bytes (half its current size), 32 bytes=256 bits, then if the routine allows, we might go sub 90 bytes.
Re: Compact 64 column print routine
Soooo... how many bytes in the print routine code are actually usable as character data?
- arkannoyed
- Manic Miner
- Posts: 438
- Joined: Mon Feb 05, 2018 9:56 am
- Location: Northamptonshire
Re: Compact 64 column print routine
Believe me, I've looked at that soooooooo many times!
There might be possibly one or two characters if the code structure would allow, but its very tricky!
New format currently underway. The routine looks like maybe 36-37 bytes, and the data maybe 62, so perhaps smaller!!
There might be possibly one or two characters if the code structure would allow, but its very tricky!
New format currently underway. The routine looks like maybe 36-37 bytes, and the data maybe 62, so perhaps smaller!!
- Einar Saukas
- Bugaboo
- Posts: 3167
- Joined: Wed Nov 15, 2017 2:48 pm
Re: Compact 64 column print routine
Instead of this:
Perhaps you can use this:
Except you will need to swap the order you are storing each pair of bytes, or store everything backwards.
Code: Select all
ld a,(bc)
ld l,a
add a,a
ret c
ld h,0fah
push de
ld a,(hl)
inc l
ld l,(hl)
ld h,a
Code: Select all
ld a,(bc)
ld (label+1),a
add a,a
ret c
push de
label:
ld hl,(0fa00h)
- arkannoyed
- Manic Miner
- Posts: 438
- Joined: Mon Feb 05, 2018 9:56 am
- Location: Northamptonshire
Re: Compact 64 column print routine
Oh yes! Very good Mr S!!
Theres a bit more to it than just swapping the Hi/Lo byte order, as some rely upon shared bytes, however I will re-align them all to save a byte!!
Thankyou!!
Theres a bit more to it than just swapping the Hi/Lo byte order, as some rely upon shared bytes, however I will re-align them all to save a byte!!
Thankyou!!
- arkannoyed
- Manic Miner
- Posts: 438
- Joined: Mon Feb 05, 2018 9:56 am
- Location: Northamptonshire
Re: Compact 64 column print routine
With Einars clever self modifying trick, and by hiding the 'E' character in the routine to make the jump vector at the end the value of 'DCh', therefore sharing the D Character first byte with the jump at the end, I've saved 2 more bytes.
Now down to 97 bytes!
I'll see if I can lose any more bytes!
Now down to 97 bytes!
Code: Select all
;15 bit 64 column format
;
;super compact 5 byte high characters
;
;DE holds screen address
;BC is message address
;End of Message byte is any value with BIT 7 set
;message must be an even number of characters long (padded with space if reqd.)
;Call routine at 0FA00h (64000d)
;
;99 bytes if we include the trailing 00h,00h (space CHR)
;97 bytes otherwise
;
;Characters A-Z...0-9..spc.
;
;Arkannoyed March 2018
;
;Special Thanks to Einar!
org 0f9fah
ld bc,example_message
ld de,4300h
start:
ld a,(bc)
ld (get_bytes+1),a
inc bc
add a,a
ret c
push de
get_bytes:
ld hl,(0fa00h)
lp0:
ld a,(de)
or 10h
add a,a
lp1:
add hl,hl
rla
jr nc,lp1
ld (de),a
inc d
ld a,d
and 07h
jr nz,lp0
pop de
ld a,c
and 01h
add a,e
ld e,a
;db %11000110,%01110011 ;E code 20h ;0c6h,73h
add a,73h ;code for CHR E ..doesn't affect anything being here.
db 18h ;jr start vector DCh which is the first byte of CHR D
db %11011100,%11010110 ;D code 23h ;0dch,0d6h
db %11011010,%01010111 ;A code 25h ;0dah,57h
db %01011100,%11010111 ;B code 27h ;5ch,0d7h
db %01000110,%01110010 ;C code 29h ;46h,72h
db %00100100,%01001001 ;I code 2bh * ;24h,49h
db %01110011 ;F code 2ch ;49h,73h
db %11010100,%01010110 ;O code 2eh * ;0d4h,56h
db %01110010 ;G code 2fh ;56h,72h
db %11011010,%10110111 ;H code 31h ;0dah,0b7h
db %00100100,%11101001 ;T code 33h * ;24h,0e9h
db %10110110 ;V code 34h ;0e9h,0b6h
db %11011100,%11100100 ;J code 36h ;0dch,0e4h
db %01011010,%10110111 ;K code 38h ;5ah,0b7h
db %01001110,%10010010 ;L code 3ah ;4eh,92h
db %11011010,%10111111 ;M code 3ch ;0dah,0bfh
db %01001000,%11010111 ;P code 3eh ;48h,0d7h
db %01011010,%11010111 ;R code 40h * ;5ah,0d7h
db %01010110 ;Q code 41h ;0d7h,56h
db %00011100,%01110001 ;S code 43h ;1ch,71h
db %11010100,%10110110 ;U code 45h ;0d4h,0b6h
db %11111010,%10110111 ;W code 47h ;0fah,0b7h
db %01011010,%10110101 ;X code 49h ;5ah,0b5h
db %00100100,%10110101 ;Y code 4bh ;24h,0b5h
db %01001110,%11100101 ;Z code 4dh ;4eh,0e5h
db %11011010,%11010110 ;N code 4fh * ;0dah,0d6h
db %11010110 ;0 code 50h ;0d6h,0d6h
db %00101110,%01011001 ;1 code 52h ;2eh,59h
db %01001110,%11000101 ;2 code 54h ;4eh,0c5h
db %10011100,%11000101 ;3 code 56h ;9ch,0c5h
db %00011100,%11110011 ;5 code 58h * ;1ch,0f3h
db %10010010 ;4 code 59h ;0f3h,92h
db %10100100,%11100100 ;7 code 5bh ;0a4h,0e4h
db %10010100,%01010101 ;9 code 5dh * ;9ch,55h
db %01010101 ;8 code 5eh * ;55h,55h
db %01010011 ;6 code 5fh * ;55h,53h
db %00000000,%00000000 ;spc cd 61h ;00h,00h
example_message:
db 25h,27h,29h,23h,20h,2ch,2fh,31h,2bh,36h,38h,3ah,3ch,4fh,2eh,3eh,41h,40h,43h,33h,45h,34h,47h,49h,4bh,4dh,50h,52h,54h,56h,59h,58h,5fh,5bh,5eh,5dh,61h,0ffh