; ------------------------------------- ; Z80 native Virtual Machine ; (c) 2015 - 2017 kio@little-bat.de ; ------------------------------------- ; Z80 Registers: ; ; AF used ; BC used ; DE VM vstack TOP value (last argument or return value) ; HL VM vstack SOT value (2nd-last argument or high word of 32 bit value) ; ; AF' … HL' unused (available for interrupt) ; ; IX ; IY ; SP only one stack: z80, vstack, rstack ; PC program address counter Der Compiler erzeugt Snippets, z.B. für Variablenzugriff oder Operatoren. Diese gehen davon aus, dass alle Argumente auf dem Stack liegen. Die Übernahme in Register ist stark formalisiert, so dass bei Optimieren möglichst alle push/pop-Paare entfernt werden können: DE = 1st (top value) HL = 2nd BC = 3rd Snippets bestehen aus einer Implementierung und erzeugen als Code pop_x, call_x und push_x, wobei push_x und pop_x des folgenden Snippets sich möglichst wieder wegoptimieren. Die häufigsten Snippets verwenden RST statt CALL. 7 code snippets können als RST aufgerufen werden: ––––––––––––––––––––––––––––––––––––––––––––––––– Immediate Values: ––––––––––––––––– Der ersetzbare Code ist immer so kurz, dass das nicht lohnt: IVAL ld de,NN 3 bytes push de Signed Byte: –––––––––––– Grundsätzlich keine Optimierung für s8 Globale Variablen: –––––––––––––––––– Globale Variablen werden eher selten referenziert, es sei denn, zur Geschwindigkeitsoptimierung. Gerade dann ist aber das Verkürzen über einen RST unerwünscht. Setter sind seltener als Getter. GVAR ld de,NN 3 bytes push de GGET ld de,(NN) 4 bytes push de GSET pop de ld (NN),de 4 bytes GGETu8 ld a,(NN) 6 bytes KANDIDAT ld e,a ld d,0 push de GSET8 pop de ld a,e 4 bytes ld (NN),a Lokale Variablen: ––––––––––––––––– Lokale Variablen werden häufig angesprochen. Außerdem ist der Code dazu meist recht lang. LVAR ld hl,OFFS 4 bytes add hl,sp push hl !! oder ex_hl_de + push_de LGET ld hl,OFFS 7 bytes add hl,sp ld e,(hl++) ld d,(hl) push de ; mit frame pointer: ld e,(IX+OFFS) 6 ld d,(IX+OFFS+1) push de LGETu8 ld hl,OFFS 6 bytes ld d,h ; 0 add hl,sp ld e,(hl) push de ; mit frame pointer: ld e,(IX+OFFS) 5 ld d,0 !! könnte wegoptimierbar sein push de LSET pop de ld hl,OFFS 7 bytes add hl,sp ld (hl++),e ld (hl),d ; mit frame pointer: pop de ld (IX+OFFS),e 6 ld (IX+OFFS+1),d LSETu8 pop de ld hl,OFFS 5 add hl,sp ld (hl),e ; mit frame pointer: pop de ld (IX+OFFS),e 3 Items in Structs: ––––––––––––––––– IVAR pop hl !! oder pop_de + ex_hl_de ld e,(hl++) 7 bytes ld d,(hl) ld hl,OFFS add hl,de push hl !! oder ex_hl_de + push_de IGET pop hl !! oder pop_de + ex_hl_de ld e,(hl++) 10 bytes ld d,(hl) ld hl,OFFS add hl,de ld e,(hl++) ld d,(hl) push de IGETu8 pop hl !! oder pop_de + ex_hl_de ld e,(hl++) 10 bytes ld d,(hl) ld hl,OFFS add hl,de ld e,(hl) ld d,0 push de ISET pop hl struct addr !! oder pop_de + pop_hl + ex_hl_de pop de value !! ld c,(hl++) ld b,(hl) ld hl,OFFS add hl,bc ld (hl++),e ld (hl),d ISET8 pop hl struct addr !! oder pop_de + pop_hl + ex_hl_de pop de value !! ld c,(hl++) ld b,(hl) ld hl,OFFS add hl,bc ld (hl),e AB HIER NOCH ALT Items in Arrays: –––––––––––––––– Eignet sich grundsätzlich gut für Unterprogramme (auch CALL statt RST), da keine Direktparameter. ATI pop hl 6+1+1 ld a,(hl++) ld h,(hl) ld l,a ; hl -> array add hl,de ; add hl,de ; hl -> word ex hl,de ATI8 pop hl 5+1+1 ld a,(hl++) ld h,(hl) ld l,a ; hl -> array add hl,de ; hl -> byte ex hl,de ATIGET pop hl 9+1 beginnt mit ATI (ohne finales ex) ld a,(hl++) ld h,(hl) ld l,a ; hl -> array add hl,de ; add hl,de ; hl -> word ld e,(hl++) ld d,(hl) ATIGETu8 pop hl 8+1 beginnt mit ATI8 (ohne finales ex) ld a,(hl++) ld h,(hl) ld l,a ; hl -> array add hl,de ; hl -> word ld e,(hl) ld d,0 ATISET pop hl 10+1+1 beginnt mit ATI (ohne finales ex) ld a,(hl++) ld h,(hl) ld l,a ; hl -> array add hl,de ; add hl,de ; hl -> word pop de ld (hl++),e ld (hl),d pop de ATISET8 pop hl 7+1+1 beginnt mit ATI (ohne finales ex) ld a,(hl++) ld h,(hl) ld l,a ; hl -> array add hl,de ; hl -> word pop de ld (hl),e pop de Combinations of LGET + IGET ––––––––––––––––––––––––––– Die könnten häufig vorkommen, wenn 'strukturiert' programmiert wird. Sie sind auf jeden Fall zu lang für RST. Und es müssen 2 Direktparameter eingeschleift werden. LGETIGET push de 18+1 begins with LGET ld hl,LOFFS could be reduced to 5 or 6 (CALL) or 3+1 (RST) bytes add hl,sp ld e,(hl++) ld d,(hl) ex hl,de ld e,(hl++) ld d,(hl) ld hl,IOFFS add hl,de ld e,(hl++) ld d,(hl) LGETIGETu8 push de 18+1 begins with LGET ld hl,LOFFS can be reduced to 5 or 6 (CALL) or 3+1 (RST) bytes add hl,sp ld e,(hl++) ld d,(hl) ex hl,de ld e,(hl++) ld d,(hl) ld hl,IOFFS add hl,de ld e,(hl) ld d,0 Combinations of LVAR + ATIGET ––––––––––––––––––––––––––––– Die könnten häufig vorkommen, wenn 'strukturiert' programmiert wird, wenn auch nicht ganz so häufig wie Kombinationen mit IGET.