[TI ASM] Optimizations
Moderator: MaxCoderz Staff
- benryves
- Maxcoderz Staff
- Posts: 3089
- Joined: Thu 16 Dec, 2004 10:06 pm
- Location: Croydon, England
- Contact:
ex hl,de is not defined in TASM80.tab (it's defined as ex de,hl). You need to add it yourself or define it in your program.
Another pitfall is that ex de,hl does not just copy one register to another - the ex instruction exchanges the values, so what was in de is now in hl and what was in hl is now in de. You can use the ex instruction to exchange registers between the two register files, or use exx to exchange all the registers through the register files to their shadow pair (useful for interrupts).
Oh, and when multiplying by powers of two, add a,a is faster than the equivalent shift operation (IIRC).
Another pitfall is that ex de,hl does not just copy one register to another - the ex instruction exchanges the values, so what was in de is now in hl and what was in hl is now in de. You can use the ex instruction to exchange registers between the two register files, or use exx to exchange all the registers through the register files to their shadow pair (useful for interrupts).
Oh, and when multiplying by powers of two, add a,a is faster than the equivalent shift operation (IIRC).
-
- Extreme Poster
- Posts: 479
- Joined: Fri 17 Dec, 2004 11:09 pm
- Contact:
i learned optimization tricks from this:
http://www.ticalc.org/archives/files/fi ... 28502.html
It has size optimization and time optimization techniques
http://www.ticalc.org/archives/files/fi ... 28502.html
It has size optimization and time optimization techniques
-
- Calc Wizard
- Posts: 680
- Joined: Wed 22 Dec, 2004 5:37 am
- Location: West Palm Beach,FL
- Contact:
Thats a rather thorough guide. I'll have to read it. Seeing that its in a zip file and the online version is not working, I might as well upload it to the web.
http://hostingproject.info/lloydkirk1989/z80optim.html
http://hostingproject.info/lloydkirk1989/z80optim.html
- Jim e
- Calc King
- Posts: 2457
- Joined: Sun 26 Dec, 2004 5:27 am
- Location: SXIOPO = Infinite lives for both players
- Contact:
I don't know about that guide, i went through it, and alot seem fine enough but there were mistakes and code not fully optimised(just a little). But one thing did get to me was this
This in't a very good method for a call table, situation is far to specific to be considered useful.
LDDing the table to the stack would be better and safer, it would at least allow for use of calls and pushes.
Any way heres one I remembered.
That can be used for other things, but it's good for fastcopy routines and mappers.
There is just so many problems with this. First off, it rare that you would have code set up in such a way that you could list many values and calls so linearly. Second his use of the stack is a bad one, it renders use of bcalls, calls, pushes and pops all useless.Whenever you need to call subroutines, you might consider using:
ld HL,param1
call sub1
ld HL,param2
call sub2
ld HL,param3
call sub1
...
sub1:
...
ret
sub2:
...
ret
This is the conventional way to do this. However, there is a much more efficient way to do this using what's known as call tables. Here's how they work:
ld SP,callTable
ret ; Jump to sub1
sub1:
pop HL
...
ret
sub2:
pop HL
...
ret
callTable:
.dw sub1,param1
.dw sub2,param2
.dw sub1,param3
In the first line, callTable is stored into the Stack Pointer (SP). Please note that altering the Stack Pointer can be potentially damaging. You'll probably want to save the contents of SP before using a call table. If used properly, call tables will prove to be very efficient. It is, as you can see, a very complex way of calling routines. And in fact, they don't always make your programs more efficient. Generally, you will only want to use call tables when you are passing a different parameters to several consecutive subroutines.
This in't a very good method for a call table, situation is far to specific to be considered useful.
LDDing the table to the stack would be better and safer, it would at least allow for use of calls and pushes.
Any way heres one I remembered.
Code: Select all
;Instead of
ld de,-767
add hl,de
;try this
dec h ; -256
dec h ; -512
dec h ; -768
inc hl ; -767
-
- MCF Legend
- Posts: 1601
- Joined: Mon 20 Dec, 2004 8:45 am
- Location: Budapest, Absurdistan
- Contact:
But such 'tricks' are definitely discouraged if you intend to distribute your source.benryves wrote:ex hl,de is not defined in TASM80.tab (it's defined as ex de,hl). You need to add it yourself or define it in your program.
There are other strange things on the page Jim linked, e. g. the section about case insensitivity also contains serious errors.
- benryves
- Maxcoderz Staff
- Posts: 3089
- Joined: Thu 16 Dec, 2004 10:06 pm
- Location: Croydon, England
- Contact:
I think there is a directive that means you can add new "instructions" to TASM's database when compiling from the current source file. But yes, it is messy and far better to stick to the ex de,hl that is more usually accepted.CoBB wrote:But such 'tricks' are definitely discouraged if you intend to distribute your source.benryves wrote:ex hl,de is not defined in TASM80.tab (it's defined as ex de,hl). You need to add it yourself or define it in your program.
I always liked stack tricks... Such as this:
Not a speed optimization, but it eliminates 2-byte pointers, since it just uses the call's return address.
It also heavily distrubs disassembly.
Code: Select all
call Disp
.db "This is some text",0
ret
Disp:
pop hl
bcall(_vputs)
jp (hl)
It also heavily distrubs disassembly.
You know your hexadecimal output routine is broken when it displays the character 'G'.
-
- Extreme Poster
- Posts: 479
- Joined: Fri 17 Dec, 2004 11:09 pm
- Contact:
That's awesomeDwedit wrote:I always liked stack tricks... Such as this:Not a speed optimization, but it eliminates 2-byte pointers, since it just uses the call's return address.Code: Select all
call Disp .db "This is some text",0 ret Disp: pop hl bcall(_vputs) jp (hl)
It also heavily distrubs disassembly.
[Gridwars Score] - E: 1860037 M: 716641 H: 261194
-
- Regular Member
- Posts: 86
- Joined: Fri 17 Dec, 2004 8:20 pm
- Contact:
Another good "article" about optimization is http://www.ticalc.org/pub/text/z80/z80opt.zip
It takes the examples and explanations further than most other articles.
It takes the examples and explanations further than most other articles.
If you want a 16-bit loop counter, never, ever do this:
Do this instead:
More info: http://map.tni.nl/articles/fast_loops.php
Code: Select all
- ; Loop body
; .
; .
; .
ld a, d
or e
jp nz, -
Code: Select all
dec de
ld b, e
inc b
inc d
- ; Loop body
; .
; .
; .
djnz -
dec d
jp nz, -
-
- Regular Member
- Posts: 86
- Joined: Fri 17 Dec, 2004 8:20 pm
- Contact:
If you want to add A to any 2-byte register and can't destroy any other registers besides A:
Code: Select all
add a,l
ld l,a
adc a,h
sub l
ld h,a
Expanding on Dwedit's trick, I created a macro system for Bot Attack.
Using it, I changed
into
This greatly reduced the size of my title screen, and would have reduced the size much more had I not already been using a routine for size reduction.
For those who do not see it already, the main difference with this routine is that it defines coordinates as in-line variables along with the string which is displayed. Again, this is good for title screens where there are constant coordinates for text.
Using it, I changed
Code: Select all
ld hl,0
ld (currow),hl
ld hl,title ; Draw title text
bcall(_puts)
ld bc,(0*256)+55
ld de,(94*256)+55
bcall(_darkline) ; Underline title text
ld de,1+(256*9)
ld hl,txt_author ; Draw author's name... ;-)
call cur_vputs
ld de,4+(256*18)
ld hl,txt_start ; Draw "2nd - Start"
call cur_vputs
ld de,4+(256*25)
ld hl,txt_size ; Draw "(/,*,-,+) - Area:"
call cur_vputs
ld de,4+(256*32)
ld hl,txt_bots ; Draw "(LEFT/RIGHT) - # of bots:"
call cur_vputs
ld de,4+(256*39)
ld hl,txt_quit ; Draw "Clear - Exit"
call cur_vputs
...
;-----> Optimized vput routine
; inputs: de=coordinates
; hl=pointer to string
; output: String displayed, smaller than using redundant code
cur_vputs:
ld (pencol),de
bcall(_vputs)
ret
Code: Select all
#define curVPutS(curPos) call cur_vputs \ .dw curPos
...
ld hl,0
ld (currow),hl
ld hl,title ; Draw title text
bcall(_puts)
ld bc,(0*256)+55
ld de,(94*256)+55
bcall(_darkline) ; Underline title text
curVPutS(1+(256*9)) ; Draw author's name... ;-)
.db "by Peter Wakefield",0
curVPutS(4+(256*18)) ; Draw "2nd - Start"
.db "2nd - Start",0
curVPutS(4+(256*25)) ; Draw "(/,*,-,+) - Area:"
.db "(/,*,-,+) - Area: ",0
curVPutS(4+(256*32)) ; Draw "(LEFT/RIGHT) - # of bots:"
.db $CF,"/",$05," - # of bots: ",0
curVPutS(4+(256*39)) ; Draw "Clear - Exit"
.db "Clear - Exit",0
...
;-----> Optimized vputs routine
; inputs: bytes following call: CoordLSB,CoordMSB,Null-terminated string
; output: String displayed, smaller than using redundant code
cur_vputs:
pop hl
ld e,(hl)
inc hl
ld d,(hl)
inc hl
ld (pencol),de
bcall(_vputs)
jp (hl)
For those who do not see it already, the main difference with this routine is that it defines coordinates as in-line variables along with the string which is displayed. Again, this is good for title screens where there are constant coordinates for text.
Long live Z80 and #tiasm!
^^ Alas, I wrote that a long time ago.
^^ Alas, I wrote that a long time ago.